Browse Source

串口数据读取

flower_linux 2 months ago
parent
commit
5b31c0b1b0

+ 70 - 0
.vscode/settings.json

@@ -0,0 +1,70 @@
+{
+    "files.associations": {
+        "*.dbclient-js": "javascript",
+        "chrono": "cpp",
+        "random": "cpp",
+        "limits": "cpp",
+        "semaphore": "cpp",
+        "system_error": "cpp",
+        "array": "cpp",
+        "atomic": "cpp",
+        "bit": "cpp",
+        "bitset": "cpp",
+        "cctype": "cpp",
+        "cinttypes": "cpp",
+        "clocale": "cpp",
+        "cmath": "cpp",
+        "codecvt": "cpp",
+        "compare": "cpp",
+        "concepts": "cpp",
+        "condition_variable": "cpp",
+        "cstdarg": "cpp",
+        "cstddef": "cpp",
+        "cstdint": "cpp",
+        "cstdio": "cpp",
+        "cstdlib": "cpp",
+        "cstring": "cpp",
+        "ctime": "cpp",
+        "cwchar": "cpp",
+        "cwctype": "cpp",
+        "deque": "cpp",
+        "forward_list": "cpp",
+        "list": "cpp",
+        "map": "cpp",
+        "set": "cpp",
+        "string": "cpp",
+        "unordered_map": "cpp",
+        "unordered_set": "cpp",
+        "vector": "cpp",
+        "exception": "cpp",
+        "algorithm": "cpp",
+        "functional": "cpp",
+        "iterator": "cpp",
+        "memory": "cpp",
+        "memory_resource": "cpp",
+        "numeric": "cpp",
+        "ratio": "cpp",
+        "regex": "cpp",
+        "string_view": "cpp",
+        "tuple": "cpp",
+        "type_traits": "cpp",
+        "utility": "cpp",
+        "fstream": "cpp",
+        "future": "cpp",
+        "initializer_list": "cpp",
+        "iomanip": "cpp",
+        "iosfwd": "cpp",
+        "iostream": "cpp",
+        "istream": "cpp",
+        "mutex": "cpp",
+        "new": "cpp",
+        "numbers": "cpp",
+        "ostream": "cpp",
+        "sstream": "cpp",
+        "stdexcept": "cpp",
+        "stop_token": "cpp",
+        "streambuf": "cpp",
+        "thread": "cpp",
+        "typeinfo": "cpp"
+    }
+}

+ 3 - 2
CMakeLists.txt

@@ -6,7 +6,7 @@ set(CMAKE_CXX_STANDARD 17)
 set(CMAKE_CXX_STANDARD_REQUIRED ON)
 
 # 查找Qt6
-find_package(Qt6 6.5 REQUIRED COMPONENTS Core Widgets SerialPort)
+find_package(Qt6 6.5 REQUIRED COMPONENTS Core Widgets SerialPort Charts)
 
 # 设置RocksDB路径
 SET(ROCKSDB_DIR "${PROJECT_SOURCE_DIR}/rocksdb")
@@ -54,7 +54,8 @@ target_link_libraries(soft_bus
     PRIVATE
         Qt6::Core
         Qt6::Widgets
-        Qt::SerialPort
+        Qt6::SerialPort
+        Qt6::Charts
         ${ROCKSDB_LIB}
 )
 

+ 331 - 4
mainwindow.cpp

@@ -1,15 +1,342 @@
 #include "mainwindow.h"
 #include "ui_mainwindow.h"
-#include <rocksdb/db.h>
+#include <QVBoxLayout>
+#include <QHBoxLayout>
+#include <QSplitter>
+#include <QListView>
+#include <QTableView>
+#include <QHeaderView>
+#include <QDateTime>
+#include <QDebug>
+#include <QItemSelectionModel>
+#include <QtCharts/QDateTimeAxis>
+#include <QtCharts/QValueAxis>
+#include <QMessageBox>
 
 MainWindow::MainWindow(QWidget *parent)
