#include "mainwindow.h" #include "ui_mainwindow.h" #include #include #include #include #include #include #include #include #include #include #include #include MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow), m_busCore(new SoftBusCore(this)), m_serialManager(new SerialManager(m_busCore, this)), m_dataTable(new QTableView(this)), m_serial_settingsModel(new QStandardItemModel(this)), m_deviceModel(new QStandardItemModel(this)), m_raw_dataModel(new QStandardItemModel(this)), m_bus_dataModel(new QStandardItemModel(this)), m_dataSeries(new QLineSeries()) { ui->setupUi(this); // 初始化系统 initializeSystem(); // 创建UI createUI(); // 创建连接 createConnections(); // 启动串口监控 m_serialManager->startDiscovery(); // 更新设备列表 updateDeviceList(); } MainWindow::~MainWindow() { // 停止串口监控 m_serialManager->stopDiscovery(); } void MainWindow::initializeSystem() { // 初始化数据库 if (!m_busCore->initDB("raw_db", "bus_db")) { qCritical() << "Failed to initialize database"; } // 注册串口设备 foreach (const QString &portName, m_serialManager->getAvailablePorts()) { DeviceInfo device; device.id = portName; device.type = "serial"; device.address = 1; device.protocol = "modbus"; // 默认协议 device.protocol_detail = "modbus-rtu"; m_busCore->registerDevice(device); } } void MainWindow::createUI() { // 左侧设备列表 ui->listV_device->setModel(m_deviceModel); ui->lineEdit_serial_send->setText("01 03 01 00 00 5C 44 0F "); // 右侧数据表格(上方为配置表格 ,下方为图表) ) ui->tableV_serial_set->setModel(m_serial_settingsModel); ui->tableV_serial_set->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); m_serial_settingsModel->setHorizontalHeaderLabels({"参数", "值"}); SerialManager::SerialConfig config = m_serialManager->getSerialConfig(); QList baudRateRow; baudRateRow << new QStandardItem("波特率") << new QStandardItem(QString::number(config.baudRate)); m_serial_settingsModel->appendRow(baudRateRow); QList dataBitsRow; dataBitsRow << new QStandardItem("数据位") << new QStandardItem(QString::number(config.dataBits)); m_serial_settingsModel->appendRow(dataBitsRow); QList parityRow; parityRow << new QStandardItem("校验") << new QStandardItem(QString::number(config.parity)); m_serial_settingsModel->appendRow(parityRow); QList stopBitsRow; stopBitsRow << new QStandardItem("停止位") << new QStandardItem(QString::number(config.stopBits)); m_serial_settingsModel->appendRow(stopBitsRow); QList flowControlRow; flowControlRow << new QStandardItem("流控") << new QStandardItem(QString::number(config.flowControl)); m_serial_settingsModel->appendRow(flowControlRow); // Raw Data Table ui->tableV_raw_data->setModel(m_raw_dataModel); m_raw_dataModel->setHorizontalHeaderLabels({"时间", "来源", "协议", "数据"}); ui->tableV_raw_data->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); ui->tableV_raw_data->setEditTriggers(QAbstractItemView::NoEditTriggers); ui->tableV_raw_data->setSelectionBehavior(QAbstractItemView::SelectRows); ui->tableV_raw_data->setSelectionMode(QAbstractItemView::SingleSelection); // Bus Data Table ui->tableV_bus_data->setModel(m_bus_dataModel); m_bus_dataModel->setHorizontalHeaderLabels({"时间", "来源", "协议", "数据"}); ui->tableV_bus_data->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); ui->tableV_bus_data->setEditTriggers(QAbstractItemView::NoEditTriggers); ui->tableV_bus_data->setSelectionBehavior(QAbstractItemView::SelectRows); ui->tableV_bus_data->setSelectionMode(QAbstractItemView::SingleSelection); // ui->tableV_bus_data->setModel(); } void MainWindow::createConnections() { // 设备注册/注销信号 connect(m_busCore, &SoftBusCore::deviceRegistered, this, &MainWindow::updateDeviceList); connect(m_busCore, &SoftBusCore::deviceUnregistered, this, &MainWindow::updateDeviceList); // 总线消息存储信号 connect(m_busCore, &SoftBusCore::busMessageStored, this, &MainWindow::updateChart); // 设备选择信号 connect(ui->listV_device->selectionModel(), &QItemSelectionModel::currentChanged, this, &MainWindow::onDeviceSelected); // 串口管理器信号 connect(m_serialManager, &SerialManager::portDiscovered, this, [this](const QString &portName, const QString &desc) { Q_UNUSED(desc); updateDeviceList(); }); connect(m_serialManager, &SerialManager::portRemoved, this, [this](const QString &portName) { updateDeviceList(); }); connect(m_serialManager, &SerialManager::dataReceived, this, &MainWindow::onSerialDataReceived); } void MainWindow::updateDeviceList() { m_deviceModel->clear(); // 添加串口设备 foreach (const QString &portName, m_serialManager->getAvailablePorts()) { QStandardItem *item = new QStandardItem("串口: " + portName); item->setData(portName, Qt::UserRole); m_deviceModel->appendRow(item); } // 添加其他类型设备(CAN、以太网等) // ... } void MainWindow::onDeviceSelected(const QModelIndex &index) { if (index.isValid()) { // 显示设备相关数据 QString deviceId = index.data(Qt::UserRole).toString(); m_currentDeviceId = deviceId; m_serialManager->openSerialPort(QSerialPortInfo(deviceId)); showRawData(deviceId); showBusMessages(deviceId); modbusSetting_ui(deviceId); } } void MainWindow::showRawData(const QString &deviceId) { m_raw_dataModel->removeRows(0, m_raw_dataModel->rowCount()); // 查询最近10分钟的原始数据 qint64 endTime = QDateTime::currentMSecsSinceEpoch(); qint64 startTime = endTime - 10 * 60 * 1000; QList rawData = m_busCore->queryRawData(deviceId, startTime, endTime); for (const QByteArray &data : rawData) { QList row; // 时间戳是数据的前8个字节 qint64 timestamp = *reinterpret_cast(data.constData()); row << new QStandardItem(QDateTime::fromMSecsSinceEpoch(timestamp).toString("hh:mm:ss")); row << new QStandardItem(deviceId); row << new QStandardItem("RAW"); row << new QStandardItem(data.mid(8).toHex()); m_raw_dataModel->appendRow(row); } } void MainWindow::showBusMessages(const QString &source) { // 查询最近10分钟的总线消息 qint64 endTime = QDateTime::currentMSecsSinceEpoch(); qint64 startTime = endTime - 10 * 60 * 1000; QList messages = m_busCore->queryBusMessages(source, "data_processor", startTime, endTime); for (const BusMessage &msg : messages) { QList row; row << new QStandardItem(QDateTime::fromMSecsSinceEpoch(msg.timestamp).toString("hh:mm:ss")); row << new QStandardItem(msg.source); row << new QStandardItem(msg.payload["protocol"].toString()); QString dataStr; if (msg.payload["protocol"] == "modbus") { dataStr = QString("ID:%1 FN:%2") .arg(msg.payload["slave_id"].toInt()) .arg(msg.payload["function_code"].toInt()); } else { dataStr = msg.payload["raw_data"].toString(); } row << new QStandardItem(dataStr); m_bus_dataModel->appendRow(row); } } void MainWindow::updateChart(const BusMessage &message) { if (message.payload["protocol"] != "modbus") return; // 解析Modbus数据并更新图表 QJsonArray dataArray = message.payload["data"].toArray(); if (dataArray.size() > 0) { double value = dataArray[0].toDouble(); qint64 timestamp = message.timestamp; m_dataSeries->append(timestamp, value); // 限制图表显示的数据点数量 if (m_dataSeries->count() > 100) { m_dataSeries->removePoints(0, m_dataSeries->count() - 100); } } } // btn_fun // QCheckBox *checkBox_serial_hex; // QCheckBox *checkBox_serial_ascii; // QTextEdit *textEdit_serial; // QPushButton *btn_serial_clear; // QPushButton *btn_serial_send; void MainWindow::on_btn_serial_clear_clicked() { ui->textEdit_serial->clear(); } void MainWindow::on_btn_serial_clear_send_clicked() { ui->lineEdit_serial_send->clear(); } // 发送串口数据 void MainWindow::on_btn_serial_send_clicked() { if (!m_serialManager->isPortOpen(m_currentDeviceId)) { QMessageBox::warning(this, "串口未打开", "请先打开串口设备"); return; } QString dataToSend = ui->lineEdit_serial_send->text(); if (dataToSend.isEmpty()) { QMessageBox::information(this, "发送数据", "请输入要发送的数据"); return; } // 根据当前显示模式处理数据 if (ui->checkbox_serial_hex->isChecked()) { // 十六进制模式 - 将输入视为十六进制字符串 QByteArray hexData = QByteArray::fromHex(dataToSend.toLatin1()); m_serialManager->writeData(m_currentDeviceId, hexData); } else { // ASCII模式 - 直接发送文本 m_serialManager->writeData(m_currentDeviceId, dataToSend.toUtf8()); } // 在接收区显示发送的数据(带发送标记) QString timestamp = QDateTime::currentDateTime().toString("[hh:mm:ss]"); ui->textEdit_serial->append(QString("%1 [发送] %2") .arg(timestamp) .arg(dataToSend)); // 清空发送输入框 // ui->lineEdit_serial_send->clear(); } // 处理接收到的串口数据 void MainWindow::onSerialDataReceived(const QString &portName, const QByteArray &data) { QString displayData; QString timestamp = QDateTime::currentDateTime().toString("[hh:mm:ss]"); if (ui->checkbox_serial_hex->isChecked()) { // 十六进制显示 displayData = data.toHex(' ').toUpper(); } else { // ASCII显示 displayData = QString::fromUtf8(data); // 替换控制字符为可见表示 displayData.replace('\r', "\\r"); displayData.replace('\n', "\\n"); displayData.replace('\t', "\\t"); } ui->textEdit_serial->append(QString("%1 串口%2 [接收] %3") .arg(timestamp) .arg(portName) .arg(displayData)); } // 切换显示模式 void MainWindow::on_checkbox_serial_hex_toggled(bool checked) { ui->checkbox_serial_ascii->setChecked(!checked); // 重新显示当前内容 QString currentText = ui->textEdit_serial->toPlainText(); ui->textEdit_serial->clear(); ui->textEdit_serial->setText(currentText); } void MainWindow::on_checkbox_serial_ascii_toggled(bool checked) { ui->checkbox_serial_hex->setChecked(!checked); // 重新显示当前内容 QString currentText = ui->textEdit_serial->toPlainText(); ui->textEdit_serial->clear(); ui->textEdit_serial->setText(currentText); } // 后续使用新的界面,这里是串口的modbus的相关设置 void MainWindow::modbusSetting_ui(const QString &deviceId) { // 查询设备相关数据 DeviceInfo device; device = m_busCore->getDeviceInfo(deviceId); if (device.id == "") return; // 设置协议类型 if (device.protocol == "modbus") { if (device.protocol_detail == "modbus-rtu") { ui->checkbox_modbus_rtu->setChecked(true); ui->checkbox_modbus_ascii->setChecked(false); ui->checkbox_modbus_tcp->setChecked(false); } else if (device.protocol_detail == "modbus-ascii") { ui->checkbox_modbus_rtu->setChecked(false); ui->checkbox_modbus_ascii->setChecked(true); ui->checkbox_modbus_tcp->setChecked(false); } else if (device.protocol_detail == "modbus-tcp") { ui->checkbox_modbus_rtu->setChecked(false); ui->checkbox_modbus_ascii->setChecked(false); ui->checkbox_modbus_tcp->setChecked(true); } } else { ui->checkbox_modbus_rtu->setChecked(false); ui->checkbox_modbus_ascii->setChecked(false); ui->checkbox_modbus_tcp->setChecked(false); } // 其他设置 ui->spinBox_modbus_slave_id->setValue(device.address); // 添加modbus指令 ui->comboBox_modbus_control_list->clear(); // QList modbus_control_list = { "01 读线圈", "02 读离散输入", "03 读输入寄存器", "04 读保持寄存器", "05 写单个线圈", "06 写单个寄存器", "15 写多个线圈", "16 写多个寄存器"}; for (const QByteArray &control : modbus_control_list) { ui->comboBox_modbus_control_list->addItem(control); } // 添加信号连接 connect(ui->comboBox_modbus_control_list, QOverload::of(&QComboBox::currentIndexChanged), this, &MainWindow::onModbusControlChanged); // 添加按钮连接 connect(ui->btn_confirm_modbus_set, &QPushButton::clicked, this, &MainWindow::onConfirmModbusSet); connect(ui->btn_gen_modbus_datagram, &QPushButton::clicked, this, &MainWindow::onGenerateModbusDatagram); // 初始更新配置表格 QString funcCode = device.properties["function_code"].toString(); int index = ui->comboBox_modbus_control_list->findText(funcCode, Qt::MatchStartsWith); if (index != -1) { ui->comboBox_modbus_control_list->setCurrentIndex(index); } else { ui->comboBox_modbus_control_list->setCurrentIndex(0); } } void MainWindow::onModbusControlChanged(int index) { // 清除现有模型 QStandardItemModel *model = new QStandardItemModel(this); ui->tableV_serial_modbus_set->setModel(model); ui->tableV_serial_modbus_set->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); model->setHorizontalHeaderLabels({"参数", "值"}); // 获取当前选择的功能码 QString selectedText = ui->comboBox_modbus_control_list->itemText(index); QString funcCode = selectedText.left(2); // 根据功能码设置不同的配置项 if (funcCode == "01" || funcCode == "02") { // 读线圈/离散输入 model->appendRow(createRow("起始地址", "0")); model->appendRow(createRow("线圈数量", "1")); } else if (funcCode == "03" || funcCode == "04") { // 读输入/保持寄存器 model->appendRow(createRow("起始地址", "0")); model->appendRow(createRow("寄存器数量", "1")); } else if (funcCode == "05") { // 写单个线圈 model->appendRow(createRow("线圈地址", "0")); model->appendRow(createRow("线圈状态", "0 (OFF)")); } else if (funcCode == "06") { // 写单个寄存器 model->appendRow(createRow("寄存器地址", "0")); model->appendRow(createRow("寄存器值", "0")); } else if (funcCode == "15") { // 写多个线圈 model->appendRow(createRow("起始地址", "0")); model->appendRow(createRow("线圈数量", "1")); model->appendRow(createRow("线圈状态", "0 (OFF)")); } else if (funcCode == "16") { // 写多个寄存器 model->appendRow(createRow("起始地址", "0")); model->appendRow(createRow("寄存器数量", "1")); model->appendRow(createRow("寄存器值", "0")); } } void MainWindow::onConfirmModbusSet() { // 获取当前选中的设备 QModelIndex index = ui->listV_device->currentIndex(); if (!index.isValid()) { return; } QString deviceId = index.data(Qt::UserRole).toString(); // 获取设备信息 DeviceInfo device = m_busCore->getDeviceInfo(deviceId); if (device.id.isEmpty()) { return; } // 更新协议细节 if (ui->checkbox_modbus_rtu->isChecked()) { device.protocol_detail = "modbus-rtu"; } else if (ui->checkbox_modbus_ascii->isChecked()) { device.protocol_detail = "modbus-ascii"; } else if (ui->checkbox_modbus_tcp->isChecked()) { device.protocol_detail = "modbus-tcp"; } // 更新从站地址 device.address = ui->spinBox_modbus_slave_id->value(); // 更新Modbus配置 QJsonObject properties; properties["slave_id"] = ui->spinBox_modbus_slave_id->value(); properties["function_code"] = ui->comboBox_modbus_control_list->currentText().left(2); // 保存表格中的配置参数 QStandardItemModel *model = qobject_cast(ui->tableV_serial_modbus_set->model()); if (model) { for (int row = 0; row < model->rowCount(); ++row) { if (model->item(row, 0)->text() == "起始地址") { properties["start_address"] = model->item(row, 1)->text(); } else if (model->item(row, 0)->text() == "线圈数量") { properties["coils_count"] = model->item(row, 1)->text(); } else if (model->item(row, 0)->text() == "寄存器数量") { properties["registers_count"] = model->item(row, 1)->text(); } else if (model->item(row, 0)->text() == "线圈地址") { properties["coil_address"] = model->item(row, 1)->text(); } else if (model->item(row, 0)->text() == "线圈状态") { properties["coil_state"] = model->item(row, 1)->text(); } else if (model->item(row, 0)->text() == "寄存器地址") { properties["register_address"] = model->item(row, 1)->text(); } else if (model->item(row, 0)->text() == "寄存器值") { properties["register_value"] = model->item(row, 1)->text(); } else { // 忽略其他参数 } } } device.properties = properties; // 更新设备信息 m_busCore->updateDevice(device); QMessageBox::information(this, "配置保存", "Modbus配置已成功保存"); } void MainWindow::onGenerateModbusDatagram() { // 获取当前选中的设备 QModelIndex index = ui->listV_device->currentIndex(); if (!index.isValid()) { return; } QString deviceId = index.data(Qt::UserRole).toString(); // 获取设备信息 DeviceInfo device = m_busCore->getDeviceInfo(deviceId); if (device.id.isEmpty() || !device.properties.contains("function_code")) { QMessageBox::warning(this, "生成报文", "请先配置Modbus参数"); return; } // 获取功能码 QString funcCodeStr = device.properties["function_code"].toString(); bool ok; int funcCode = funcCodeStr.toInt(&ok); if (!ok) { QMessageBox::warning(this, "生成报文", "无效的功能码"); return; } // 生成Modbus报文 QByteArray datagram; // 添加从站地址 datagram.append(static_cast(device.address)); // 添加功能码 datagram.append(static_cast(funcCode)); // 根据功能码添加数据 switch (funcCode) { case 1: // 读线圈 case 2: // 读离散输入 case 3: // 读输入寄存器 case 4: { // 读保持寄存器 int startAddr = device.properties["start_address"].toString().toInt(); int count = device.properties["registers_count"].toString().toInt(); datagram.append(static_cast((startAddr >> 8) & 0xFF)); datagram.append(static_cast(startAddr & 0xFF)); datagram.append(static_cast((count >> 8) & 0xFF)); datagram.append(static_cast(count & 0xFF)); break; } case 5: { // 写单个线圈 int coilAddr = device.properties["coil_address"].toString().toInt(); int coilState = device.properties["coil_state"].toString().toInt(); datagram.append(static_cast((coilAddr >> 8) & 0xFF)); datagram.append(static_cast(coilAddr & 0xFF)); datagram.append(static_cast(coilState ? 0xFF : 0x00)); datagram.append(static_cast(0x00)); break; } case 6: { // 写单个寄存器 int regAddr = device.properties["register_address"].toString().toInt(); int regValue = device.properties["register_value"].toString().toInt(); datagram.append(static_cast((regAddr >> 8) & 0xFF)); datagram.append(static_cast(regAddr & 0xFF)); datagram.append(static_cast((regValue >> 8) & 0xFF)); datagram.append(static_cast(regValue & 0xFF)); break; } case 15: { // 写多个线圈 int startAddr = device.properties["start_address"].toString().toInt(); int count = device.properties["coils_count"].toString().toInt(); QString coilStates = device.properties["coil_state"].toString(); // 计算字节数 int byteCount = (count + 7) / 8; datagram.append(static_cast((startAddr >> 8) & 0xFF)); datagram.append(static_cast(startAddr & 0xFF)); datagram.append(static_cast((count >> 8) & 0xFF)); datagram.append(static_cast(count & 0xFF)); datagram.append(static_cast(byteCount)); // 添加线圈状态数据 // 这里简化处理,实际需要解析线圈状态字符串 for (int i = 0; i < byteCount; ++i) { datagram.append(static_cast(0x00)); // 默认所有线圈为OFF } break; } case 16: { // 写多个寄存器 int startAddr = device.properties["start_address"].toString().toInt(); int count = device.properties["registers_count"].toString().toInt(); QString regValues = device.properties["register_value"].toString(); // 计算字节数 int byteCount = count * 2; datagram.append(static_cast((startAddr >> 8) & 0xFF)); datagram.append(static_cast(startAddr & 0xFF)); datagram.append(static_cast((count >> 8) & 0xFF)); datagram.append(static_cast(count & 0xFF)); datagram.append(static_cast(byteCount)); // 添加寄存器数据 // 这里简化处理,实际需要解析寄存器值字符串 for (int i = 0; i < count; ++i) { datagram.append(static_cast(0x00)); // 高字节 datagram.append(static_cast(0x00)); // 低字节 } break; } default: QMessageBox::warning(this, "生成报文", "不支持的功能码"); return; } // 如果是RTU模式,添加CRC校验 if (device.protocol_detail == "modbus-rtu") { quint16 crc = calculateCRC(datagram); datagram.append(static_cast(crc & 0xFF)); datagram.append(static_cast((crc >> 8) & 0xFF)); } // 显示生成的报文 ui->lineEdit_serial_send->setText(datagram.toHex(' ').toUpper()); QMessageBox::information(this, "生成报文", "Modbus报文已生成并填充到发送框"); } // CRC计算函数 quint16 MainWindow::calculateCRC(const QByteArray &data) { quint16 crc = 0xFFFF; for (int i = 0; i < data.size(); ++i) { crc ^= static_cast(data[i]); for (int j = 0; j < 8; j++) { if (crc & 0x0001) { crc = (crc >> 1) ^ 0xA001; } else { crc = crc >> 1; } } } return crc; } QList MainWindow::createRow(const QString ¶m, const QString &defaultValue) { QList row; row << new QStandardItem(param); row << new QStandardItem(defaultValue); return row; } void MainWindow::on_checkbox_modbus_rtu_toggled(bool checked) { if (checked) { ui->checkbox_modbus_ascii->setChecked(!checked); ui->checkbox_modbus_tcp->setChecked(!checked); if (m_currentDeviceId != "") { DeviceInfo device = m_busCore->getDeviceInfo(m_currentDeviceId); device.protocol = "modbus"; device.protocol_detail = "modbus-rtu"; m_busCore->registerDevice(device); } } } void MainWindow::on_checkbox_modbus_ascii_toggled(bool checked) { if (checked) { ui->checkbox_modbus_rtu->setChecked(!checked); ui->checkbox_modbus_tcp->setChecked(!checked); if (m_currentDeviceId != "") { DeviceInfo device = m_busCore->getDeviceInfo(m_currentDeviceId); device.protocol = "modbus"; device.protocol_detail = "modbus-ascii"; m_busCore->registerDevice(device); } } } void MainWindow::on_checkbox_modbus_tcp_toggled(bool checked) { if (checked) { ui->checkbox_modbus_rtu->setChecked(!checked); ui->checkbox_modbus_ascii->setChecked(!checked); if (m_currentDeviceId != "") { DeviceInfo device = m_busCore->getDeviceInfo(m_currentDeviceId); device.protocol = "modbus"; device.protocol_detail = "modbus-tcp"; m_busCore->registerDevice(device); } } }