From 37cd43791e9c6f3289fd65a85c810cac98a389cc Mon Sep 17 00:00:00 2001 From: zhangsheng Date: Sat, 19 Apr 2025 16:25:33 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=A7=A6=E5=8F=91=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=EF=BC=8C=E9=80=BB=E8=BE=91=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TSI_Config.pro | 7 + config_mgr.cpp | 103 +++++++++---- config_mgr.h | 26 ++++ data_config.h | 30 +++- mainwindow.cpp | 77 +++++++++- rangeslider.cpp | 67 +++++--- rangeslider.h | 7 +- setpoint.cpp | 115 ++++++++++---- setpoint.h | 4 + setpoint.ui | 6 +- singlerelay.cpp | 108 ++++++++++++- singlerelay.h | 133 +++++++++++++--- singlerelay.ui | 191 +++++++---------------- tachometer_data.h | 4 +- tmrrelayassociation.cpp | 328 +++++++++++++++++++++++++++++++++++++++- tmrrelayassociation.h | 78 +++++++++- tmrrelayassociation.ui | 170 ++++++++++----------- vibrationdata.h | 2 +- 18 files changed, 1104 insertions(+), 352 deletions(-) diff --git a/TSI_Config.pro b/TSI_Config.pro index 2fb7fb1..704e81f 100644 --- a/TSI_Config.pro +++ b/TSI_Config.pro @@ -24,9 +24,12 @@ SOURCES += \ relaysetting.cpp \ seismic_monitor.cpp \ setpoint.cpp \ + setpoint_tachometer.cpp \ singlerelay.cpp \ + singlerelay_data.cpp \ tachometer.cpp \ tachometer_data.cpp \ + tmrrelayassociation.cpp \ velocity.cpp \ vibrationdata.cpp @@ -48,9 +51,12 @@ HEADERS += \ relaysetting.h \ seismic_monitor.h \ setpoint.h \ + setpoint_tachometer.h \ singlerelay.h \ + singlerelay_data.h \ tachometer.h \ tachometer_data.h \ + tmrrelayassociation.h \ velocity.h \ velocity_ds.h \ vibrationdata.h @@ -64,6 +70,7 @@ FORMS += \ relaysetting.ui \ seismic_monitor.ui \ setpoint.ui \ + setpoint_tachometer.ui \ singlerelay.ui \ tachometer.ui \ tmrrelayassociation.ui \ diff --git a/config_mgr.cpp b/config_mgr.cpp index 2f23741..35f255d 100644 --- a/config_mgr.cpp +++ b/config_mgr.cpp @@ -8,6 +8,7 @@ #include "vibrationdata.h" #include "tachometer_data.h" #include "keyphase_data.h" +#include "singlerelay_data.h" #include @@ -35,13 +36,15 @@ void ConfigMgr::Save(QString & file_path) { card_type_[i] != kCardSpeedTMRPrimary && card_type_[i] != kCardKeyphaseSingle && card_type_[i] != kCardRelaySingle && - card_type_[i] != kCardRelayTMRPrimary) { + card_type_[i] != kCardRelayTMRPrimary && + card_type_[i] != kCardRelaySingleNOK) { continue; } // process slot QJsonObject slot_item; if (card_type_[i] != kCardRelaySingle && - card_type_[i] != kCardRelayTMRPrimary) { + card_type_[i] != kCardRelayTMRPrimary && + card_type_[i] != kCardRelaySingleNOK) { for (int cid = 0; cid < CHANNEL_COUNT; ++cid) { QJsonObject channel_item; if (card_type_[i] == kCardVibSingle || @@ -64,17 +67,17 @@ void ConfigMgr::Save(QString & file_path) { voltage_range.append(ptr->base_config_[cid].normal_voltage_high); channel_item["normal_voltage_range"] = voltage_range; QJsonObject setpoint_data; - setpoint_data["direct_upper"] = qRound(ptr->vib_alert_danger[cid].direct_upper * 10)/10.0; - setpoint_data["direct_enable"] = ptr->vib_alert_danger[cid].direct_enable; - setpoint_data["1x_ampl_upper"] = qRound(ptr->vib_alert_danger[cid].x1_ampl_upper * 10)/10.0; - setpoint_data["1x_ampl_lower"] = qRound(ptr->vib_alert_danger[cid].x1_ampl_lower * 10)/10.0; - setpoint_data["1x_ampl_enable"] = ptr->vib_alert_danger[cid].x1_ampl_enable; - setpoint_data["2x_ampl_upper"] = qRound(ptr->vib_alert_danger[cid].x2_ampl_upper * 10)/10.0; - setpoint_data["2x_ampl_lower"] = qRound(ptr->vib_alert_danger[cid].x2_ampl_lower * 10)/10.0; - setpoint_data["2x_ampl_enable"] = ptr->vib_alert_danger[cid].x2_ampl_enable; - setpoint_data["danger_param"] = ptr->vib_alert_danger[cid].danger_param; - setpoint_data["danger_upper"] = qRound(ptr->vib_alert_danger[cid].danger_upper * 10)/10.0; - setpoint_data["danger_enable"] = ptr->vib_alert_danger[cid].danger_enable; + setpoint_data["direct_upper"] = qRound(ptr->alert_danger[cid].direct_upper * 10)/10.0; + setpoint_data["direct_enable"] = ptr->alert_danger[cid].direct_enable; + setpoint_data["1x_ampl_upper"] = qRound(ptr->alert_danger[cid].x1_ampl_upper * 10)/10.0; + setpoint_data["1x_ampl_lower"] = qRound(ptr->alert_danger[cid].x1_ampl_lower * 10)/10.0; + setpoint_data["1x_ampl_enable"] = ptr->alert_danger[cid].x1_ampl_enable; + setpoint_data["2x_ampl_upper"] = qRound(ptr->alert_danger[cid].x2_ampl_upper * 10)/10.0; + setpoint_data["2x_ampl_lower"] = qRound(ptr->alert_danger[cid].x2_ampl_lower * 10)/10.0; + setpoint_data["2x_ampl_enable"] = ptr->alert_danger[cid].x2_ampl_enable; + setpoint_data["danger_param"] = ptr->alert_danger[cid].danger_param; + setpoint_data["danger_upper"] = qRound(ptr->alert_danger[cid].danger_upper * 10)/10.0; + setpoint_data["danger_enable"] = ptr->alert_danger[cid].danger_enable; channel_item["setpoint"] = setpoint_data; // variables QJsonObject variables; @@ -226,6 +229,16 @@ void ConfigMgr::Save(QString & file_path) { QJsonArray voltage_range_array; voltage_range_array.append(ptr->variables_[cid].normal_voltage_low); voltage_range_array.append(ptr->variables_[cid].normal_voltage_high); + QJsonObject setpoint_data; + setpoint_data["speed_upper"] = qRound(ptr->alert_danger[cid].speed_upper * 10)/10.0; + setpoint_data["speed_lower"] = ptr->alert_danger[cid].speed_lower; + setpoint_data["speed_upper_enable"] = ptr->alert_danger[cid].speed_upper_enable; + setpoint_data["speed_lower_enable"] = ptr->alert_danger[cid].speed_lower_enable; + setpoint_data["danger_speed_upper"] = ptr->alert_danger[cid].danger_speed_upper; + setpoint_data["danger_speed_lower"] = ptr->alert_danger[cid].danger_speed_lower; + setpoint_data["danger_upper_enable"] = ptr->alert_danger[cid].danger_upper_enable; + setpoint_data["danger_lower_enable"] = ptr->alert_danger[cid].danger_lower_enable; + channel_item["setpoint"] = setpoint_data; channel_item.insert("active", ptr->variables_[cid].active); channel_item.insert("normal_voltage_range", voltage_range_array); channel_item.insert("threshold", ptr->variables_[cid].threshold); @@ -259,7 +272,24 @@ void ConfigMgr::Save(QString & file_path) { } slot_item["version"] = 1; }else{ - // TODO: save relay data + QJsonObject channel_item; + for(int ch = 0;ch < RELAY_COUNT;++ch){ + 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); + + }else if(card_type_[i] == kCardRelaySingle){ + + }else if(card_type_[i] == kCardRelayTMRPrimary){ + + } + slot_item[QString::number(ch + 1)] = channel_item; + } + slot_item["version"] = 1; } doc_obj[QString::number(slot)] = slot_item; } @@ -341,17 +371,17 @@ void ConfigMgr::Load(QString filename) { vib_data->base_config_[j].power = channel["power"].toBool(); //setpoint QJsonObject setpoint_data = channel["setpoint"].toObject(); - vib_data->vib_alert_danger[j].direct_upper = setpoint_data["direct_upper"].toDouble(); - vib_data->vib_alert_danger[j].direct_enable = setpoint_data["direct_enable"].toBool(); - vib_data->vib_alert_danger[j].x1_ampl_upper = setpoint_data["1x_ampl_upper"].toDouble(); - vib_data->vib_alert_danger[j].x1_ampl_lower = setpoint_data["1x_ampl_lower"].toDouble(); - vib_data->vib_alert_danger[j].x1_ampl_enable = setpoint_data["1x_ampl_enable"].toBool(); - vib_data->vib_alert_danger[j].x2_ampl_upper = setpoint_data["2x_ampl_upper"].toDouble(); - vib_data->vib_alert_danger[j].x2_ampl_lower = setpoint_data["2x_ampl_lower"].toDouble(); - vib_data->vib_alert_danger[j].x2_ampl_enable = setpoint_data["2x_ampl_enable"].toBool(); - vib_data->vib_alert_danger[j].danger_param = setpoint_data["danger_param"].toInt(); - vib_data->vib_alert_danger[j].danger_upper = setpoint_data["danger_upper"].toDouble(); - vib_data->vib_alert_danger[j].danger_enable = setpoint_data["danger_enable"].toBool(); + vib_data->alert_danger[j].direct_upper = setpoint_data["direct_upper"].toDouble(); + vib_data->alert_danger[j].direct_enable = setpoint_data["direct_enable"].toBool(); + vib_data->alert_danger[j].x1_ampl_upper = setpoint_data["1x_ampl_upper"].toDouble(); + vib_data->alert_danger[j].x1_ampl_lower = setpoint_data["1x_ampl_lower"].toDouble(); + vib_data->alert_danger[j].x1_ampl_enable = setpoint_data["1x_ampl_enable"].toBool(); + vib_data->alert_danger[j].x2_ampl_upper = setpoint_data["2x_ampl_upper"].toDouble(); + vib_data->alert_danger[j].x2_ampl_lower = setpoint_data["2x_ampl_lower"].toDouble(); + vib_data->alert_danger[j].x2_ampl_enable = setpoint_data["2x_ampl_enable"].toBool(); + vib_data->alert_danger[j].danger_param = setpoint_data["danger_param"].toInt(); + vib_data->alert_danger[j].danger_upper = setpoint_data["danger_upper"].toDouble(); + vib_data->alert_danger[j].danger_enable = setpoint_data["danger_enable"].toBool(); // variables QJsonObject tmp_variable = channel["variable"].toObject(); switch (vib_data->base_config_[j].channel_type) { @@ -414,7 +444,7 @@ void ConfigMgr::Load(QString filename) { // filter QJsonArray filter_array = tmp_variable["filter"].toArray(); for (int k = 0; k < filter_array.size(); k++) { - QJsonObject filter_ele = filter_array[i].toObject(); + QJsonObject filter_ele = filter_array[k].toObject(); variable->filter_[k].low = filter_ele["low"].toInt(); variable->filter_[k].high = filter_ele["high"].toInt(); variable->filter_[k].checked = filter_ele["checked"].toBool(); @@ -481,6 +511,17 @@ void ConfigMgr::Load(QString filename) { speed_data->variables_[j].normal_latching = channel["normal_latching"].toBool(); speed_data->variables_[j].speed_peek = channel["speed_peak"].toInt(); speed_data->variables_[j].default_speed = channel["default_speed"].toInt(); + + + QJsonObject setpoint_data = channel["setpoint"].toObject(); + speed_data->alert_danger[j].speed_upper = setpoint_data["speed_upper"].toDouble(); + speed_data->alert_danger[j].speed_lower = setpoint_data["speed_lower"].toDouble(); + speed_data->alert_danger[j].speed_upper_enable = setpoint_data["speed_upper_enable"].toBool(); + speed_data->alert_danger[j].speed_lower_enable = setpoint_data["speed_lower_enable"].toBool(); + speed_data->alert_danger[j].danger_speed_upper = setpoint_data["danger_speed_upper"].toDouble(); + speed_data->alert_danger[j].danger_speed_lower = setpoint_data["danger_speed_lower"].toDouble(); + speed_data->alert_danger[j].danger_upper_enable = setpoint_data["danger_upper_enable"].toBool(); + speed_data->alert_danger[j].danger_lower_enable = setpoint_data["danger_lower_enable"].toBool(); } cards_.push_back(speed_data); } else if (card_type_[i] == kCardKeyphaseSingle) { @@ -499,6 +540,16 @@ void ConfigMgr::Load(QString filename) { keyphase_data->variables_[j].events_per_revolution = channel["events_per_revolution"].toInt(); } cards_.push_back(keyphase_data); + }else if (card_type_[i] == kCardRelaySingleNOK || card_type_[i] == kCardRelayTMRPrimary || card_type_[i] == kCardRelaySingle){ + std::shared_ptr singlereay_data = std::make_shared(); + singlereay_data->slot_ = slot; + singlereay_data->card_type_ = static_cast(card_type_[i]); + singlereay_data->version_ = temp_obj["version"].toInt(); + for (int j = 0; j < RELAY_COUNT; ++j) { + channel = temp_obj[QString::number(j + 1)].toObject(); + singlereay_data->single_relay_nok[j].logic_expression = channel["logic_expression"].toString(); + } + cards_.push_back(singlereay_data); } } } diff --git a/config_mgr.h b/config_mgr.h index b42bbcc..1e2454c 100644 --- a/config_mgr.h +++ b/config_mgr.h @@ -3,7 +3,33 @@ #include #include #include "cardbase.h" +#include +#include +#include +#include +#include +class DraggableListWidget : public QListWidget { +public: + DraggableListWidget(QWidget *parent = nullptr) : QListWidget(parent) { + setDragEnabled(true); + } + +protected: + void startDrag(Qt::DropActions supportedActions) override { + QListWidgetItem *item = currentItem(); + if (!item) return; + + QMimeData *mimeData = new QMimeData; + + QString customData = item->data(Qt::UserRole).toString(); + mimeData->setData("application/x-custom", customData.toUtf8()); + + QDrag *drag = new QDrag(this); + drag->setMimeData(mimeData); + drag->exec(Qt::CopyAction); + } +}; class ConfigMgr { private: static ConfigMgr *instance; diff --git a/data_config.h b/data_config.h index f81c9e0..c4c75a5 100644 --- a/data_config.h +++ b/data_config.h @@ -12,6 +12,7 @@ extern QString g_strServerIp; // 服务端IP #define SLOT_NUM 15 #define CHANNEL_COUNT 4 +#define RELAY_COUNT 8 typedef enum { kCardNone = 0, @@ -32,6 +33,7 @@ typedef enum { kCardRelaySingle = 32, kCardRelayTMRPrimary = 33, kCardRelayTMRBackup = 34, + kCardRelaySingleNOK = 35, } CardType; @@ -235,27 +237,43 @@ typedef struct VibAlertDanger_{ float danger_upper; bool danger_enable; VibAlertDanger_(){ + direct_upper = 0.0; direct_enable = false; + x1_ampl_upper = 0.0; + x1_ampl_lower = 0.0; x1_ampl_enable = false; + x2_ampl_upper = 0.0; + x2_ampl_lower = 0.0; x2_ampl_enable = false; + danger_upper = 0.0; danger_enable = false; } } VibAlertDanger; -typedef struct{ +typedef struct SpeedAlert_{ float speed_upper; float speed_lower; bool speed_upper_enable; bool speed_lower_enable; - float speed_bnd_upper; - float speed_bnd_lower; - bool speed_bnd_enable; float danger_speed_upper; float danger_speed_lower; - bool danger_speed_upper_enable; - bool danger_speed_lower_enable; + bool danger_upper_enable; + bool danger_lower_enable; + SpeedAlert_(){ + speed_upper = 0; + speed_lower = 0; + danger_speed_upper = 0; + danger_speed_lower = 0; + } } SpeedAlert; +typedef struct SingleRelayNOK_{ + QString logic_expression; + SingleRelayNOK_(){ + logic_expression = ""; + } +} SingleRelayNOK; + #pragma pack(1) typedef struct { uint8_t head[3]; // 固定值:0xAA55AA diff --git a/mainwindow.cpp b/mainwindow.cpp index 2ce5884..a3dc761 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -21,6 +21,8 @@ #include "config_mgr.h" #include "vibrationdata.h" #include "connect.h" +#include "tmrrelayassociation.h" +#include "setpoint_tachometer.h" QString g_strServerIp; @@ -215,8 +217,10 @@ void MainWindow::createMenu(const QString &rootTitle, QPushButton *parent) { // 创建第二层子菜单:/DOM810 继电器模块 QAction *relays_1 = relays->addAction("/DOM810 单板卡"); relays_1->setData(kCardRelaySingle); - QAction *relays_2 = relays->addAction("/DOM810 三冗余板卡"); - relays_2->setData(kCardRelayTMRPrimary); + QAction *relays_2 = relays->addAction("/DOM810 单板卡-非OK"); + relays_2->setData(kCardRelaySingleNOK); + QAction *relays_3 = relays->addAction("/DOM810 三冗余板卡"); + relays_3->setData(kCardRelayTMRPrimary); // 将子菜单加入上一级菜单 monitors->addMenu(proximitor_menu); // 将第二层加入第一层 monitors->addMenu(rpm_menu); // 第二层另一个子菜单 @@ -348,6 +352,11 @@ void MainWindow::onMenuActionTriggered() { map_slot_config[button_id].rack_type = "Single"; map_slot_config[button_id].chan_display = chan_display; button->setText(chan_display); + }else if (rack_type == "单板卡-非OK" && map_slot_config[button_id].slot_type == "") { + map_slot_config[button_id].slot_type = slot_type; + map_slot_config[button_id].rack_type = "Single"; + map_slot_config[button_id].chan_display = chan_display; + button->setText(chan_display); } if (action->text() == "重置模块") { if (ConfigMgr::Instance()->card_type_[button_id - 1] == kCardRelayTMRPrimary) { @@ -381,6 +390,11 @@ void MainWindow::onMenuActionTriggered() { ConfigMgr::Instance()->card_type_[button_id - 1] == kCardKeyphaseSingle) { ConfigMgr::Instance()->card_type_[button_id - 1] = kCardNone; map_slot_config[button_id].slot_btn->setText(""); + }else if (ConfigMgr::Instance()->card_type_[button_id - 1] == kCardRelaySingle || + ConfigMgr::Instance()->card_type_[button_id - 1] == kCardRelaySingleNOK || + ConfigMgr::Instance()->card_type_[button_id - 1] == kCardRelayTMRPrimary) { + ConfigMgr::Instance()->card_type_[button_id - 1] = kCardNone; + map_slot_config[button_id].slot_btn->setText(""); } } else if (action->text() == "升级固件") { sendUpgradePackage(button_id); @@ -410,9 +424,20 @@ void MainWindow::OnButtonGroup(QAbstractButton *slot_btn) { key_phase->setWindowModality(Qt::ApplicationModal); key_phase->show(); } else if (slot_config.slot_type == "DOM810") { // 继电器模块 - SingleRelay *single_relay = new SingleRelay(); - single_relay->setWindowModality(Qt::ApplicationModal); - single_relay->show(); + switch (card_type) { + case kCardRelaySingle: + case kCardRelayTMRPrimary:{ + TMRRelayAssociation *single_tmr_relay = new TMRRelayAssociation(button_id,card_type); + single_tmr_relay->setWindowModality(Qt::ApplicationModal); + single_tmr_relay->show(); + }break; + case kCardRelaySingleNOK:{ + SingleRelay *single_relay = new SingleRelay(button_id,card_type); + single_relay->setWindowModality(Qt::ApplicationModal); + single_relay->show(); + }break; + } + } else if (slot_config.slot_type == "HAM824") { // 振动模块 Seismic_monitor *seismic_monitor = new Seismic_monitor(button_id,card_type); seismic_monitor->setWindowModality(Qt::ApplicationModal); @@ -437,14 +462,44 @@ void MainWindow::OnButtonGroup(QAbstractButton *slot_btn) { key_phase->show(); break; } + case kCardRelaySingleNOK:{ + SingleRelay *single_relay = new SingleRelay(button_id,card_type); + single_relay->setWindowModality(Qt::ApplicationModal); + single_relay->show(); + break; + } + case kCardRelaySingle: + case kCardRelayTMRPrimary:{ + TMRRelayAssociation *single_tmr_relay = new TMRRelayAssociation(button_id,card_type); + single_tmr_relay->setWindowModality(Qt::ApplicationModal); + single_tmr_relay->show(); + break; + } } } if (slot_btn != NULL && ui->pushButton_alarm->isChecked()) { QString object_name = slot_btn->objectName(); int button_id = object_name.right(object_name.length() - 15).toInt(); - Setpoint *setpoint = new Setpoint(button_id,ConfigMgr::Instance()->card_type_[button_id]); - setpoint->setWindowModality(Qt::ApplicationModal); - setpoint->show(); + std::shared_ptr base_ptr = ConfigMgr::Instance()->GetSlotPtr(button_id); + switch(base_ptr->card_type_){ + case kCardVibSingle:{ + QString object_name = slot_btn->objectName(); + int button_id = object_name.right(object_name.length() - 15).toInt(); + Setpoint *setpoint = new Setpoint(button_id,ConfigMgr::Instance()->card_type_[button_id - 1]); + setpoint->setWindowModality(Qt::ApplicationModal); + setpoint->show(); + break; + } + case kCardSpeedSingle:{ + QString object_name = slot_btn->objectName(); + int button_id = object_name.right(object_name.length() - 15).toInt(); + Setpoint_Tachometer *setpoint_tachometer = new Setpoint_Tachometer(button_id,ConfigMgr::Instance()->card_type_[button_id - 1]); + setpoint_tachometer->setWindowModality(Qt::ApplicationModal); + setpoint_tachometer->show(); + break; + } + + } } } @@ -602,6 +657,12 @@ void MainWindow::on_pushButton_open_clicked() { buttonList[i + 1]->setText("转速"); break; } + case kCardRelaySingle: + case kCardRelaySingleNOK: + case kCardRelayTMRPrimary:{ + buttonList[i + 1]->setText("继电器"); + break; + } default: break; } diff --git a/rangeslider.cpp b/rangeslider.cpp index 7209503..768004e 100644 --- a/rangeslider.cpp +++ b/rangeslider.cpp @@ -2,10 +2,12 @@ #include #include #include +#include -RangeSlider::RangeSlider(int style,QWidget *parent) +RangeSlider::RangeSlider(int style_,QWidget *parent) : QWidget(parent) { setMinimumSize(20, 240); + style = style_; } void RangeSlider::setRange(int min, int max) { @@ -83,11 +85,10 @@ void RangeSlider::paintEvent(QPaintEvent *) { p.setBrush(Qt::green); p.drawRect(x - sliderWidth / 2, yUpper, sliderWidth, yLower - yUpper); - // Draw simple red handles (circles) - p.setPen(Qt::NoPen); - p.setBrush(Qt::red); - p.drawEllipse(QPointF(x, yLower), handleRadius, handleRadius); - p.drawEllipse(QPointF(x, yUpper), handleRadius, handleRadius); + // Draw simple black handles (lines) + p.setPen(QPen(Qt::black, 2)); + p.drawLine(x - sliderWidth / 2, yLower, x + sliderWidth, yLower); + p.drawLine(x - sliderWidth / 2, yUpper, x + sliderWidth, yUpper); // Draw ticks drawTicks(&p); @@ -114,25 +115,57 @@ void RangeSlider::drawTemperatureStyle(QPainter *p) { p->drawRect(x - sliderWidth / 2, yTop, sliderWidth, yBottom - yTop); // Draw yellow outside the range - p->setBrush(Qt::yellow); - p->drawRect(x - sliderWidth / 2, yTop, sliderWidth, valueToY(m_lower) - yTop); // Above lower range - p->drawRect(x - sliderWidth / 2, valueToY(m_upper), sliderWidth, yBottom - valueToY(m_upper)); // Below upper range + if(style != 0){ + p->setBrush(Qt::red); + p->drawRect(x - sliderWidth / 2, yTop, sliderWidth, valueToY(m_lower) - yTop); // Above lower range + p->drawRect(x - sliderWidth / 2, valueToY(m_upper), sliderWidth, yBottom - valueToY(m_upper)); // Below upper range + }else{ + p->setBrush(Qt::yellow); + p->drawRect(x - sliderWidth / 2, yTop, sliderWidth, valueToY(m_lower) - yTop); // Above lower range + p->drawRect(x - sliderWidth / 2, valueToY(m_upper), sliderWidth, yBottom - valueToY(m_upper)); // Below upper range + } // Draw green inside the range p->setBrush(Qt::green); p->drawRect(x - sliderWidth / 2, valueToY(m_upper), sliderWidth, valueToY(m_lower) - valueToY(m_upper)); // Green area } +int RangeSlider::niceStep(int range, int maxLabels) { + double rawStep = static_cast(range) / maxLabels; + // 取一个"好看"的步长 + double magnitude = pow(10, floor(log10(rawStep))); // 10 的整数次幂 + double residual = rawStep / magnitude; + + double niceResidual; + if (residual < 1.5) + niceResidual = 1; + else if (residual < 3) + niceResidual = 2; + else if (residual < 7) + niceResidual = 5; + else + niceResidual = 10; + + return static_cast(niceResidual * magnitude); +} void RangeSlider::drawTicks(QPainter *p) { - int tickCount = 11; - p->setPen(Qt::black); - p->setFont(QFont("Arial", 8)); - int x = width() / 2 + handleRadius + 4; + int range = m_max - m_min; + int labelStep = niceStep(range, 10); + int minorStep = qMax(1, labelStep / 5); - for (int i = 0; i < tickCount; ++i) { - int val = m_min + i * (m_max - m_min) / (tickCount - 1); + int x = width() / 2 + handleRadius + 4; + p->setFont(QFont("Arial", 8)); + + for (int val = m_min; val <= m_max; val += minorStep) { int y = valueToY(val); - p->drawLine(x, y, x + 3, y); // 刻度宽度 - p->drawText(x + 8, y + 4, QString::number(val)); + + if (val % labelStep == 0) { + p->setPen(QPen(Qt::black, 1.5)); // 主刻度 + p->drawLine(x, y, x + 6, y); + p->drawText(x + 10, y + 4, QString::number(val)); + } else { + p->setPen(QPen(Qt::gray, 1)); // 次刻度 + p->drawLine(x, y, x + 3, y); + } } } diff --git a/rangeslider.h b/rangeslider.h index 4530c1d..fc78427 100644 --- a/rangeslider.h +++ b/rangeslider.h @@ -7,7 +7,7 @@ class RangeSlider : public QWidget { Q_OBJECT public: - explicit RangeSlider(int style = 0,QWidget *parent = nullptr); + explicit RangeSlider(int style_ = 0,QWidget *parent = nullptr); void setRange(int min, int max); void setSliderWidth(int width); // 新增方法:设置宽度 @@ -17,6 +17,7 @@ public: void setUpperValue(float val); float m_lower = 3.5; float m_upper = 6.5; + int style = 0; signals: void rangeChanged(float lower, float upper); @@ -30,7 +31,7 @@ private: float m_min = 0; float m_max = 10; - int sliderWidth = 15; // 默认宽度(可以根据需求调整) + int sliderWidth = 10; // 默认宽度(可以根据需求调整) int handleRadius = 8; enum HandleType { NoHandle, LowerHandle, UpperHandle }; @@ -39,7 +40,7 @@ private: float valueToY(float value) const; float yToValue(float y) const; HandleType handleHitTest(float y) const; - + int niceStep(int range, int maxLabels); void drawTicks(QPainter *p); void drawTemperatureStyle(QPainter *p); }; diff --git a/setpoint.cpp b/setpoint.cpp index 25d890e..746d05e 100644 --- a/setpoint.cpp +++ b/setpoint.cpp @@ -13,6 +13,9 @@ Setpoint::Setpoint(int slot_no_,int cardtype,QWidget *parent) : ui->label_slot->setText(QString::number(slot_no)); Init(); + connect(ui->comboBox_chan, QOverload::of(&QComboBox::currentIndexChanged), + this, &Setpoint::onComboBoxIndexChanged); + current_index = ui->comboBox_chan->currentIndex(); } Setpoint::~Setpoint() @@ -42,11 +45,11 @@ void Setpoint::Init(){ layout_2x_ampl->addWidget(slider_2x_ampl); QVBoxLayout *layout_danger = new QVBoxLayout(ui->widget_danger); - slider_danger = new RangeSlider; + slider_danger = new RangeSlider(1); layout_danger->addWidget(slider_danger); std::shared_ptr base_ptr = ConfigMgr::Instance()->GetSlotPtr(slot_no); - + vib_alert_ptr = std::dynamic_pointer_cast(base_ptr); switch (car_type) { case kCardVibSingle:{ @@ -56,22 +59,31 @@ void Setpoint::Init(){ slider_danger->setRange(0,20); int chan = ui->comboBox_chan->currentIndex(); std::shared_ptr setpoint_data = std::dynamic_pointer_cast(base_ptr); - ui->lineEdit_direct_upper->setText(QString::number(setpoint_data->vib_alert_danger[chan].direct_upper)); - ui->checkBox_direct->setChecked(setpoint_data->vib_alert_danger[chan].direct_enable); - slider_direct->m_upper = setpoint_data->vib_alert_danger[chan].direct_upper; - ui->lineEdit_1x_ampl_upper->setText(QString::number(setpoint_data->vib_alert_danger[chan].x1_ampl_upper)); - ui->lineEdit_1x_ampl_lower->setText(QString::number(setpoint_data->vib_alert_danger[chan].x1_ampl_lower)); - ui->checkBox_1x_ampl->setChecked(setpoint_data->vib_alert_danger[chan].x1_ampl_enable); - slider_1x_ampl->m_upper = setpoint_data->vib_alert_danger[chan].x1_ampl_upper; - slider_1x_ampl->m_lower = setpoint_data->vib_alert_danger[chan].x1_ampl_lower; - ui->lineEdit_2x_ampl_upper->setText(QString::number(setpoint_data->vib_alert_danger[chan].x2_ampl_upper)); - ui->lineEdit_2x_ampl_lower->setText(QString::number(setpoint_data->vib_alert_danger[chan].x2_ampl_lower)); - ui->checkBox_2x_ampl->setChecked(setpoint_data->vib_alert_danger[chan].x2_ampl_enable); - slider_2x_ampl->m_upper = setpoint_data->vib_alert_danger[chan].x2_ampl_upper; - slider_2x_ampl->m_lower = setpoint_data->vib_alert_danger[chan].x2_ampl_lower; - ui->lineEdit_danger_upper->setText(QString::number(setpoint_data->vib_alert_danger[chan].danger_upper)); - ui->checkBox_danger->setChecked(setpoint_data->vib_alert_danger[chan].danger_enable); - slider_danger->m_upper = setpoint_data->vib_alert_danger[chan].danger_upper; + ui->lineEdit_direct_upper->setText(QString::number(setpoint_data->alert_danger[chan].direct_upper)); + ui->checkBox_direct->setChecked(setpoint_data->alert_danger[chan].direct_enable); + if(setpoint_data->alert_danger[chan].direct_upper > 0){ + slider_direct->m_upper = setpoint_data->alert_danger[chan].direct_upper; + } + ui->lineEdit_1x_ampl_upper->setText(QString::number(setpoint_data->alert_danger[chan].x1_ampl_upper)); + ui->lineEdit_1x_ampl_lower->setText(QString::number(setpoint_data->alert_danger[chan].x1_ampl_lower)); + ui->checkBox_1x_ampl->setChecked(setpoint_data->alert_danger[chan].x1_ampl_enable); + if(setpoint_data->alert_danger[chan].x1_ampl_upper > 0 && setpoint_data->alert_danger[chan].x1_ampl_lower > 0){ + slider_1x_ampl->m_upper = setpoint_data->alert_danger[chan].x1_ampl_upper; + slider_1x_ampl->m_lower = setpoint_data->alert_danger[chan].x1_ampl_lower; + } + ui->lineEdit_2x_ampl_upper->setText(QString::number(setpoint_data->alert_danger[chan].x2_ampl_upper)); + ui->lineEdit_2x_ampl_lower->setText(QString::number(setpoint_data->alert_danger[chan].x2_ampl_lower)); + ui->checkBox_2x_ampl->setChecked(setpoint_data->alert_danger[chan].x2_ampl_enable); + if(setpoint_data->alert_danger[chan].x2_ampl_upper > 0 && setpoint_data->alert_danger[chan].x2_ampl_lower > 0){ + slider_2x_ampl->m_upper = setpoint_data->alert_danger[chan].x2_ampl_upper; + slider_2x_ampl->m_lower = setpoint_data->alert_danger[chan].x2_ampl_lower; + } + ui->lineEdit_danger_upper->setText(QString::number(setpoint_data->alert_danger[chan].danger_upper)); + ui->checkBox_danger->setChecked(setpoint_data->alert_danger[chan].danger_enable); + if(setpoint_data->alert_danger[chan].danger_upper > 0){ + slider_danger->m_upper = setpoint_data->alert_danger[chan].danger_upper; + slider_danger->m_lower = 0; + } }break; case kCardSpeedSingle:{ slider_direct->setRange(0,5000); @@ -117,24 +129,22 @@ void Setpoint::Init(){ void Setpoint::on_pushButton_confirm_clicked() { - std::shared_ptr base_ptr = ConfigMgr::Instance()->GetSlotPtr(slot_no); - if (base_ptr == nullptr) { + if (vib_alert_ptr == nullptr) { qCritical() << "[Setpoint::confirm] should not be here"; return; } - int chan = ui->comboBox_chan->currentIndex(); - std::shared_ptr ptr = std::dynamic_pointer_cast(base_ptr); - ptr->vib_alert_danger[chan].direct_upper = ui->lineEdit_direct_upper->text().toFloat(); - ptr->vib_alert_danger[chan].direct_enable = ui->checkBox_direct->checkState(); - ptr->vib_alert_danger[chan].x1_ampl_upper = ui->lineEdit_1x_ampl_upper->text().toFloat(); - ptr->vib_alert_danger[chan].x1_ampl_lower = ui->lineEdit_1x_ampl_lower->text().toFloat(); - ptr->vib_alert_danger[chan].x1_ampl_enable = ui->checkBox_1x_ampl->checkState(); - ptr->vib_alert_danger[chan].x2_ampl_upper = ui->lineEdit_2x_ampl_upper->text().toFloat(); - ptr->vib_alert_danger[chan].x2_ampl_lower = ui->lineEdit_2x_ampl_lower->text().toFloat(); - ptr->vib_alert_danger[chan].x2_ampl_enable = ui->checkBox_2x_ampl->checkState(); - ptr->vib_alert_danger[chan].danger_param = ui->comboBox_danger->currentIndex(); - ptr->vib_alert_danger[chan].danger_upper = ui->lineEdit_danger_upper->text().toFloat(); - ptr->vib_alert_danger[chan].danger_enable = ui->checkBox_danger->checkState(); + + vib_alert_ptr->alert_danger[current_index].direct_upper = ui->lineEdit_direct_upper->text().toFloat(); + vib_alert_ptr->alert_danger[current_index].direct_enable = ui->checkBox_direct->checkState(); + vib_alert_ptr->alert_danger[current_index].x1_ampl_upper = ui->lineEdit_1x_ampl_upper->text().toFloat(); + vib_alert_ptr->alert_danger[current_index].x1_ampl_lower = ui->lineEdit_1x_ampl_lower->text().toFloat(); + vib_alert_ptr->alert_danger[current_index].x1_ampl_enable = ui->checkBox_1x_ampl->checkState(); + vib_alert_ptr->alert_danger[current_index].x2_ampl_upper = ui->lineEdit_2x_ampl_upper->text().toFloat(); + vib_alert_ptr->alert_danger[current_index].x2_ampl_lower = ui->lineEdit_2x_ampl_lower->text().toFloat(); + vib_alert_ptr->alert_danger[current_index].x2_ampl_enable = ui->checkBox_2x_ampl->checkState(); + vib_alert_ptr->alert_danger[current_index].danger_param = ui->comboBox_danger->currentIndex(); + vib_alert_ptr->alert_danger[current_index].danger_upper = ui->lineEdit_danger_upper->text().toFloat(); + vib_alert_ptr->alert_danger[current_index].danger_enable = ui->checkBox_danger->checkState(); this->close(); } @@ -149,4 +159,43 @@ void Setpoint::on_pushButton_set_default_clicked() { } +void Setpoint::onComboBoxIndexChanged(int index){ + vib_alert_ptr->alert_danger[current_index].direct_upper = ui->lineEdit_direct_upper->text().toFloat(); + vib_alert_ptr->alert_danger[current_index].direct_enable = ui->checkBox_direct->checkState(); + vib_alert_ptr->alert_danger[current_index].x1_ampl_upper = ui->lineEdit_1x_ampl_upper->text().toFloat(); + vib_alert_ptr->alert_danger[current_index].x1_ampl_lower = ui->lineEdit_1x_ampl_lower->text().toFloat(); + vib_alert_ptr->alert_danger[current_index].x1_ampl_enable = ui->checkBox_1x_ampl->checkState(); + vib_alert_ptr->alert_danger[current_index].x2_ampl_upper = ui->lineEdit_2x_ampl_upper->text().toFloat(); + vib_alert_ptr->alert_danger[current_index].x2_ampl_lower = ui->lineEdit_2x_ampl_lower->text().toFloat(); + vib_alert_ptr->alert_danger[current_index].x2_ampl_enable = ui->checkBox_2x_ampl->checkState(); + vib_alert_ptr->alert_danger[current_index].danger_param = ui->comboBox_danger->currentIndex(); + vib_alert_ptr->alert_danger[current_index].danger_upper = ui->lineEdit_danger_upper->text().toFloat(); + vib_alert_ptr->alert_danger[current_index].danger_enable = ui->checkBox_danger->checkState(); + + current_index = index; + + ui->lineEdit_direct_upper->setText(QString::number(vib_alert_ptr->alert_danger[index].direct_upper)); + ui->checkBox_direct->setChecked(vib_alert_ptr->alert_danger[index].direct_enable); + if(vib_alert_ptr->alert_danger[index].direct_upper > 0) + slider_direct->m_upper = vib_alert_ptr->alert_danger[index].direct_upper; + ui->lineEdit_1x_ampl_upper->setText(QString::number(vib_alert_ptr->alert_danger[index].x1_ampl_upper)); + ui->lineEdit_1x_ampl_lower->setText(QString::number(vib_alert_ptr->alert_danger[index].x1_ampl_lower)); + ui->checkBox_1x_ampl->setChecked(vib_alert_ptr->alert_danger[index].x1_ampl_enable); + if(vib_alert_ptr->alert_danger[index].x1_ampl_upper > 0 && vib_alert_ptr->alert_danger[index].x1_ampl_lower > 0){ + slider_1x_ampl->m_upper = vib_alert_ptr->alert_danger[index].x1_ampl_upper; + slider_1x_ampl->m_lower = vib_alert_ptr->alert_danger[index].x1_ampl_lower; + } + ui->lineEdit_2x_ampl_upper->setText(QString::number(vib_alert_ptr->alert_danger[index].x2_ampl_upper)); + ui->lineEdit_2x_ampl_lower->setText(QString::number(vib_alert_ptr->alert_danger[index].x2_ampl_lower)); + ui->checkBox_2x_ampl->setChecked(vib_alert_ptr->alert_danger[index].x2_ampl_enable); + if(vib_alert_ptr->alert_danger[index].x2_ampl_upper > 0 && vib_alert_ptr->alert_danger[index].x2_ampl_lower > 0){ + slider_2x_ampl->m_upper = vib_alert_ptr->alert_danger[index].x2_ampl_upper; + slider_2x_ampl->m_lower = vib_alert_ptr->alert_danger[index].x2_ampl_lower; + } + ui->lineEdit_danger_upper->setText(QString::number(vib_alert_ptr->alert_danger[index].danger_upper)); + ui->checkBox_danger->setChecked(vib_alert_ptr->alert_danger[index].danger_enable); + if(vib_alert_ptr->alert_danger[index].danger_upper > 0){ + slider_danger->m_upper = vib_alert_ptr->alert_danger[index].danger_upper; + } +} diff --git a/setpoint.h b/setpoint.h index b59bd15..2bf629d 100644 --- a/setpoint.h +++ b/setpoint.h @@ -26,12 +26,16 @@ private slots: void on_pushButton_set_default_clicked(); + void onComboBoxIndexChanged(int index); + private: Ui::Setpoint *ui; RangeSlider *slider_direct; RangeSlider *slider_1x_ampl; RangeSlider *slider_2x_ampl; RangeSlider *slider_danger; + std::shared_ptr vib_alert_ptr = nullptr; + int current_index; void Init(); }; diff --git a/setpoint.ui b/setpoint.ui index de23c23..d63f0ca 100644 --- a/setpoint.ui +++ b/setpoint.ui @@ -106,19 +106,19 @@ 0 116 - 80 + 100 260 - 80 + 100 260 - 80 + 100 260 diff --git a/singlerelay.cpp b/singlerelay.cpp index 412bd72..22177d3 100644 --- a/singlerelay.cpp +++ b/singlerelay.cpp @@ -1,21 +1,121 @@ #include "singlerelay.h" #include "ui_singlerelay.h" -SingleRelay::SingleRelay(QWidget *parent) + +SingleRelay::SingleRelay(int slot,int cardtype,QWidget *parent) : QDialog(parent) , ui(new Ui::SingleRelay) { ui->setupUi(this); + slot_no = slot; + car_type = static_cast(cardtype); + ui->label_slot_no->setText(QString::number(slot_no)); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); - QVBoxLayout *layout = new QVBoxLayout(ui->widget_relay); - DropTextEdit *textEdit = new DropTextEdit; + QVBoxLayout *layout_relay = new QVBoxLayout(ui->widget_relay); + textEdit_relay = new DropTextEdit; + layout_relay->addWidget(textEdit_relay); + QVBoxLayout *layout_available = new QVBoxLayout(ui->widget_available); + list_widget_available = new DraggableListWidget; + layout_available->addWidget(list_widget_available); - layout->addWidget(textEdit); + btnGroup_slot = new QButtonGroup(this); + btnGroup_slot->addButton(ui->pushButton_slot1); + btnGroup_slot->addButton(ui->pushButton_slot2); + btnGroup_slot->addButton(ui->pushButton_slot3); + btnGroup_slot->addButton(ui->pushButton_slot4); + btnGroup_slot->addButton(ui->pushButton_slot5); + btnGroup_slot->addButton(ui->pushButton_slot6); + btnGroup_slot->addButton(ui->pushButton_slot7); + btnGroup_slot->addButton(ui->pushButton_slot8); + btnGroup_slot->addButton(ui->pushButton_slot9); + btnGroup_slot->addButton(ui->pushButton_slot10); + btnGroup_slot->addButton(ui->pushButton_slot11); + btnGroup_slot->addButton(ui->pushButton_slot12); + btnGroup_slot->addButton(ui->pushButton_slot13); + btnGroup_slot->addButton(ui->pushButton_slot14); + btnGroup_slot->addButton(ui->pushButton_slot15); + btnGroup_slot->addButton(ui->pushButton_slot16); + + connect(btnGroup_slot, SIGNAL(buttonClicked(QAbstractButton *)), this, SLOT(OnButtonGroup(QAbstractButton *))); + connect(ui->pushButton_backspace, &QPushButton::clicked, textEdit_relay, &DropTextEdit::removeLastElement); + connect(ui->comboBox_relay_ch, QOverload::of(&QComboBox::currentIndexChanged), + this, &SingleRelay::onComboBoxIndexChanged); + Init(); + current_index = ui->comboBox_relay_ch->currentIndex(); + if(single_relay_nok_data->single_relay_nok[current_index].logic_expression != "") + textEdit_relay->setPlainText(single_relay_nok_data->single_relay_nok[current_index].logic_expression); } SingleRelay::~SingleRelay() { delete ui; } +void SingleRelay::Init(){ + std::shared_ptr base_ptr = ConfigMgr::Instance()->GetSlotPtr(slot_no); + if (base_ptr == nullptr) { + // do nothing or use template to init it. + single_relay_nok_data = std::make_shared(); + single_relay_nok_data->card_type_ = car_type; + single_relay_nok_data->slot_ = slot_no; + ConfigMgr::Instance()->AddCard(single_relay_nok_data); + return; + } + single_relay_nok_data = std::dynamic_pointer_cast(base_ptr); +} void SingleRelay::on_pushButton_cancel_clicked() { this->close(); } + +void SingleRelay::OnButtonGroup(QAbstractButton *slot_btn) { + if (slot_btn != NULL) { + list_widget_available->clear(); + QString object_name = slot_btn->objectName(); + qDebug() << object_name ; + int button_id = object_name.right(object_name.length() - 15).toInt(); + for(int var = 0; var < CHANNEL_COUNT ; ++var){ + QString item_str = QString("S%1C%2P##NO (Slot %3 Channel %4 Not OK)").arg(QString::number(button_id, 10).rightJustified(2, '0')).arg(QString::number(var+1, 10).rightJustified(2, '0')).arg(button_id).arg(var+1); + QListWidgetItem *item = new QListWidgetItem(item_str); + QString item_data = QString("S%1C%2P##NO").arg(QString::number(button_id, 10).rightJustified(2, '0')).arg(QString::number(var+1, 10).rightJustified(2, '0')); + item->setData(Qt::UserRole, item_data); + list_widget_available->addItem(item); + } + } +} + + +void SingleRelay::on_pushButton_enter_clicked() +{ + +} + + +void SingleRelay::on_pushButton_clr_clicked() +{ + textEdit_relay->setText(""); +} + + +void SingleRelay::on_pushButton_backspace_clicked() +{ + +} +void SingleRelay::keyPressEvent(QKeyEvent *event) { +// if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) { +// removeLastElement(); +// return; +// } +// QTextEdit::keyPressEvent(event); +} + +void SingleRelay::on_pushButton_confirm_clicked() +{ + single_relay_nok_data->single_relay_nok[current_index].logic_expression = textEdit_relay->toPlainText(); + this->close(); +} +void SingleRelay::onComboBoxIndexChanged(int index){ + + qDebug()<< "[SingleRelay]:index " << index; + single_relay_nok_data->single_relay_nok[current_index].logic_expression = textEdit_relay->toPlainText(); + current_index = index; + textEdit_relay->setPlainText(single_relay_nok_data->single_relay_nok[index].logic_expression); +} + diff --git a/singlerelay.h b/singlerelay.h index 5fce5e5..3795149 100644 --- a/singlerelay.h +++ b/singlerelay.h @@ -3,39 +3,72 @@ #include #include -#include -#include -#include -#include +#include +#include +#include "data_config.h" +#include "config_mgr.h" +#include "singlerelay_data.h" namespace Ui { class SingleRelay; } -class SingleRelay : public QDialog { - Q_OBJECT - - public: - explicit SingleRelay(QWidget *parent = nullptr); - ~SingleRelay(); - - private slots: - void on_pushButton_cancel_clicked(); - - private: - Ui::SingleRelay *ui; -}; class DropTextEdit : public QTextEdit { + Q_OBJECT public: DropTextEdit(QWidget *parent = nullptr) : QTextEdit(parent) { setAcceptDrops(true); - setReadOnly(false); // 确保不是只读的 } +public slots: + void removeLastElement() { + QString html = this->toHtml(); + // 匹配 元素 + QRegularExpression spanRe(R"(]*>[^<]*)"); + QRegularExpressionMatchIterator spanIt = spanRe.globalMatch(html); + + // 匹配符号元素(注意符号两边可能有空格) + QRegularExpression symbolRe(R"((\s?[+*()]\s?))"); + QRegularExpressionMatchIterator symbolIt = symbolRe.globalMatch(html); + + // 保存所有匹配结果:位置 + 匹配内容 + struct Match { + int start; + int length; + }; + QList matches; + + while (spanIt.hasNext()) { + auto m = spanIt.next(); + matches.append({ m.capturedStart(), m.capturedLength() }); + } + + while (symbolIt.hasNext()) { + auto m = symbolIt.next(); + matches.append({ m.capturedStart(), m.capturedLength() }); + } + + if (matches.isEmpty()) + return; + + // 找出最后出现的元素 + std::sort(matches.begin(), matches.end(), [](const Match &a, const Match &b) { + return a.start < b.start; + }); + + // 删除最后一个匹配 + Match last = matches.last(); + html.remove(last.start, last.length); + this->setHtml(html); + + // 保持光标在末尾 + QTextCursor cursor = this->textCursor(); + cursor.movePosition(QTextCursor::End); + this->setTextCursor(cursor); + } protected: void dragEnterEvent(QDragEnterEvent *event) override { - qDebug() << "dragEnterEvent" << event->mimeData()->formats(); - if (event->mimeData()->hasText()) { + if (event->mimeData()->hasFormat("application/x-custom")) { event->acceptProposedAction(); } else { event->ignore(); @@ -43,7 +76,7 @@ protected: } void dragMoveEvent(QDragMoveEvent *event) override { - if (event->mimeData()->hasText()) { + if (event->mimeData()->hasFormat("application/x-custom")) { event->acceptProposedAction(); } else { event->ignore(); @@ -51,12 +84,66 @@ protected: } void dropEvent(QDropEvent *event) override { - if (event->mimeData()->hasText()) { - insertPlainText(event->mimeData()->text()); + if (!this->toPlainText().isEmpty()) { + event->ignore(); + return; + } + if (event->mimeData()->hasFormat("application/x-custom")) { + QByteArray data = event->mimeData()->data("application/x-custom"); + QString text = QString::fromUtf8(data); + + QTextCursor cursor = this->textCursor(); + this->setTextCursor(cursor); + + QString html = QString( + "%1" + ).arg(text); + cursor.insertHtml(html); event->acceptProposedAction(); } else { event->ignore(); } } }; +class SingleRelay : public QDialog { + Q_OBJECT + + public: + explicit SingleRelay(int slot,int cardtype,QWidget *parent = nullptr); + ~SingleRelay(); + int slot_no; + CardType car_type; + private slots: + void keyPressEvent(QKeyEvent *event); + void on_pushButton_cancel_clicked(); + void OnButtonGroup(QAbstractButton *); + + void on_pushButton_enter_clicked(); + + void on_pushButton_backspace_clicked(); + + void on_pushButton_clr_clicked(); + + void on_pushButton_confirm_clicked(); + + void onComboBoxIndexChanged(int index); + +private: + Ui::SingleRelay *ui; + QButtonGroup * btnGroup_slot = nullptr; + DraggableListWidget *list_widget_available = nullptr; + DropTextEdit *textEdit_relay = nullptr; + std::shared_ptr single_relay_nok_data = nullptr; + int current_index; + void Init(); +}; + #endif // SINGLERELAY_H diff --git a/singlerelay.ui b/singlerelay.ui index da020b3..57f59c0 100644 --- a/singlerelay.ui +++ b/singlerelay.ui @@ -6,7 +6,7 @@ 0 0 - 943 + 924 569 @@ -26,7 +26,7 @@ 告警驱动逻辑: - + 220 @@ -52,24 +52,11 @@ NCT6100T - - - - 690 - 230 - 61 - 31 - - - - 或(*) - - 620 - 30 + 10 111 16 @@ -78,13 +65,13 @@ 可用的告警: - + false - 510 + 420 530 71 32 @@ -94,42 +81,6 @@ 打 印... - - - - 620 - 50 - 301 - 161 - - - - true - - - QAbstractItemView::DragOnly - - - - S02C01P##NO (Slot 2 Channel 1 Not OK) - - - - - S02C02P##NO (Slot 2 Channel 2 Not OK) - - - - - S02C03P##NO (Slot 2 Channel 3 Not OK) - - - - - S02C04P##NO (Slot 2 Channel 4 Not OK) - - - @@ -142,7 +93,7 @@ 继电器关联 - + 20 @@ -259,58 +210,6 @@ - - - - 690 - 270 - 61 - 31 - - - - ) - - - - - - 113 - 9 - 31 - 21 - - - - 13 - - - - - - 620 - 230 - 61 - 31 - - - - 与(*) - - - - - - 620 - 270 - 61 - 31 - - - - - - @@ -324,10 +223,10 @@ 继电器槽位: - + - 760 + 630 230 61 71 @@ -337,13 +236,13 @@ Enter - + false - 600 + 520 530 81 32 @@ -353,10 +252,10 @@ 帮 助 - + - 850 + 710 270 61 31 @@ -366,10 +265,10 @@ CLR - + - 850 + 710 230 61 31 @@ -382,7 +281,7 @@ - 410 + 320 530 71 32 @@ -392,7 +291,7 @@ 取 消 - + 620 @@ -777,7 +676,7 @@ - + 30 @@ -796,7 +695,7 @@ - + 30 @@ -815,7 +714,7 @@ - + 30 @@ -834,7 +733,7 @@ - + 30 @@ -853,7 +752,7 @@ - + 30 @@ -872,7 +771,7 @@ - + 30 @@ -891,7 +790,7 @@ - + 30 @@ -910,7 +809,7 @@ - + 30 @@ -929,7 +828,7 @@ - + 30 @@ -948,7 +847,7 @@ - + 30 @@ -967,7 +866,7 @@ - + 30 @@ -986,7 +885,7 @@ - + 30 @@ -1005,7 +904,7 @@ - + 30 @@ -1024,7 +923,7 @@ - + 30 @@ -1043,7 +942,7 @@ - + 30 @@ -1062,7 +961,7 @@ - + 30 @@ -1095,6 +994,32 @@ + + + + 620 + 40 + 291 + 181 + + + + + + + 110 + 10 + 61 + 16 + + + + TextLabel + + + Qt::AlignCenter + + diff --git a/tachometer_data.h b/tachometer_data.h index 8b768bc..f9ae659 100644 --- a/tachometer_data.h +++ b/tachometer_data.h @@ -2,13 +2,15 @@ #define TACHOMETERDATA_H #include "cardbase.h" +#include +#include class TachometerData : public CardBase { public: TachometerData(); TachometerVariables variables_[4]; - SpeedAlert speed_alert; + SpeedAlert alert_danger[CHANNEL_COUNT]; }; #endif // TACHOMETERDATA_H diff --git a/tmrrelayassociation.cpp b/tmrrelayassociation.cpp index 25966b3..b103b13 100644 --- a/tmrrelayassociation.cpp +++ b/tmrrelayassociation.cpp @@ -1,14 +1,340 @@ #include "tmrrelayassociation.h" #include "ui_tmrrelayassociation.h" +#include "vibrationdata.h" +#include +#include -TMRRelayAssociation::TMRRelayAssociation(QWidget *parent) + + +TMRRelayAssociation::TMRRelayAssociation(int slot,int cardtype,QWidget *parent) : QDialog(parent) , ui(new Ui::TMRRelayAssociation) { ui->setupUi(this); + slot_no = slot; + car_type = static_cast(cardtype); + ui->label_slot_no->setText(QString::number(slot_no)); + QVBoxLayout *layout_available = new QVBoxLayout(ui->widget_available); + list_widget_available = new DraggableListWidget; + layout_available->addWidget(list_widget_available); + list_widget_available->setDragEnabled(true); + + QVBoxLayout *layout_relay = new QVBoxLayout(ui->widget_relay); + treeView_relay = new QTreeView; + layout_relay->addWidget(treeView_relay); + treeView_relay->setDragEnabled(true); // 启用拖动 + treeView_relay->setAcceptDrops(true); // 接受放下 + treeView_relay->setDropIndicatorShown(true); // 显示放置指示器 + treeView_relay->setDragDropMode(QAbstractItemView::DropOnly); + model_Relay = new DropTreeModel(this); //创建模型指定父类 + treeView_relay->setModel(model_Relay); + treeView_relay->setHeaderHidden(true); + + btnGroup_slot = new QButtonGroup(this); + btnGroup_slot->addButton(ui->pushButton_slot1); + btnGroup_slot->addButton(ui->pushButton_slot2); + btnGroup_slot->addButton(ui->pushButton_slot3); + btnGroup_slot->addButton(ui->pushButton_slot4); + btnGroup_slot->addButton(ui->pushButton_slot5); + btnGroup_slot->addButton(ui->pushButton_slot6); + btnGroup_slot->addButton(ui->pushButton_slot7); + btnGroup_slot->addButton(ui->pushButton_slot8); + btnGroup_slot->addButton(ui->pushButton_slot9); + btnGroup_slot->addButton(ui->pushButton_slot10); + btnGroup_slot->addButton(ui->pushButton_slot11); + btnGroup_slot->addButton(ui->pushButton_slot12); + btnGroup_slot->addButton(ui->pushButton_slot13); + btnGroup_slot->addButton(ui->pushButton_slot14); + btnGroup_slot->addButton(ui->pushButton_slot15); + btnGroup_slot->addButton(ui->pushButton_slot16); + + connect(btnGroup_slot, SIGNAL(buttonClicked(QAbstractButton *)), this, SLOT(OnButtonGroup(QAbstractButton *))); + connect(ui->comboBox_relay_ch, QOverload::of(&QComboBox::currentIndexChanged), + 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(); + // QString expr = "((S01C01A1 + S01C02A1 + (S02C01A1 * S02C01A2)) * (S02C01A2 + S02C01A1 + (S02C01A1 + S02C01A2)) * (S02C01A1 * S02C01A2))"; + // setExpressionToTreeView(treeView_relay, expr); } TMRRelayAssociation::~TMRRelayAssociation() { delete ui; } +void TMRRelayAssociation::Init(){ + +} +ExprNode* TMRRelayAssociation::parseExpression(const QString& expr, int& pos) { + auto skipSpaces = [&]() { + while (pos < expr.length() && expr[pos].isSpace()) pos++; + }; + + QStack nodeStack; + QStack opStack; + + while (pos < expr.length()) { + skipSpaces(); + if (pos >= expr.length()) break; + + QChar ch = expr[pos]; + + if (ch == '(') { + pos++; + nodeStack.push(parseExpression(expr, pos)); + } else if (ch == ')') { + pos++; + break; + } else if (ch == '+' || ch == '*') { + opStack.push(QString(ch)); + pos++; + } else { + QString token; + while (pos < expr.length() && expr[pos].isLetterOrNumber()) { + token += expr[pos++]; + } + nodeStack.push(new ExprNode{token, {}}); + } + + while (opStack.size() > 0 && nodeStack.size() >= 2) { + QString op = opStack.pop(); + ExprNode* right = nodeStack.pop(); + ExprNode* left = nodeStack.pop(); + + if (left->value == op) { + left->children.append(right); + nodeStack.push(left); + } else if (right->value == op) { + right->children.prepend(left); + nodeStack.push(right); + } else { + ExprNode* parent = new ExprNode{op, {left, right}}; + nodeStack.push(parent); + } + } + } + + return nodeStack.isEmpty() ? nullptr : nodeStack.top(); +} +QStandardItem* TMRRelayAssociation::buildItemTree(ExprNode* node) { + if (!node) return nullptr; + QStandardItem* item = new QStandardItem(node->value); + for (ExprNode* child : node->children) { + item->appendRow(buildItemTree(child)); + } + return item; +} +void TMRRelayAssociation::setExpressionToTreeView(QTreeView* treeView, const QString& expr) { + int pos = 0; + ExprNode* root = parseExpression(expr, pos); + QStandardItem* rootItem = buildItemTree(root); + + QStandardItemModel* model = new QStandardItemModel(); + model->appendRow(rootItem); + treeView->setModel(model); + treeView->expandAll(); +} +QString TMRRelayAssociation::buildLogicExpression(QStandardItem *item) { + if (!item) return ""; + + int childCount = item->rowCount(); + QString text = item->text().trimmed(); + + if (childCount == 0) { + // 叶子节点,直接返回表达式,比如 S01C01A1 + return text; + } + + // 判断当前是 +(OR)还是 *(AND) + QString opStr = (text == "+") ? "+" : + (text == "*") ? "*" : ""; + + // 如果不是 +/*,视为叶子节点 + if (opStr.isEmpty()) { + return text; + } + + QStringList subExprs; + for (int i = 0; i < childCount; ++i) { + QStandardItem *child = item->child(i); + subExprs << buildLogicExpression(child); + } + + return "(" + subExprs.join(" " + opStr + " ") + ")"; +} +QStandardItem* TMRRelayAssociation::parseExpression(const QString &expr) { + QStack stack; // 用来存储节点 + QStack ops; // 用来存储操作符 + + int pos = 0; + int length = expr.length(); + + while (pos < length) { + QRegExp regex("(\\()|([A-Za-z0-9]+)|([+*])|(\\))"); + + if (regex.indexIn(expr, pos) != -1) { + QString matchedText = regex.cap(0); + QString group1 = regex.cap(1); // ( + QString group2 = regex.cap(2); // S01C01A1 + QString group3 = regex.cap(3); // + or * + QString group4 = regex.cap(4); // ) + + // 处理左括号,表示子表达式的开始 + if (!group1.isEmpty()) { + ops.push("("); // 推入栈 + } + // 处理右括号,表示子表达式的结束 + else if (!group4.isEmpty()) { + // 遇到右括号时开始弹出栈中的操作符,直到遇到左括号 + while (!ops.isEmpty() && ops.top() != "(") { + QString op = ops.pop(); + QStandardItem* right = stack.pop(); + QStandardItem* left = stack.pop(); + QStandardItem* node = new QStandardItem(op); + node->appendRow(left); // 左子树 + node->appendRow(right); // 右子树 + stack.push(node); // 将新的节点推入栈 + } + ops.pop(); // 弹出左括号 + } + // 处理操作符 + 和 * + else if (!group3.isEmpty()) { + ops.push(group3); // 操作符入栈 + } + // 处理终端元素(比如 S01C01A1) + else if (!group2.isEmpty()) { + QStandardItem* item = new QStandardItem(group2); + stack.push(item); // 将数据节点推入栈 + } + + pos = regex.pos(0) + regex.matchedLength(); + } else { + break; // 防止无限循环 + } + } + + // 最终合并栈中的所有内容 + while (!ops.isEmpty()) { + QString op = ops.pop(); + QStandardItem* right = stack.pop(); + QStandardItem* left = stack.pop(); + QStandardItem* node = new QStandardItem(op); + node->appendRow(left); // 左子树 + node->appendRow(right); // 右子树 + stack.push(node); + } + + // 返回栈顶的节点,应该是根节点 + return stack.isEmpty() ? nullptr : stack.pop(); +} +void TMRRelayAssociation::buildTreeFromExpression(QTreeView *treeView, const QString &expr) { + QStandardItemModel* model = new QStandardItemModel(); + QStandardItem* rootItem = parseExpression(expr); + + if (rootItem) { + model_Relay->appendRow(rootItem); + } + + treeView_relay->setModel(model_Relay); +} + +void TMRRelayAssociation::OnButtonGroup(QAbstractButton *slot_btn) { + if (slot_btn != NULL) { + list_widget_available->clear(); + QString object_name = slot_btn->objectName(); + 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); + for(int var = 0; var < CHANNEL_COUNT ; ++var){ + if(ptr->alert_danger[var].direct_enable || + ptr->alert_danger[var].x1_ampl_enable || + ptr->alert_danger[var].x2_ampl_enable){ + QString item_str = QString("S%1C%2A1 (槽位 %3 通道 %4 警报)").arg(QString::number(button_id, 10).rightJustified(2, '0')).arg(QString::number(var+1, 10).rightJustified(2, '0')).arg(button_id).arg(var+1); + QListWidgetItem *item = new QListWidgetItem(item_str); + QString item_data = QString("S%1C%2A1").arg(QString::number(button_id, 10).rightJustified(2, '0')).arg(QString::number(var+1, 10).rightJustified(2, '0')); + item->setData(Qt::UserRole, item_data); + list_widget_available->addItem(item); + } + if(ptr->alert_danger[var].danger_enable){ + QString item_str = QString("S%1C%2A2 (槽位 %3 通道 %4 危险)").arg(QString::number(button_id, 10).rightJustified(2, '0')).arg(QString::number(var+1, 10).rightJustified(2, '0')).arg(button_id).arg(var+1); + QListWidgetItem *item = new QListWidgetItem(item_str); + QString item_data = QString("S%1C%2A2").arg(QString::number(button_id, 10).rightJustified(2, '0')).arg(QString::number(var+1, 10).rightJustified(2, '0')); + 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() +{ + this->close(); +} + + +void TMRRelayAssociation::on_pushButton_confirm_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); + if (!finalExpr.isEmpty()) { + finalExpr += " OR "; + } + finalExpr += expr; + } + + qDebug() << "逻辑表达式:" << finalExpr; + this->close(); +} +void TMRRelayAssociation::onComboBoxIndexChanged(int index){ + +} + +void TMRRelayAssociation::on_pushButton_and_clicked() +{ + +} + + +void TMRRelayAssociation::on_pushButton_or_clicked() +{ + +} +void TMRRelayAssociation::slotDeleteItem() +{ + QModelIndex curIndex = treeView_relay->currentIndex(); + if(curIndex.isValid()){ + model_Relay->removeRow(curIndex.row(),curIndex.parent()); + } + +} +void TMRRelayAssociation::on_treeView_Relay_customContextMenuRequested(const QPoint &pos) +{ + qDebug() << "on_treeView_Relay_customContextMenuRequested" <indexAt(pos); //当前点击的元素的index + QModelIndex index = curIndex.sibling(curIndex.row(),0); //该行的第1列元素的index + QMenu menu(this); + if (index.isValid()){ + //添加一行菜单,进行展开 + menu.addAction(QStringLiteral("删除"), this, SLOT(slotDeleteItem())); + menu.addSeparator(); //添加一个分隔线 + } + menu.exec(QCursor::pos()); //显示菜单 +} diff --git a/tmrrelayassociation.h b/tmrrelayassociation.h index 55cace7..1f198ae 100644 --- a/tmrrelayassociation.h +++ b/tmrrelayassociation.h @@ -2,21 +2,97 @@ #define TMRRELAYASSOCIATION_H #include +#include +#include +#include "data_config.h" +#include "config_mgr.h" +#include //数据模型类 +#include namespace Ui { class TMRRelayAssociation; } +struct ExprNode { + QString value; + QList children; +}; + +class DropTreeModel : public QStandardItemModel { +public: + using QStandardItemModel::QStandardItemModel; + + QStringList mimeTypes() const override { + return { "application/x-custom" }; + } + + bool dropMimeData(const QMimeData *data, Qt::DropAction action, + int row, int column, const QModelIndex &parent) override { + if (!data->hasFormat("application/x-custom")) + return false; + + QByteArray rawData = data->data("application/x-custom"); + QString customText = QString::fromUtf8(rawData); + + QStandardItem *newItem = new QStandardItem(customText); + newItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | + Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled); + + QStandardItem *parentItem = this->itemFromIndex(parent); + if (!parentItem) parentItem = this->invisibleRootItem(); + + if (row < 0) + parentItem->appendRow(newItem); + else + parentItem->insertRow(row, newItem); + + return true; + } + + Qt::DropActions supportedDropActions() const override { + return Qt::CopyAction; + } +}; class TMRRelayAssociation : public QDialog { Q_OBJECT public: - explicit TMRRelayAssociation(QWidget *parent = nullptr); + explicit TMRRelayAssociation(int slot,int cardtype,QWidget *parent = nullptr); ~TMRRelayAssociation(); + int slot_no; + CardType car_type; +private slots: + void on_pushButton_cancel_clicked(); + void on_pushButton_confirm_clicked(); + + void onComboBoxIndexChanged(int index); + + void OnButtonGroup(QAbstractButton *); + + + void on_pushButton_and_clicked(); + + void on_pushButton_or_clicked(); + + void on_treeView_Relay_customContextMenuRequested(const QPoint &pos); + void slotDeleteItem(); private: Ui::TMRRelayAssociation *ui; + QButtonGroup * btnGroup_slot = nullptr; + DraggableListWidget *list_widget_available = nullptr; + int current_index; + QTreeView *treeView_relay; + QStandardItemModel *model_Relay; + + void Init(); + void buildTreeFromExpression(QTreeView *treeView, const QString &expr); + ExprNode* parseExpression(const QString& expr, int& pos); + QStandardItem* buildItemTree(ExprNode* node); + void setExpressionToTreeView(QTreeView* treeView, const QString& expr); + QStandardItem* parseExpression(const QString &expr); + QString buildLogicExpression(QStandardItem *item); }; #endif // TMRRELAYASSOCIATION_H diff --git a/tmrrelayassociation.ui b/tmrrelayassociation.ui index 6c39c67..fc3e1eb 100644 --- a/tmrrelayassociation.ui +++ b/tmrrelayassociation.ui @@ -6,7 +6,7 @@ 0 0 - 853 + 869 624 @@ -26,19 +26,6 @@ 继电器槽位: - - - - 123 - 19 - 31 - 21 - - - - 13 - - @@ -52,56 +39,6 @@ 可用的告警: - - - - 230 - 360 - 361 - 161 - - - - - S02C01A1 (Slot 2 Channel 1 Alert) - - - - - S02C01A2 (Slot 2 Channel 1 Danger) - - - - - S02C02A1 (Slot 2 Channel 2 Alert) - - - - - S02C02A2 (Slot 2 Channel 2 Danger) - - - - - S02C03A1 (Slot 2 Channel 3 Alert) - - - - - S02C03A2 (Slot 2 Channel 3 Danger) - - - - - S02C04A1 (Slot 2 Channel 4 Alert) - - - - - S02C04A2 (Slot 2 Channel 4 Danger) - - - @@ -114,7 +51,7 @@ TMR继电器关联 - + 20 @@ -234,8 +171,8 @@ - 60 - 550 + 620 + 60 91 16 @@ -270,10 +207,10 @@ 打 印... - + - 230 + 240 590 71 32 @@ -302,7 +239,7 @@ - 410 + 350 590 71 32 @@ -325,7 +262,7 @@ NCT6100T - + 30 @@ -710,7 +647,7 @@ - + 30 @@ -729,7 +666,7 @@ - + 30 @@ -748,7 +685,7 @@ - + 30 @@ -767,7 +704,7 @@ - + 30 @@ -786,7 +723,7 @@ - + 30 @@ -805,7 +742,7 @@ - + 30 @@ -824,7 +761,7 @@ - + 30 @@ -843,7 +780,7 @@ - + 30 @@ -862,7 +799,7 @@ - + 30 @@ -881,7 +818,7 @@ - + 30 @@ -900,7 +837,7 @@ - + 30 @@ -919,7 +856,7 @@ - + 30 @@ -938,7 +875,7 @@ - + 30 @@ -957,7 +894,7 @@ - + 30 @@ -976,7 +913,7 @@ - + 30 @@ -995,7 +932,7 @@ - + 30 @@ -1018,13 +955,62 @@ - + - 620 - 90 - 201 - 431 + 130 + 20 + 54 + 12 + + + + TextLabel + + + + + + 540 + 380 + 51 + 41 + + + + 与(+) + + + + + + 540 + 440 + 51 + 41 + + + + 或(*) + + + + + + 230 + 360 + 301 + 161 + + + + + + + 610 + 80 + 191 + 421 diff --git a/vibrationdata.h b/vibrationdata.h index da29cf4..94e5026 100644 --- a/vibrationdata.h +++ b/vibrationdata.h @@ -12,7 +12,7 @@ class VibrationData : public CardBase { void RemoveChannel(int cid); SeismicMonitor base_config_[CHANNEL_COUNT]; std::vector> variables_; - VibAlertDanger vib_alert_danger[CHANNEL_COUNT]; + VibAlertDanger alert_danger[CHANNEL_COUNT]; }; #endif // VIBRATIONDATA_H