From 69eecc682499aae9410754fee634c4c2cb955eaf Mon Sep 17 00:00:00 2001 From: zhangsheng Date: Fri, 11 Apr 2025 20:27:45 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=B8=8A=E4=BC=A0=E4=B8=8B?= =?UTF-8?q?=E8=BD=BD=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MyTcpClient.cpp | 50 +++++++++++++++++- MyTcpClient.h | 5 ++ config_mgr.cpp | 2 +- data_config.h | 48 ++++++++++++++++- mainwindow.cpp | 138 +++++++++++++++++++++++++++++++----------------- mainwindow.h | 1 + mainwindow.ui | 4 +- setpoint.ui | 2 +- 8 files changed, 194 insertions(+), 56 deletions(-) diff --git a/MyTcpClient.cpp b/MyTcpClient.cpp index c070f57..caed475 100644 --- a/MyTcpClient.cpp +++ b/MyTcpClient.cpp @@ -70,8 +70,54 @@ void MyTcpClient::onConnected() { } void MyTcpClient::onReadyRead() { - QByteArray data = socket->readAll(); - emit dataReceived(data); + while (socket->bytesAvailable() > 0) { + if (m_waitingForHeader) { + // 1. 先尝试读取头部(固定长度) + if (socket->bytesAvailable() < sizeof(PackageHead)) { + return; // 数据不够,等待下次触发 + } + + // 读取头部 + socket->read(reinterpret_cast(&m_currentHead), sizeof(PackageHead)); + + // 验证头部标识(0xAA55AA) + if (m_currentHead.head[0] != 0xAA || + m_currentHead.head[1] != 0x55 || + m_currentHead.head[2] != 0xAA) { + qWarning() << "Invalid header! Disconnecting..."; + return; + } + + // 进入等待数据状态 + m_waitingForHeader = false; + m_buffer.clear(); + m_buffer.append(reinterpret_cast(&m_currentHead), sizeof(PackageHead)); // 先存头部 + } else { + // 2. 根据头部的 len 读取剩余数据 + qint64 remainingBytes = m_currentHead.len - (m_buffer.size() - sizeof(PackageHead)); + + if (remainingBytes <= 0) { + // 数据已经完整,触发信号 + emit dataReceived(m_buffer); + m_waitingForHeader = true; // 重置状态,准备接收下一个包 + break; // 继续处理缓冲区可能的下一个包 + } + + // 读取剩余数据(不超过 remainingBytes) + QByteArray newData = socket->read(remainingBytes); + qDebug() << "Read" << newData.size() << "bytes"; + m_buffer.append(newData); + + // 检查是否已经读完 + if (m_buffer.size() - sizeof(PackageHead) >= m_currentHead.len) { + qDebug() << "m_buffer" << m_buffer.size() << "bytes"; + emit dataReceived(m_buffer); + m_waitingForHeader = true; // 准备接收下一个包 + } + } + } +// QByteArray data = socket->readAll(); +// emit dataReceived(data); } void MyTcpClient::onDisconnected() { diff --git a/MyTcpClient.h b/MyTcpClient.h index c42d4da..70aaa90 100644 --- a/MyTcpClient.h +++ b/MyTcpClient.h @@ -4,6 +4,7 @@ #include #include #include +#include "data_config.h" class MyTcpClient : public QObject { Q_OBJECT @@ -39,6 +40,10 @@ private: quint16 serverPort; bool shouldReconnect; // 标记是否需要重连 static MyTcpClient* m_instance; + + QByteArray m_buffer; // 存储当前正在接收的数据 + bool m_waitingForHeader = true; // 是否在等待头部 + PackageHead m_currentHead; // 当前包的头部信息 }; #endif // MYTCPCLIENT_H diff --git a/config_mgr.cpp b/config_mgr.cpp index 27924e7..84bb2c7 100644 --- a/config_mgr.cpp +++ b/config_mgr.cpp @@ -326,7 +326,7 @@ void ConfigMgr::Load(QString filename) { // filter QJsonArray filter_array = channel["filter"].toArray(); for (int k = 0; k < filter_array.size(); k++) { - QJsonObject filter_ele = filter_array[i].toObject(); + QJsonObject filter_ele = filter_array[k].toObject(); variable->filter_[k].low = filter_ele["low"].toInt(); variable->filter_[k].high = filter_ele["high"].toInt(); variable->filter_[k].checked = filter_ele["checked"].toBool(); diff --git a/data_config.h b/data_config.h index 54d3be0..de6a540 100644 --- a/data_config.h +++ b/data_config.h @@ -58,9 +58,28 @@ enum CMTCommand { kGetVersionInfo = 4, kRelaySetting = 5, kRelayStatus = 6, - kUpgradeProgress = 7 + kUpgradeProgress = 7, + kCalibrationMode = 8, + kGetDcValue = 9, + kSetCalibrationCoe = 10, + kGetCalibrationCoe = 11, + kClearCalibrationCoe = 12, + kGetWaveData = 13, + kUploadConfigFile = 14, + kDownloadConfigFile = 15, + kConfigSubCard = 16, // 请求无包体,响应有包体 + kRS485BaudrateSet = 17, // RS485波特率配置 + kRS485BaudrateGet = 18, // RS485波特率获取 +}; +enum RS485Baudrate { + kBaudrate2400 = 0, + kBaudrate4800 = 1, + kBaudrate9600 = 2, // 默认值 + kBaudrate19200 = 3, + kBaudrate38400 = 4, + kBaudrate57600 = 5, + kBaudrate115200 = 6 }; - // 振动板采样率 typedef enum { kVibSR16K = 0, // 16k @@ -198,6 +217,7 @@ typedef struct { double scale_factor; } Transducer; + #pragma pack(1) typedef struct { uint8_t head[3]; // 固定值:0xAA55AA @@ -244,6 +264,30 @@ typedef struct { uint8_t status; // 7 测试状态,8 手动状态,9 工作状态 } RelayStatusRsp; +typedef struct { + char data[0]; +} UploadConfigReq, DownloadConfigRsp; + +typedef struct { + uint8_t code; +} UploadConfigRsp, DownloadConfigReq; + +typedef struct { + uint8_t card_id; +} ConfigSubCardReq; + +typedef struct { + uint8_t code; // 0: success 1: 无配置文件 2:失败 +} ConfigSubCardRsp; + +typedef struct { + uint8_t baudrate; // kRS485BaudrateSet, kRS485BaudrateGet +} BaudrateSetReq, BaudrateGetRsp; + +typedef struct { + uint8_t code; // 0: success +} BaudrateSetRsp; + #pragma pack() #endif // DATA_CONFIG_H diff --git a/mainwindow.cpp b/mainwindow.cpp index 3a2f893..d6dd5ed 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -87,7 +87,7 @@ MainWindow::MainWindow(QWidget *parent) connect(btnGroup_slot, SIGNAL(buttonClicked(QAbstractButton *)), this, SLOT(OnButtonGroup(QAbstractButton *))); QSettings settingsread(QCoreApplication::applicationDirPath() + "\\config\\config.ini", QSettings::IniFormat); g_strServerIp = settingsread.value("Server/IP").toString(); - //connectServer(); + connectServer(); // 设置自定义日志处理函数 #ifndef QT_DEBUG qInstallMessageHandler(messageHandler); @@ -199,6 +199,7 @@ void MainWindow::createMenu(const QString &rootTitle, QPushButton *parent) { QAction *proximitor_2 = proximitor_menu->addAction("/HAM824 三冗余板卡"); proximitor_2->setData(kCardVibTMRPrimary); QAction *rpm_1 = rpm_menu->addAction("/OPM844 单板卡"); + rpm_1->setData(kCardSpeedSingle); // 创建第二层子菜单:/KPM834 键相模块 QAction *keyphasor_1 = keyphasor->addAction("/KPM834 单板卡"); keyphasor_1->setData(kCardKeyphaseSingle); @@ -342,7 +343,7 @@ void MainWindow::onMenuActionTriggered() { button->setText(chan_display); } if (action->text() == "重置模块") { - if (map_slot_config[button_id].rack_type == "TMR1") { + if (ConfigMgr::Instance()->card_type_[button_id - 1] == kCardRelayTMRPrimary) { map_slot_config[button_id].slot_type = ""; map_slot_config[button_id].rack_type = "0"; map_slot_config[button_id].slot_btn->setText(""); @@ -355,7 +356,7 @@ void MainWindow::onMenuActionTriggered() { map_slot_config[button_id + 2].rack_type = "0"; map_slot_config[button_id + 2].slot_btn->setText(""); map_slot_config[button_id + 2].chan_display = ""; - } else if (map_slot_config[button_id].rack_type == "TMR2") { + } else if (ConfigMgr::Instance()->card_type_[button_id - 1] == kCardRelayTMRBackup) { map_slot_config[button_id - 1].slot_type = ""; map_slot_config[button_id - 1].rack_type = "0"; map_slot_config[button_id - 1].slot_btn->setText(""); @@ -368,44 +369,11 @@ void MainWindow::onMenuActionTriggered() { map_slot_config[button_id + 1].rack_type = "0"; map_slot_config[button_id + 1].slot_btn->setText(""); map_slot_config[button_id + 1].chan_display = ""; - } else if (map_slot_config[button_id].rack_type == "TMR3") { - map_slot_config[button_id - 2].slot_type = ""; - map_slot_config[button_id - 2].rack_type = "0"; - map_slot_config[button_id - 2].slot_btn->setText(""); - map_slot_config[button_id - 2].chan_display = ""; - map_slot_config[button_id - 1].slot_type = ""; - map_slot_config[button_id - 1].rack_type = "0"; - map_slot_config[button_id - 1].slot_btn->setText(""); - map_slot_config[button_id - 1].chan_display = ""; - map_slot_config[button_id].slot_type = ""; - map_slot_config[button_id].rack_type = "0"; + }else if (ConfigMgr::Instance()->card_type_[button_id - 1] == kCardVibSingle || + ConfigMgr::Instance()->card_type_[button_id - 1] == kCardSpeedSingle || + ConfigMgr::Instance()->card_type_[button_id - 1] == kCardKeyphaseSingle) { + ConfigMgr::Instance()->card_type_[button_id - 1] = kCardNone; map_slot_config[button_id].slot_btn->setText(""); - map_slot_config[button_id].chan_display = ""; - } - if (map_slot_config[button_id].rack_type == "Double1") { - map_slot_config[button_id].slot_type = ""; - map_slot_config[button_id].rack_type = "0"; - map_slot_config[button_id].slot_btn->setText(""); - map_slot_config[button_id].chan_display = ""; - map_slot_config[button_id + 1].slot_type = ""; - map_slot_config[button_id + 1].rack_type = "0"; - map_slot_config[button_id + 1].slot_btn->setText(""); - map_slot_config[button_id + 1].chan_display = ""; - } else if (map_slot_config[button_id].rack_type == "Double2") { - map_slot_config[button_id - 1].slot_type = ""; - map_slot_config[button_id - 1].rack_type = "0"; - map_slot_config[button_id - 1].slot_btn->setText(""); - map_slot_config[button_id - 1].chan_display = ""; - map_slot_config[button_id].slot_type = ""; - map_slot_config[button_id].rack_type = "0"; - map_slot_config[button_id].slot_btn->setText(""); - map_slot_config[button_id].chan_display = ""; - } - if (map_slot_config[button_id].rack_type == "Single") { - map_slot_config[button_id].slot_type = ""; - map_slot_config[button_id].rack_type = "0"; - map_slot_config[button_id].slot_btn->setText(""); - map_slot_config[button_id].chan_display = ""; } } else if (action->text() == "升级固件") { sendUpgradePackage(button_id); @@ -527,9 +495,64 @@ void MainWindow::onMenuAction_relay() { relay_setting->setWindowModality(Qt::ApplicationModal); relay_setting->show(); } - +uint8_t calculate_crc(uint8_t c, const QByteArray &data) { + uint8_t crc = c; + for (int i = 0; i < data.size(); ++i) { + crc += static_cast(data[i]); // 累加每个字节 + } + return crc; +} void MainWindow::on_pushButton_save_clicked() { ConfigMgr::Instance()->Save(); + // 读取文件内容 + QFile file(QCoreApplication::applicationDirPath() + "\\config\\tsi_config_file.json"); + if (!file.open(QIODevice::ReadOnly)) { + qWarning() << "Failed to open update file."; + return; + } + QByteArray fileData = file.readAll(); + int fileSize = fileData.size(); + if (fileSize > 10 * 1024 * 1024) { + QMessageBox::information(this, QStringLiteral("提示"), "文件大小超过10M,请重新选择!"); + file.close(); + return; + } + qDebug() << "fileSize" << fileSize ; + // 创建 PackageHead 结构体 + PackageHead header = { {0xAA, 0x55, 0xAA}, kUploadConfigFile, fileSize, 0, {} }; + // 计算文件的 CRC 校验和 + header.crc = calculate_crc(0, fileData); + header.len = fileSize; + char *send_buf = NULL; + send_buf = (char *)malloc(sizeof(PackageHead) + fileData.size() + 1); + memset(send_buf, 0, sizeof(PackageHead) + fileData.size() + 1); + memcpy(send_buf, &header, sizeof(PackageHead)); + memcpy(send_buf + sizeof(PackageHead), fileData.data(), fileData.size()); + int length = sizeof(PackageHead) + fileData.size(); + const int MAX_CHUNK_SIZE = 50 * 1024; // 50 KB + qint64 bytesSent = 0; + qint64 totalBytes = length; + qDebug() << "totalBytes" << totalBytes ; + while (bytesSent < totalBytes) { + qint64 chunkSize = 0; + if (MAX_CHUNK_SIZE < totalBytes - bytesSent) { + chunkSize = MAX_CHUNK_SIZE; + } else { + chunkSize = totalBytes - bytesSent; + } + qint64 bytesWritten = m_tcpClient->sendData(send_buf + bytesSent, chunkSize); + qDebug() << "bytesWritten" << bytesWritten << "bytesSent" << bytesSent << "chunkSize" << chunkSize ; + if (bytesWritten == -1) { + break; + } + bytesSent += bytesWritten; + } + qDebug() << "bytesSent" << bytesSent; + m_tcpClient->waitForRead(); + file.close(); + if (send_buf != NULL) { + free(send_buf); + } } void MainWindow::on_pushButton_open_clicked() { @@ -559,13 +582,6 @@ void MainWindow::on_pushButton_open_clicked() { } } -uint8_t calculate_crc(uint8_t c, const QByteArray &data) { - uint8_t crc = c; - for (int i = 0; i < data.size(); ++i) { - crc += static_cast(data[i]); // 累加每个字节 - } - return crc; -} uint32_t myHtonl(uint32_t value) { return ((value >> 24) & 0x000000FF) | // 提取最高的8位 @@ -702,5 +718,31 @@ void MainWindow::readData(const QByteArray &data) { statusBar()->showMessage("升级完成!", 3000); // 显示3秒 } //qDebug() << "Server response: " << upgrade_resp.code; + } else if(header.cmd == kDownloadConfigFile){ + //qDebug() << "header.len" << header.len; + char *config_file = NULL; + config_file = (char*)malloc(header.len + 1); + memset(config_file,0,header.len + 1); + memcpy(config_file, data.data() + sizeof(PackageHead), header.len); + QString filename_ = QCoreApplication::applicationDirPath() + "\\config\\tsi_config_file2.json"; + //qDebug() << config_file ; + QFile file(filename_); + file.open(QIODevice::WriteOnly); + file.write(config_file,header.len); + file.close(); + if(config_file != NULL) + free(config_file); } } + +void MainWindow::on_pushButton_download_clicked() +{ + PackageHead header = { {0xAA, 0x55, 0xAA}, kDownloadConfigFile, 1, 0, {} }; + char send_buf[20] = {0}; + memcpy(send_buf, (char *)&header, sizeof(PackageHead)); + int length = sizeof(PackageHead); + qint64 bytesWritten = m_tcpClient->sendData(send_buf, length); + m_tcpClient->waitForRead(); + qDebug() << "bytesWritten: " << bytesWritten; +} + diff --git a/mainwindow.h b/mainwindow.h index ba881a9..5d7e69d 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -72,5 +72,6 @@ private slots: void on_pushButton_point_name_clicked(); void on_pushButton_save_clicked(); void on_pushButton_open_clicked(); + void on_pushButton_download_clicked(); }; #endif // MAINWINDOW_H diff --git a/mainwindow.ui b/mainwindow.ui index 97f51e3..a0cbf12 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -122,7 +122,7 @@ - + 140 @@ -144,7 +144,7 @@ - + 下载 diff --git a/setpoint.ui b/setpoint.ui index ef50bcf..db4b548 100644 --- a/setpoint.ui +++ b/setpoint.ui @@ -11,7 +11,7 @@ - Form + 触发配置