-    : QMainWindow(parent)
-    , ui(new Ui::MainWindow)
+    : 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_dataModel(new QStandardItemModel(this)),
+      m_dataSeries(new QLineSeries())
 {
     ui->setupUi(this);
+    // 初始化系统
+    initializeSystem();
+
+    // 创建UI
+    createUI();
+
+    // 创建连接
+    createConnections();
+
+    // 启动串口监控
+    m_serialManager->startDiscovery();
+
+    // 更新设备列表
+    updateDeviceList();
 }
 
 MainWindow::~MainWindow()
 {
-    delete ui;
+    // 停止串口监控
+    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 = portName;
+        device.protocol = "modbus"; // 默认协议
+        m_busCore->registerDevice(device);
+    }
+}
+
+void MainWindow::createUI()
+{
+    // 左侧设备列表
+    ui->listV_device->setModel(m_deviceModel);
+
+    // 右侧数据表格(上方为配置表格 ,下方为图表) )
+    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<QStandardItem *> baudRateRow;
+    baudRateRow << new QStandardItem("波特率") << new QStandardItem(QString::number(config.baudRate));
+    m_serial_settingsModel->appendRow(baudRateRow);
+
+    QList<QStandardItem *> dataBitsRow;
+    dataBitsRow << new QStandardItem("数据位") << new QStandardItem(QString::number(config.dataBits));
+    m_serial_settingsModel->appendRow(dataBitsRow);
+
+    QList<QStandardItem *> parityRow;
+    parityRow << new QStandardItem("校验") << new QStandardItem(QString::number(config.parity));
+    m_serial_settingsModel->appendRow(parityRow);
+
+    QList<QStandardItem *> stopBitsRow;
+    stopBitsRow << new QStandardItem("停止位") << new QStandardItem(QString::number(config.stopBits));
+    m_serial_settingsModel->appendRow(stopBitsRow);
+
+    QList<QStandardItem *> flowControlRow;
+    flowControlRow << new QStandardItem("流控") << new QStandardItem(QString::number(config.flowControl));
+    m_serial_settingsModel->appendRow(flowControlRow);
+
+    // Raw Data Table
+    ui->tableV_raw_data->setModel(m_dataModel);
+    m_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);
+
+    // 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);
+    }
+}
+
+void MainWindow::showRawData(const QString &deviceId)
+{
+    m_dataModel->removeRows(0, m_dataModel->rowCount());
+
+    // 查询最近10分钟的原始数据
+    qint64 endTime = QDateTime::currentMSecsSinceEpoch();
+    qint64 startTime = endTime - 10 * 60 * 1000;
+
+    QList<QByteArray> rawData = m_busCore->queryRawData(deviceId, startTime, endTime);
+
+    for (const QByteArray &data : rawData)
+    {
+        QList<QStandardItem *> row;
+        // 时间戳是数据的前8个字节
+        qint64 timestamp = *reinterpret_cast<const qint64 *>(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_dataModel->appendRow(row);
+    }
+}
+
+void MainWindow::showBusMessages(const QString &source)
+{
+    // 查询最近10分钟的总线消息
+    qint64 endTime = QDateTime::currentMSecsSinceEpoch();
+    qint64 startTime = endTime - 10 * 60 * 1000;
+
+    QList<BusMessage> messages = m_busCore->queryBusMessages(source, "data_processor", startTime, endTime);
+
+    for (const BusMessage &msg : messages)
+    {
+        QList<QStandardItem *> 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_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("<span style='color:blue;'>%1 [发送] %2</span>")
+                                    .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("<span style='color:green;'>%1 串口%2 [接收] %3</span>")
+                                    .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);
 }

+ 57 - 3
mainwindow.h

@@ -2,22 +2,76 @@
 #define MAINWINDOW_H
 
 #include <QMainWindow>
+#include <QStandardItemModel>
+#include <QtCharts/QChartView>
+#include <QtCharts/QLineSeries>
+#include <QtCharts/QDateTimeAxis>
+#include <QtCharts/QValueAxis>
+#include "soft_bus_core/soft_bus_core.h"
+#include "serial_manager/serial_manager.h"
 
 QT_BEGIN_NAMESPACE
+class QListView;
+class QTableView;
+class QSplitter;
+class QLabel;
 namespace Ui {
 class MainWindow;
 }
 QT_END_NAMESPACE
 
-class MainWindow : public QMainWindow
-{
+namespace QtCharts {
+class QChart;
+}
+
+class MainWindow : public QMainWindow {
     Q_OBJECT
 
 public:
-    MainWindow(QWidget *parent = nullptr);
+    explicit MainWindow(QWidget *parent = nullptr);
     ~MainWindow();
 
+private slots:
+    void updateDeviceList();
+    void showRawData(const QString &deviceId);
+    void showBusMessages(const QString &source);
+    void updateChart(const BusMessage &message);
+    void onDeviceSelected(const QModelIndex &index);
+    void onSerialDataReceived(const QString &portName, const QByteArray &data);
+
+    // btn_fun
+    void on_btn_serial_clear_clicked();
+    void on_btn_serial_clear_send_clicked();
+    void on_btn_serial_send_clicked();
+    void on_checkBox_serial_hex_toggled(bool checked);
+    void on_checkBox_serial_ascii_toggled(bool checked);
+
 private:
     Ui::MainWindow *ui;
+    void createUI();
+    void createConnections();
+    void initializeSystem();
+
+
+    // 核心组件
+    SoftBusCore *m_busCore;
+    SerialManager *m_serialManager;
+
+    // UI组件
+
+    QTableView *m_dataTable; // 原始数据表
+
+
+
+    QStandardItemModel *m_deviceModel;
+    QStandardItemModel *m_dataModel;
+    QStandardItemModel *m_serial_settingsModel; // 串口设置表Table;
+    QLineSeries *m_dataSeries;
+    QtCharts::QChart *m_chart;
+
+    QString m_currentDeviceId; // 当前选择的设备ID
+
+
 };
+
 #endif // MAINWINDOW_H

+ 381 - 4
mainwindow.ui

@@ -6,20 +6,397 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>800</width>
-    <height>600</height>
+    <width>1083</width>
+    <height>748</height>
    </rect>
   </property>
   <property name="windowTitle">
    <string>MainWindow</string>
   </property>
-  <widget class="QWidget" name="centralwidget"/>
+  <widget class="QWidget" name="centralwidget">
+   <layout class="QGridLayout" name="gridLayout_2">
+    <item row="0" column="0">
+     <widget class="QWidget" name="widget" native="true">
+      <property name="minimumSize">
+       <size>
+        <width>0</width>
+        <height>0</height>
+       </size>
+      </property>
+      <layout class="QGridLayout" name="gridLayout_3">
+       <item row="1" column="0">
+        <widget class="QSplitter" name="splitter">
+         <property name="orientation">
+          <enum>Qt::Orientation::Horizontal</enum>
+         </property>
+         <widget class="QScrollArea" name="scrollArea">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="widgetResizable">
+           <bool>true</bool>
+          </property>
+          <widget class="QWidget" name="scrollAreaWidgetContents">
+           <property name="geometry">
+            <rect>
+             <x>0</x>
+             <y>0</y>
+             <width>280</width>
+             <height>661</height>
+            </rect>
+           </property>
+           <layout class="QGridLayout" name="gridLayout">
+            <item row="0" column="0">
+             <widget class="QListView" name="listV_device"/>
+            </item>
+           </layout>
+          </widget>
+         </widget>
+         <widget class="QTabWidget" name="tabWidget">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+            <horstretch>10</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="currentIndex">
+           <number>0</number>
+          </property>
+          <widget class="QWidget" name="tab_serial">
+           <attribute name="title">
+            <string>serial</string>
+           </attribute>
+           <layout class="QGridLayout" name="gridLayout_9">
+            <item row="0" column="0">
+             <widget class="QSplitter" name="splitter_9">
+              <property name="orientation">
+               <enum>Qt::Orientation::Vertical</enum>
+              </property>
+              <widget class="QGroupBox" name="groupBox">
+               <property name="title">
+                <string/>
+               </property>
+               <layout class="QGridLayout" name="gridLayout_15">
+                <item row="0" column="0">
+                 <widget class="QSplitter" name="splitter_12">
+                  <property name="orientation">
+                   <enum>Qt::Orientation::Horizontal</enum>
+                  </property>
+                  <widget class="QSplitter" name="splitter_11">
+                   <property name="sizePolicy">
+                    <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+                     <horstretch>5</horstretch>
+                     <verstretch>0</verstretch>
+                    </sizepolicy>
+                   </property>
+                   <property name="orientation">
+                    <enum>Qt::Orientation::Horizontal</enum>
+                   </property>
+                   <widget class="QTableView" name="tableV_serial_set">
+                    <property name="sizePolicy">
+                     <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+                      <horstretch>1</horstretch>
+                      <verstretch>0</verstretch>
+                     </sizepolicy>
+                    </property>
+                   </widget>
+                   <widget class="QTabWidget" name="tabWidget_serial">
+                    <property name="sizePolicy">
+                     <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+                      <horstretch>2</horstretch>
+                      <verstretch>0</verstretch>
+                     </sizepolicy>
+                    </property>
+                    <property name="currentIndex">
+                     <number>0</number>
+                    </property>
+                    <widget class="QWidget" name="modbus">
+                     <attribute name="title">
+                      <string>modbus</string>
+                     </attribute>
+                     <layout class="QGridLayout" name="gridLayout_14">
+                      <item row="0" column="0">
+                       <widget class="QSplitter" name="splitter_10">
+                        <property name="orientation">
+                         <enum>Qt::Orientation::Vertical</enum>
+                        </property>
+                        <widget class="QSplitter" name="splitter_8">
+                         <property name="orientation">
+                          <enum>Qt::Orientation::Vertical</enum>
+                         </property>
+                         <widget class="QSplitter" name="splitter_6">
+                          <property name="orientation">
+                           <enum>Qt::Orientation::Vertical</enum>
+                          </property>
+                          <widget class="QFrame" name="frame_4">
+                           <property name="frameShape">
+                            <enum>QFrame::Shape::StyledPanel</enum>
+                           </property>
+                           <property name="frameShadow">
+                            <enum>QFrame::Shadow::Raised</enum>
+                           </property>
+                           <layout class="QHBoxLayout" name="horizontalLayout">
+                            <item>
+                             <widget class="QCheckBox" name="checkBox">
+                              <property name="text">
+                               <string>RTU</string>
+                              </property>
+                             </widget>
+                            </item>
+                            <item>
+                             <widget class="QCheckBox" name="checkBox_2">
+                              <property name="text">
+                               <string>ASCII</string>
+                              </property>
+                             </widget>
+                            </item>
+                            <item>
+                             <widget class="QCheckBox" name="checkBox_3">
+                              <property name="text">
+                               <string>TCP</string>
+                              </property>
+                             </widget>
+                            </item>
+                           </layout>
+                          </widget>
+                          <widget class="QFrame" name="frame_5">
+                           <property name="frameShape">
+                            <enum>QFrame::Shape::StyledPanel</enum>
+                           </property>
+                           <property name="frameShadow">
+                            <enum>QFrame::Shadow::Raised</enum>
+                           </property>
+                           <layout class="QVBoxLayout" name="verticalLayout">
+                            <item>
+                             <layout class="QGridLayout" name="gridLayout_7">
+                              <item row="0" column="0">
+                               <widget class="QLabel" name="label_3">
+                                <property name="text">
+                                 <string>从设备编号</string>
+                                </property>
+                               </widget>
+                              </item>
+                              <item row="0" column="1">
+                               <widget class="QSpinBox" name="spinBox_modbus_slave_id"/>
+                              </item>
+                             </layout>
+                            </item>
+                            <item>
+                             <layout class="QGridLayout" name="gridLayout_10">
+                              <item row="0" column="0">
+                               <widget class="QLabel" name="label_4">
+                                <property name="text">
+                                 <string>功能码</string>
+                                </property>
+                               </widget>
+                              </item>
+                              <item row="0" column="1">
+                               <widget class="QComboBox" name="comboBox_modbus_control_list"/>
+                              </item>
+                             </layout>
+                            </item>
+                           </layout>
+                          </widget>
+                         </widget>
+                         <widget class="QSplitter" name="splitter_3">
+                          <property name="orientation">
+                           <enum>Qt::Orientation::Vertical</enum>
+                          </property>
+                          <widget class="QTableView" name="tableV_serial_modbus_set">
+                           <property name="sizePolicy">
+                            <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+                             <horstretch>2</horstretch>
+                             <verstretch>0</verstretch>
+                            </sizepolicy>
+                           </property>
+                          </widget>
+                          <widget class="QLineEdit" name="lineEdit_modbus_datagram"/>
+                         </widget>
+                        </widget>
+                        <widget class="QWidget" name="">
+                         <layout class="QGridLayout" name="gridLayout_13">
+                          <item row="0" column="0">
+                           <widget class="QPushButton" name="btn_gen_modbus_datagram">
+                            <property name="text">
+                             <string>生成命令</string>
+                            </property>
+                           </widget>
+                          </item>
+                          <item row="0" column="1">
+                           <widget class="QPushButton" name="btn_confirm_modbus_set">
+                            <property name="text">
+                             <string>确认设置</string>
+                            </property>
+                           </widget>
+                          </item>
+                         </layout>
+                        </widget>
+                       </widget>
+                      </item>
+                     </layout>
+                    </widget>
+                    <widget class="QWidget" name="tab_2">
+                     <attribute name="title">
+                      <string>JT808</string>
+                     </attribute>
+                    </widget>
+                   </widget>
+                  </widget>
+                  <widget class="QTextEdit" name="textEdit_serial">
+                   <property name="sizePolicy">
+                    <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+                     <horstretch>3</horstretch>
+                     <verstretch>0</verstretch>
+                    </sizepolicy>
+                   </property>
+                  </widget>
+                 </widget>
+                </item>
+                <item row="1" column="0">
+                 <widget class="QSplitter" name="splitter_7">
+                  <property name="orientation">
+                   <enum>Qt::Orientation::Vertical</enum>
+                  </property>
+                  <widget class="QPushButton" name="btn_serial_clear">
+                   <property name="text">
+                    <string>清空</string>
+                   </property>
+                  </widget>
+                  <widget class="QSplitter" name="splitter_5">
+                   <property name="orientation">
+                    <enum>Qt::Orientation::Vertical</enum>
+                   </property>
+                   <widget class="QSplitter" name="splitter_4">
+                    <property name="orientation">
+                     <enum>Qt::Orientation::Horizontal</enum>
+                    </property>
+                    <widget class="QFrame" name="frame_2">
+                     <property name="frameShape">
+                      <enum>QFrame::Shape::StyledPanel</enum>
+                     </property>
+                     <property name="frameShadow">
+                      <enum>QFrame::Shadow::Raised</enum>
+                     </property>
+                     <layout class="QGridLayout" name="gridLayout_5">
+                      <item row="0" column="0">
+                       <widget class="QCheckBox" name="checkBox_serial_hex">
+                        <property name="text">
+                         <string>HEX</string>
+                        </property>
+                       </widget>
+                      </item>
+                      <item row="1" column="0">
+                       <widget class="QCheckBox" name="checkBox_serial_ascii">
+                        <property name="text">
+                         <string>ASCII</string>
+                        </property>
+                       </widget>
+                      </item>
+                     </layout>
+                    </widget>
+                    <widget class="QLineEdit" name="lineEdit_serial_send">
+                     <property name="sizePolicy">
+                      <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+                       <horstretch>5</horstretch>
+                       <verstretch>0</verstretch>
+                      </sizepolicy>
+                     </property>
+                    </widget>
+                   </widget>
+                   <widget class="QWidget" name="">
+                    <layout class="QGridLayout" name="gridLayout_6">
+                     <item row="0" column="0">
+                      <widget class="QPushButton" name="btn_serial_clear_send">
+                       <property name="text">
+                        <string>清空</string>
+                       </property>
+                      </widget>
+                     </item>
+                     <item row="0" column="1">
+                      <widget class="QPushButton" name="btn_serial_send">
+                       <property name="text">
+                        <string>发送</string>
+                       </property>
+                      </widget>
+                     </item>
+                    </layout>
+                   </widget>
+                  </widget>
+                 </widget>
+                </item>
+               </layout>
+              </widget>
+              <widget class="QSplitter" name="splitter_2">
+               <property name="orientation">
+                <enum>Qt::Orientation::Horizontal</enum>
+               </property>
+               <widget class="QFrame" name="frame">
+                <property name="frameShape">
+                 <enum>QFrame::Shape::StyledPanel</enum>
+                </property>
+                <property name="frameShadow">
+                 <enum>QFrame::Shadow::Raised</enum>
+                </property>
+                <layout class="QGridLayout" name="gridLayout_4">
+                 <item row="2" column="0">
+                  <widget class="QTableView" name="tableV_raw_data"/>
+                 </item>
+                 <item row="1" column="0">
+                  <widget class="QLabel" name="label">
+                   <property name="text">
+                    <string>原始数据</string>
+                   </property>
+                  </widget>
+                 </item>
+                </layout>
+               </widget>
+               <widget class="QFrame" name="frame_3">
+                <property name="frameShape">
+                 <enum>QFrame::Shape::StyledPanel</enum>
+                </property>
+                <property name="frameShadow">
+                 <enum>QFrame::Shadow::Raised</enum>
+                </property>
+                <layout class="QGridLayout" name="gridLayout_8">
+                 <item row="2" column="0">
+                  <widget class="QTableView" name="tableV_bus_data"/>
+                 </item>
+                 <item row="1" column="0">
+                  <widget class="QLabel" name="label_2">
+                   <property name="text">
+                    <string>软总线数据</string>
+                   </property>
+                  </widget>
+                 </item>
+                </layout>
+               </widget>
+              </widget>
+             </widget>
+            </item>
+           </layout>
+          </widget>
+          <widget class="QWidget" name="tab_can">
+           <attribute name="title">
+            <string>can</string>
+           </attribute>
+          </widget>
+         </widget>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+    </item>
+   </layout>
+  </widget>
   <widget class="QMenuBar" name="menubar">
    <property name="geometry">
     <rect>
      <x>0</x>
      <y>0</y>
-     <width>800</width>
+     <width>1083</width>
      <height>27</height>
     </rect>
    </property>

+ 287 - 214
src/serial_manager/serial_manager.cpp

@@ -1,319 +1,392 @@
 #include "serial_manager.h"
+#include <QDebug>
+#include <QDateTime>
+#include <QJsonDocument>
 #include <QJsonArray>
 #include <QJsonObject>
-#include <QJsonDocument>
-#include <QDateTime>
-#include <QDebug>
 
-// SerialManager 类管理串口的发现、打开、关闭和数据读写
-SerialManager::SerialManager(QObject *parent) : QObject(parent)
+SerialManager::SerialManager(SoftBusCore *busCore, QObject *parent)
+    : QObject(parent),
+      m_busCore(busCore),
+      m_discoveryTimer(new QTimer(this)),
+      m_serialConfig()
 {
-    m_discoveryTimer = new QTimer(this);
+    // 连接定时器信号
     connect(m_discoveryTimer, &QTimer::timeout, this, &SerialManager::discoverSerialPorts);
-
-    // 初始化串口配置
-    m_serialConfig.baudRate = QSerialPort::Baud9600;
-    m_serialConfig.dataBits = QSerialPort::Data8;
-    m_serialConfig.parity = QSerialPort::NoParity;
-    m_serialConfig.stopBits = QSerialPort::OneStop;
-    m_serialConfig.flowControl = QSerialPort::NoFlowControl;
 }
 
 SerialManager::~SerialManager()
 {
+    stopDiscovery();
     closeAllPorts();
 }
 
-// 启动串口发现定时器,并立即尝试发现一次串口
 void SerialManager::startDiscovery(int intervalMs)
 {
-    m_discoveryTimer->start(intervalMs);
-    discoverSerialPorts(); // 立即执行一次发现
+    // 立即执行一次发现
+    discoverSerialPorts();
+
+    // 启动定时器
+    if (intervalMs > 0)
+    {
+        m_discoveryTimer->start(intervalMs);
+    }
 }
 
-// 停止串口发现定时器
 void SerialManager::stopDiscovery()
 {
     m_discoveryTimer->stop();
 }
 
-// 发现可用的串口,并处理新发现的和已移除的串口
-void SerialManager::discoverSerialPorts()
-{
-    QList<QSerialPortInfo> availablePorts = QSerialPortInfo::availablePorts();
-    QSet<QString> currentPorts;
-
-    // 检查新端口
-    for (const QSerialPortInfo &portInfo : availablePorts) {
-        QString portName = portInfo.portName();
-        currentPorts.insert(portName);
-
-        if (!m_openedPorts.contains(portName)) {
-            // 尝试打开新端口
-            if (openSerialPort(portInfo)) {
-                emit portDiscovered(portName, portInfo.description());
-            }
-        }
-    }
-
-    // 检查已关闭的端口
-    QSet<QString> removedPorts = m_openedPorts - currentPorts;
-    for (const QString &portName : removedPorts) {
-        closeSerialPort(portName);
-        emit portRemoved(portName);
-    }
-}
-
-// 根据提供的串口信息打开串口
 bool SerialManager::openSerialPort(const QSerialPortInfo &portInfo)
 {
-    QString portName = portInfo.portName();
-
-    if (m_openedPorts.contains(portName)) {
-        return true; // 已经打开
+    // 如果端口已经打开,直接返回成功
+    if (m_serialPorts.contains(portInfo.portName()))
+    {
+        return true;
     }
 
-    QSerialPort *serialPort = new QSerialPort(this);
-    serialPort->setPort(portInfo);
+    // 创建新的串口对象
+    QSerialPort *serialPort = new QSerialPort(portInfo, this);
+
+    // 应用配置
     serialPort->setBaudRate(m_serialConfig.baudRate);
     serialPort->setDataBits(m_serialConfig.dataBits);
     serialPort->setParity(m_serialConfig.parity);
     serialPort->setStopBits(m_serialConfig.stopBits);
     serialPort->setFlowControl(m_serialConfig.flowControl);
 
-    if (serialPort->open(QIODevice::ReadWrite)) {
-        m_openedPorts.insert(portName);
-        m_serialPorts[portName] = serialPort;
+    // 尝试打开串口
+    if (serialPort->open(QIODevice::ReadWrite))
+    {
+        // 添加到管理列表
+        m_serialPorts.insert(portInfo.portName(), serialPort);
+        m_openedPorts.insert(portInfo.portName());
 
-        connect(serialPort, &QSerialPort::readyRead, this, [this, portName]() {
-            onDataReceived(portName);
-        });
-
-        connect(serialPort, &QSerialPort::errorOccurred, this, [this, portName](QSerialPort::SerialPortError error) {
-            if (error != QSerialPort::NoError) {
-                qWarning() << "Serial port error:" << portName << error;
-                closeSerialPort(portName);
-            }
-        });
+        // 连接数据接收信号
+        connect(serialPort, &QSerialPort::readyRead, this, [this, portInfo]()
+                { onReadyRead(portInfo.portName()); });
 
+        qDebug() << "Opened serial port:" << portInfo.portName();
         return true;
-    } else {
+    }
+    else
+    {
+        // 打开失败,清理资源
+        qWarning() << "Failed to open port" << portInfo.portName() << ":" << serialPort->errorString();
         delete serialPort;
-        qWarning() << "Failed to open serial port:" << portName << serialPort->errorString();
         return false;
     }
 }
 
-// 关闭并删除指定名称的串口
 void SerialManager::closeSerialPort(const QString &portName)
 {
-    if (m_serialPorts.contains(portName)) {
-        QSerialPort *serialPort = m_serialPorts.take(portName);
-        serialPort->close();
-        serialPort->deleteLater();
+    if (m_serialPorts.contains(portName))
+    {
+        QSerialPort *port = m_serialPorts.take(portName);
+        port->close();
+        delete port;
         m_openedPorts.remove(portName);
+        emit portRemoved(portName);
+        qDebug() << "Closed serial port:" << portName;
     }
 }
+bool SerialManager::isPortOpen(const QString &portName)
+{
+    return m_serialPorts.contains(portName) && m_serialPorts[portName]->isOpen();
+}
 
-// 关闭并删除所有已打开的串口
 void SerialManager::closeAllPorts()
 {
-    for (QSerialPort *serialPort : m_serialPorts) {
-        serialPort->close();
-        serialPort->deleteLater();
+    for (QSerialPort *port : m_serialPorts.values())
+    {
+        port->close();
+        delete port;
     }
     m_serialPorts.clear();
     m_openedPorts.clear();
+    qDebug() << "All serial ports closed";
 }
 
-// 处理接收到的数据
-void SerialManager::onDataReceived(const QString &portName)
+void SerialManager::setSerialConfig(const SerialConfig &config)
 {
-    if (!m_serialPorts.contains(portName)) {
-        return;
-    }
-
-    QSerialPort *serialPort = m_serialPorts[portName];
-    QByteArray data = serialPort->readAll();
-
-    if (!data.isEmpty()) {
-        // 存储原始数据
-        storeRawData(portName, data);
-
-        // 解析数据
-        parseData(portName, data);
+    m_serialConfig = config;
 
-        emit dataReceived(portName, data);
+    // 更新所有已打开端口的配置
+    for (QSerialPort *port : m_serialPorts.values())
+    {
+        port->setBaudRate(config.baudRate);
+        port->setDataBits(config.dataBits);
+        port->setParity(config.parity);
+        port->setStopBits(config.stopBits);
+        port->setFlowControl(config.flowControl);
     }
+
+    qDebug() << "Serial configuration updated";
 }
 
-// 存储接收到的原始数据
-void SerialManager::storeRawData(const QString &portName, const QByteArray &data)
+SerialManager::SerialConfig SerialManager::getSerialConfig() const
 {
-    qint64 timestamp = QDateTime::currentMSecsSinceEpoch();
-    QString key = QString("%1_%2").arg(timestamp).arg(portName);
-
-    // 这里应该调用存储服务存储原始数据
-    // m_storageService->storeRawData(key, data);
+    return m_serialConfig;
+}
 
-    qDebug() << "Stored raw data:" << key << "Size:" << data.size();
+QStringList SerialManager::getOpenedPorts() const
+{
+    return m_openedPorts.values();
 }
 
-// 解析接收到的数据
-void SerialManager::parseData(const QString &portName, const QByteArray &data)
+QStringList SerialManager::getAvailablePorts() const
 {
-    // 尝试解析为Modbus协议
-    if (data.size() >= 4) { // Modbus RTU最小帧长度
-        parseModbus(data, portName);
+    QStringList ports;
+    foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
+    {
+        if (isRealSerialPort(info))
+        {
+            // qDebug() << "Available port:" << info.portName() << "-" << info.description();
+            ports << info.portName();
+        }
     }
-
-    // 可以添加其他协议解析
-    parseCustomProtocol(data, portName);
+    return ports;
 }
 
-// 解析Modbus RTU协议数据
-void SerialManager::parseModbus(const QByteArray &data, const QString &portName)
+bool SerialManager::isRealSerialPort(const QSerialPortInfo &info) const
 {
-    // 简单的Modbus RTU帧检查
-    if (data.size() < 4) return;
+    // 1. 尝试打开串口进行验证
+    QSerialPort testPort;
+    testPort.setPort(info);
+
+    if (testPort.open(QIODevice::ReadWrite))
+    {
+        testPort.close();
+        return true; // 能成功打开关闭的是真实串口
+    }
 
-    // 计算CRC校验(简化版本)
-    uint16_t crc = calculateCRC(data.constData(), data.size() - 2);
-    uint16_t receivedCrc = static_cast<uint8_t>(data[data.size()-2]) << 8 |
-                           static_cast<uint8_t>(data[data.size()-1]);
+    // 2. 检查系统特定的虚拟串口标识
+#ifdef Q_OS_WIN
+    // Windows: 过滤蓝牙虚拟串口
+    if (info.description().contains("Bluetooth", Qt::CaseInsensitive) ||
+        info.manufacturer().contains("Standard Serial over Bluetooth", Qt::CaseInsensitive))
+    {
+        return false;
+    }
+#elif defined(Q_OS_LINUX)
+    // Linux: 过滤虚拟终端
+    if (info.portName().startsWith("ttyS") &&
+        info.description().contains("virtual terminal", Qt::CaseInsensitive))
+    {
+        return false;
+    }
+#elif defined(Q_OS_MACOS)
+    // macOS: 过滤蓝牙虚拟串口
+    if (info.portName().startsWith("Bluetooth-") ||
+        info.description().contains("Bluetooth", Qt::CaseInsensitive))
+    {
+        return false;
+    }
+#endif
 
-    if (crc != receivedCrc) {
-        return; // CRC校验失败
+    // 3. 检查是否有物理设备属性
+    if (info.vendorIdentifier() == 0 && info.productIdentifier() == 0)
+    {
+        // 没有硬件ID的可能是虚拟端口
+        return false;
     }
 
-    uint8_t slaveId = static_cast<uint8_t>(data[0]);
-    uint8_t functionCode = static_cast<uint8_t>(data[1]);
+    // 4. 检查串口是否在系统设备列表中
+    if (info.isNull())
+    {
+        return false;
+    }
 
-    QJsonObject modbusData;
-    modbusData["timestamp"] = QDateTime::currentMSecsSinceEpoch();
-    modbusData["port"] = portName;
-    modbusData["slave_id"] = slaveId;
-    modbusData["function_code"] = functionCode;
-    modbusData["raw_data"] = QString(data.toHex());
+    return true;
+}
 
-    // 解析数据部分
-    QJsonArray dataArray;
-    if (functionCode == 0x03 || functionCode == 0x04) {
-        // 读保持寄存器/输入寄存器
-        uint8_t byteCount = static_cast<uint8_t>(data[2]);
-        for (int i = 0; i < byteCount; i += 2) {
-            if (i + 3 < data.size()) {
-                uint16_t value = static_cast<uint8_t>(data[3 + i]) << 8 |
-                                 static_cast<uint8_t>(data[4 + i]);
-                dataArray.append(value);
-            }
+bool SerialManager::writeData(const QString &portName, const QByteArray &data)
+{
+    if (m_serialPorts.contains(portName))
+    {
+        qint64 bytesWritten = m_serialPorts[portName]->write(data);
+        if (bytesWritten == data.size())
+        {
+            qDebug() << "Data written to" << portName << ":" << data.toHex();
+            return true;
         }
-    } else if (functionCode == 0x06 || functionCode == 0x10) {
-        // 写单个/多个寄存器
-        uint16_t address = static_cast<uint8_t>(data[2]) << 8 |
-                           static_cast<uint8_t>(data[3]);
-        dataArray.append(address);
-
-        if (functionCode == 0x06) {
-            uint16_t value = static_cast<uint8_t>(data[4]) << 8 |
-                             static_cast<uint8_t>(data[5]);
-            dataArray.append(value);
+        else
+        {
+            qWarning() << "Failed to write all data to" << portName
+                       << ". Written:" << bytesWritten << "of" << data.size();
         }
     }
+    return false;
+}
 
-    modbusData["parsed_data"] = dataArray;
-    modbusData["crc"] = receivedCrc;
-
-    // 发射解析后的数据信号
-    emit modbusDataParsed(modbusData);
-
-    // 存储到软总线格式
-    storeBusMessage(modbusData);
+void SerialManager::setBusCore(SoftBusCore *busCore)
+{
+    m_busCore = busCore;
+    qDebug() << "Bus core set for SerialManager";
 }
 
-// 解析自定义协议数据
-void SerialManager::parseCustomProtocol(const QByteArray &data, const QString &portName)
+SoftBusCore *SerialManager::getBusCore() const
 {
-    // 自定义协议解析逻辑
-    // 这里可以实现您的自定义协议解析
-
-    if (data.size() > 2) {
-        QJsonObject customData;
-        customData["timestamp"] = QDateTime::currentMSecsSinceEpoch();
-        customData["port"] = portName;
-        customData["protocol"] = "custom";
-        customData["data_length"] = data.size();
-        customData["raw_data"] = QString(data.toHex());
-
-        emit customDataParsed(customData);
-        storeBusMessage(customData);
-    }
+    return m_busCore;
 }
 
-// 存储解析后的软总线格式数据
-void SerialManager::storeBusMessage(const QJsonObject &message)
+void SerialManager::discoverSerialPorts()
 {
-    // 这里应该调用存储服务存储软总线格式数据
-    // m_storageService->storeBusMessage(message);
+    // 获取当前所有可用串口
+    QSet<QString> currentPorts;
+    foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
+    {
+        QString portName = info.portName();
+        currentPorts.insert(portName);
+
+        // 如果是新发现的端口
+        if (!m_lastDiscoveredPorts.contains(portName))
+        {
+            emit portDiscovered(portName, info.description());
+            qDebug() << "New port discovered:" << portName << "-" << info.description();
+        }
+    }
 
-    qDebug() << "Stored bus message:" << QJsonDocument(message).toJson(QJsonDocument::Compact);
+    // 检查是否有端口被移除
+    QSet<QString> removedPorts = m_lastDiscoveredPorts - currentPorts;
+    for (const QString &portName : removedPorts)
+    {
+        // 如果端口是打开的,先关闭它
+        if (m_openedPorts.contains(portName))
+        {
+            closeSerialPort(portName);
+        }
+        emit portRemoved(portName);
+        qDebug() << "Port removed:" << portName;
+    }
+
+    // 更新上次发现的端口列表
+    m_lastDiscoveredPorts = currentPorts;
 }
 
-// 计算CRC校验值
-uint16_t SerialManager::calculateCRC(const char *data, int length)
+void SerialManager::onReadyRead(const QString &portName)
 {
-    uint16_t crc = 0xFFFF;
-
-    for (int pos = 0; pos < length; pos++) {
-        crc ^= static_cast<uint8_t>(data[pos]);
-
-        for (int i = 8; i != 0; i--) {
-            if ((crc & 0x0001) != 0) {
-                crc >>= 1;
-                crc ^= 0xA001;
-            } else {
-                crc >>= 1;
-            }
+    if (m_serialPorts.contains(portName))
+    {
+        QSerialPort *port = m_serialPorts[portName];
+        QByteArray data = port->readAll();
+
+        if (!data.isEmpty())
+        {
+            // 发出数据接收信号
+            qDebug()<< "receive data" << data.toHex();
+            emit dataReceived(portName, data);
+
+            // 存储原始数据
+            storeRawData(portName, data);
+
+            // 解析数据
+            parseData(portName, data);
         }
     }
+}
 
-    return crc;
+void SerialManager::parseData(const QString &portName, const QByteArray &data)
+{
+    // 这里可以根据实际需求选择解析协议
+    // 简单实现:根据数据长度判断协议类型
+    if (data.size() >= 6)
+    { // Modbus RTU最小帧长度
+        parseModbus(data, portName);
+    }
+    else
+    {
+        parseCustomProtocol(data, portName);
+    }
 }
 
-// 设置串口配置,并更新所有已打开串口的配置
-void SerialManager::setSerialConfig(const SerialConfig &config)
+void SerialManager::parseModbus(const QByteArray &data, const QString &portName)
 {
-    m_serialConfig = config;
+    // 简化的Modbus解析
+    if (data.size() < 4)
+        return; // 最小长度检查
 
-    // 更新所有已打开端口的配置
-    for (QSerialPort *serialPort : m_serialPorts) {
-        serialPort->setBaudRate(config.baudRate);
-        serialPort->setDataBits(config.dataBits);
-        serialPort->setParity(config.parity);
-        serialPort->setStopBits(config.stopBits);
-        serialPort->setFlowControl(config.flowControl);
+    uint8_t slaveId = static_cast<uint8_t>(data[0]);
+    uint8_t functionCode = static_cast<uint8_t>(data[1]);
+
+    // 创建消息对象
+    BusMessage message;
+    message.id = QString("%1_%2_%3").arg(portName).arg(slaveId).arg(functionCode);
+    message.source = portName;
+    message.destination = "data_processor";
+    message.timestamp = QDateTime::currentMSecsSinceEpoch();
+
+    // 创建payload
+    QJsonObject payload;
+    payload["protocol"] = "modbus";
+    payload["slave_id"] = slaveId;
+    payload["function_code"] = functionCode;
+
+    // 提取数据部分(跳过地址和功能码)
+    QJsonArray dataArray;
+    for (int i = 2; i < data.size() - 2; i++)
+    { // 跳过CRC
+        dataArray.append(static_cast<uint8_t>(data[i]));
+    }
+    payload["data"] = dataArray;
+
+    message.payload = payload;
+
+    // 存储总线消息
+    if (m_busCore)
+    {
+        m_busCore->storeBusMessage(message);
     }
+
+    // 发出信号
+    emit modbusDataParsed(payload);
+    qDebug() << "Modbus data parsed from" << portName << ":" << payload;
 }
 
-// 获取当前的串口配置
-SerialManager::SerialConfig SerialManager::getSerialConfig() const
+void SerialManager::parseCustomProtocol(const QByteArray &data, const QString &portName)
 {
-    return m_serialConfig;
+    // 创建消息对象
+    BusMessage message;
+    message.id = QString("%1_custom_%2").arg(portName).arg(QDateTime::currentMSecsSinceEpoch());
+    message.source = portName;
+    message.destination = "data_processor";
+    message.timestamp = QDateTime::currentMSecsSinceEpoch();
+
+    // 创建payload
+    QJsonObject payload;
+    payload["protocol"] = "custom";
+    payload["raw_data"] = QString(data.toHex());
+
+    message.payload = payload;
+
+    // 存储总线消息
+    if (m_busCore)
+    {
+        m_busCore->storeBusMessage(message);
+    }
+
+    // 发出信号
+    emit customDataParsed(payload);
+    qDebug() << "Custom protocol data parsed from" << portName << ":" << payload;
 }
 
-// 获取所有已打开的串口名称列表
-QStringList SerialManager::getOpenedPorts() const
+void SerialManager::storeRawData(const QString &portName, const QByteArray &data)
 {
-    return m_openedPorts.values();
+    if (m_busCore)
+    {
+        m_busCore->storeRawData(portName, data);
+        qDebug() << "Raw data stored for" << portName << ":" << data.toHex();
+    }
 }
 
-// 向指定名称的串口写入数据
-bool SerialManager::writeData(const QString &portName, const QByteArray &data)
+uint16_t SerialManager::calculateCRC(const char *data, int length)
 {
-    if (m_serialPorts.contains(portName)) {
-        QSerialPort *serialPort = m_serialPorts[portName];
-        qint64 bytesWritten = serialPort->write(data);
-        return serialPort->waitForBytesWritten(1000) && bytesWritten == data.size();
+    // 简化的CRC计算(实际应用中应使用标准CRC算法)
+    uint16_t crc = 0;
+    for (int i = 0; i < length; i++)
+    {
+        crc += static_cast<uint8_t>(data[i]);
     }
-    return false;
-}
+    return crc;
+}

+ 37 - 8
src/serial_manager/serial_manager.h

@@ -9,23 +9,34 @@
 #include <QMap>
 #include <QJsonObject>
 #include <QJsonArray>
+#include "soft_bus_core/soft_bus_core.h"
 
 class SerialManager : public QObject
 {
     Q_OBJECT
 
 public:
-    // 串口配置 
-    struct SerialConfig {
+    // 串口配置
+    struct SerialConfig
+    {
         QSerialPort::BaudRate baudRate;
         QSerialPort::DataBits dataBits;
         QSerialPort::Parity parity;
         QSerialPort::StopBits stopBits;
         QSerialPort::FlowControl flowControl;
+
+        SerialConfig()
+        {
+            baudRate = QSerialPort::Baud9600;
+            dataBits = QSerialPort::Data8;
+            parity = QSerialPort::NoParity;
+            stopBits = QSerialPort::OneStop;
+            flowControl = QSerialPort::NoFlowControl;
+        }
     };
 
-    // 构造函数
-    explicit SerialManager(QObject *parent = nullptr);
+    // 构造函数 - 集成SoftBusCore
+    explicit SerialManager(SoftBusCore *busCore = nullptr, QObject *parent = nullptr);
     // 析构函数
     ~SerialManager();
 
@@ -38,6 +49,9 @@ public:
     bool openSerialPort(const QSerialPortInfo &portInfo);
     // 关闭指定名称的串口
     void closeSerialPort(const QString &portName);
+    //
+    bool isPortOpen(const QString &portName);
+
     // 关闭所有已打开的串口
     void closeAllPorts();
 
@@ -48,10 +62,19 @@ public:
 
     // 获取所有已打开的串口名称列表
     QStringList getOpenedPorts() const;
+    // 获取所有可用串口名称列表
+    QStringList getAvailablePorts() const;
+
+    bool isRealSerialPort(const QSerialPortInfo &info) const;
 
     // 向指定串口写入数据
     bool writeData(const QString &portName, const QByteArray &data);
 
+    // 设置软总线核心
+    void setBusCore(SoftBusCore *busCore);
+    // 获取软总线核心
+    SoftBusCore *getBusCore() const;
+
 signals:
     // 发现新串口时发出的信号,包含串口名称和描述
     void portDiscovered(const QString &portName, const QString &description);
@@ -63,12 +86,14 @@ signals:
     void modbusDataParsed(const QJsonObject &data);
     // 解析自定义协议数据后发出的信号,包含解析后的数据
     void customDataParsed(const QJsonObject &data);
+    // 软总线消息存储后发出的信号
+    void busMessageStored(const QJsonObject &message);
 
 private slots:
     // 定时发现串口
     void discoverSerialPorts();
-    // 当串口接收到数据时调用,portName为串口名称
-    void onDataReceived(const QString &portName);
+    // 当串口接收到数据时调用
+    void onReadyRead(const QString &portName);
 
 private:
     // 解析从串口接收到的数据,portName为串口名称,data为接收到的数据
@@ -87,6 +112,8 @@ private:
     uint16_t calculateCRC(const char *data, int length);
 
 private:
+    // 软总线核心
+    SoftBusCore *m_busCore;
     // 定时器,用于定时发现串口
     QTimer *m_discoveryTimer;
     // 当前串口配置
@@ -95,7 +122,9 @@ private:
     // 已打开的串口名称集合
     QSet<QString> m_openedPorts;
     // 串口名称与串口对象映射表
-    QMap<QString, QSerialPort*> m_serialPorts;
+    QMap<QString, QSerialPort *> m_serialPorts;
+    // 上次发现的串口列表
+    QSet<QString> m_lastDiscoveredPorts;
 };
 
-#endif // SERIAL_MANAGER_H
+#endif // SERIAL_MANAGER_H

+ 172 - 59
src/soft_bus_core/soft_bus_core.cpp

@@ -1,99 +1,166 @@
 #include "soft_bus_core.h"
+#include <QDebug>
+#include <QDateTime>
+#include <QtEndian>
 #include <rocksdb/options.h>
 #include <rocksdb/slice.h>
 #include <rocksdb/status.h>
-#include <QDateTime>
-#include <QJsonDocument>
+#include <rocksdb/write_batch.h>
 
 SoftBusCore::SoftBusCore(QObject *parent) : QObject(parent),
-    m_rawDb(nullptr), m_busDb(nullptr) {}
+    m_rawDb(nullptr),
+    m_busDb(nullptr),
+    m_dbInitialized(false)
+{
+}
 
 SoftBusCore::~SoftBusCore() {
-    delete m_rawDb;
-    delete m_busDb;
+    closeDB();
 }
 
 bool SoftBusCore::initDB(const QString &rawDbPath, const QString &busDbPath) {
-    rocksdb::Options options;
-    options.create_if_missing = true;
+    // 关闭现有数据库
+    closeDB();
 
     // 打开原始数据数据库
+    rocksdb::Options options;
+    options.create_if_missing = true;
     rocksdb::Status status = rocksdb::DB::Open(options, rawDbPath.toStdString(), &m_rawDb);
-    if (!status.ok()) return false;
 
-    // 打开软总线数据数据库
+    if (!status.ok()) {
+        qCritical() << "Failed to open raw database:" << status.ToString().c_str();
+        return false;
+    }
+
+    // 打开总线消息数据库
     status = rocksdb::DB::Open(options, busDbPath.toStdString(), &m_busDb);
-    return status.ok();
+
+    if (!status.ok()) {
+        qCritical() << "Failed to open bus database:" << status.ToString().c_str();
+        delete m_rawDb;
+        m_rawDb = nullptr;
+        return false;
+    }
+
+    m_dbInitialized = true;
+    return true;
+}
+
+void SoftBusCore::closeDB() {
+    if (m_rawDb) {
+        delete m_rawDb;
+        m_rawDb = nullptr;
+    }
+
+    if (m_busDb) {
+        delete m_busDb;
+        m_busDb = nullptr;
+    }
+
+    m_dbInitialized = false;
 }
 
 void SoftBusCore::registerDevice(const DeviceInfo &device) {
-    if (m_devices.contains(device.id)) return;
+    if (m_devices.contains(device.id)) {
+        qWarning() << "Device" << device.id << "is already registered";
+        return;
+    }
 
     m_devices.insert(device.id, device);
     emit deviceRegistered(device);
 }
 
 void SoftBusCore::unregisterDevice(const QString &deviceId) {
-    if (!m_devices.contains(deviceId)) return;
+    if (!m_devices.contains(deviceId)) {
+        qWarning() << "Device" << deviceId << "is not registered";
+        return;
+    }
 
     m_devices.remove(deviceId);
     emit deviceUnregistered(deviceId);
 }
 
+DeviceInfo SoftBusCore::getDeviceInfo(const QString &deviceId) const {
+    return m_devices.value(deviceId);
+}
+
+QList<DeviceInfo> SoftBusCore::getAllDevices() const {
+    return m_devices.values();
+}
+
 void SoftBusCore::routeMessage(const BusMessage &message) {
     emit messageReceived(message);
     storeBusMessage(message);
 }
 
 void SoftBusCore::storeRawData(const QString &deviceId, const QByteArray &data) {
-    if (!m_rawDb) return;
+    if (!m_dbInitialized || !m_rawDb) {
+        qWarning() << "Database not initialized for storing raw data";
+        return;
+    }
 
     qint64 timestamp = QDateTime::currentMSecsSinceEpoch();
     std::string key = generateRawKey(deviceId, timestamp);
+    std::string value(data.constData(), data.size());
 
-    rocksdb::Status s = m_rawDb->Put(rocksdb::WriteOptions(),
-                                     key,
-                                     rocksdb::Slice(data.constData(), data.size()));
+    rocksdb::Status status = m_rawDb->Put(rocksdb::WriteOptions(), key, value);
 
-    if (s.ok()) {
+    if (!status.ok()) {
+        qCritical() << "Failed to store raw data:" << status.ToString().c_str();
+        emit databaseError(QString::fromStdString(status.ToString()));
+    } else {
         emit rawDataStored(deviceId, data);
     }
 }
 
 void SoftBusCore::storeBusMessage(const BusMessage &message) {
-    if (!m_busDb) return;
+    if (!m_dbInitialized || !m_busDb) {
+        qWarning() << "Database not initialized for storing bus message";
+        return;
+    }
+
+    // 序列化消息
+    QJsonObject json;
+    json["id"] = message.id;
+    json["source"] = message.source;
+    json["destination"] = message.destination;
+    json["payload"] = message.payload;
+    json["timestamp"] = message.timestamp;
+
+    QJsonDocument doc(json);
+    QByteArray data = doc.toJson(QJsonDocument::Compact);
 
     std::string key = generateBusKey(message);
-    QJsonDocument doc(message.payload);
-    QByteArray json = doc.toJson();
+    std::string value(data.constData(), data.size());
 
-    rocksdb::Status s = m_busDb->Put(rocksdb::WriteOptions(),
-                                     key,
-                                     rocksdb::Slice(json.constData(), json.size()));
+    rocksdb::Status status = m_busDb->Put(rocksdb::WriteOptions(), key, value);
 
-    if (s.ok()) {
+    if (!status.ok()) {
+        qCritical() << "Failed to store bus message:" << status.ToString().c_str();
+        emit databaseError(QString::fromStdString(status.ToString()));
+    } else {
         emit busMessageStored(message);
     }
 }
 
 QList<QByteArray> SoftBusCore::queryRawData(const QString &deviceId, qint64 startTime, qint64 endTime) {
     QList<QByteArray> results;
-    if (!m_rawDb) return results;
 
-    rocksdb::Iterator* it = m_rawDb->NewIterator(rocksdb::ReadOptions());
-    std::string prefix = deviceId.toStdString() + "_";
+    if (!m_dbInitialized || !m_rawDb) {
+        qWarning() << "Database not initialized for querying raw data";
+        return results;
+    }
 
-    for (it->Seek(prefix); it->Valid() && it->key().starts_with(prefix); it->Next()) {
-        // 解析时间戳
-        std::string keyStr = it->key().ToString();
-        size_t pos = keyStr.find_last_of('_');
-        if (pos == std::string::npos) continue;
+    // 创建迭代器
+    rocksdb::Iterator* it = m_rawDb->NewIterator(rocksdb::ReadOptions());
 
-        qint64 timestamp = std::stoll(keyStr.substr(pos + 1));
+    // 生成起始键和结束键
+    std::string startKey = generateRawKey(deviceId, startTime);
+    std::string endKey = generateRawKey(deviceId, endTime);
 
-        if (timestamp >= startTime && timestamp <= endTime) {
-            results.append(QByteArray(it->value().data(), it->value().size()));
-        }
+    // 遍历范围内的键
+    for (it->Seek(startKey); it->Valid() && it->key().ToString() <= endKey; it->Next()) {
+        results.append(QByteArray(it->value().data(), it->value().size()));
     }
 
     delete it;
@@ -103,29 +170,35 @@ QList<QByteArray> SoftBusCore::queryRawData(const QString &deviceId, qint64 star
 QList<BusMessage> SoftBusCore::queryBusMessages(const QString &source, const QString &destination,
                                                 qint64 startTime, qint64 endTime) {
     QList<BusMessage> results;
-    if (!m_busDb) return results;
-
-    rocksdb::Iterator* it = m_busDb->NewIterator(rocksdb::ReadOptions());
-    std::string prefix = source.toStdString() + "_" + destination.toStdString() + "_";
-
-    for (it->Seek(prefix); it->Valid() && it->key().starts_with(prefix); it->Next()) {
-        // 解析时间戳
-        std::string keyStr = it->key().ToString();
-        size_t pos = keyStr.find_last_of('_');
-        if (pos == std::string::npos) continue;
 
-        qint64 timestamp = std::stoll(keyStr.substr(pos + 1));
-
-        if (timestamp >= startTime && timestamp <= endTime) {
-            BusMessage msg;
-            msg.id = QString::fromStdString(keyStr.substr(0, pos));
-            msg.timestamp = timestamp;
+    if (!m_dbInitialized || !m_busDb) {
+        qWarning() << "Database not initialized for querying bus messages";
+        return results;
+    }
 
-            QByteArray jsonData(it->value().data(), it->value().size());
-            QJsonDocument doc = QJsonDocument::fromJson(jsonData);
-            msg.payload = doc.object();
+    // 创建迭代器
+    rocksdb::Iterator* it = m_busDb->NewIterator(rocksdb::ReadOptions());
 
-            results.append(msg);
+    // 生成起始键和结束键
+    std::string prefix = source.toStdString() + "_" + destination.toStdString() + "_";
+    std::string startKey = prefix + std::to_string(startTime);
+    std::string endKey = prefix + std::to_string(endTime);
+
+    // 遍历范围内的键
+    for (it->Seek(startKey); it->Valid() && it->key().ToString() <= endKey; it->Next()) {
+        QByteArray data(it->value().data(), it->value().size());
+        QJsonDocument doc = QJsonDocument::fromJson(data);
+        if (doc.isObject()) {
+            QJsonObject json = doc.object();
+
+            BusMessage message;
+            message.id = json["id"].toString();
+            message.source = json["source"].toString();
+            message.destination = json["destination"].toString();
+            message.payload = json["payload"].toObject();
+            message.timestamp = static_cast<qint64>(json["timestamp"].toDouble());
+
+            results.append(message);
         }
     }
 
@@ -134,10 +207,50 @@ QList<BusMessage> SoftBusCore::queryBusMessages(const QString &source, const QSt
 }
 
 std::string SoftBusCore::generateRawKey(const QString &deviceId, qint64 timestamp) {
-    return (deviceId + "_" + QString::number(timestamp)).toStdString();
+    // 格式: deviceId_timestamp
+    return deviceId.toStdString() + "_" + std::to_string(timestamp);
 }
 
 std::string SoftBusCore::generateBusKey(const BusMessage &message) {
-    return (message.source + "_" + message.destination + "_" +
-            QString::number(message.timestamp)).toStdString();
+    // 格式: source_destination_timestamp_messageId
+    return message.source.toStdString() + "_" +
+           message.destination.toStdString() + "_" +
+           std::to_string(message.timestamp) + "_" +
+           message.id.toStdString();
+}
+
+bool SoftBusCore::openDatabase(rocksdb::DB** db, const std::string& path) {
+    rocksdb::Options options;
+    options.create_if_missing = true;
+    rocksdb::Status status = rocksdb::DB::Open(options, path, db);
+
+    if (!status.ok()) {
+        qCritical() << "Failed to open database at" << QString::fromStdString(path)
+        << ":" << status.ToString().c_str();
+        return false;
+    }
+
+    return true;
+}
+
+bool SoftBusCore::putData(rocksdb::DB* db, const std::string& key, const std::string& value) {
+    if (!db) return false;
+
+    rocksdb::Status status = db->Put(rocksdb::WriteOptions(), key, value);
+    return status.ok();
+}
+
+std::string SoftBusCore::getData(rocksdb::DB* db, const std::string& key) {
+    if (!db) return "";
+
+    std::string value;
+    rocksdb::Status status = db->Get(rocksdb::ReadOptions(), key, &value);
+
+    if (!status.ok()) {
+        qWarning() << "Failed to get data for key" << QString::fromStdString(key)
+        << ":" << status.ToString().c_str();
+        return "";
+    }
+
+    return value;
 }

+ 26 - 1
src/soft_bus_core/soft_bus_core.h

@@ -5,6 +5,7 @@
 #include <QMap>
 #include <QString>
 #include <QJsonObject>
+#include <QList>
 #include <rocksdb/db.h>
 
 // 设备信息结构
@@ -14,6 +15,11 @@ struct DeviceInfo {
     QString address;
     QString protocol; // "modbus", "custom"
     QJsonObject properties;
+
+    DeviceInfo() = default;
+    DeviceInfo(const QString &id, const QString &type, const QString &address = "",
+               const QString &protocol = "", const QJsonObject &properties = QJsonObject())
+        : id(id), type(type), address(address), protocol(protocol), properties(properties) {}
 };
 
 // 软总线消息结构
@@ -23,6 +29,11 @@ struct BusMessage {
     QString destination;
     QJsonObject payload;
     qint64 timestamp;
+
+    BusMessage() : timestamp(0) {}
+    BusMessage(const QString &id, const QString &source, const QString &destination,
+               const QJsonObject &payload = QJsonObject(), qint64 timestamp = 0)
+        : id(id), source(source), destination(destination), payload(payload), timestamp(timestamp) {}
 };
 
 class SoftBusCore : public QObject {
@@ -37,6 +48,8 @@ public:
     // 设备管理
     void registerDevice(const DeviceInfo &device);
     void unregisterDevice(const QString &deviceId);
+    DeviceInfo getDeviceInfo(const QString &deviceId) const;
+    QList<DeviceInfo> getAllDevices() const;
 
     // 消息路由
     void routeMessage(const BusMessage &message);
@@ -47,7 +60,11 @@ public:
 
     // 数据查询
     QList<QByteArray> queryRawData(const QString &deviceId, qint64 startTime, qint64 endTime);
-    QList<BusMessage> queryBusMessages(const QString &source, const QString &destination, qint64 startTime, qint64 endTime);
+    QList<BusMessage> queryBusMessages(const QString &source, const QString &destination,
+                                       qint64 startTime, qint64 endTime);
+
+    // 数据库操作
+    void closeDB();
 
 signals:
     void deviceRegistered(const DeviceInfo &device);
@@ -55,15 +72,23 @@ signals:
     void messageReceived(const BusMessage &message);
     void rawDataStored(const QString &deviceId, const QByteArray &data);
     void busMessageStored(const BusMessage &message);
+    void databaseError(const QString &error);
 
 private:
     rocksdb::DB* m_rawDb;
     rocksdb::DB* m_busDb;
     QMap<QString, DeviceInfo> m_devices;
+    bool m_dbInitialized;
 
     // KV键生成
     std::string generateRawKey(const QString &deviceId, qint64 timestamp);
+    std::string generateBusKey(const QString &source, const QString &destination, qint64 timestamp);
     std::string generateBusKey(const BusMessage &message);
+
+    // 数据库工具函数
+    bool openDatabase(rocksdb::DB** db, const std::string& path);
+    bool putData(rocksdb::DB* db, const std::string& key, const std::string& value);
+    std::string getData(rocksdb::DB* db, const std::string& key);
 };
 
 #endif // SOFT_BUS_CORE_H