mainwindow.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809
  1. #include "mainwindow.h"
  2. #include "ui_mainwindow.h"
  3. #include <QVBoxLayout>
  4. #include <QHBoxLayout>
  5. #include <QSplitter>
  6. #include <QListView>
  7. #include <QTableView>
  8. #include <QHeaderView>
  9. #include <QDateTime>
  10. #include <QDebug>
  11. #include <QItemSelectionModel>
  12. #include <QtCharts/QDateTimeAxis>
  13. #include <QtCharts/QValueAxis>
  14. #include <QMessageBox>
  15. MainWindow::MainWindow(QWidget *parent)
  16. : QMainWindow(parent),
  17. ui(new Ui::MainWindow),
  18. m_busCore(new SoftBusCore(this)),
  19. m_serialManager(new SerialManager(m_busCore, this)),
  20. m_dataTable(new QTableView(this)),
  21. m_serial_settingsModel(new QStandardItemModel(this)),
  22. m_deviceModel(new QStandardItemModel(this)),
  23. m_raw_dataModel(new QStandardItemModel(this)),
  24. m_bus_dataModel(new QStandardItemModel(this)),
  25. m_dataSeries(new QLineSeries())
  26. {
  27. ui->setupUi(this);
  28. // 初始化系统
  29. initializeSystem();
  30. // 创建UI
  31. createUI();
  32. // 创建连接
  33. createConnections();
  34. // 启动串口监控
  35. m_serialManager->startDiscovery();
  36. // 更新设备列表
  37. updateDeviceList();
  38. }
  39. MainWindow::~MainWindow()
  40. {
  41. // 停止串口监控
  42. m_serialManager->stopDiscovery();
  43. }
  44. void MainWindow::initializeSystem()
  45. {
  46. // 初始化数据库
  47. if (!m_busCore->initDB("raw_db", "bus_db"))
  48. {
  49. qCritical() << "Failed to initialize database";
  50. }
  51. // 注册串口设备
  52. foreach (const QString &portName, m_serialManager->getAvailablePorts())
  53. {
  54. DeviceInfo device;
  55. device.id = portName;
  56. device.type = "serial";
  57. device.address = 1;
  58. device.protocol = "modbus"; // 默认协议
  59. device.protocol_detail = "modbus-rtu";
  60. m_busCore->registerDevice(device);
  61. }
  62. }
  63. void MainWindow::createUI()
  64. {
  65. // 左侧设备列表
  66. ui->listV_device->setModel(m_deviceModel);
  67. ui->lineEdit_serial_send->setText("01 03 01 00 00 5C 44 0F ");
  68. // 右侧数据表格(上方为配置表格 ,下方为图表) )
  69. ui->tableV_serial_set->setModel(m_serial_settingsModel);
  70. ui->tableV_serial_set->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
  71. m_serial_settingsModel->setHorizontalHeaderLabels({"参数", "值"});
  72. SerialManager::SerialConfig config = m_serialManager->getSerialConfig();
  73. QList<QStandardItem *> baudRateRow;
  74. baudRateRow << new QStandardItem("波特率") << new QStandardItem(QString::number(config.baudRate));
  75. m_serial_settingsModel->appendRow(baudRateRow);
  76. QList<QStandardItem *> dataBitsRow;
  77. dataBitsRow << new QStandardItem("数据位") << new QStandardItem(QString::number(config.dataBits));
  78. m_serial_settingsModel->appendRow(dataBitsRow);
  79. QList<QStandardItem *> parityRow;
  80. parityRow << new QStandardItem("校验") << new QStandardItem(QString::number(config.parity));
  81. m_serial_settingsModel->appendRow(parityRow);
  82. QList<QStandardItem *> stopBitsRow;
  83. stopBitsRow << new QStandardItem("停止位") << new QStandardItem(QString::number(config.stopBits));
  84. m_serial_settingsModel->appendRow(stopBitsRow);
  85. QList<QStandardItem *> flowControlRow;
  86. flowControlRow << new QStandardItem("流控") << new QStandardItem(QString::number(config.flowControl));
  87. m_serial_settingsModel->appendRow(flowControlRow);
  88. // Raw Data Table
  89. ui->tableV_raw_data->setModel(m_raw_dataModel);
  90. m_raw_dataModel->setHorizontalHeaderLabels({"时间", "来源", "协议", "数据"});
  91. ui->tableV_raw_data->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
  92. ui->tableV_raw_data->setEditTriggers(QAbstractItemView::NoEditTriggers);
  93. ui->tableV_raw_data->setSelectionBehavior(QAbstractItemView::SelectRows);
  94. ui->tableV_raw_data->setSelectionMode(QAbstractItemView::SingleSelection);
  95. // Bus Data Table
  96. ui->tableV_bus_data->setModel(m_bus_dataModel);
  97. m_bus_dataModel->setHorizontalHeaderLabels({"时间", "来源", "协议", "数据"});
  98. ui->tableV_bus_data->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
  99. ui->tableV_bus_data->setEditTriggers(QAbstractItemView::NoEditTriggers);
  100. ui->tableV_bus_data->setSelectionBehavior(QAbstractItemView::SelectRows);
  101. ui->tableV_bus_data->setSelectionMode(QAbstractItemView::SingleSelection);
  102. // ui->tableV_bus_data->setModel();
  103. }
  104. void MainWindow::createConnections()
  105. {
  106. // 设备注册/注销信号
  107. connect(m_busCore, &SoftBusCore::deviceRegistered, this, &MainWindow::updateDeviceList);
  108. connect(m_busCore, &SoftBusCore::deviceUnregistered, this, &MainWindow::updateDeviceList);
  109. // 总线消息存储信号
  110. connect(m_busCore, &SoftBusCore::busMessageStored, this, &MainWindow::updateChart);
  111. // 设备选择信号
  112. connect(ui->listV_device->selectionModel(), &QItemSelectionModel::currentChanged, this, &MainWindow::onDeviceSelected);
  113. // 串口管理器信号
  114. connect(m_serialManager, &SerialManager::portDiscovered, this, [this](const QString &portName, const QString &desc)
  115. {
  116. Q_UNUSED(desc);
  117. updateDeviceList(); });
  118. connect(m_serialManager, &SerialManager::portRemoved, this, [this](const QString &portName)
  119. { updateDeviceList(); });
  120. connect(m_serialManager, &SerialManager::dataReceived, this, &MainWindow::onSerialDataReceived);
  121. }
  122. void MainWindow::updateDeviceList()
  123. {
  124. m_deviceModel->clear();
  125. // 添加串口设备
  126. foreach (const QString &portName, m_serialManager->getAvailablePorts())
  127. {
  128. QStandardItem *item = new QStandardItem("串口: " + portName);
  129. item->setData(portName, Qt::UserRole);
  130. m_deviceModel->appendRow(item);
  131. }
  132. // 添加其他类型设备(CAN、以太网等)
  133. // ...
  134. }
  135. void MainWindow::onDeviceSelected(const QModelIndex &index)
  136. {
  137. if (index.isValid())
  138. {
  139. // 显示设备相关数据
  140. QString deviceId = index.data(Qt::UserRole).toString();
  141. m_currentDeviceId = deviceId;
  142. m_serialManager->openSerialPort(QSerialPortInfo(deviceId));
  143. showRawData(deviceId);
  144. showBusMessages(deviceId);
  145. modbusSetting_ui(deviceId);
  146. }
  147. }
  148. void MainWindow::showRawData(const QString &deviceId)
  149. {
  150. m_raw_dataModel->removeRows(0, m_raw_dataModel->rowCount());
  151. // 查询最近10分钟的原始数据
  152. qint64 endTime = QDateTime::currentMSecsSinceEpoch();
  153. qint64 startTime = endTime - 10 * 60 * 1000;
  154. QList<QByteArray> rawData = m_busCore->queryRawData(deviceId, startTime, endTime);
  155. for (const QByteArray &data : rawData)
  156. {
  157. QList<QStandardItem *> row;
  158. // 时间戳是数据的前8个字节
  159. qint64 timestamp = *reinterpret_cast<const qint64 *>(data.constData());
  160. row << new QStandardItem(QDateTime::fromMSecsSinceEpoch(timestamp).toString("hh:mm:ss"));
  161. row << new QStandardItem(deviceId);
  162. row << new QStandardItem("RAW");
  163. row << new QStandardItem(data.mid(8).toHex());
  164. m_raw_dataModel->appendRow(row);
  165. }
  166. }
  167. void MainWindow::showBusMessages(const QString &source)
  168. {
  169. // 查询最近10分钟的总线消息
  170. qint64 endTime = QDateTime::currentMSecsSinceEpoch();
  171. qint64 startTime = endTime - 10 * 60 * 1000;
  172. QList<BusMessage> messages = m_busCore->queryBusMessages(source, "data_processor", startTime, endTime);
  173. for (const BusMessage &msg : messages)
  174. {
  175. QList<QStandardItem *> row;
  176. row << new QStandardItem(QDateTime::fromMSecsSinceEpoch(msg.timestamp).toString("hh:mm:ss"));
  177. row << new QStandardItem(msg.source);
  178. row << new QStandardItem(msg.payload["protocol"].toString());
  179. QString dataStr;
  180. if (msg.payload["protocol"] == "modbus")
  181. {
  182. dataStr = QString("ID:%1 FN:%2")
  183. .arg(msg.payload["slave_id"].toInt())
  184. .arg(msg.payload["function_code"].toInt());
  185. }
  186. else
  187. {
  188. dataStr = msg.payload["raw_data"].toString();
  189. }
  190. row << new QStandardItem(dataStr);
  191. m_bus_dataModel->appendRow(row);
  192. }
  193. }
  194. void MainWindow::updateChart(const BusMessage &message)
  195. {
  196. if (message.payload["protocol"] != "modbus")
  197. return;
  198. // 解析Modbus数据并更新图表
  199. QJsonArray dataArray = message.payload["data"].toArray();
  200. if (dataArray.size() > 0)
  201. {
  202. double value = dataArray[0].toDouble();
  203. qint64 timestamp = message.timestamp;
  204. m_dataSeries->append(timestamp, value);
  205. // 限制图表显示的数据点数量
  206. if (m_dataSeries->count() > 100)
  207. {
  208. m_dataSeries->removePoints(0, m_dataSeries->count() - 100);
  209. }
  210. }
  211. }
  212. // btn_fun
  213. // QCheckBox *checkBox_serial_hex;
  214. // QCheckBox *checkBox_serial_ascii;
  215. // QTextEdit *textEdit_serial;
  216. // QPushButton *btn_serial_clear;
  217. // QPushButton *btn_serial_send;
  218. void MainWindow::on_btn_serial_clear_clicked()
  219. {
  220. ui->textEdit_serial->clear();
  221. }
  222. void MainWindow::on_btn_serial_clear_send_clicked()
  223. {
  224. ui->lineEdit_serial_send->clear();
  225. }
  226. // 发送串口数据
  227. void MainWindow::on_btn_serial_send_clicked()
  228. {
  229. if (!m_serialManager->isPortOpen(m_currentDeviceId))
  230. {
  231. QMessageBox::warning(this, "串口未打开", "请先打开串口设备");
  232. return;
  233. }
  234. QString dataToSend = ui->lineEdit_serial_send->text();
  235. if (dataToSend.isEmpty())
  236. {
  237. QMessageBox::information(this, "发送数据", "请输入要发送的数据");
  238. return;
  239. }
  240. // 根据当前显示模式处理数据
  241. if (ui->checkbox_serial_hex->isChecked())
  242. {
  243. // 十六进制模式 - 将输入视为十六进制字符串
  244. QByteArray hexData = QByteArray::fromHex(dataToSend.toLatin1());
  245. m_serialManager->writeData(m_currentDeviceId, hexData);
  246. }
  247. else
  248. {
  249. // ASCII模式 - 直接发送文本
  250. m_serialManager->writeData(m_currentDeviceId, dataToSend.toUtf8());
  251. }
  252. // 在接收区显示发送的数据(带发送标记)
  253. QString timestamp = QDateTime::currentDateTime().toString("[hh:mm:ss]");
  254. ui->textEdit_serial->append(QString("<span style='color:blue;'>%1 [发送] %2</span>")
  255. .arg(timestamp)
  256. .arg(dataToSend));
  257. // 清空发送输入框
  258. // ui->lineEdit_serial_send->clear();
  259. }
  260. // 处理接收到的串口数据
  261. void MainWindow::onSerialDataReceived(const QString &portName, const QByteArray &data)
  262. {
  263. QString displayData;
  264. QString timestamp = QDateTime::currentDateTime().toString("[hh:mm:ss]");
  265. if (ui->checkbox_serial_hex->isChecked())
  266. {
  267. // 十六进制显示
  268. displayData = data.toHex(' ').toUpper();
  269. }
  270. else
  271. {
  272. // ASCII显示
  273. displayData = QString::fromUtf8(data);
  274. // 替换控制字符为可见表示
  275. displayData.replace('\r', "\\r");
  276. displayData.replace('\n', "\\n");
  277. displayData.replace('\t', "\\t");
  278. }
  279. ui->textEdit_serial->append(QString("<span style='color:green;'>%1 串口%2 [接收] %3</span>")
  280. .arg(timestamp)
  281. .arg(portName)
  282. .arg(displayData));
  283. }
  284. // 切换显示模式
  285. void MainWindow::on_checkbox_serial_hex_toggled(bool checked)
  286. {
  287. ui->checkbox_serial_ascii->setChecked(!checked);
  288. // 重新显示当前内容
  289. QString currentText = ui->textEdit_serial->toPlainText();
  290. ui->textEdit_serial->clear();
  291. ui->textEdit_serial->setText(currentText);
  292. }
  293. void MainWindow::on_checkbox_serial_ascii_toggled(bool checked)
  294. {
  295. ui->checkbox_serial_hex->setChecked(!checked);
  296. // 重新显示当前内容
  297. QString currentText = ui->textEdit_serial->toPlainText();
  298. ui->textEdit_serial->clear();
  299. ui->textEdit_serial->setText(currentText);
  300. }
  301. // 后续使用新的界面,这里是串口的modbus的相关设置
  302. void MainWindow::modbusSetting_ui(const QString &deviceId)
  303. {
  304. // 查询设备相关数据
  305. DeviceInfo device;
  306. device = m_busCore->getDeviceInfo(deviceId);
  307. if (device.id == "")
  308. return;
  309. // 设置协议类型
  310. if (device.protocol == "modbus")
  311. {
  312. if (device.protocol_detail == "modbus-rtu")
  313. {
  314. ui->checkbox_modbus_rtu->setChecked(true);
  315. ui->checkbox_modbus_ascii->setChecked(false);
  316. ui->checkbox_modbus_tcp->setChecked(false);
  317. }
  318. else if (device.protocol_detail == "modbus-ascii")
  319. {
  320. ui->checkbox_modbus_rtu->setChecked(false);
  321. ui->checkbox_modbus_ascii->setChecked(true);
  322. ui->checkbox_modbus_tcp->setChecked(false);
  323. }
  324. else if (device.protocol_detail == "modbus-tcp")
  325. {
  326. ui->checkbox_modbus_rtu->setChecked(false);
  327. ui->checkbox_modbus_ascii->setChecked(false);
  328. ui->checkbox_modbus_tcp->setChecked(true);
  329. }
  330. }
  331. else
  332. {
  333. ui->checkbox_modbus_rtu->setChecked(false);
  334. ui->checkbox_modbus_ascii->setChecked(false);
  335. ui->checkbox_modbus_tcp->setChecked(false);
  336. }
  337. // 其他设置
  338. ui->spinBox_modbus_slave_id->setValue(device.address);
  339. // 添加modbus指令
  340. ui->comboBox_modbus_control_list->clear();
  341. //
  342. QList<QByteArray> modbus_control_list = {
  343. "01 读线圈",
  344. "02 读离散输入",
  345. "03 读输入寄存器",
  346. "04 读保持寄存器",
  347. "05 写单个线圈",
  348. "06 写单个寄存器",
  349. "15 写多个线圈",
  350. "16 写多个寄存器"};
  351. for (const QByteArray &control : modbus_control_list)
  352. {
  353. ui->comboBox_modbus_control_list->addItem(control);
  354. }
  355. // 添加信号连接
  356. connect(ui->comboBox_modbus_control_list, QOverload<int>::of(&QComboBox::currentIndexChanged),
  357. this, &MainWindow::onModbusControlChanged);
  358. // 添加按钮连接
  359. connect(ui->btn_confirm_modbus_set, &QPushButton::clicked,
  360. this, &MainWindow::onConfirmModbusSet);
  361. connect(ui->btn_gen_modbus_datagram, &QPushButton::clicked,
  362. this, &MainWindow::onGenerateModbusDatagram);
  363. // 初始更新配置表格
  364. QString funcCode = device.properties["function_code"].toString();
  365. int index = ui->comboBox_modbus_control_list->findText(funcCode, Qt::MatchStartsWith);
  366. if (index != -1)
  367. {
  368. ui->comboBox_modbus_control_list->setCurrentIndex(index);
  369. }
  370. else
  371. {
  372. ui->comboBox_modbus_control_list->setCurrentIndex(0);
  373. }
  374. }
  375. void MainWindow::onModbusControlChanged(int index)
  376. {
  377. // 清除现有模型
  378. QStandardItemModel *model = new QStandardItemModel(this);
  379. ui->tableV_serial_modbus_set->setModel(model);
  380. ui->tableV_serial_modbus_set->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
  381. model->setHorizontalHeaderLabels({"参数", "值"});
  382. // 获取当前选择的功能码
  383. QString selectedText = ui->comboBox_modbus_control_list->itemText(index);
  384. QString funcCode = selectedText.left(2);
  385. // 根据功能码设置不同的配置项
  386. if (funcCode == "01" || funcCode == "02")
  387. {
  388. // 读线圈/离散输入
  389. model->appendRow(createRow("起始地址", "0"));
  390. model->appendRow(createRow("线圈数量", "1"));
  391. }
  392. else if (funcCode == "03" || funcCode == "04")
  393. {
  394. // 读输入/保持寄存器
  395. model->appendRow(createRow("起始地址", "0"));
  396. model->appendRow(createRow("寄存器数量", "1"));
  397. }
  398. else if (funcCode == "05")
  399. {
  400. // 写单个线圈
  401. model->appendRow(createRow("线圈地址", "0"));
  402. model->appendRow(createRow("线圈状态", "0 (OFF)"));
  403. }
  404. else if (funcCode == "06")
  405. {
  406. // 写单个寄存器
  407. model->appendRow(createRow("寄存器地址", "0"));
  408. model->appendRow(createRow("寄存器值", "0"));
  409. }
  410. else if (funcCode == "15")
  411. {
  412. // 写多个线圈
  413. model->appendRow(createRow("起始地址", "0"));
  414. model->appendRow(createRow("线圈数量", "1"));
  415. model->appendRow(createRow("线圈状态", "0 (OFF)"));
  416. }
  417. else if (funcCode == "16")
  418. {
  419. // 写多个寄存器
  420. model->appendRow(createRow("起始地址", "0"));
  421. model->appendRow(createRow("寄存器数量", "1"));
  422. model->appendRow(createRow("寄存器值", "0"));
  423. }
  424. }
  425. void MainWindow::onConfirmModbusSet()
  426. {
  427. // 获取当前选中的设备
  428. QModelIndex index = ui->listV_device->currentIndex();
  429. if (!index.isValid())
  430. {
  431. return;
  432. }
  433. QString deviceId = index.data(Qt::UserRole).toString();
  434. // 获取设备信息
  435. DeviceInfo device = m_busCore->getDeviceInfo(deviceId);
  436. if (device.id.isEmpty())
  437. {
  438. return;
  439. }
  440. // 更新协议细节
  441. if (ui->checkbox_modbus_rtu->isChecked())
  442. {
  443. device.protocol_detail = "modbus-rtu";
  444. }
  445. else if (ui->checkbox_modbus_ascii->isChecked())
  446. {
  447. device.protocol_detail = "modbus-ascii";
  448. }
  449. else if (ui->checkbox_modbus_tcp->isChecked())
  450. {
  451. device.protocol_detail = "modbus-tcp";
  452. }
  453. // 更新从站地址
  454. device.address = ui->spinBox_modbus_slave_id->value();
  455. // 更新Modbus配置
  456. QJsonObject properties;
  457. properties["slave_id"] = ui->spinBox_modbus_slave_id->value();
  458. properties["function_code"] = ui->comboBox_modbus_control_list->currentText().left(2);
  459. // 保存表格中的配置参数
  460. QStandardItemModel *model = qobject_cast<QStandardItemModel *>(ui->tableV_serial_modbus_set->model());
  461. if (model)
  462. {
  463. for (int row = 0; row < model->rowCount(); ++row)
  464. {
  465. if (model->item(row, 0)->text() == "起始地址")
  466. {
  467. properties["start_address"] = model->item(row, 1)->text();
  468. }
  469. else if (model->item(row, 0)->text() == "线圈数量")
  470. {
  471. properties["coils_count"] = model->item(row, 1)->text();
  472. }
  473. else if (model->item(row, 0)->text() == "寄存器数量")
  474. {
  475. properties["registers_count"] = model->item(row, 1)->text();
  476. }
  477. else if (model->item(row, 0)->text() == "线圈地址")
  478. {
  479. properties["coil_address"] = model->item(row, 1)->text();
  480. }
  481. else if (model->item(row, 0)->text() == "线圈状态")
  482. {
  483. properties["coil_state"] = model->item(row, 1)->text();
  484. }
  485. else if (model->item(row, 0)->text() == "寄存器地址")
  486. {
  487. properties["register_address"] = model->item(row, 1)->text();
  488. }
  489. else if (model->item(row, 0)->text() == "寄存器值")
  490. {
  491. properties["register_value"] = model->item(row, 1)->text();
  492. }
  493. else
  494. {
  495. // 忽略其他参数
  496. }
  497. }
  498. }
  499. device.properties = properties;
  500. // 更新设备信息
  501. m_busCore->updateDevice(device);
  502. QMessageBox::information(this, "配置保存", "Modbus配置已成功保存");
  503. }
  504. void MainWindow::onGenerateModbusDatagram()
  505. {
  506. // 获取当前选中的设备
  507. QModelIndex index = ui->listV_device->currentIndex();
  508. if (!index.isValid())
  509. {
  510. return;
  511. }
  512. QString deviceId = index.data(Qt::UserRole).toString();
  513. // 获取设备信息
  514. DeviceInfo device = m_busCore->getDeviceInfo(deviceId);
  515. if (device.id.isEmpty() || !device.properties.contains("function_code"))
  516. {
  517. QMessageBox::warning(this, "生成报文", "请先配置Modbus参数");
  518. return;
  519. }
  520. // 获取功能码
  521. QString funcCodeStr = device.properties["function_code"].toString();
  522. bool ok;
  523. int funcCode = funcCodeStr.toInt(&ok);
  524. if (!ok)
  525. {
  526. QMessageBox::warning(this, "生成报文", "无效的功能码");
  527. return;
  528. }
  529. // 生成Modbus报文
  530. QByteArray datagram;
  531. // 添加从站地址
  532. datagram.append(static_cast<char>(device.address));
  533. // 添加功能码
  534. datagram.append(static_cast<char>(funcCode));
  535. // 根据功能码添加数据
  536. switch (funcCode)
  537. {
  538. case 1: // 读线圈
  539. case 2: // 读离散输入
  540. case 3: // 读输入寄存器
  541. case 4:
  542. { // 读保持寄存器
  543. int startAddr = device.properties["start_address"].toString().toInt();
  544. int count = device.properties["registers_count"].toString().toInt();
  545. datagram.append(static_cast<char>((startAddr >> 8) & 0xFF));
  546. datagram.append(static_cast<char>(startAddr & 0xFF));
  547. datagram.append(static_cast<char>((count >> 8) & 0xFF));
  548. datagram.append(static_cast<char>(count & 0xFF));
  549. break;
  550. }
  551. case 5:
  552. { // 写单个线圈
  553. int coilAddr = device.properties["coil_address"].toString().toInt();
  554. int coilState = device.properties["coil_state"].toString().toInt();
  555. datagram.append(static_cast<char>((coilAddr >> 8) & 0xFF));
  556. datagram.append(static_cast<char>(coilAddr & 0xFF));
  557. datagram.append(static_cast<char>(coilState ? 0xFF : 0x00));
  558. datagram.append(static_cast<char>(0x00));
  559. break;
  560. }
  561. case 6:
  562. { // 写单个寄存器
  563. int regAddr = device.properties["register_address"].toString().toInt();
  564. int regValue = device.properties["register_value"].toString().toInt();
  565. datagram.append(static_cast<char>((regAddr >> 8) & 0xFF));
  566. datagram.append(static_cast<char>(regAddr & 0xFF));
  567. datagram.append(static_cast<char>((regValue >> 8) & 0xFF));
  568. datagram.append(static_cast<char>(regValue & 0xFF));
  569. break;
  570. }
  571. case 15:
  572. { // 写多个线圈
  573. int startAddr = device.properties["start_address"].toString().toInt();
  574. int count = device.properties["coils_count"].toString().toInt();
  575. QString coilStates = device.properties["coil_state"].toString();
  576. // 计算字节数
  577. int byteCount = (count + 7) / 8;
  578. datagram.append(static_cast<char>((startAddr >> 8) & 0xFF));
  579. datagram.append(static_cast<char>(startAddr & 0xFF));
  580. datagram.append(static_cast<char>((count >> 8) & 0xFF));
  581. datagram.append(static_cast<char>(count & 0xFF));
  582. datagram.append(static_cast<char>(byteCount));
  583. // 添加线圈状态数据
  584. // 这里简化处理,实际需要解析线圈状态字符串
  585. for (int i = 0; i < byteCount; ++i)
  586. {
  587. datagram.append(static_cast<char>(0x00)); // 默认所有线圈为OFF
  588. }
  589. break;
  590. }
  591. case 16:
  592. { // 写多个寄存器
  593. int startAddr = device.properties["start_address"].toString().toInt();
  594. int count = device.properties["registers_count"].toString().toInt();
  595. QString regValues = device.properties["register_value"].toString();
  596. // 计算字节数
  597. int byteCount = count * 2;
  598. datagram.append(static_cast<char>((startAddr >> 8) & 0xFF));
  599. datagram.append(static_cast<char>(startAddr & 0xFF));
  600. datagram.append(static_cast<char>((count >> 8) & 0xFF));
  601. datagram.append(static_cast<char>(count & 0xFF));
  602. datagram.append(static_cast<char>(byteCount));
  603. // 添加寄存器数据
  604. // 这里简化处理,实际需要解析寄存器值字符串
  605. for (int i = 0; i < count; ++i)
  606. {
  607. datagram.append(static_cast<char>(0x00)); // 高字节
  608. datagram.append(static_cast<char>(0x00)); // 低字节
  609. }
  610. break;
  611. }
  612. default:
  613. QMessageBox::warning(this, "生成报文", "不支持的功能码");
  614. return;
  615. }
  616. // 如果是RTU模式,添加CRC校验
  617. if (device.protocol_detail == "modbus-rtu")
  618. {
  619. quint16 crc = calculateCRC(datagram);
  620. datagram.append(static_cast<char>(crc & 0xFF));
  621. datagram.append(static_cast<char>((crc >> 8) & 0xFF));
  622. }
  623. // 显示生成的报文
  624. ui->lineEdit_serial_send->setText(datagram.toHex(' ').toUpper());
  625. QMessageBox::information(this, "生成报文", "Modbus报文已生成并填充到发送框");
  626. }
  627. // CRC计算函数
  628. quint16 MainWindow::calculateCRC(const QByteArray &data)
  629. {
  630. quint16 crc = 0xFFFF;
  631. for (int i = 0; i < data.size(); ++i)
  632. {
  633. crc ^= static_cast<quint8>(data[i]);
  634. for (int j = 0; j < 8; j++)
  635. {
  636. if (crc & 0x0001)
  637. {
  638. crc = (crc >> 1) ^ 0xA001;
  639. }
  640. else
  641. {
  642. crc = crc >> 1;
  643. }
  644. }
  645. }
  646. return crc;
  647. }
  648. QList<QStandardItem *> MainWindow::createRow(const QString &param, const QString &defaultValue)
  649. {
  650. QList<QStandardItem *> row;
  651. row << new QStandardItem(param);
  652. row << new QStandardItem(defaultValue);
  653. return row;
  654. }
  655. void MainWindow::on_checkbox_modbus_rtu_toggled(bool checked)
  656. {
  657. if (checked)
  658. {
  659. ui->checkbox_modbus_ascii->setChecked(!checked);
  660. ui->checkbox_modbus_tcp->setChecked(!checked);
  661. if (m_currentDeviceId != "")
  662. {
  663. DeviceInfo device = m_busCore->getDeviceInfo(m_currentDeviceId);
  664. device.protocol = "modbus";
  665. device.protocol_detail = "modbus-rtu";
  666. m_busCore->registerDevice(device);
  667. }
  668. }
  669. }
  670. void MainWindow::on_checkbox_modbus_ascii_toggled(bool checked)
  671. {
  672. if (checked)
  673. {
  674. ui->checkbox_modbus_rtu->setChecked(!checked);
  675. ui->checkbox_modbus_tcp->setChecked(!checked);
  676. if (m_currentDeviceId != "")
  677. {
  678. DeviceInfo device = m_busCore->getDeviceInfo(m_currentDeviceId);
  679. device.protocol = "modbus";
  680. device.protocol_detail = "modbus-ascii";
  681. m_busCore->registerDevice(device);
  682. }
  683. }
  684. }
  685. void MainWindow::on_checkbox_modbus_tcp_toggled(bool checked)
  686. {
  687. if (checked)
  688. {
  689. ui->checkbox_modbus_rtu->setChecked(!checked);
  690. ui->checkbox_modbus_ascii->setChecked(!checked);
  691. if (m_currentDeviceId != "")
  692. {
  693. DeviceInfo device = m_busCore->getDeviceInfo(m_currentDeviceId);
  694. device.protocol = "modbus";
  695. device.protocol_detail = "modbus-tcp";
  696. m_busCore->registerDevice(device);
  697. }
  698. }
  699. }