diff --git a/TSI_Config.pro b/TSI_Config.pro index 642c3b5..319c72a 100644 --- a/TSI_Config.pro +++ b/TSI_Config.pro @@ -19,6 +19,7 @@ SOURCES += \ keyphase_data.cpp \ main.cpp \ mainwindow.cpp \ + pointname.cpp \ radial_vibration.cpp \ rangeslider.cpp \ relaysetting.cpp \ @@ -47,6 +48,7 @@ HEADERS += \ keyphase.h \ keyphase_data.h \ mainwindow.h \ + pointname.h \ radial_vibration.h \ rangeslider.h \ relaysetting.h \ @@ -68,6 +70,7 @@ FORMS += \ connect.ui \ keyphase.ui \ mainwindow.ui \ + pointname.ui \ radial_vibration.ui \ relaysetting.ui \ seismic_monitor.ui \ diff --git a/config_mgr.cpp b/config_mgr.cpp index 0836337..6720be5 100644 --- a/config_mgr.cpp +++ b/config_mgr.cpp @@ -273,26 +273,42 @@ void ConfigMgr::Save(QString & file_path) { } slot_item["version"] = 1; }else{ - QJsonObject channel_item; for(int ch = 0;ch < RELAY_COUNT;++ch){ + QJsonObject channel_item; if(card_type_[i] == kCardRelaySingleNOK){ std::shared_ptr base_ptr = ConfigMgr::Instance()->GetSlotPtr(slot); if (base_ptr == nullptr) { continue; } std::shared_ptr ptr = std::dynamic_pointer_cast(base_ptr); - channel_item.insert("logic_expression", ptr->single_relay_nok[ch].logic_expression); + if(ptr->single_relay_nok[ch].logic_expression != ""){ + qDebug() << "ch" << ch << ptr->single_relay_nok[ch].logic_expression; + channel_item.insert("logic_expression", ptr->single_relay_nok[ch].logic_expression); + } - }else if(card_type_[i] == kCardRelaySingle || card_type_[i] == kCardRelayTMRPrimary){ + }else if(card_type_[i] == kCardRelaySingle){ std::shared_ptr base_ptr = ConfigMgr::Instance()->GetSlotPtr(slot); if (base_ptr == nullptr) { continue; } std::shared_ptr ptr = std::dynamic_pointer_cast(base_ptr); - channel_item.insert("logic_expression", ptr->tmr_relay[ch].logic_expression); - channel_item.insert("sgcc_enable", ptr->tmr_relay[ch].sgcc_enable); + if(ptr->tmr_relay[ch].logic_expression != "") + channel_item.insert("logic_expression", ptr->tmr_relay[ch].logic_expression); + }else if(card_type_[i] == kCardRelayTMRPrimary){ + std::shared_ptr base_ptr = ConfigMgr::Instance()->GetSlotPtr(slot); + if (base_ptr == nullptr) { + continue; + } + std::shared_ptr ptr = std::dynamic_pointer_cast(base_ptr); + if(ptr->tmr_relay[ch].logic_expression != "" && !ptr->tmr_relay[ch].sgcc_enable){ + channel_item.insert("logic_expression", ptr->tmr_relay[ch].logic_expression); + channel_item.insert("sgcc_enable", ptr->tmr_relay[ch].sgcc_enable); + }else if(ptr->tmr_relay[ch].logic_expression == "" && ptr->tmr_relay[ch].sgcc_enable){ + channel_item.insert("sgcc_enable", ptr->tmr_relay[ch].sgcc_enable); + } } - slot_item[QString::number(ch + 1)] = channel_item; + if(!channel_item.isEmpty()) + slot_item[QString::number(ch + 1)] = channel_item; } slot_item["version"] = 1; } @@ -555,7 +571,17 @@ void ConfigMgr::Load(QString filename) { singlerelay_data->single_relay_nok[j].logic_expression = channel["logic_expression"].toString(); } cards_.push_back(singlerelay_data); - }else if(card_type_[i] == kCardRelayTMRPrimary || card_type_[i] == kCardRelaySingle){ + }else if(card_type_[i] == kCardRelaySingle){ + std::shared_ptr relay_data = std::make_shared(); + relay_data->slot_ = slot; + relay_data->card_type_ = static_cast(card_type_[i]); + relay_data->version_ = temp_obj["version"].toInt(); + for (int j = 0; j < RELAY_COUNT; ++j) { + channel = temp_obj[QString::number(j + 1)].toObject(); + relay_data->tmr_relay[j].logic_expression = channel["logic_expression"].toString(); + } + cards_.push_back(relay_data); + }else if(card_type_[i] == kCardRelayTMRPrimary){ std::shared_ptr relay_data = std::make_shared(); relay_data->slot_ = slot; relay_data->card_type_ = static_cast(card_type_[i]); diff --git a/data_config.h b/data_config.h index b284173..7089351 100644 --- a/data_config.h +++ b/data_config.h @@ -103,7 +103,7 @@ typedef enum { typedef struct { int id; -// QString channel_name; + QString point_name; bool standby; bool active; int rack_type; // VibRackType @@ -357,6 +357,7 @@ typedef struct { uint8_t ethn; // 0: eth0, 1: eth1 char ip[16]; char netmask[16]; + char gw[16]; } ConfigIPv4Req; // 配置IP的响应结构为CommonRsp diff --git a/mainwindow.cpp b/mainwindow.cpp index 00ce3be..320dbb1 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -96,7 +96,7 @@ MainWindow::MainWindow(QWidget *parent) //connectServer(); // 设置自定义日志处理函数 #ifndef QT_DEBUG - qInstallMessageHandler(messageHandler); + //qInstallMessageHandler(messageHandler); #endif } @@ -246,6 +246,7 @@ void MainWindow::createMenu(const QString &rootTitle, QPushButton *parent) { QObject::connect(rpm_1, &QAction::triggered, this, &MainWindow::onMenuActionTriggered); QObject::connect(relays_1, &QAction::triggered, this, &MainWindow::onMenuActionTriggered); QObject::connect(relays_2, &QAction::triggered, this, &MainWindow::onMenuActionTriggered); + QObject::connect(relays_3, &QAction::triggered, this, &MainWindow::onMenuActionTriggered); QObject::connect(keyphasor_1, &QAction::triggered, this, &MainWindow::onMenuActionTriggered); QObject::connect(keyphasor_2, &QAction::triggered, this, &MainWindow::onMenuActionTriggered); QObject::connect(reset, &QAction::triggered, this, &MainWindow::onMenuActionTriggered); @@ -462,6 +463,12 @@ void MainWindow::OnButtonGroup(QAbstractButton *slot_btn) { key_phase->show(); break; } + case kCardSpeedSingle:{ + Tachometer *tachometer = new Tachometer(button_id,card_type); + tachometer->setWindowModality(Qt::ApplicationModal); + tachometer->show(); + break; + } case kCardRelaySingleNOK:{ SingleRelay *single_relay = new SingleRelay(button_id,card_type); single_relay->setWindowModality(Qt::ApplicationModal); diff --git a/mainwindow.ui b/mainwindow.ui index ac5106c..7dbd10a 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -50,7 +50,7 @@ - 20 + 80 20 45 45 @@ -75,7 +75,7 @@ - 80 + 20 20 45 45 diff --git a/seismic_monitor.cpp b/seismic_monitor.cpp index 10f5eab..1ed5f19 100644 --- a/seismic_monitor.cpp +++ b/seismic_monitor.cpp @@ -34,8 +34,6 @@ Seismic_monitor::Seismic_monitor(int slot,int cardtype, QWidget *parent) : car_type = static_cast(cardtype); QString slot_no_ = QString("%1").arg(slot_no); ui->label_slot_no->setText(slot_no_); -// QString filePath = QCoreApplication::applicationDirPath() + QString("\\config\\%1\\seismic_monitor_slot.json").arg(slot_no); -// readJsonFile(filePath); Init(); } @@ -43,71 +41,6 @@ Seismic_monitor::~Seismic_monitor() { delete ui; } -//void Seismic_monitor::readJsonFile(const QString &filePath) { -// // 创建文件对象 -// QFile file(filePath); -// if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { -// qDebug() << "Cannot open file for reading:" << filePath; -// return; -// } -// QString content = file.readAll(); -// file.close(); -// QByteArray jsonData = content.toUtf8(); -// QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData); -// if (jsonDoc.isNull()) { -// qDebug() << "Cannot parse JSON document"; -// return; -// } -// if (!jsonDoc.isObject() && !jsonDoc.isArray()) { -// qDebug() << "JSON document is not an object or an array"; -// return; -// } -// QJsonObject json_obj = jsonDoc.object(); -// card_type = json_obj["card_type"].toInt(); -// QJsonArray chan_array = json_obj["chan"].toArray(); -// for (int i = 0; i < chan_array.size(); i++) { -// QJsonObject temp_obj = chan_array[i].toObject(); -// seismic_monitor[i].id = temp_obj["id"].toInt(); -//// seismic_monitor[i].channel_name = temp_obj["channle_name"].toString(); -// seismic_monitor[i].standby = temp_obj["standby"].toBool(); -// seismic_monitor[i].active = temp_obj["active"].toBool(); -// seismic_monitor[i].rack_type = temp_obj["rack_type"].toInt(); -// seismic_monitor[i].tmr_group = temp_obj["tmr_group"].toString(); -// seismic_monitor[i].channel_type = temp_obj["channel_type"].toInt(); -// seismic_monitor[i].transducer_name = temp_obj["transducer_name"].toString(); -// seismic_monitor[i].scale_factor = temp_obj["scale_factor"].toDouble(); -// seismic_monitor[i].sampling_rate = temp_obj["sampling_rate"].toInt(); -// QJsonArray voltage_range_array = temp_obj["normal_voltage_range"].toArray(); -// seismic_monitor[i].normal_voltage_low = voltage_range_array[0].toDouble(); -// seismic_monitor[i].normal_voltage_high = voltage_range_array[1].toDouble(); -// } -// QFile file_transducer(QCoreApplication::applicationDirPath() + QString("\\config\\transducer.json")); -// if (!file_transducer.open(QIODevice::ReadOnly | QIODevice::Text)) { -// qDebug() << "Cannot open file for reading:" << filePath; -// return; -// } -// QString content_transducer = file_transducer.readAll(); -// file_transducer.close(); -// QByteArray jsonData2 = content_transducer.toUtf8(); -// QJsonDocument jsonDoc2 = QJsonDocument::fromJson(jsonData2); -// if (jsonDoc2.isNull()) { -// qDebug() << "Cannot parse JSON document"; -// return; -// } -// if (!jsonDoc2.isObject() && !jsonDoc2.isArray()) { -// qDebug() << "JSON document is not an object or an array"; -// return; -// } -// QJsonArray json_array = jsonDoc2.array(); -// for (int var = 0; var < json_array.size(); ++var) { -// Transducer transducer; -// QJsonObject temp_obj = json_array[var].toObject(); -// transducer.transducer_name = temp_obj["transducer_name"].toString(); -// transducer.scale_factor = temp_obj["scale_factor"].toDouble(); -// vec_transducer.push_back(transducer); -// } -//} - void Seismic_monitor::Init() { // for (int var = 0; var < vec_transducer.size(); ++var) { // ui->comboBox_transducer_name_1->addItem(vec_transducer[var].transducer_name); diff --git a/tmrrelayassociation.cpp b/tmrrelayassociation.cpp index 0044650..767c724 100644 --- a/tmrrelayassociation.cpp +++ b/tmrrelayassociation.cpp @@ -3,9 +3,7 @@ #include "vibrationdata.h" #include #include - - - +#include TMRRelayAssociation::TMRRelayAssociation(int slot,int cardtype,QWidget *parent) : QDialog(parent) @@ -14,6 +12,9 @@ TMRRelayAssociation::TMRRelayAssociation(int slot,int cardtype,QWidget *parent) ui->setupUi(this); slot_no = slot; car_type = static_cast(cardtype); + if(car_type == kCardRelaySingle){ + ui->checkBox_sgcc->setVisible(0); + } ui->label_slot_no->setText(QString::number(slot_no)); QVBoxLayout *layout_available = new QVBoxLayout(ui->widget_available); list_widget_available = new DraggableListWidget; @@ -54,9 +55,9 @@ TMRRelayAssociation::TMRRelayAssociation(int slot,int cardtype,QWidget *parent) this, &TMRRelayAssociation::onComboBoxIndexChanged); treeView_relay->setContextMenuPolicy(Qt::CustomContextMenu); connect(treeView_relay,&QTreeView::customContextMenuRequested,this,&TMRRelayAssociation::on_treeView_Relay_customContextMenuRequested); - - Init(); current_index = ui->comboBox_relay_ch->currentIndex(); + Init(); + // QString expr = "((S01C01A1 + S01C02A1 + (S02C01A1 * S02C01A2)) * (S02C01A2 + S02C01A1 + (S02C01A1 + S02C01A2)) * (S02C01A1 * S02C01A2))"; // setExpressionToTreeView(treeView_relay, expr); } @@ -104,6 +105,8 @@ void TMRRelayAssociation::Init(){ return; } relay_data = std::dynamic_pointer_cast(base_ptr); + qDebug() << "logic" <tmr_relay[current_index].logic_expression; + ui->checkBox_sgcc->setChecked(relay_data->tmr_relay[current_index].sgcc_enable); setExpressionToTreeView(treeView_relay, relay_data->tmr_relay[current_index].logic_expression); } @@ -268,6 +271,63 @@ QStandardItem* TMRRelayAssociation::parseExpression(const QString &expr) { // 返回栈顶的节点,应该是根节点 return stack.isEmpty() ? nullptr : stack.pop(); } + +ExprValidationResult TMRRelayAssociation::validateLogicExpression(const QString& expr) { + int bracketCount = 0; + bool lastWasOperator = true; + bool lastWasOpenParen = false; + + for (int i = 0; i < expr.length(); ++i) { + QChar ch = expr[i]; + + if (ch.isSpace()) continue; + + if (ch == '(') { + bracketCount++; + lastWasOpenParen = true; + lastWasOperator = true; + } else if (ch == ')') { + bracketCount--; + if (bracketCount < 0) { + return {false, i, "多余的右括号 ')'"}; + } + lastWasOpenParen = false; + lastWasOperator = false; + } else if (ch == '+' || ch == '*') { + if (lastWasOperator || lastWasOpenParen) { + return {false, i, QString("无效的运算符 '%1' 的位置").arg(ch)}; + } + lastWasOperator = true; + lastWasOpenParen = false; + } else if (ch.isLetterOrNumber()) { + QString token; + int start = i; + while (i < expr.length() && expr[i].isLetterOrNumber()) { + token += expr[i]; + ++i; + } + --i; // 修正多读了一位 + if (token.isEmpty()) { + return {false, start, "变量名称缺失"}; + } + lastWasOperator = false; + lastWasOpenParen = false; + } else { + return {false, i, QString("不支持的字符 '%1'").arg(ch)}; + } + } + + if (bracketCount != 0) { + return {false, expr.length(), "括号不匹配"}; + } + + if (lastWasOperator) { + return {false, expr.length() - 1, "表达式不能以运算符结尾"}; + } + + return {true, -1, ""}; +} + void TMRRelayAssociation::buildTreeFromExpression(QTreeView *treeView, const QString &expr) { QStandardItemModel* model = new QStandardItemModel(); QStandardItem* rootItem = parseExpression(expr); @@ -283,10 +343,20 @@ void TMRRelayAssociation::OnButtonGroup(QAbstractButton *slot_btn) { if (slot_btn != NULL) { list_widget_available->clear(); QString object_name = slot_btn->objectName(); - qDebug() << object_name ; + if(slot_btn->text().isEmpty()) + return; + qDebug() << object_name; int button_id = object_name.right(object_name.length() - 15).toInt(); std::shared_ptr base_ptr = ConfigMgr::Instance()->GetSlotPtr(button_id); std::shared_ptr ptr = std::dynamic_pointer_cast(base_ptr); + QString item_str = QString("*"); + QListWidgetItem *item_or = new QListWidgetItem("*"); + item_or->setData(Qt::UserRole, "*"); + list_widget_available->addItem(item_or); + + QListWidgetItem *item_and = new QListWidgetItem("+"); + item_and->setData(Qt::UserRole, "+"); + list_widget_available->addItem(item_and); for(int var = 0; var < CHANNEL_COUNT ; ++var){ if(ptr->alert_danger[var].direct_enable || ptr->alert_danger[var].x1_ampl_enable || @@ -304,17 +374,7 @@ void TMRRelayAssociation::OnButtonGroup(QAbstractButton *slot_btn) { item->setData(Qt::UserRole, item_data); list_widget_available->addItem(item); } - } - - QString item_str = QString("*"); - QListWidgetItem *item_or = new QListWidgetItem("*"); - item_or->setData(Qt::UserRole, "*"); - list_widget_available->addItem(item_or); - - QListWidgetItem *item_and = new QListWidgetItem("+"); - item_and->setData(Qt::UserRole, "+"); - list_widget_available->addItem(item_and); } } void TMRRelayAssociation::on_pushButton_cancel_clicked() @@ -338,6 +398,12 @@ void TMRRelayAssociation::on_pushButton_confirm_clicked() // } finalExpr += expr; } + ExprValidationResult result = validateLogicExpression(finalExpr); + if (!result.isValid && !finalExpr.isEmpty()) { + QMessageBox::warning(this, "表达式错误", + QString("错误位置:%1\n错误描述:%2").arg(result.errorPos).arg(result.errorMsg)); + return; + } relay_data->tmr_relay[current_index].logic_expression = finalExpr; relay_data->tmr_relay[current_index].sgcc_enable = ui->checkBox_sgcc->checkState(); qDebug() << "逻辑表达式:" << finalExpr; @@ -357,6 +423,12 @@ void TMRRelayAssociation::onComboBoxIndexChanged(int index){ // } finalExpr += expr; } + ExprValidationResult result = validateLogicExpression(finalExpr); + if (!result.isValid && !finalExpr.isEmpty()) { + QMessageBox::warning(this, "表达式错误", + QString("错误位置:%1\n错误描述:%2").arg(result.errorPos).arg(result.errorMsg)); + return; + } relay_data->tmr_relay[current_index].logic_expression = finalExpr; relay_data->tmr_relay[current_index].sgcc_enable = ui->checkBox_sgcc->checkState(); current_index = index; @@ -399,3 +471,36 @@ void TMRRelayAssociation::on_treeView_Relay_customContextMenuRequested(const QPo } menu.exec(QCursor::pos()); //显示菜单 } + +void TMRRelayAssociation::on_checkBox_sgcc_stateChanged(int arg1) +{ + if(ui->checkBox_sgcc->checkState()){ + treeView_relay->setEnabled(false); + list_widget_available->setEnabled(false); + }else{ + treeView_relay->setEnabled(true); + list_widget_available->setEnabled(true); + } +} + + +void TMRRelayAssociation::on_pushButton_logic_clicked() +{ + QStandardItemModel *model = qobject_cast(treeView_relay->model()); + if (!model) return; + QStandardItem *root = model->invisibleRootItem(); + QString finalExpr; + for (int i = 0; i < root->rowCount(); ++i) { + QStandardItem *topItem = root->child(i); + QString expr = buildLogicExpression(topItem); + finalExpr += expr; + } + ExprValidationResult result = validateLogicExpression(finalExpr); + if (!result.isValid && !finalExpr.isEmpty()) { + QMessageBox::warning(this, "表达式错误", + QString("错误位置:%1\n错误描述:%2").arg(result.errorPos).arg(result.errorMsg)); + return; + } + ui->textEdit_logic->setPlainText(finalExpr); +} + diff --git a/tmrrelayassociation.h b/tmrrelayassociation.h index 66c01c9..878c29d 100644 --- a/tmrrelayassociation.h +++ b/tmrrelayassociation.h @@ -17,7 +17,11 @@ struct ExprNode { QString value; QList children; }; - +struct ExprValidationResult { + bool isValid; + int errorPos; + QString errorMsg; +}; class DropTreeModel : public QStandardItemModel { public: using QStandardItemModel::QStandardItemModel; @@ -79,6 +83,10 @@ private slots: void on_treeView_Relay_customContextMenuRequested(const QPoint &pos); void slotDeleteItem(); + void on_checkBox_sgcc_stateChanged(int arg1); + + void on_pushButton_logic_clicked(); + private: Ui::TMRRelayAssociation *ui; QButtonGroup * btnGroup_slot = nullptr; @@ -95,6 +103,7 @@ private: void setExpressionToTreeView(QTreeView* treeView, const QString& expr); QStandardItem* parseExpression(const QString &expr); QString buildLogicExpression(QStandardItem *item); + ExprValidationResult validateLogicExpression(const QString& expr); }; #endif // TMRRELAYASSOCIATION_H diff --git a/tmrrelayassociation.ui b/tmrrelayassociation.ui index 853d1a2..9922478 100644 --- a/tmrrelayassociation.ui +++ b/tmrrelayassociation.ui @@ -6,12 +6,12 @@ 0 0 - 869 - 624 + 821 + 634 - Dialog + 继电器组态 @@ -185,11 +185,23 @@ 110 - 540 + 538 691 - 31 + 40 + + + 0 + 40 + + + + + 16777215 + 40 + + @@ -198,7 +210,7 @@ 450 - 580 + 590 71 32 @@ -211,7 +223,7 @@ 240 - 580 + 590 71 32 @@ -227,7 +239,7 @@ 550 - 580 + 590 81 32 @@ -240,7 +252,7 @@ 350 - 580 + 590 71 32 @@ -252,8 +264,8 @@ - 760 - 595 + 740 + 600 71 20 @@ -1014,17 +1026,17 @@ - + - 30 - 550 - 71 - 16 + 20 + 540 + 75 + 31 - 逻辑表达式: + 逻辑表达式