2025-06-20 09:25:17 +08:00
|
|
|
|
#include <pthread.h>
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
#include <time.h>
|
|
|
|
|
|
#include <queue>
|
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
#include <atomic>
|
2025-07-25 10:47:50 +08:00
|
|
|
|
#include <fstream>
|
2025-09-23 14:03:11 +08:00
|
|
|
|
#include <sys/stat.h> // 用于mkdir
|
2025-06-24 10:33:31 +08:00
|
|
|
|
#include <iostream>
|
2025-07-09 09:39:29 +08:00
|
|
|
|
|
|
|
|
|
|
#include "cloudfront/code/interface.h" //lnk20250708
|
|
|
|
|
|
#include "cloudfront/code/rocketmq.h" //lnk20250708
|
2025-09-24 14:07:09 +08:00
|
|
|
|
#include "cloudfront/code/log4.h" //lnk20250924
|
2025-07-09 09:39:29 +08:00
|
|
|
|
#include "client2.h"
|
2025-09-23 14:03:11 +08:00
|
|
|
|
#include "cloudfront/code/log4.h"
|
2025-07-09 09:39:29 +08:00
|
|
|
|
|
2025-06-24 10:33:31 +08:00
|
|
|
|
using namespace std;
|
2025-06-20 09:25:17 +08:00
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
SafeMessageQueue message_queue; // 全局消息队列
|
2025-06-20 09:25:17 +08:00
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//时间转换函数
|
2025-07-11 14:12:47 +08:00
|
|
|
|
time_t ConvertToTimestamp(const tagTime& time) {
|
2025-07-09 09:39:29 +08:00
|
|
|
|
struct tm t = {};
|
2025-09-23 14:03:11 +08:00
|
|
|
|
t.tm_year = time.DeviceYear - 1900; // tm_year 从 1900 开始计
|
|
|
|
|
|
t.tm_mon = time.DeviceMonth - 1; // tm_mon 从 0(1月)开始
|
2025-07-11 14:12:47 +08:00
|
|
|
|
t.tm_mday = time.DeviceDay;
|
|
|
|
|
|
t.tm_hour = time.DeviceHour;
|
|
|
|
|
|
t.tm_min = time.DeviceMinute;
|
|
|
|
|
|
t.tm_sec = time.DeviceSecond;
|
2025-07-09 09:39:29 +08:00
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 返回时间戳(本地时间)
|
2025-07-09 09:39:29 +08:00
|
|
|
|
return mktime(&t);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//文件分割取字段
|
2025-07-25 10:47:50 +08:00
|
|
|
|
std::string extract_filename(const std::string& path) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 查找最后一个'/'的位置
|
2025-07-25 10:47:50 +08:00
|
|
|
|
size_t last_slash = path.find_last_of('/');
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 如果找到'/',则返回'/'之后的部分
|
2025-07-25 10:47:50 +08:00
|
|
|
|
if (last_slash != std::string::npos) {
|
|
|
|
|
|
return path.substr(last_slash + 1);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 如果没有'/',直接返回原字符串
|
2025-07-25 10:47:50 +08:00
|
|
|
|
return path;
|
|
|
|
|
|
}
|
2025-08-05 15:41:04 +08:00
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//文件crc校验函数
|
2025-09-08 14:37:39 +08:00
|
|
|
|
uint16_t crc_16_new(const uint8_t* buf, uint32_t len) {
|
|
|
|
|
|
uint16_t crc = 0xffff;
|
|
|
|
|
|
for (uint32_t i = 0; i < len; i++) {
|
|
|
|
|
|
crc = (uint16_t)(crc ^ buf[i]);
|
|
|
|
|
|
for (int j = 0; j < 8; j++) {
|
|
|
|
|
|
if (crc & 1) {
|
|
|
|
|
|
crc = (uint16_t)((crc >> 1) ^ 0xA001);
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
crc = (uint16_t)(crc >> 1);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return crc;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//消息处理逻辑
|
2025-06-25 10:54:09 +08:00
|
|
|
|
void process_received_message(string mac, string id,const char* data, size_t length) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 实际的消息处理逻辑
|
2025-06-25 10:54:09 +08:00
|
|
|
|
std::cout << "Active connections: " << mac << " id:" << id << " size:" << length << std::endl;
|
2025-09-04 15:37:26 +08:00
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 接收到消息后,先找到指定装置刷新对应最新通讯时间戳
|
2025-09-04 15:37:26 +08:00
|
|
|
|
ClientManager::instance().set_cloudmessage_time(id);
|
2025-06-25 10:54:09 +08:00
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//数据处理逻辑
|
2025-07-03 11:13:16 +08:00
|
|
|
|
if (length > 0) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 将数据转为无符号类型以便处理二进制值
|
2025-07-03 11:13:16 +08:00
|
|
|
|
const unsigned char* udata = reinterpret_cast<const unsigned char*>(data);
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//对数据消息的初步处理--登录报文格式解析不出来
|
2025-07-03 11:13:16 +08:00
|
|
|
|
MessageParser parser;
|
|
|
|
|
|
bool bool_msgset = parser.SetMsg(udata, length);
|
2025-06-25 10:54:09 +08:00
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//云服务登录报文
|
2025-07-03 11:13:16 +08:00
|
|
|
|
if (udata[0] == 0xEB && udata[1] == 0x90 && udata[2] == 0xEB && udata[3] == 0x90) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//通讯状态报文
|
2025-07-03 11:13:16 +08:00
|
|
|
|
if (udata[8] == 0x01) {
|
|
|
|
|
|
std::cout << "cloud login: " << mac << " state: " << static_cast<int>(udata[16]) << static_cast<int>(udata[17]) << static_cast<int>(udata[18]) << static_cast<int>(udata[19]) << std::endl;
|
|
|
|
|
|
if (udata[19] == 0x10) {
|
|
|
|
|
|
std::cout << "cloud login: " << mac << " state: success!" << std::endl;
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//装置登录成功
|
|
|
|
|
|
ClientManager::instance().set_cloud_status(id, 1); //设置了云前置登录状态为已登录
|
|
|
|
|
|
ClientManager::instance().read_devversion_action_to_device(id);//主动触发,读取装置版本配置信息,仅在装置登录后执行一次,当前获取版本信息确认对时报文结构。
|
|
|
|
|
|
|
|
|
|
|
|
//ClientManager::instance().get_dev_status(id);//设备在线情况判断 ture在线 false离线
|
|
|
|
|
|
//ClientManager::instance().set_real_state_count("D002", 1,1);//登录后测试实时
|
|
|
|
|
|
//ClientManager::instance().add_file_menu_action_to_device("D002","/etc");//测试文件目录读取
|
|
|
|
|
|
//ClientManager::instance().add_file_download_action_to_device("D002", "/etc/NPQS570_VX_ZJ_2(V103).icd");//测试文件下载
|
|
|
|
|
|
//ClientManager::instance().get_fixedvalue_action_to_device(id,1);//测试获取装置测点定值数据
|
|
|
|
|
|
//ClientManager::instance().get_fixedvaluedes_action_to_device(id);//测试获取装置定值描述
|
|
|
|
|
|
//ClientManager::instance().set_fixedvalue_action_to_device();//装置修改定值测试(参数需要外部提供)
|
|
|
|
|
|
//ClientManager::instance().get_interfixedvalue_action_to_device(id);//装置获取内部定值
|
|
|
|
|
|
//ClientManager::instance().get_fixedvalucontrolword_action_to_device(id,1);//获取 1-内部定值描述 或者 2-控制字描述
|
|
|
|
|
|
//ClientManager::instance().set_interfixedvalue_action_to_device();装置修改内部定值测试(参数由外部提供)
|
|
|
|
|
|
//ClientManager::instance().read_runninginformation_action_to_device(id);//主动触发,读取装置运行信息
|
|
|
|
|
|
|
|
|
|
|
|
//// 设置起始时间: 2025年9月1日 10:30:45
|
2025-09-08 14:37:39 +08:00
|
|
|
|
//std::tm start_time = {};
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//start_time.tm_year = 2025 - 1900; // 年份从1900开始计算
|
|
|
|
|
|
//start_time.tm_mon = 8 - 1; // 月份从0开始 (0=一月)
|
2025-09-08 14:37:39 +08:00
|
|
|
|
//start_time.tm_mday = 20;
|
|
|
|
|
|
//start_time.tm_hour = 1;
|
|
|
|
|
|
//start_time.tm_min = 1;
|
|
|
|
|
|
//start_time.tm_sec = 1;
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//// 设置结束时间: 2025年9月4日 12:15:30
|
2025-09-08 14:37:39 +08:00
|
|
|
|
//std::tm end_time = {};
|
|
|
|
|
|
//end_time.tm_year = 2025 - 1900;
|
|
|
|
|
|
//end_time.tm_mon = 8 - 1;
|
|
|
|
|
|
//end_time.tm_mday = 25;
|
|
|
|
|
|
//end_time.tm_hour = 1;
|
|
|
|
|
|
//end_time.tm_min = 1;
|
|
|
|
|
|
//end_time.tm_sec = 1;
|
|
|
|
|
|
//ClientManager::instance().read_eventlog_action_to_device(id, start_time, end_time,2,1);
|
2025-10-24 08:46:24 +08:00
|
|
|
|
/*DIY_ERRORLOG_CODE("111", 0, static_cast<int>(LogCode::LOG_CODE_OTHER), "【ERROR】测试告警发送 前置");
|
2025-09-24 14:07:09 +08:00
|
|
|
|
DIY_ERRORLOG_CODE(id, 1, static_cast<int>(LogCode::LOG_CODE_OTHER), "【ERROR】测试告警发送 设备");
|
|
|
|
|
|
std::string mpid;
|
2025-09-23 14:03:11 +08:00
|
|
|
|
get_monitor_id_by_dev_and_seq(id, 1, mpid);
|
|
|
|
|
|
if (!mpid.empty()) {
|
|
|
|
|
|
DIY_ERRORLOG_CODE(mpid, 2, static_cast<int>(LogCode::LOG_CODE_OTHER), "【ERROR】测试告警发送 测点");
|
2025-10-24 08:46:24 +08:00
|
|
|
|
}*/
|
2025-07-03 11:13:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
if (udata[19] == 0x00) {
|
|
|
|
|
|
std::cout << "cloud login: " << mac << " state: fail!" << std::endl;
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//装置登录失败 关闭客户端连接 等待20秒重新登录
|
2025-07-03 11:13:16 +08:00
|
|
|
|
ClientManager::instance().restart_device(id);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
std::cout << "cloud login: " << mac << " state: error!"<< std::endl;
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//装置登录失败 关闭客户端连接 等待20秒重新登录
|
2025-07-03 11:13:16 +08:00
|
|
|
|
ClientManager::instance().restart_device(id);
|
|
|
|
|
|
}
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//登录报文处理完毕,当前报文处理逻辑结束并返回
|
2025-07-03 11:13:16 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//装置主动上送报文 暂态事件报文/暂态波形文件报文
|
2025-07-25 10:47:50 +08:00
|
|
|
|
if (udata[8] == static_cast<unsigned char>(MsgResponseType::Response_Event)) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//处理主动上送的暂态事件报文
|
2025-09-03 08:49:38 +08:00
|
|
|
|
NewTaglogbuffer event = NewTaglogbuffer::createFromData(parser.RecvData.data(), parser.RecvData.size());
|
2025-07-25 10:47:50 +08:00
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//获取测点id
|
|
|
|
|
|
std::string mpid;
|
|
|
|
|
|
get_monitor_id_by_dev_and_seq(id, 1, mpid);
|
|
|
|
|
|
|
|
|
|
|
|
//判断事件逻辑是否需要上送告警
|
|
|
|
|
|
if (!mpid.empty()) {
|
|
|
|
|
|
switch (event.head.LogCode)
|
|
|
|
|
|
{
|
|
|
|
|
|
case 2:
|
|
|
|
|
|
DIY_ERRORLOG_CODE(mpid, 2, static_cast<int>(LogCode::LOG_CODE_DEV_ALARM), "【ERROR】系统事件:突变量启动录波(NPQS-570特殊功能)");
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 21:
|
|
|
|
|
|
DIY_ERRORLOG_CODE(mpid, 2, static_cast<int>(LogCode::LOG_CODE_DEV_ALARM), "【ERROR】硬件告警事件:装置掉电");
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 22:
|
|
|
|
|
|
DIY_ERRORLOG_CODE(mpid, 2, static_cast<int>(LogCode::LOG_CODE_DEV_ALARM), "【ERROR】硬件告警事件:装置上电");
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 23:
|
|
|
|
|
|
DIY_ERRORLOG_CODE(mpid, 2, static_cast<int>(LogCode::LOG_CODE_DEV_ALARM), "【ERROR】硬件告警事件:时钟出错");
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 24:
|
|
|
|
|
|
DIY_ERRORLOG_CODE(mpid, 2, static_cast<int>(LogCode::LOG_CODE_DEV_ALARM), "【ERROR】硬件告警事件:AD采集出错");
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 25:
|
|
|
|
|
|
DIY_ERRORLOG_CODE(mpid, 2, static_cast<int>(LogCode::LOG_CODE_DEV_ALARM), "【ERROR】硬件告警事件:主存储器出错");
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 26:
|
|
|
|
|
|
DIY_ERRORLOG_CODE(mpid, 2, static_cast<int>(LogCode::LOG_CODE_DEV_ALARM), "【ERROR】硬件告警事件:内存出错");
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 31:
|
|
|
|
|
|
DIY_ERRORLOG_CODE(mpid, 2, static_cast<int>(LogCode::LOG_CODE_DEV_ALARM), "【ERROR】运行告警事件:程序升级成功");
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 32:
|
|
|
|
|
|
DIY_ERRORLOG_CODE(mpid, 2, static_cast<int>(LogCode::LOG_CODE_DEV_ALARM), "【ERROR】运行告警事件:程序升级失败");
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 33:
|
|
|
|
|
|
DIY_ERRORLOG_CODE(mpid, 2, static_cast<int>(LogCode::LOG_CODE_DEV_ALARM), "【ERROR】运行告警事件:程序文件出错");
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 34:
|
|
|
|
|
|
DIY_ERRORLOG_CODE(mpid, 2, static_cast<int>(LogCode::LOG_CODE_DEV_ALARM), "【ERROR】运行告警事件:ICD文件解析出错");
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 35:
|
|
|
|
|
|
DIY_ERRORLOG_CODE(mpid, 2, static_cast<int>(LogCode::LOG_CODE_DEV_ALARM), "【ERROR】运行告警事件:定值出错");
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 36:
|
|
|
|
|
|
DIY_ERRORLOG_CODE(mpid, 2, static_cast<int>(LogCode::LOG_CODE_DEV_ALARM), "【ERROR】运行告警事件:Pqdif配置模板出错");
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 51:
|
|
|
|
|
|
DIY_ERRORLOG_CODE(mpid, 2, static_cast<int>(LogCode::LOG_CODE_DEV_ALARM), "【ERROR】电度告警事件:失压事件");
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 52:
|
|
|
|
|
|
DIY_ERRORLOG_CODE(mpid, 2, static_cast<int>(LogCode::LOG_CODE_DEV_ALARM), "【ERROR】电度告警事件:欠压事件");
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 53:
|
|
|
|
|
|
DIY_ERRORLOG_CODE(mpid, 2, static_cast<int>(LogCode::LOG_CODE_DEV_ALARM), "【ERROR】电度告警事件:过压事件");
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 54:
|
|
|
|
|
|
DIY_ERRORLOG_CODE(mpid, 2, static_cast<int>(LogCode::LOG_CODE_DEV_ALARM), "【ERROR】电度告警事件:断相事件");
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 55:
|
|
|
|
|
|
DIY_ERRORLOG_CODE(mpid, 2, static_cast<int>(LogCode::LOG_CODE_DEV_ALARM), "【ERROR】电度告警事件:电压不平衡事件");
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 56:
|
|
|
|
|
|
DIY_ERRORLOG_CODE(mpid, 2, static_cast<int>(LogCode::LOG_CODE_DEV_ALARM), "【ERROR】电度告警事件:电流不平衡事件");
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 57:
|
|
|
|
|
|
DIY_ERRORLOG_CODE(mpid, 2, static_cast<int>(LogCode::LOG_CODE_DEV_ALARM), "【ERROR】电度告警事件:失流事件");
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 58:
|
|
|
|
|
|
DIY_ERRORLOG_CODE(mpid, 2, static_cast<int>(LogCode::LOG_CODE_DEV_ALARM), "【ERROR】电度告警事件:过流事件");
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 59:
|
|
|
|
|
|
DIY_ERRORLOG_CODE(mpid, 2, static_cast<int>(LogCode::LOG_CODE_DEV_ALARM), "【ERROR】电度告警事件:断流事件");
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取测点参数
|
|
|
|
|
|
std::string strScale;//电压等级
|
|
|
|
|
|
int nPTType;//接线方式
|
2025-07-25 10:47:50 +08:00
|
|
|
|
float fPT = 1.0f;
|
|
|
|
|
|
float fCT = 1.0f;
|
|
|
|
|
|
if (ClientManager::instance().get_point_scale_and_pttype(
|
2025-09-23 14:03:11 +08:00
|
|
|
|
id, // 或使用id
|
|
|
|
|
|
event.head.name, // 从报文中解析出的测点序号
|
2025-07-25 10:47:50 +08:00
|
|
|
|
strScale,
|
|
|
|
|
|
nPTType) && ClientManager::instance().get_pt_ct_ratio(id, event.head.name, fPT, fCT))
|
|
|
|
|
|
{
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 使用获取的参数解析事件记录
|
2025-07-25 10:47:50 +08:00
|
|
|
|
QVVRRecord record = DynamicLog_GetQVVRRecordFromLogBuffer(
|
|
|
|
|
|
strScale, nPTType, fPT, event);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 使用记录数据(示例:打印到控制台)
|
|
|
|
|
|
std::cout << "事件类型: " << record.nType
|
|
|
|
|
|
<< ", 持续时间: " << record.fPersisstime << "s"
|
|
|
|
|
|
<< ", 特征幅值: " << record.fMagntitude << " pu"
|
|
|
|
|
|
<< ", 时间戳: " << record.triggerTimeMs << "ms" << std::endl;
|
2025-07-03 11:13:16 +08:00
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//lnk20250805 事件上送先记录,录波文件上传结束后再更新文件
|
2025-09-22 16:46:33 +08:00
|
|
|
|
append_qvvr_event(id,event.head.name,
|
|
|
|
|
|
record.nType,record.fPersisstime,record.fMagntitude,record.triggerTimeMs,record.phase);
|
2025-08-07 18:59:11 +08:00
|
|
|
|
transfer_json_qvvr_data(id,event.head.name,
|
|
|
|
|
|
record.fMagntitude,record.fPersisstime,record.triggerTimeMs,record.nType,record.phase,
|
|
|
|
|
|
"");
|
2025-10-22 15:57:50 +08:00
|
|
|
|
|
|
|
|
|
|
//事件主动上送处理完成,不需要通知状态机
|
2025-07-25 10:47:50 +08:00
|
|
|
|
}
|
|
|
|
|
|
else {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 处理获取失败的情况
|
2025-07-25 10:47:50 +08:00
|
|
|
|
std::cerr << "Failed to get point parameters for: " << mac << std::endl;
|
|
|
|
|
|
}
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//处理完毕主动上送报文后直接退出,不要干扰装置正常应答
|
2025-07-25 10:47:50 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (udata[8] == static_cast<unsigned char>(MsgResponseType::Response_ActiveSOEInfo)) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//处理主动上送的波形文件信息报文
|
|
|
|
|
|
unsigned char file_type = udata[12];//录波文件类型数 cfg dat hdr 1-3
|
|
|
|
|
|
unsigned char line_id = udata[13];//录波测点 1-6
|
|
|
|
|
|
const uint8_t* data_ptr = parser.RecvData.data() + 2;//数据体去除前两位
|
2025-07-25 10:47:50 +08:00
|
|
|
|
size_t data_size = parser.RecvData.size() - 2;
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 直接构造字符串(避免额外拷贝)
|
2025-07-25 10:47:50 +08:00
|
|
|
|
std::string tempfilename(
|
|
|
|
|
|
reinterpret_cast<const char*>(data_ptr),
|
|
|
|
|
|
data_size
|
|
|
|
|
|
);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// ========== 新增:处理终止符 ==========
|
|
|
|
|
|
// 查找字符串中的第一个空字符或其他终止符
|
2025-09-16 10:10:32 +08:00
|
|
|
|
size_t terminator_pos = tempfilename.find_first_of("\0\r\n", 0, 3);
|
|
|
|
|
|
if (terminator_pos != std::string::npos) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 如果找到终止符,截断字符串
|
2025-09-16 10:10:32 +08:00
|
|
|
|
tempfilename.resize(terminator_pos);
|
|
|
|
|
|
std::cout << "Found terminator at position: " << terminator_pos
|
|
|
|
|
|
<< ", truncated filename to: " << tempfilename << std::endl;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// ========== 新增文件路径处理逻辑 ==========
|
|
|
|
|
|
// 1. 分割原始文件名和后缀
|
2025-07-25 10:47:50 +08:00
|
|
|
|
size_t dotPos = tempfilename.find_last_of('.');
|
|
|
|
|
|
std::string baseName, originalExt;
|
|
|
|
|
|
if (dotPos != std::string::npos) {
|
|
|
|
|
|
baseName = tempfilename.substr(0, dotPos);
|
|
|
|
|
|
originalExt = tempfilename.substr(dotPos);
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
baseName = tempfilename;
|
|
|
|
|
|
originalExt = "";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 2. 确定大小写风格
|
2025-07-25 10:47:50 +08:00
|
|
|
|
bool isUppercase = false;
|
|
|
|
|
|
if (!originalExt.empty()) {
|
|
|
|
|
|
isUppercase = true;
|
|
|
|
|
|
for (char c : originalExt) {
|
|
|
|
|
|
if (std::isalpha(c) && std::islower(c)) {
|
|
|
|
|
|
isUppercase = false;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 3. 生成需要的后缀列表
|
2025-07-25 10:47:50 +08:00
|
|
|
|
std::vector<std::string> requiredExts;
|
2025-09-23 14:03:11 +08:00
|
|
|
|
if (file_type == 3) { // 需要三个文件
|
2025-07-25 10:47:50 +08:00
|
|
|
|
requiredExts = { ".cfg", ".dat", ".hdr" };
|
|
|
|
|
|
}
|
2025-09-23 14:03:11 +08:00
|
|
|
|
else { // 默认需要两个文件
|
2025-07-25 10:47:50 +08:00
|
|
|
|
requiredExts = { ".cfg", ".dat" };
|
|
|
|
|
|
//requiredExts = { ".dat" };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 4. 调整后缀大小写
|
2025-07-25 10:47:50 +08:00
|
|
|
|
if (isUppercase) {
|
|
|
|
|
|
for (auto& ext : requiredExts) {
|
|
|
|
|
|
for (char& c : ext) {
|
|
|
|
|
|
if (std::isalpha(c)) c = std::toupper(c);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 5. 构建完整路径列表
|
2025-07-25 10:47:50 +08:00
|
|
|
|
std::vector<std::string> fullFilenames;
|
|
|
|
|
|
for (const auto& ext : requiredExts) {
|
|
|
|
|
|
fullFilenames.push_back(baseName + ext);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 6. 打印结果(实际使用中可能需要替换这里的打印逻辑)
|
2025-07-25 10:47:50 +08:00
|
|
|
|
std::cout << "Generated filenames: ";
|
|
|
|
|
|
for (const auto& name : fullFilenames) {
|
|
|
|
|
|
std::cout << name << " ";
|
|
|
|
|
|
}
|
|
|
|
|
|
std::cout << std::endl;
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//lnk20250805录波文件目录接口
|
2025-08-07 18:59:11 +08:00
|
|
|
|
assign_qvvr_file_list(id, line_id, fullFilenames);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// ========== 新增:为每个文件生成下载请求 ==========
|
2025-07-25 10:47:50 +08:00
|
|
|
|
for (const auto& filename : fullFilenames) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 生成下载请求报文 (帧序号固定为1,代表开始新文件的下载)
|
2025-07-25 10:47:50 +08:00
|
|
|
|
auto downloadMsg = generate_downloadfile_message(1, filename);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 将下载动作添加到设备队列
|
2025-07-25 10:47:50 +08:00
|
|
|
|
ClientManager::instance().add_action_to_device(
|
|
|
|
|
|
id,
|
|
|
|
|
|
DeviceState::READING_EVENTFILE,
|
|
|
|
|
|
downloadMsg
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
std::cout << "Added download request for: " << filename << std::endl;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//最后报文收发处理逻辑(如果当前装置空闲则尝试执行后续动作)(如果当前装置存在其他状态则直接退出,不要干扰装置后续执行)
|
|
|
|
|
|
DeviceState currentState = DeviceState::IDLE;//获取当前装置的状态
|
2025-07-25 10:47:50 +08:00
|
|
|
|
if (!ClientManager::instance().get_device_state(id, currentState)) {
|
|
|
|
|
|
std::cerr << "Failed to get device state for: " << id << std::endl;
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
switch (currentState) {
|
|
|
|
|
|
case DeviceState::IDLE:
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//当前装置空闲中,可以执行后续动作
|
2025-07-25 10:47:50 +08:00
|
|
|
|
ClientManager::instance().post_message_processing(id);
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//非空闲的其他状态直接退出即可,等待后续处理完毕后再尝试获取波形文件
|
2025-07-25 10:47:50 +08:00
|
|
|
|
break;
|
|
|
|
|
|
}
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//处理完毕主动上送报文后直接退出,不要干扰装置正常应答
|
2025-07-25 10:47:50 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//常规通讯报文
|
2025-07-03 11:13:16 +08:00
|
|
|
|
{
|
2025-09-23 14:03:11 +08:00
|
|
|
|
DeviceState currentState = DeviceState::IDLE;//获取当前装置的状态
|
2025-07-03 11:13:16 +08:00
|
|
|
|
if (!ClientManager::instance().get_device_state(id, currentState)) {
|
|
|
|
|
|
std::cerr << "Failed to get device state for: " << id << std::endl;
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-07-10 10:32:29 +08:00
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 根据装置状态处理报文
|
2025-07-03 11:13:16 +08:00
|
|
|
|
switch (currentState) {
|
|
|
|
|
|
case DeviceState::IDLE:
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 空闲状态下收到报文,可能是主动上报数据
|
2025-07-03 11:13:16 +08:00
|
|
|
|
std::cout << "IDLE state: Received active report from " << mac << std::endl;
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 这里可以添加处理主动上报数据的逻辑
|
2025-07-03 11:13:16 +08:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case DeviceState::READING_STATS:
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 读取统计数据状态
|
2025-07-03 11:13:16 +08:00
|
|
|
|
if (udata[8] == static_cast<unsigned char>(MsgResponseType::Response_Stat)) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 一发多收,需要在这里等待所有报文收全再组装相应数据 一帧1K 直到所有数据传送完毕
|
|
|
|
|
|
//当前帧未收全,直接退出消息处理,等待后续帧
|
2025-07-03 11:13:16 +08:00
|
|
|
|
std::cout << "mac: " << mac << " count" << static_cast<int>(udata[10]) << std::endl;
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 解析帧信息 (根据实际协议调整)
|
|
|
|
|
|
int current_packet = static_cast<int>(udata[10]); // 当前帧序号
|
|
|
|
|
|
int total_packets = Stat_PacketNum; // 总帧数
|
2025-07-03 11:13:16 +08:00
|
|
|
|
std::vector<unsigned char> packet_data(udata, udata + length);
|
|
|
|
|
|
bool complete = ClientManager::instance().add_stat_packet_to_device(
|
|
|
|
|
|
id, packet_data, current_packet, total_packets
|
|
|
|
|
|
);
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//判断是否收全
|
2025-07-03 11:13:16 +08:00
|
|
|
|
if (complete) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 1. 获取并清空缓存数据包
|
2025-07-03 11:13:16 +08:00
|
|
|
|
auto packets = ClientManager::instance().get_and_clear_stat_packets(id);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 2. 按帧序号排序
|
2025-07-03 11:13:16 +08:00
|
|
|
|
std::sort(packets.begin(), packets.end(),
|
|
|
|
|
|
[](const ClientContext::StatPacket& a, const ClientContext::StatPacket& b) {
|
|
|
|
|
|
return a.packet_index < b.packet_index;
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 3. 解析每帧数据并提取数据体
|
2025-07-03 11:13:16 +08:00
|
|
|
|
std::vector<unsigned char> full_data;
|
|
|
|
|
|
MessageParser parser;
|
|
|
|
|
|
|
|
|
|
|
|
for (const auto& packet : packets) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 解析单帧报文
|
2025-07-03 11:13:16 +08:00
|
|
|
|
if (!parser.SetMsg(packet.data.data(), packet.data.size())) {
|
|
|
|
|
|
std::cerr << "Failed to parse packet " << packet.packet_index
|
|
|
|
|
|
<< " for device " << id << std::endl;
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 将数据体添加到完整序列
|
2025-07-03 11:13:16 +08:00
|
|
|
|
full_data.insert(full_data.end(),
|
|
|
|
|
|
parser.RecvData.begin(),
|
|
|
|
|
|
parser.RecvData.end());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 4. 组装 tagPqData 对象
|
2025-07-03 11:13:16 +08:00
|
|
|
|
tagPqData pq_data;
|
|
|
|
|
|
if (!pq_data.SetStructBuf(full_data.data(), full_data.size())) {
|
|
|
|
|
|
std::cerr << "Failed to assemble tagPqData for device " << id << std::endl;
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 成功组装,可以在这里使用 pq_data 对象
|
2025-07-03 11:13:16 +08:00
|
|
|
|
std::cout << "Successfully assembled tagPqData for device: "
|
|
|
|
|
|
<< id << std::endl;
|
|
|
|
|
|
|
|
|
|
|
|
float fPT = 1.0f;
|
|
|
|
|
|
float fCT = 1.0f;
|
|
|
|
|
|
if (ClientManager::instance().get_pt_ct_ratio(id, pq_data.name, fPT, fCT)) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 使用获取的变比值进行数据转换
|
2025-07-03 11:13:16 +08:00
|
|
|
|
tagPqData_Float float_data;
|
|
|
|
|
|
float_data.SetFloatValue(pq_data, fPT, fCT);
|
|
|
|
|
|
float_data.name = pq_data.name;
|
|
|
|
|
|
float_data.Data_Type = pq_data.Data_Type;
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 将浮点数据添加到缓存
|
|
|
|
|
|
// 添加到缓存并检查是否收全
|
2025-07-03 11:13:16 +08:00
|
|
|
|
bool complete = ClientManager::instance().add_float_data_to_device(
|
|
|
|
|
|
id, pq_data.name, pq_data.Data_Type, float_data);
|
|
|
|
|
|
|
|
|
|
|
|
if (complete) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 如果收全,立即取出处理
|
2025-07-03 11:13:16 +08:00
|
|
|
|
std::array<tagPqData_Float, 4> all_data =
|
|
|
|
|
|
ClientManager::instance().get_and_clear_float_data(id, pq_data.name);
|
|
|
|
|
|
|
|
|
|
|
|
if (!all_data.empty()) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//单个测点 4组数据处理逻辑
|
2025-07-03 11:13:16 +08:00
|
|
|
|
tagPqData_Float max_data = all_data[0];
|
|
|
|
|
|
tagPqData_Float min_data = all_data[1];
|
|
|
|
|
|
tagPqData_Float avg_data = all_data[2];
|
|
|
|
|
|
tagPqData_Float cp95_data = all_data[3];
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
std::string strScale;//电压等级
|
|
|
|
|
|
int nPTType = 0;//接线方式
|
2025-07-25 10:47:50 +08:00
|
|
|
|
ClientManager::instance().get_point_scale_and_pttype(
|
2025-09-23 14:03:11 +08:00
|
|
|
|
id, // 或使用id
|
|
|
|
|
|
pq_data.name, // 从报文中解析出的测点序号
|
2025-07-25 10:47:50 +08:00
|
|
|
|
strScale,
|
|
|
|
|
|
nPTType);
|
2025-07-09 09:39:29 +08:00
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 转换为Base64字符串
|
2025-07-25 10:47:50 +08:00
|
|
|
|
std::string max_base64Str = max_data.ConvertToBase64(nPTType);
|
|
|
|
|
|
std::string min_base64Str = min_data.ConvertToBase64(nPTType);
|
|
|
|
|
|
std::string avg_base64Str = avg_data.ConvertToBase64(nPTType);
|
|
|
|
|
|
std::string cp95_base64Str = cp95_data.ConvertToBase64(nPTType);
|
|
|
|
|
|
//std::cout << "New star base64Str0:" << max_base64Str << std::endl;
|
|
|
|
|
|
//std::cout << "New del base64Str1:" << avg_data.ConvertToBase64(1) << std::endl;
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//lnk20250708使用接口发送
|
2025-07-11 14:12:47 +08:00
|
|
|
|
time_t data_time = ConvertToTimestamp(avg_data.time);
|
2025-07-09 09:39:29 +08:00
|
|
|
|
|
2025-09-24 15:58:50 +08:00
|
|
|
|
enqueue_stat_pq(max_base64Str,
|
|
|
|
|
|
min_base64Str,
|
|
|
|
|
|
avg_base64Str,
|
|
|
|
|
|
cp95_base64Str,
|
|
|
|
|
|
data_time,
|
|
|
|
|
|
mac,
|
|
|
|
|
|
avg_data.name);
|
2025-07-03 11:13:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 处理获取变比值失败的情况
|
2025-07-03 11:13:16 +08:00
|
|
|
|
std::cerr << "Failed to get PT/CT ratio for device: "
|
|
|
|
|
|
<< mac << " lineno: " << pq_data.name << std::endl;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//数据组装完毕,修改为空闲状态等待下一项工作
|
2025-07-03 11:13:16 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//未收全则直接结束处理,等待后续报文应答
|
2025-07-03 11:13:16 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 装置答非所问异常
|
|
|
|
|
|
// 接收统计数据错误,调整为空闲状态,处理下一项工作。
|
2025-07-03 11:13:16 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case DeviceState::READING_STATS_TIME:
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 读取统计时间状态
|
2025-07-03 11:13:16 +08:00
|
|
|
|
if (udata[8] == static_cast<unsigned char>(MsgResponseType::Response_StatTime)) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
std::vector<PointInfo> points;//装置测点信息
|
2025-07-03 11:13:16 +08:00
|
|
|
|
if (ClientManager::instance().get_device_points(mac, points)) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 成功获取测点信息
|
|
|
|
|
|
// 处理接收装置的时标
|
2025-07-03 11:13:16 +08:00
|
|
|
|
tagTime t3;
|
|
|
|
|
|
t3.SetStructBuf(parser.RecvData.data(), parser.RecvData.size());
|
2025-09-23 14:03:11 +08:00
|
|
|
|
int first = 0;//第一次标记
|
2025-07-03 11:13:16 +08:00
|
|
|
|
for (const auto& point : points) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
for (ushort i = 0; i < 4; i++)//每个测点需要单独召唤最大,最小,平均,95概率值
|
2025-07-03 11:13:16 +08:00
|
|
|
|
{
|
2025-09-23 14:03:11 +08:00
|
|
|
|
auto sendbuff = generate_statequerystat_message(t3, point.nCpuNo, i);//组装询问统计数据报文
|
2025-07-03 11:13:16 +08:00
|
|
|
|
if (first == 0) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//首次尝试组装报文 直接将当前状态调整 并等待最后启动发送
|
2025-07-03 11:13:16 +08:00
|
|
|
|
first++;
|
|
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::READING_STATS, sendbuff);
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//非首次进入,将动作传入队列等待
|
2025-07-03 11:13:16 +08:00
|
|
|
|
ClientManager::instance().add_action_to_device(id, DeviceState::READING_STATS, sendbuff);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 未找到装置下属测点异常
|
|
|
|
|
|
// 接收统计数据时间错误,调整为空闲状态,处理下一项工作。
|
2025-07-03 11:13:16 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 装置答非所问异常
|
|
|
|
|
|
// 接收统计数据时间错误,调整为空闲状态,处理下一项工作。
|
2025-07-03 11:13:16 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
2025-07-10 10:32:29 +08:00
|
|
|
|
case DeviceState::READING_REALSTAT:
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//读取实时数据状态
|
2025-07-10 10:32:29 +08:00
|
|
|
|
if (udata[8] == static_cast<unsigned char>(MsgResponseType::Response_New_3S)) {
|
|
|
|
|
|
unsigned char packet_type = udata[13];
|
2025-07-14 13:27:38 +08:00
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//取监测点号
|
2025-07-14 13:27:38 +08:00
|
|
|
|
unsigned char cid = udata[12];
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 将数据添加到缓存
|
2025-07-10 10:32:29 +08:00
|
|
|
|
const uint8_t* data_ptr = parser.RecvData.data() + 4;
|
|
|
|
|
|
size_t data_size = parser.RecvData.size() - 4;
|
|
|
|
|
|
ClientManager::instance().add_realtime_packet_to_device(
|
|
|
|
|
|
id, packet_type, data_ptr, data_size
|
|
|
|
|
|
);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 如果不是最后一个包,请求下一个包
|
2025-07-10 10:32:29 +08:00
|
|
|
|
if (packet_type != 0x06) {
|
|
|
|
|
|
unsigned char next_packet_type = packet_type + 1;
|
|
|
|
|
|
auto sendbuff = generate_realstat_message(
|
|
|
|
|
|
static_cast<unsigned char>(udata[12]),
|
|
|
|
|
|
next_packet_type,
|
|
|
|
|
|
static_cast<unsigned char>(0x01)
|
|
|
|
|
|
);
|
|
|
|
|
|
ClientManager::instance().change_device_state(
|
|
|
|
|
|
id, DeviceState::READING_REALSTAT, sendbuff
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 获取并清空缓存
|
2025-07-10 10:32:29 +08:00
|
|
|
|
auto packets = ClientManager::instance().get_and_clear_realtime_packets(id);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 按包类型排序(01-06)
|
2025-07-10 10:32:29 +08:00
|
|
|
|
std::sort(packets.begin(), packets.end(),
|
|
|
|
|
|
[](const ClientContext::RealtimePacket& a,
|
|
|
|
|
|
const ClientContext::RealtimePacket& b) {
|
|
|
|
|
|
return a.packet_type < b.packet_type;
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
RealtagPqDate_float realdata;
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 按顺序解析每个包
|
2025-07-10 10:32:29 +08:00
|
|
|
|
for (const auto& packet : packets) {
|
|
|
|
|
|
switch (packet.packet_type) {
|
|
|
|
|
|
case 0x01:
|
|
|
|
|
|
realdata.ParsePacket1(packet.data.data(), packet.data.size());
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 0x02:
|
|
|
|
|
|
realdata.ParsePacket2(packet.data.data(), packet.data.size());
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 0x03:
|
|
|
|
|
|
realdata.ParsePacket3(packet.data.data(), packet.data.size());
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 0x04:
|
|
|
|
|
|
realdata.ParsePacket4(packet.data.data(), packet.data.size());
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 0x05:
|
|
|
|
|
|
realdata.ParsePacket5(packet.data.data(), packet.data.size());
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 0x06:
|
|
|
|
|
|
realdata.ParsePacket6(packet.data.data(), packet.data.size());
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
std::string strScale;//电压等级
|
|
|
|
|
|
int nPTType = 0;//接线方式
|
2025-07-25 10:50:49 +08:00
|
|
|
|
ClientManager::instance().get_point_scale_and_pttype(
|
2025-09-23 14:03:11 +08:00
|
|
|
|
id, // 或使用id
|
|
|
|
|
|
static_cast<unsigned char>(udata[12]), // 从报文中解析出的测点序号
|
2025-07-25 10:50:49 +08:00
|
|
|
|
strScale,
|
|
|
|
|
|
nPTType);
|
|
|
|
|
|
|
2025-09-24 15:58:50 +08:00
|
|
|
|
// 转换为Base64字符串并发送lnk20250924
|
|
|
|
|
|
enqueue_realtime_pq(realdata, nPTType, cid, mac, id);
|
2025-07-25 10:47:50 +08:00
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 处理完成后重置状态
|
2025-07-10 10:32:29 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 装置答非所问异常
|
2025-09-10 16:59:50 +08:00
|
|
|
|
on_device_response_minimal(static_cast<int>(ResponseCode::INTERNAL_ERROR), id,0, static_cast<int>(DeviceState::READING_REALSTAT));
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 接收实时数据错误,调整为空闲状态,处理下一项工作。
|
2025-07-10 10:32:29 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
2025-07-25 10:47:50 +08:00
|
|
|
|
case DeviceState::READING_EVENTFILE:
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 暂态波形文件下载
|
2025-07-25 10:47:50 +08:00
|
|
|
|
if (udata[8] == static_cast<unsigned char>(MsgResponseType::Response_File_Download)) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 提取当前帧序号(12-15字节,大端序)
|
2025-07-25 10:47:50 +08:00
|
|
|
|
int current_frame = (static_cast<int>(udata[12]) << 24) |
|
|
|
|
|
|
(static_cast<int>(udata[13]) << 16) |
|
|
|
|
|
|
(static_cast<int>(udata[14]) << 8) |
|
|
|
|
|
|
static_cast<int>(udata[15]);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 提取总帧数(16-19字节,大端序)
|
2025-07-25 10:47:50 +08:00
|
|
|
|
int total_frames = (static_cast<int>(udata[16]) << 24) |
|
|
|
|
|
|
(static_cast<int>(udata[17]) << 16) |
|
|
|
|
|
|
(static_cast<int>(udata[18]) << 8) |
|
|
|
|
|
|
static_cast<int>(udata[19]);
|
|
|
|
|
|
|
|
|
|
|
|
//std::cout << "eventfile frames: " << current_frame << "/" << total_frames << std::endl;
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 将数据添加到缓存 去除数据体前14位 (逻辑稍后编写)
|
2025-07-25 10:47:50 +08:00
|
|
|
|
const uint8_t* data_ptr = parser.RecvData.data() + 14;
|
|
|
|
|
|
size_t data_size = parser.RecvData.size() - 14;
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 如果是第一帧,记录文件名
|
2025-07-25 10:47:50 +08:00
|
|
|
|
if (current_frame == 1) {
|
|
|
|
|
|
ClientManager::DownloadInfo info;
|
|
|
|
|
|
if (ClientManager::instance().parse_download_packet(id, info)) {
|
|
|
|
|
|
ClientManager::instance().update_current_filename(id, info.filename);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 获取文件名
|
2025-07-25 10:47:50 +08:00
|
|
|
|
std::string filename = ClientManager::instance().get_current_filename(id);
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 添加到缓存
|
2025-07-25 10:47:50 +08:00
|
|
|
|
ClientManager::instance().add_file_packet_to_device(id, current_frame, data_ptr, data_size);
|
|
|
|
|
|
|
|
|
|
|
|
//std::cout << "fileinfo: " << info.filename << "/" << info.current_frame << std::endl;
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//判断是否收全,未收全则继续发送报文,收全则取出所有缓存组装文件并保存至本地,推送消息
|
2025-07-25 10:47:50 +08:00
|
|
|
|
if (current_frame < total_frames) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 未收全,更新帧序号并保持状态,等待后续自动发送已修改的新报文
|
2025-07-25 10:47:50 +08:00
|
|
|
|
int nextframe = current_frame + 1;
|
|
|
|
|
|
auto downloadMsg = generate_downloadfile_message(nextframe, filename);
|
|
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::READING_EVENTFILE, downloadMsg);
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 已收全,在此处处理文件
|
2025-07-25 10:47:50 +08:00
|
|
|
|
std::cout << "mac: " << mac << " fileinfo: " << filename <<std::endl;
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 获取缓存中的所有分片
|
2025-07-25 10:47:50 +08:00
|
|
|
|
auto packets = ClientManager::instance().get_and_clear_file_packets(id);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 合并文件内容
|
2025-07-25 10:47:50 +08:00
|
|
|
|
std::vector<unsigned char> file_data;
|
|
|
|
|
|
for (const auto& packet : packets) {
|
|
|
|
|
|
file_data.insert(file_data.end(), packet.begin(), packet.end());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 保存文件
|
|
|
|
|
|
std::string wavefile = "wave"; // 使用MAC地址作为目录名
|
|
|
|
|
|
// 创建目录(如果不存在)
|
2025-07-30 13:52:52 +08:00
|
|
|
|
if (mkdir(wavefile.c_str(), 0777) != 0 && errno != EEXIST) {
|
|
|
|
|
|
std::cerr << "Failed to create directory: " << wavefile << std::endl;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 保存文件
|
|
|
|
|
|
std::string mac_dir = wavefile + "/" + mac; // 使用MAC地址作为目录名
|
|
|
|
|
|
// 创建目录(如果不存在)
|
2025-07-25 10:47:50 +08:00
|
|
|
|
if (mkdir(mac_dir.c_str(), 0777) != 0 && errno != EEXIST) {
|
|
|
|
|
|
std::cerr << "Failed to create directory: " << mac_dir << std::endl;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::string path = extract_filename(filename);
|
|
|
|
|
|
|
|
|
|
|
|
std::string file_path = mac_dir + "/" + path;
|
|
|
|
|
|
std::ofstream out_file(file_path, std::ios::binary);
|
|
|
|
|
|
if (out_file) {
|
|
|
|
|
|
out_file.write(reinterpret_cast<const char*>(file_data.data()),
|
|
|
|
|
|
file_data.size());
|
|
|
|
|
|
std::cout << "File saved: " << file_path << std::endl;
|
2025-08-07 18:59:11 +08:00
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//lnk20250805文件保存成功调用录波文件上送接口
|
2025-08-07 18:59:11 +08:00
|
|
|
|
update_qvvr_file_download(file_path, id);
|
2025-07-25 10:47:50 +08:00
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
std::cerr << "Failed to save file: " << file_path
|
|
|
|
|
|
<< ", Error: " << strerror(errno) << std::endl;
|
2025-09-05 16:28:26 +08:00
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 文件保存失败,通知云端
|
2025-09-11 15:25:57 +08:00
|
|
|
|
/*on_device_response_minimal(static_cast<int>(ResponseCode::BAD_REQUEST),
|
|
|
|
|
|
id, 0, static_cast<int>(DeviceState::READING_EVENTFILE));*/
|
2025-07-25 10:47:50 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//当前文件下载完毕,调整为空闲处理下一项工作(如果这里后续有新文件等待下载,一般已经存入等待队列等候处理了,调成空闲状态后直接就会开始新文件的下载工作)
|
2025-07-25 10:47:50 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 装置答非所问异常
|
2025-09-11 15:25:57 +08:00
|
|
|
|
//on_device_response_minimal(static_cast<int>(ResponseCode::INTERNAL_ERROR), id, 0, static_cast<int>(DeviceState::READING_EVENTFILE));
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 接收波形文件数据错误,调整为空闲状态,处理下一项工作。
|
2025-07-30 13:52:52 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case DeviceState::READING_FILEMENU:
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//读取文件目录
|
2025-07-30 13:52:52 +08:00
|
|
|
|
if (udata[8] == static_cast<unsigned char>(MsgResponseType::Response_FileDir)) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 计算结构体大小
|
2025-07-30 13:52:52 +08:00
|
|
|
|
const size_t struct_size = sizeof(tag_dir_info);
|
|
|
|
|
|
const uint8_t* data_ptr = parser.RecvData.data();
|
|
|
|
|
|
size_t data_size = parser.RecvData.size();
|
|
|
|
|
|
|
|
|
|
|
|
std::vector<tag_dir_info> FileList;
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 遍历接收到的数据
|
2025-07-30 13:52:52 +08:00
|
|
|
|
for (size_t i = 0; i < data_size; i += struct_size) {
|
|
|
|
|
|
if (i + struct_size > data_size) break;
|
|
|
|
|
|
|
|
|
|
|
|
tag_dir_info dir_info;
|
|
|
|
|
|
memcpy(&dir_info, data_ptr + i, struct_size);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 字节序转换 (大端 -> 小端)
|
2025-07-30 13:52:52 +08:00
|
|
|
|
dir_info.flag = ntohl(dir_info.flag);
|
|
|
|
|
|
dir_info.size = ntohl(dir_info.size);
|
|
|
|
|
|
|
|
|
|
|
|
std::string gbk_name(dir_info.name, strnlen(dir_info.name, sizeof(dir_info.name)));
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 打印文件名
|
2025-07-30 13:52:52 +08:00
|
|
|
|
std::cout << "file name:" << gbk_name << std::endl;
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 添加到文件列表
|
2025-07-30 13:52:52 +08:00
|
|
|
|
FileList.push_back(dir_info);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 这里可以添加发送文件列表的逻辑
|
2025-09-12 17:08:25 +08:00
|
|
|
|
//send_file_list(id,FileList);//lnk20250813
|
|
|
|
|
|
filemenu_cache_put(id,FileList);
|
2025-07-30 13:52:52 +08:00
|
|
|
|
|
2025-10-28 20:59:05 +08:00
|
|
|
|
on_device_response_minimal(static_cast<int>(ResponseCode::OK), id, 0, static_cast<int>(DeviceState::READING_FILEMENU));
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 处理完成后重置状态
|
2025-07-30 13:52:52 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
2025-09-08 14:37:39 +08:00
|
|
|
|
std::cout << "reason code: " << static_cast<int>(udata[8]) << "-" << static_cast<int>(udata[9]) << "-" << static_cast<int>(udata[10]) << "-" << static_cast<int>(udata[11]) << std::endl;
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 装置答非所问异常
|
2025-09-10 16:59:50 +08:00
|
|
|
|
on_device_response_minimal(static_cast<int>(ResponseCode::INTERNAL_ERROR), id, 0, static_cast<int>(DeviceState::READING_FILEMENU));
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 接收目录数据错误,调整为空闲状态,处理下一项工作。
|
2025-07-30 13:52:52 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case DeviceState::READING_FILEDATA:
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//下载文件数据 和暂态文件下载共用同一功能码
|
2025-07-30 13:52:52 +08:00
|
|
|
|
if (udata[8] == static_cast<unsigned char>(MsgResponseType::Response_File_Download))
|
|
|
|
|
|
{
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 提取当前帧序号(12-15字节,大端序)
|
2025-07-30 13:52:52 +08:00
|
|
|
|
int current_frame = (static_cast<int>(udata[12]) << 24) |
|
|
|
|
|
|
(static_cast<int>(udata[13]) << 16) |
|
|
|
|
|
|
(static_cast<int>(udata[14]) << 8) |
|
|
|
|
|
|
static_cast<int>(udata[15]);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 提取总帧数(16-19字节,大端序)
|
2025-07-30 13:52:52 +08:00
|
|
|
|
int total_frames = (static_cast<int>(udata[16]) << 24) |
|
|
|
|
|
|
(static_cast<int>(udata[17]) << 16) |
|
|
|
|
|
|
(static_cast<int>(udata[18]) << 8) |
|
|
|
|
|
|
static_cast<int>(udata[19]);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//提取数据
|
2025-07-30 13:52:52 +08:00
|
|
|
|
const uint8_t* data_ptr = parser.RecvData.data() + 14;
|
2025-10-30 20:57:19 +08:00
|
|
|
|
size_t data_size = parser.RecvData.size() - 14;
|
2025-07-30 13:52:52 +08:00
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 如果是第一帧,记录文件名
|
2025-07-30 13:52:52 +08:00
|
|
|
|
if (current_frame == 1) {
|
|
|
|
|
|
ClientManager::DownloadInfo info;
|
|
|
|
|
|
if (ClientManager::instance().parse_download_packet(id, info)) {
|
|
|
|
|
|
ClientManager::instance().update_current_filename(id, info.filename);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 获取文件名
|
2025-07-30 13:52:52 +08:00
|
|
|
|
std::string filename = ClientManager::instance().get_current_filename(id);
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 添加到缓存
|
2025-07-30 13:52:52 +08:00
|
|
|
|
ClientManager::instance().add_file_packet_to_device(id, current_frame, data_ptr, data_size);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//判断是否收全,未收全则继续发送报文,收全则取出所有缓存组装文件并保存至本地,推送消息
|
2025-07-30 13:52:52 +08:00
|
|
|
|
if (current_frame < total_frames) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 未收全,更新帧序号并保持状态,等待后续自动发送已修改的新报文
|
2025-07-30 13:52:52 +08:00
|
|
|
|
int nextframe = current_frame + 1;
|
|
|
|
|
|
auto downloadMsg = generate_downloadfile_message(nextframe, filename);
|
|
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::READING_FILEDATA, downloadMsg);
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 已收全,在此处处理文件
|
2025-07-30 13:52:52 +08:00
|
|
|
|
std::cout << "mac: " << mac << " fileinfo: " << filename << std::endl;
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 获取缓存中的所有分片
|
2025-07-30 13:52:52 +08:00
|
|
|
|
auto packets = ClientManager::instance().get_and_clear_file_packets(id);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 合并文件内容
|
2025-07-30 13:52:52 +08:00
|
|
|
|
std::vector<unsigned char> file_data;
|
|
|
|
|
|
for (const auto& packet : packets) {
|
|
|
|
|
|
file_data.insert(file_data.end(), packet.begin(), packet.end());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 保存文件
|
|
|
|
|
|
std::string wavefile = "download"; // 使用MAC地址作为目录名
|
|
|
|
|
|
// 创建目录(如果不存在)
|
2025-07-30 13:52:52 +08:00
|
|
|
|
if (mkdir(wavefile.c_str(), 0777) != 0 && errno != EEXIST) {
|
|
|
|
|
|
std::cerr << "Failed to create directory: " << wavefile << std::endl;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 保存文件
|
|
|
|
|
|
std::string mac_dir = wavefile + "/" + mac; // 使用MAC地址作为目录名
|
|
|
|
|
|
// 创建目录(如果不存在)
|
2025-07-30 13:52:52 +08:00
|
|
|
|
if (mkdir(mac_dir.c_str(), 0777) != 0 && errno != EEXIST) {
|
|
|
|
|
|
std::cerr << "Failed to create directory: " << mac_dir << std::endl;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::string path = extract_filename(filename);
|
|
|
|
|
|
|
|
|
|
|
|
std::string file_path = mac_dir + "/" + path;
|
|
|
|
|
|
std::ofstream out_file(file_path, std::ios::binary);
|
|
|
|
|
|
if (out_file) {
|
|
|
|
|
|
out_file.write(reinterpret_cast<const char*>(file_data.data()),
|
|
|
|
|
|
file_data.size());
|
|
|
|
|
|
std::cout << "File saved: " << file_path << std::endl;
|
2025-09-02 14:58:19 +08:00
|
|
|
|
|
2025-10-30 20:57:19 +08:00
|
|
|
|
//调试用
|
|
|
|
|
|
// 若是 .cfg,先查看并打印内容(限长)
|
|
|
|
|
|
{
|
|
|
|
|
|
auto dot = file_path.find_last_of('.');
|
|
|
|
|
|
std::string ext = (dot == std::string::npos) ? "" : file_path.substr(dot);
|
|
|
|
|
|
// 转小写比较
|
|
|
|
|
|
for (auto& c : ext) c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
|
|
|
|
|
|
if (ext == ".cfg") {
|
|
|
|
|
|
std::ifstream fin(file_path, std::ios::binary);
|
|
|
|
|
|
if (!fin) {
|
|
|
|
|
|
std::cerr << "[CFG] open failed: " << file_path << " (" << std::strerror(errno) << ")\n";
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 读取前 8KB 作为预览,避免日志过大
|
|
|
|
|
|
constexpr size_t kMaxPreview = 8 * 1024;
|
|
|
|
|
|
std::string buf;
|
|
|
|
|
|
buf.resize(kMaxPreview);
|
|
|
|
|
|
fin.read(&buf[0], static_cast<std::streamsize>(kMaxPreview));
|
|
|
|
|
|
std::streamsize got = fin.gcount();
|
|
|
|
|
|
buf.resize(static_cast<size_t>(got));
|
|
|
|
|
|
|
|
|
|
|
|
std::cout << "================ [CFG PREVIEW BEGIN] ================\n";
|
|
|
|
|
|
std::cout << "path=" << file_path << ", size=" << file_data.size()
|
|
|
|
|
|
<< " bytes, preview=" << got << " bytes\n";
|
|
|
|
|
|
// 直接打印文本预览;如果包含不可见字符,会按原样输出
|
|
|
|
|
|
std::cout.write(buf.data(), static_cast<std::streamsize>(buf.size()));
|
|
|
|
|
|
if (static_cast<size_t>(got) == kMaxPreview && fin.peek() != EOF) {
|
|
|
|
|
|
std::cout << "\n...[truncated]\n";
|
|
|
|
|
|
}
|
|
|
|
|
|
std::cout << "\n================ [CFG PREVIEW END] ==================\n";
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//使用接口上送文件lnk20250826
|
2025-09-02 14:58:19 +08:00
|
|
|
|
std::string filename;
|
2025-10-30 20:57:19 +08:00
|
|
|
|
//SendFileWebAuto(id, file_path, file_path, filename);//如果是补招文件的下载,下载后也是直接上传,这样单纯补招波形也可以保证传文件
|
|
|
|
|
|
std::cout << "File download success wait for upload: " << filename << std::endl;
|
2025-09-02 14:58:19 +08:00
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//通知文件上传
|
2025-09-12 17:08:25 +08:00
|
|
|
|
on_device_response_minimal(static_cast<int>(ResponseCode::OK), id, 0, static_cast<int>(DeviceState::READING_FILEDATA));
|
|
|
|
|
|
|
2025-07-30 13:52:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
else {
|
2025-09-11 15:25:57 +08:00
|
|
|
|
on_device_response_minimal(static_cast<int>(ResponseCode::INTERNAL_ERROR), id, 0, static_cast<int>(DeviceState::READING_FILEDATA));
|
2025-07-30 13:52:52 +08:00
|
|
|
|
std::cerr << "Failed to save file: " << file_path
|
|
|
|
|
|
<< ", Error: " << strerror(errno) << std::endl;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//当前文件下载完毕,调整为空闲处理下一项工作(如果这里后续有新文件等待下载,一般已经存入等待队列等候处理了,调成空闲状态后直接就会开始新文件的下载工作)
|
2025-10-30 20:57:19 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
2025-07-30 13:52:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 装置答非所问异常
|
2025-09-10 16:59:50 +08:00
|
|
|
|
on_device_response_minimal(static_cast<int>(ResponseCode::INTERNAL_ERROR), id, 0, static_cast<int>(DeviceState::READING_FILEDATA));
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 下载文件数据错误,调整为空闲状态,处理下一项工作。
|
2025-07-25 10:47:50 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
2025-08-05 15:41:04 +08:00
|
|
|
|
case DeviceState::READING_FIXEDVALUE:
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//读取指定测点定值数据
|
2025-08-05 15:41:04 +08:00
|
|
|
|
if (udata[8] == static_cast<unsigned char>(MsgResponseType::Response_FixValue)) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 确保数据长度足够包含测点序号
|
2025-08-05 15:41:04 +08:00
|
|
|
|
if (parser.RecvData.size() < 1) {
|
|
|
|
|
|
std::cout << "Invalid fix value data length" << std::endl;
|
2025-09-11 15:25:57 +08:00
|
|
|
|
on_device_response_minimal(static_cast<int>(ResponseCode::INTERNAL_ERROR), id, 0, static_cast<int>(DeviceState::READING_FIXEDVALUE));
|
2025-08-05 15:41:04 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 提取测点序号 (第一个字节)
|
2025-08-05 15:41:04 +08:00
|
|
|
|
uint8_t monitor_index = parser.RecvData[0];
|
|
|
|
|
|
std::cout << "Monitor Index: " << static_cast<int>(monitor_index) << std::endl;
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 计算有效数据长度 (排除测点序号)
|
2025-08-05 15:41:04 +08:00
|
|
|
|
size_t bufflen = parser.RecvData.size() - 1;
|
2025-09-23 14:03:11 +08:00
|
|
|
|
const size_t structlen = 4; // 每个浮点数占4字节
|
2025-08-05 15:41:04 +08:00
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 检查数据长度是否合法
|
2025-08-05 15:41:04 +08:00
|
|
|
|
if (bufflen % structlen != 0) {
|
|
|
|
|
|
std::cout << "Invalid fix value data length: " << bufflen
|
|
|
|
|
|
<< " (not multiple of 4)" << std::endl;
|
2025-09-11 15:25:57 +08:00
|
|
|
|
on_device_response_minimal(static_cast<int>(ResponseCode::INTERNAL_ERROR), id, 0, static_cast<int>(DeviceState::READING_FIXEDVALUE));
|
2025-08-05 15:41:04 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 存储浮点值的容器
|
2025-08-05 15:41:04 +08:00
|
|
|
|
std::vector<float> fList;
|
2025-09-23 14:03:11 +08:00
|
|
|
|
fList.reserve(bufflen / structlen); // 预分配空间
|
2025-08-05 15:41:04 +08:00
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 解析浮点数据 (从第二个字节开始)
|
2025-08-05 15:41:04 +08:00
|
|
|
|
for (size_t i = 1; i < parser.RecvData.size(); i += structlen) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 复制4字节数据
|
2025-08-05 15:41:04 +08:00
|
|
|
|
uint8_t bytes[4] = {
|
|
|
|
|
|
parser.RecvData[i],
|
|
|
|
|
|
parser.RecvData[i + 1],
|
|
|
|
|
|
parser.RecvData[i + 2],
|
|
|
|
|
|
parser.RecvData[i + 3]
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 翻转字节序 (大端转小端)
|
2025-08-05 15:41:04 +08:00
|
|
|
|
std::swap(bytes[0], bytes[3]);
|
|
|
|
|
|
std::swap(bytes[1], bytes[2]);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 转换为float
|
2025-08-05 15:41:04 +08:00
|
|
|
|
float value;
|
|
|
|
|
|
memcpy(&value, bytes, sizeof(float));
|
|
|
|
|
|
fList.push_back(value);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 打印解析结果
|
2025-08-05 15:41:04 +08:00
|
|
|
|
std::cout << "Parsed " << fList.size() << " fix values:" << std::endl;
|
|
|
|
|
|
for (size_t j = 0; j < fList.size(); ++j) {
|
|
|
|
|
|
std::cout << " Value[" << j << "]: " << fList[j] << std::endl;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//存储定值lnk20250827
|
2025-09-05 16:28:26 +08:00
|
|
|
|
save_set_value(id, monitor_index, fList);
|
2025-09-02 14:58:19 +08:00
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//测试定值修改功能
|
2025-08-05 15:41:04 +08:00
|
|
|
|
//ClientManager::instance().set_fixedvalue_action_to_device(id, monitor_index, fList);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//定值读取完毕,调整为空闲,处理后续工作。
|
2025-08-05 15:41:04 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 装置答非所问异常
|
2025-09-10 16:59:50 +08:00
|
|
|
|
on_device_response_minimal(static_cast<int>(ResponseCode::INTERNAL_ERROR), id, 0, static_cast<int>(DeviceState::READING_FIXEDVALUE));
|
2025-09-05 16:28:26 +08:00
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 读取定值错误,调整为空闲状态,处理下一项工作。
|
2025-08-05 15:41:04 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case DeviceState::READING_FIXEDVALUEDES:
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//读取指定测点定值描述
|
2025-08-05 15:41:04 +08:00
|
|
|
|
if (udata[8] == static_cast<unsigned char>(MsgResponseType::Response_FixDes)) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 计算结构体大小
|
2025-08-05 15:41:04 +08:00
|
|
|
|
const size_t structlen = sizeof(DZ_TAB_STRUCT);
|
|
|
|
|
|
const size_t bufflen = parser.RecvData.size();
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 检查数据长度是否有效
|
2025-08-05 15:41:04 +08:00
|
|
|
|
if (bufflen == 0 || bufflen % structlen != 0) {
|
|
|
|
|
|
std::cerr << "Invalid fixdes data length: " << bufflen
|
|
|
|
|
|
<< " (expected multiple of " << structlen << ")" << std::endl;
|
2025-09-11 15:25:57 +08:00
|
|
|
|
on_device_response_minimal(static_cast<int>(ResponseCode::INTERNAL_ERROR), id, 0, static_cast<int>(DeviceState::READING_FIXEDVALUEDES));
|
2025-08-05 15:41:04 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 存储所有解析出的定值描述
|
2025-08-05 15:41:04 +08:00
|
|
|
|
std::vector<DZ_TAB_STRUCT> dz_list;
|
|
|
|
|
|
dz_list.reserve(bufflen / structlen);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 遍历所有定值描述结构体
|
2025-08-05 15:41:04 +08:00
|
|
|
|
for (size_t i = 0, j = 1; i < bufflen; i += structlen, j++) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 复制数据到临时缓冲区
|
2025-08-05 15:41:04 +08:00
|
|
|
|
std::vector<uint8_t> buff(structlen);
|
|
|
|
|
|
memcpy(buff.data(), parser.RecvData.data() + i, structlen);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 执行字节序转换(与C#相同)
|
2025-08-05 15:41:04 +08:00
|
|
|
|
ReversalBuff(buff.data(), 0, 2); // LN_Num
|
|
|
|
|
|
ReversalBuff(buff.data(), 2, 2); // DZ_Num
|
|
|
|
|
|
ReversalBuff(buff.data(), 70, 2); // DZ_Type
|
|
|
|
|
|
ReversalBuff(buff.data(), 72, 4); // DZ_Min
|
|
|
|
|
|
ReversalBuff(buff.data(), 76, 4); // DZ_Max
|
|
|
|
|
|
ReversalBuff(buff.data(), 80, 4); // DZ_Default
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 解析为结构体
|
2025-08-05 15:41:04 +08:00
|
|
|
|
DZ_TAB_STRUCT dz_info;
|
|
|
|
|
|
memcpy(&dz_info, buff.data(), structlen);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 正确处理字符串 - 查找第一个'\0'作为结束符
|
2025-08-05 15:41:04 +08:00
|
|
|
|
auto find_string_end = [](const char* arr, size_t max_len) -> size_t {
|
|
|
|
|
|
for (size_t i = 0; i < max_len; i++) {
|
|
|
|
|
|
if (arr[i] == '\0') return i;
|
|
|
|
|
|
}
|
|
|
|
|
|
return max_len;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 提取原始GBK字符串
|
2025-08-05 15:41:04 +08:00
|
|
|
|
size_t name_len = find_string_end(dz_info.DZ_Name, sizeof(dz_info.DZ_Name));
|
|
|
|
|
|
size_t unit_len = find_string_end(dz_info.DZ_UNIT, sizeof(dz_info.DZ_UNIT));
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 转换为可打印字符串(可选)(GBK编码)
|
2025-08-05 15:41:04 +08:00
|
|
|
|
std::string dz_name(dz_info.DZ_Name, name_len);
|
|
|
|
|
|
std::string dz_unit(dz_info.DZ_UNIT, unit_len);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 保存到上下文
|
2025-08-05 15:41:04 +08:00
|
|
|
|
dz_list.push_back(dz_info);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 调试输出(可选)
|
2025-08-05 15:41:04 +08:00
|
|
|
|
std::cout << "Parsed DZ entry #" << j << ": "
|
|
|
|
|
|
<< "LN=" << dz_info.LN_Num
|
|
|
|
|
|
<< ", ID=" << dz_info.DZ_Num
|
|
|
|
|
|
<< ", Name=" << dz_name
|
|
|
|
|
|
<< ", Type=" << dz_info.DZ_Type
|
|
|
|
|
|
<< ", Min=" << dz_info.DZ_Min
|
|
|
|
|
|
<< ", Max=" << dz_info.DZ_Max
|
|
|
|
|
|
<< ", Default=" << dz_info.DZ_Default
|
|
|
|
|
|
<< ", Unit=" << dz_unit << std::endl;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-02 14:58:19 +08:00
|
|
|
|
//lnk20250828
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 提取测点序号 (第一个字节)
|
2025-09-02 14:58:19 +08:00
|
|
|
|
uint8_t monitor_index = parser.RecvData[0];
|
|
|
|
|
|
std::cout << "Monitor Index: " << static_cast<int>(monitor_index) << std::endl;
|
2025-09-05 16:28:26 +08:00
|
|
|
|
send_set_value_reply(id, monitor_index, dz_list);
|
2025-09-16 10:13:47 +08:00
|
|
|
|
on_device_response_minimal(static_cast<int>(ResponseCode::OK), id, 0, static_cast<int>(DeviceState::READING_FIXEDVALUE));
|
2025-08-05 15:41:04 +08:00
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//定值描述读取完毕,调整为空闲,处理后续工作。
|
2025-08-05 15:41:04 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 装置答非所问异常
|
2025-09-10 16:59:50 +08:00
|
|
|
|
on_device_response_minimal(static_cast<int>(ResponseCode::INTERNAL_ERROR),id,0,static_cast<int>(DeviceState::READING_FIXEDVALUEDES));
|
2025-09-05 16:28:26 +08:00
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 读取定值描述,调整为空闲状态,处理下一项工作。
|
2025-08-05 15:41:04 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case DeviceState::SET_FIXEDVALUE:
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//设置装置定值
|
2025-08-05 15:41:04 +08:00
|
|
|
|
if (udata[8] == static_cast<unsigned char>(MsgResponseType::Response_NewACK)) {
|
|
|
|
|
|
std::cout << "set success" << mac << std::endl;
|
2025-09-02 14:58:19 +08:00
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//响应lnk20250828
|
2025-09-10 16:59:50 +08:00
|
|
|
|
on_device_response_minimal(static_cast<int>(ResponseCode::OK),id,0,static_cast<int>(DeviceState::SET_FIXEDVALUE));
|
2025-09-02 14:58:19 +08:00
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//定值设置成功,调整为空闲,处理后续工作。
|
2025-08-05 15:41:04 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (udata[8] == static_cast<unsigned char>(MsgResponseType::Response_NewNACK)) {
|
|
|
|
|
|
std::cout << "set error" << mac << std::endl;
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 装置否定应答,定值设置失败
|
2025-09-04 20:59:17 +08:00
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//响应lnk20250828
|
2025-09-10 16:59:50 +08:00
|
|
|
|
on_device_response_minimal(static_cast<int>(ResponseCode::BAD_REQUEST),id,0,static_cast<int>(DeviceState::SET_FIXEDVALUE));
|
2025-09-04 20:59:17 +08:00
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 设置装置定值失败,调整为空闲状态,处理下一项工作。
|
2025-08-05 15:41:04 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 装置答非所问异常
|
|
|
|
|
|
// 设置装置定值失败,调整为空闲状态,处理下一项工作。
|
2025-09-04 20:59:17 +08:00
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//响应lnk20250828
|
2025-09-10 16:59:50 +08:00
|
|
|
|
on_device_response_minimal(static_cast<int>(ResponseCode::INTERNAL_ERROR),id,0,static_cast<int>(DeviceState::SET_FIXEDVALUE));
|
2025-09-04 20:59:17 +08:00
|
|
|
|
|
2025-08-05 15:41:04 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case DeviceState::READING_INTERFIXEDVALUE:
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//读取内部定值
|
2025-08-05 15:41:04 +08:00
|
|
|
|
if (udata[8] == static_cast<unsigned char>(MsgResponseType::Response_Read_InterFix)) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 获取数据长度
|
2025-08-05 15:41:04 +08:00
|
|
|
|
size_t bufflen = parser.RecvData.size();
|
2025-09-23 14:03:11 +08:00
|
|
|
|
const size_t structlen = 2; // 每个ushort占2字节
|
2025-08-05 15:41:04 +08:00
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 存储解析结果的容器
|
2025-08-05 15:41:04 +08:00
|
|
|
|
std::vector<ushort> fList;
|
2025-09-23 14:03:11 +08:00
|
|
|
|
fList.reserve(bufflen / structlen); // 预分配空间
|
2025-08-05 15:41:04 +08:00
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 解析每个ushort数据
|
2025-08-05 15:41:04 +08:00
|
|
|
|
for (size_t i = 0; i < bufflen; i += structlen) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 复制2字节数据
|
2025-08-05 15:41:04 +08:00
|
|
|
|
uint8_t bytes[2] = {
|
|
|
|
|
|
parser.RecvData[i],
|
|
|
|
|
|
parser.RecvData[i + 1]
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 翻转字节序 (大端转小端)
|
2025-08-05 15:41:04 +08:00
|
|
|
|
std::swap(bytes[0], bytes[1]);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 转换为ushort - 使用memcpy确保正确处理字节序
|
2025-08-05 15:41:04 +08:00
|
|
|
|
ushort value;
|
|
|
|
|
|
memcpy(&value, bytes, sizeof(ushort));
|
|
|
|
|
|
fList.push_back(value);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 打印解析结果(调试用)
|
2025-08-05 15:41:04 +08:00
|
|
|
|
std::cout << "Parsed " << fList.size() << " internal fixed values:" << std::endl;
|
|
|
|
|
|
for (size_t j = 0; j < fList.size(); ++j) {
|
|
|
|
|
|
std::cout << " Value[" << j << "]: " << fList[j] << std::endl;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//存储定值lnk20250827
|
2025-09-05 16:28:26 +08:00
|
|
|
|
save_internal_value(id, fList);
|
2025-09-02 14:58:19 +08:00
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//内部定值修改测试
|
2025-08-05 15:41:04 +08:00
|
|
|
|
//ClientManager::instance().set_interfixedvalue_action_to_device(id, fList);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//内部定值获取完毕,调整为空闲,处理后续工作。
|
2025-08-05 15:41:04 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 装置答非所问异常
|
2025-09-05 16:28:26 +08:00
|
|
|
|
|
2025-09-10 16:59:50 +08:00
|
|
|
|
on_device_response_minimal(static_cast<int>(ResponseCode::INTERNAL_ERROR), id, 0, static_cast<int>(DeviceState::READING_INTERFIXEDVALUE));
|
2025-09-05 16:28:26 +08:00
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 读取装置内部定值失败,调整为空闲状态,处理下一项工作。
|
2025-08-05 15:41:04 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case DeviceState::READING_INTERFIXEDVALUEDES:
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//读取内部定值描述
|
2025-08-05 15:41:04 +08:00
|
|
|
|
if (udata[8] == static_cast<unsigned char>(MsgResponseType::Response_Read_InterFixDes)) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 获取接收数据
|
2025-08-05 15:41:04 +08:00
|
|
|
|
std::vector<uint8_t>& recvData = parser.RecvData;
|
|
|
|
|
|
size_t bufflen = recvData.size();
|
|
|
|
|
|
const size_t structlen = sizeof(NameFixValue);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 存储解析结果的向量
|
2025-08-05 15:41:04 +08:00
|
|
|
|
std::vector<NameFixValue> fixValueList;
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 检查数据长度是否合法
|
2025-08-05 15:41:04 +08:00
|
|
|
|
if (bufflen == 0 || bufflen % structlen != 0) {
|
|
|
|
|
|
std::cerr << "Invalid internal fixdes data length: " << bufflen
|
|
|
|
|
|
<< " (expected multiple of " << structlen << ")" << std::endl;
|
|
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
2025-09-11 15:25:57 +08:00
|
|
|
|
on_device_response_minimal(static_cast<int>(ResponseCode::INTERNAL_ERROR), id, 0, static_cast<int>(DeviceState::READING_INTERFIXEDVALUEDES));
|
2025-08-05 15:41:04 +08:00
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 计算结构体数量
|
2025-08-05 15:41:04 +08:00
|
|
|
|
size_t structCount = bufflen / structlen;
|
|
|
|
|
|
fixValueList.reserve(structCount);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 遍历所有结构体
|
2025-08-05 15:41:04 +08:00
|
|
|
|
for (size_t i = 0, k = 1; i < bufflen; i += structlen, k++)
|
|
|
|
|
|
{
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 复制当前结构体数据到缓冲区
|
2025-08-05 15:41:04 +08:00
|
|
|
|
std::vector<uint8_t> buff(structlen);
|
|
|
|
|
|
memcpy(buff.data(), recvData.data() + i, structlen);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 翻转数据类型DataType (偏移22, 2字节)
|
2025-08-05 15:41:04 +08:00
|
|
|
|
ReversalBuff(buff.data(), 22, 2);
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 翻转最小值MinValue (偏移24, 2字节)
|
2025-08-05 15:41:04 +08:00
|
|
|
|
ReversalBuff(buff.data(), 24, 2);
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 翻转最大值MaxValue (偏移26, 2字节)
|
2025-08-05 15:41:04 +08:00
|
|
|
|
ReversalBuff(buff.data(), 26, 2);
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 翻转缺省值DefaultValue (偏移28, 2字节)
|
2025-08-05 15:41:04 +08:00
|
|
|
|
ReversalBuff(buff.data(), 28, 2);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 解析为结构体
|
2025-08-05 15:41:04 +08:00
|
|
|
|
NameFixValue dz_info;
|
|
|
|
|
|
memcpy(&dz_info, buff.data(), structlen);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 添加到结果列表
|
2025-08-05 15:41:04 +08:00
|
|
|
|
fixValueList.push_back(dz_info);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 调试输出
|
2025-08-05 15:41:04 +08:00
|
|
|
|
std::string fixName(dz_info.sFixValueName,
|
|
|
|
|
|
strnlen(dz_info.sFixValueName, sizeof(dz_info.sFixValueName)));
|
|
|
|
|
|
std::string dimension(dz_info.sDimension,
|
|
|
|
|
|
strnlen(dz_info.sDimension, sizeof(dz_info.sDimension)));
|
|
|
|
|
|
|
|
|
|
|
|
std::cout << "Parsed internal fix value #" << k << ": "
|
|
|
|
|
|
<< "Name=" << fixName << ", "
|
|
|
|
|
|
<< "Type=" << dz_info.DataType << ", "
|
|
|
|
|
|
<< "Min=" << dz_info.MinValue << ", "
|
|
|
|
|
|
<< "Max=" << dz_info.MaxValue << ", "
|
|
|
|
|
|
<< "Default=" << dz_info.DefaultValue << ", "
|
|
|
|
|
|
<< "Unit=" << dimension << std::endl;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-05 16:28:26 +08:00
|
|
|
|
//lnk20250905
|
|
|
|
|
|
save_internal_info(id, fixValueList);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//内部定值描述获取完毕,调整为空闲状态,处理下一项工作。
|
2025-08-05 15:41:04 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 装置答非所问异常
|
2025-09-05 16:28:26 +08:00
|
|
|
|
|
2025-09-10 16:59:50 +08:00
|
|
|
|
on_device_response_minimal(static_cast<int>(ResponseCode::INTERNAL_ERROR), id, 0, static_cast<int>(DeviceState::READING_INTERFIXEDVALUEDES));
|
2025-09-05 16:28:26 +08:00
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 读取装置内部定值描述失败,调整为空闲状态,处理下一项工作。
|
2025-08-05 15:41:04 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case DeviceState::READING_CONTROLWORD:
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//读取控制字描述
|
2025-08-05 15:41:04 +08:00
|
|
|
|
if (udata[8] == static_cast<unsigned char>(MsgResponseType::Response_Read_InterFixDes)) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 计算结构体大小
|
2025-08-05 15:41:04 +08:00
|
|
|
|
const size_t structlen = sizeof(DZ_kzz_bit);
|
|
|
|
|
|
const size_t bufflen = parser.RecvData.size();
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 检查数据长度是否有效
|
2025-08-05 15:41:04 +08:00
|
|
|
|
if (bufflen == 0 || bufflen % structlen != 0) {
|
|
|
|
|
|
std::cerr << "Invalid control word data length: " << bufflen
|
|
|
|
|
|
<< " (expected multiple of " << structlen << ")" << std::endl;
|
2025-09-11 15:25:57 +08:00
|
|
|
|
on_device_response_minimal(static_cast<int>(ResponseCode::INTERNAL_ERROR), id, 0, static_cast<int>(DeviceState::READING_CONTROLWORD));
|
2025-08-05 15:41:04 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 存储解析结果
|
2025-08-05 15:41:04 +08:00
|
|
|
|
std::vector<DZ_kzz_bit> control_words;
|
|
|
|
|
|
control_words.reserve(bufflen / structlen);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 遍历所有控制字描述结构体
|
2025-08-05 15:41:04 +08:00
|
|
|
|
for (size_t i = 0; i < bufflen; i += structlen) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 复制数据到临时缓冲区
|
2025-08-05 15:41:04 +08:00
|
|
|
|
std::vector<uint8_t> buff(structlen);
|
|
|
|
|
|
memcpy(buff.data(), parser.RecvData.data() + i, structlen);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 解析为结构体
|
2025-08-05 15:41:04 +08:00
|
|
|
|
DZ_kzz_bit dz_info;
|
|
|
|
|
|
memcpy(&dz_info, buff.data(), structlen);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 正确处理字符串 - 查找第一个'\0'作为结束符
|
2025-08-05 15:41:04 +08:00
|
|
|
|
auto find_string_end = [](const char* arr, size_t max_len) -> size_t {
|
|
|
|
|
|
for (size_t i = 0; i < max_len; i++) {
|
|
|
|
|
|
if (arr[i] == '\0') return i;
|
|
|
|
|
|
}
|
|
|
|
|
|
return max_len;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 提取原始GBK字符串
|
2025-08-05 15:41:04 +08:00
|
|
|
|
size_t name_len = find_string_end(dz_info.kzz_bit, sizeof(dz_info.kzz_bit));
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 直接存储原始GBK数据(不转换UTF-8)
|
2025-08-05 15:41:04 +08:00
|
|
|
|
control_words.push_back(dz_info);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 调试输出(可选)
|
2025-08-05 15:41:04 +08:00
|
|
|
|
std::string gbk_name(dz_info.kzz_bit,name_len);
|
|
|
|
|
|
std::cout << "Control word: " << gbk_name
|
|
|
|
|
|
<< ", enable: " << static_cast<int>(dz_info.bit_enable) << std::endl;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-05 16:28:26 +08:00
|
|
|
|
send_internal_value_reply(id, control_words);
|
2025-09-16 10:13:47 +08:00
|
|
|
|
on_device_response_minimal(static_cast<int>(ResponseCode::OK), id, 0, static_cast<int>(DeviceState::READING_INTERFIXEDVALUE));
|
2025-09-05 16:28:26 +08:00
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 控制字描述读取完毕,调整为空闲,处理后续工作
|
2025-08-05 15:41:04 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 装置答非所问异常
|
2025-09-10 16:59:50 +08:00
|
|
|
|
on_device_response_minimal(static_cast<int>(ResponseCode::INTERNAL_ERROR), id, 0, static_cast<int>(DeviceState::READING_CONTROLWORD));
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 读取装置控制字描述失败,调整为空闲状态,处理下一项工作。
|
2025-08-05 15:41:04 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case DeviceState::SET_INTERFIXEDVALUE:
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//设置内部定值
|
2025-08-05 15:41:04 +08:00
|
|
|
|
if (udata[8] == static_cast<unsigned char>(MsgResponseType::Response_NewACK)) {
|
|
|
|
|
|
std::cout << "set success" << mac << std::endl;
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//内部定值设置成功,调整为空闲,处理后续工作。
|
2025-09-10 16:59:50 +08:00
|
|
|
|
on_device_response_minimal(static_cast<int>(ResponseCode::OK), id, 0, static_cast<int>(DeviceState::SET_INTERFIXEDVALUE));
|
2025-09-05 16:28:26 +08:00
|
|
|
|
|
2025-08-05 15:41:04 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (udata[8] == static_cast<unsigned char>(MsgResponseType::Response_NewNACK)) {
|
|
|
|
|
|
std::cout << "set error" << mac << std::endl;
|
|
|
|
|
|
|
|
|
|
|
|
std::cout << "reason code: " << static_cast<int>(udata[8]) << "-" << static_cast<int>(udata[9]) << "-" << static_cast<int>(udata[10]) << "-" << static_cast<int>(udata[11]) << std::endl;
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 装置否定应答,内部定值设置失败
|
2025-09-10 16:59:50 +08:00
|
|
|
|
on_device_response_minimal(static_cast<int>(ResponseCode::BAD_REQUEST), id, 0, static_cast<int>(DeviceState::SET_INTERFIXEDVALUE));
|
2025-09-05 16:28:26 +08:00
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 设置装置内部定值失败,调整为空闲状态,处理下一项工作。
|
2025-08-05 15:41:04 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 装置答非所问异常
|
2025-09-10 16:59:50 +08:00
|
|
|
|
on_device_response_minimal(static_cast<int>(ResponseCode::INTERNAL_ERROR), id, 0, static_cast<int>(DeviceState::SET_INTERFIXEDVALUE));
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 设置装置内部定值失败,调整为空闲状态,处理下一项工作。
|
2025-08-05 15:41:04 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
2025-09-03 08:49:38 +08:00
|
|
|
|
case DeviceState::READING_RUNNINGINFORMATION_1:
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//读取装置运行信息(主动触发)
|
2025-09-03 08:49:38 +08:00
|
|
|
|
if (udata[8] == static_cast<unsigned char>(MsgResponseType::Response_Read_RunningInformation)) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 获取解析后的数据体
|
2025-09-03 08:49:38 +08:00
|
|
|
|
std::vector<uint8_t>& recvData = parser.RecvData;
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 检查数据长度是否足够
|
2025-09-03 08:49:38 +08:00
|
|
|
|
if (recvData.size() < 2) {
|
|
|
|
|
|
std::cerr << "Invalid running information data: too short ("
|
|
|
|
|
|
<< recvData.size() << " bytes)" << std::endl;
|
|
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 提取有效载荷长度
|
2025-09-03 08:49:38 +08:00
|
|
|
|
size_t payloadLength = recvData.size() - 2;
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 复制有效载荷数据
|
2025-09-03 08:49:38 +08:00
|
|
|
|
std::vector<uint8_t> payloadBytes(payloadLength);
|
|
|
|
|
|
if (recvData.size() >= 2 + payloadLength) {
|
|
|
|
|
|
std::copy(recvData.begin() + 2, recvData.begin() + 2 + payloadLength, payloadBytes.begin());
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
std::cerr << "Invalid payload length: " << payloadLength
|
|
|
|
|
|
<< ", available: " << (recvData.size() - 2) << std::endl;
|
|
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 转换为UTF-8字符串
|
2025-09-03 08:49:38 +08:00
|
|
|
|
std::string payload(payloadBytes.begin(), payloadBytes.end());
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 定义类似New_MachMessage的结构体
|
2025-09-03 08:49:38 +08:00
|
|
|
|
struct RunningInformation {
|
|
|
|
|
|
std::string Time;
|
|
|
|
|
|
std::string CpuLoad;
|
|
|
|
|
|
std::string FreeMemory;
|
|
|
|
|
|
std::string TotalMemory;
|
|
|
|
|
|
std::string FreeStorage;
|
|
|
|
|
|
std::string TotalStorage;
|
|
|
|
|
|
std::string HardTimeSync;
|
|
|
|
|
|
std::string SntpTimeSync;
|
|
|
|
|
|
std::string CloudTimeSync;
|
|
|
|
|
|
std::string SignalStrength;
|
|
|
|
|
|
} result;
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 辅助函数:去除字符串两端的引号
|
2025-09-03 08:49:38 +08:00
|
|
|
|
auto trimQuotes = [](const std::string& str) -> std::string {
|
|
|
|
|
|
if (str.size() >= 2 && str.front() == '"' && str.back() == '"') {
|
|
|
|
|
|
return str.substr(1, str.size() - 2);
|
|
|
|
|
|
}
|
|
|
|
|
|
return str;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 辅助函数:处理CPU负载值
|
2025-09-03 08:49:38 +08:00
|
|
|
|
auto processCpuLoad = [](const std::string& cpuValue) -> std::string {
|
|
|
|
|
|
if (cpuValue.empty()) return cpuValue;
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 处理多核格式(如"39_38")
|
2025-09-03 08:49:38 +08:00
|
|
|
|
if (cpuValue.find('_') != std::string::npos) {
|
|
|
|
|
|
std::vector<std::string> cores;
|
|
|
|
|
|
size_t start = 0, end;
|
|
|
|
|
|
while ((end = cpuValue.find('_', start)) != std::string::npos) {
|
|
|
|
|
|
cores.push_back(cpuValue.substr(start, end - start));
|
|
|
|
|
|
start = end + 1;
|
|
|
|
|
|
}
|
2025-09-23 14:03:11 +08:00
|
|
|
|
cores.push_back(cpuValue.substr(start)); // 添加最后一部分
|
2025-09-03 08:49:38 +08:00
|
|
|
|
|
|
|
|
|
|
for (auto& core : cores) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 手动转换整数(替代std::stoi)
|
2025-09-03 08:49:38 +08:00
|
|
|
|
const char* str = core.c_str();
|
|
|
|
|
|
char* endptr = nullptr;
|
|
|
|
|
|
long value = strtol(str, &endptr, 10);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 检查转换是否有效
|
2025-09-03 08:49:38 +08:00
|
|
|
|
if (endptr != str && *endptr == '\0') {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 校正超范围值
|
2025-09-03 08:49:38 +08:00
|
|
|
|
if (value > 100) value /= 100;
|
|
|
|
|
|
core = std::to_string(value);
|
|
|
|
|
|
}
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 转换失败保持原值
|
2025-09-03 08:49:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::string result;
|
|
|
|
|
|
for (size_t i = 0; i < cores.size(); ++i) {
|
|
|
|
|
|
if (i > 0) result += '_';
|
|
|
|
|
|
result += cores[i];
|
|
|
|
|
|
}
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 处理单核格式
|
2025-09-03 08:49:38 +08:00
|
|
|
|
else {
|
|
|
|
|
|
const char* str = cpuValue.c_str();
|
|
|
|
|
|
char* endptr = nullptr;
|
|
|
|
|
|
long value = strtol(str, &endptr, 10);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 检查转换是否有效
|
2025-09-03 08:49:38 +08:00
|
|
|
|
if (endptr != str && *endptr == '\0') {
|
|
|
|
|
|
if (value > 100) value /= 100;
|
|
|
|
|
|
return std::to_string(value);
|
|
|
|
|
|
}
|
|
|
|
|
|
return cpuValue;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 分割字段并处理
|
2025-09-03 08:49:38 +08:00
|
|
|
|
std::vector<std::string> fields;
|
|
|
|
|
|
size_t start = 0;
|
|
|
|
|
|
while (start < payload.length()) {
|
|
|
|
|
|
size_t end = payload.find(',', start);
|
|
|
|
|
|
if (end == std::string::npos) {
|
|
|
|
|
|
fields.push_back(payload.substr(start));
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
fields.push_back(payload.substr(start, end - start));
|
|
|
|
|
|
start = end + 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for (const auto& field : fields) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 跳过空字段
|
2025-09-03 08:49:38 +08:00
|
|
|
|
if (field.empty()) continue;
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 查找冒号位置
|
2025-09-03 08:49:38 +08:00
|
|
|
|
size_t colonPos = field.find(':');
|
|
|
|
|
|
if (colonPos == std::string::npos || colonPos == 0 || colonPos == field.length() - 1) {
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 分割键值对
|
2025-09-03 08:49:38 +08:00
|
|
|
|
std::string key = field.substr(0, colonPos);
|
|
|
|
|
|
std::string value = field.substr(colonPos + 1);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 去除键的空白
|
2025-09-03 08:49:38 +08:00
|
|
|
|
size_t keyStart = key.find_first_not_of(" \t");
|
|
|
|
|
|
size_t keyEnd = key.find_last_not_of(" \t");
|
|
|
|
|
|
if (keyStart != std::string::npos && keyEnd != std::string::npos) {
|
|
|
|
|
|
key = key.substr(keyStart, keyEnd - keyStart + 1);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 去除值的空白
|
2025-09-03 08:49:38 +08:00
|
|
|
|
size_t valStart = value.find_first_not_of(" \t");
|
|
|
|
|
|
size_t valEnd = value.find_last_not_of(" \t");
|
|
|
|
|
|
if (valStart != std::string::npos && valEnd != std::string::npos) {
|
|
|
|
|
|
value = value.substr(valStart, valEnd - valStart + 1);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 去除值两端的引号
|
2025-09-03 08:49:38 +08:00
|
|
|
|
if (value.size() >= 2 && value.front() == '"' && value.back() == '"') {
|
|
|
|
|
|
value = value.substr(1, value.size() - 2);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 尝试将键转换为整数
|
2025-09-03 08:49:38 +08:00
|
|
|
|
const char* keyStr = key.c_str();
|
|
|
|
|
|
char* endPtr = nullptr;
|
|
|
|
|
|
long fieldId = strtol(keyStr, &endPtr, 10);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 检查转换是否有效
|
2025-09-03 08:49:38 +08:00
|
|
|
|
if (endPtr != keyStr && *endPtr == '\0' && fieldId >= 1 && fieldId <= 10) {
|
|
|
|
|
|
switch (fieldId) {
|
|
|
|
|
|
case 1: result.Time = value; break;
|
|
|
|
|
|
case 2: result.CpuLoad = value; break;
|
|
|
|
|
|
case 3: result.FreeMemory = value; break;
|
|
|
|
|
|
case 4: result.TotalMemory = value; break;
|
|
|
|
|
|
case 5: result.FreeStorage = value; break;
|
|
|
|
|
|
case 6: result.TotalStorage = value; break;
|
|
|
|
|
|
case 7: result.HardTimeSync = value; break;
|
|
|
|
|
|
case 8: result.SntpTimeSync = value; break;
|
|
|
|
|
|
case 9: result.CloudTimeSync = value; break;
|
|
|
|
|
|
case 10: result.SignalStrength = value; break;
|
|
|
|
|
|
default: break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 特殊处理CPU负载
|
2025-09-03 08:49:38 +08:00
|
|
|
|
result.CpuLoad = processCpuLoad(result.CpuLoad);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 打印解析结果(实际应用中可替换为其他处理逻辑)
|
2025-09-03 08:49:38 +08:00
|
|
|
|
std::cout << "Device Running Information (" << mac << "):\n"
|
|
|
|
|
|
<< " Time: " << result.Time << "\n"
|
|
|
|
|
|
<< " CPU Load: " << result.CpuLoad << "\n"
|
|
|
|
|
|
<< " Memory: " << result.FreeMemory << "/" << result.TotalMemory << " MB\n"
|
|
|
|
|
|
<< " Storage: " << result.FreeStorage << "/" << result.TotalStorage << " GB\n"
|
|
|
|
|
|
<< " Time Sync: Hard=" << result.HardTimeSync
|
|
|
|
|
|
<< ", SNTP=" << result.SntpTimeSync
|
|
|
|
|
|
<< ", Cloud=" << result.CloudTimeSync << "\n"
|
|
|
|
|
|
<< " Signal: " << result.SignalStrength << std::endl;
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//读取装置运行信息(主动触发)成功,调整为空闲,处理后续工作。
|
2025-09-03 08:49:38 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 装置答非所问异常
|
|
|
|
|
|
// 读取装置运行信息(主动触发)失败,调整为空闲状态,处理下一项工作。
|
2025-09-03 08:49:38 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case DeviceState::READING_RUNNINGINFORMATION_2:
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//读取装置运行信息(定时触发) 接收与解析和主动触发一致,仅修改数据发送部分
|
2025-09-03 08:49:38 +08:00
|
|
|
|
if (udata[8] == static_cast<unsigned char>(MsgResponseType::Response_Read_RunningInformation)) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 获取解析后的数据体
|
2025-09-03 08:49:38 +08:00
|
|
|
|
std::vector<uint8_t>& recvData = parser.RecvData;
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 检查数据长度是否足够
|
2025-09-03 08:49:38 +08:00
|
|
|
|
if (recvData.size() < 2) {
|
|
|
|
|
|
std::cerr << "Invalid running information data: too short ("
|
|
|
|
|
|
<< recvData.size() << " bytes)" << std::endl;
|
|
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 提取有效载荷长度
|
2025-09-03 08:49:38 +08:00
|
|
|
|
size_t payloadLength = recvData.size() - 2;
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 复制有效载荷数据
|
2025-09-03 08:49:38 +08:00
|
|
|
|
std::vector<uint8_t> payloadBytes(payloadLength);
|
|
|
|
|
|
if (recvData.size() >= 2 + payloadLength) {
|
|
|
|
|
|
std::copy(recvData.begin() + 2, recvData.begin() + 2 + payloadLength, payloadBytes.begin());
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
std::cerr << "Invalid payload length: " << payloadLength
|
|
|
|
|
|
<< ", available: " << (recvData.size() - 2) << std::endl;
|
|
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 转换为UTF-8字符串
|
2025-09-03 08:49:38 +08:00
|
|
|
|
std::string payload(payloadBytes.begin(), payloadBytes.end());
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 定义类似New_MachMessage的结构体
|
2025-09-03 08:49:38 +08:00
|
|
|
|
struct RunningInformation {
|
|
|
|
|
|
std::string Time;
|
|
|
|
|
|
std::string CpuLoad;
|
|
|
|
|
|
std::string FreeMemory;
|
|
|
|
|
|
std::string TotalMemory;
|
|
|
|
|
|
std::string FreeStorage;
|
|
|
|
|
|
std::string TotalStorage;
|
|
|
|
|
|
std::string HardTimeSync;
|
|
|
|
|
|
std::string SntpTimeSync;
|
|
|
|
|
|
std::string CloudTimeSync;
|
|
|
|
|
|
std::string SignalStrength;
|
|
|
|
|
|
} result;
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 辅助函数:去除字符串两端的引号
|
2025-09-03 08:49:38 +08:00
|
|
|
|
auto trimQuotes = [](const std::string& str) -> std::string {
|
|
|
|
|
|
if (str.size() >= 2 && str.front() == '"' && str.back() == '"') {
|
|
|
|
|
|
return str.substr(1, str.size() - 2);
|
|
|
|
|
|
}
|
|
|
|
|
|
return str;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 辅助函数:处理CPU负载值
|
2025-09-03 08:49:38 +08:00
|
|
|
|
auto processCpuLoad = [](const std::string& cpuValue) -> std::string {
|
|
|
|
|
|
if (cpuValue.empty()) return cpuValue;
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 处理多核格式(如"39_38")
|
2025-09-03 08:49:38 +08:00
|
|
|
|
if (cpuValue.find('_') != std::string::npos) {
|
|
|
|
|
|
std::vector<std::string> cores;
|
|
|
|
|
|
size_t start = 0, end;
|
|
|
|
|
|
while ((end = cpuValue.find('_', start)) != std::string::npos) {
|
|
|
|
|
|
cores.push_back(cpuValue.substr(start, end - start));
|
|
|
|
|
|
start = end + 1;
|
|
|
|
|
|
}
|
2025-09-23 14:03:11 +08:00
|
|
|
|
cores.push_back(cpuValue.substr(start)); // 添加最后一部分
|
2025-09-03 08:49:38 +08:00
|
|
|
|
|
|
|
|
|
|
for (auto& core : cores) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 手动转换整数(替代std::stoi)
|
2025-09-03 08:49:38 +08:00
|
|
|
|
const char* str = core.c_str();
|
|
|
|
|
|
char* endptr = nullptr;
|
|
|
|
|
|
long value = strtol(str, &endptr, 10);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 检查转换是否有效
|
2025-09-03 08:49:38 +08:00
|
|
|
|
if (endptr != str && *endptr == '\0') {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 校正超范围值
|
2025-09-03 08:49:38 +08:00
|
|
|
|
if (value > 100) value /= 100;
|
|
|
|
|
|
core = std::to_string(value);
|
|
|
|
|
|
}
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 转换失败保持原值
|
2025-09-03 08:49:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::string result;
|
|
|
|
|
|
for (size_t i = 0; i < cores.size(); ++i) {
|
|
|
|
|
|
if (i > 0) result += '_';
|
|
|
|
|
|
result += cores[i];
|
|
|
|
|
|
}
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 处理单核格式
|
2025-09-03 08:49:38 +08:00
|
|
|
|
else {
|
|
|
|
|
|
const char* str = cpuValue.c_str();
|
|
|
|
|
|
char* endptr = nullptr;
|
|
|
|
|
|
long value = strtol(str, &endptr, 10);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 检查转换是否有效
|
2025-09-03 08:49:38 +08:00
|
|
|
|
if (endptr != str && *endptr == '\0') {
|
|
|
|
|
|
if (value > 100) value /= 100;
|
|
|
|
|
|
return std::to_string(value);
|
|
|
|
|
|
}
|
|
|
|
|
|
return cpuValue;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 分割字段并处理
|
2025-09-03 08:49:38 +08:00
|
|
|
|
std::vector<std::string> fields;
|
|
|
|
|
|
size_t start = 0;
|
|
|
|
|
|
while (start < payload.length()) {
|
|
|
|
|
|
size_t end = payload.find(',', start);
|
|
|
|
|
|
if (end == std::string::npos) {
|
|
|
|
|
|
fields.push_back(payload.substr(start));
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
fields.push_back(payload.substr(start, end - start));
|
|
|
|
|
|
start = end + 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for (const auto& field : fields) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 跳过空字段
|
2025-09-03 08:49:38 +08:00
|
|
|
|
if (field.empty()) continue;
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 查找冒号位置
|
2025-09-03 08:49:38 +08:00
|
|
|
|
size_t colonPos = field.find(':');
|
|
|
|
|
|
if (colonPos == std::string::npos || colonPos == 0 || colonPos == field.length() - 1) {
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 分割键值对
|
2025-09-03 08:49:38 +08:00
|
|
|
|
std::string key = field.substr(0, colonPos);
|
|
|
|
|
|
std::string value = field.substr(colonPos + 1);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 去除键的空白
|
2025-09-03 08:49:38 +08:00
|
|
|
|
size_t keyStart = key.find_first_not_of(" \t");
|
|
|
|
|
|
size_t keyEnd = key.find_last_not_of(" \t");
|
|
|
|
|
|
if (keyStart != std::string::npos && keyEnd != std::string::npos) {
|
|
|
|
|
|
key = key.substr(keyStart, keyEnd - keyStart + 1);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 去除值的空白
|
2025-09-03 08:49:38 +08:00
|
|
|
|
size_t valStart = value.find_first_not_of(" \t");
|
|
|
|
|
|
size_t valEnd = value.find_last_not_of(" \t");
|
|
|
|
|
|
if (valStart != std::string::npos && valEnd != std::string::npos) {
|
|
|
|
|
|
value = value.substr(valStart, valEnd - valStart + 1);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 去除值两端的引号
|
2025-09-03 08:49:38 +08:00
|
|
|
|
if (value.size() >= 2 && value.front() == '"' && value.back() == '"') {
|
|
|
|
|
|
value = value.substr(1, value.size() - 2);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 尝试将键转换为整数
|
2025-09-03 08:49:38 +08:00
|
|
|
|
const char* keyStr = key.c_str();
|
|
|
|
|
|
char* endPtr = nullptr;
|
|
|
|
|
|
long fieldId = strtol(keyStr, &endPtr, 10);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 检查转换是否有效
|
2025-09-03 08:49:38 +08:00
|
|
|
|
if (endPtr != keyStr && *endPtr == '\0' && fieldId >= 1 && fieldId <= 10) {
|
|
|
|
|
|
switch (fieldId) {
|
|
|
|
|
|
case 1: result.Time = value; break;
|
|
|
|
|
|
case 2: result.CpuLoad = value; break;
|
|
|
|
|
|
case 3: result.FreeMemory = value; break;
|
|
|
|
|
|
case 4: result.TotalMemory = value; break;
|
|
|
|
|
|
case 5: result.FreeStorage = value; break;
|
|
|
|
|
|
case 6: result.TotalStorage = value; break;
|
|
|
|
|
|
case 7: result.HardTimeSync = value; break;
|
|
|
|
|
|
case 8: result.SntpTimeSync = value; break;
|
|
|
|
|
|
case 9: result.CloudTimeSync = value; break;
|
|
|
|
|
|
case 10: result.SignalStrength = value; break;
|
|
|
|
|
|
default: break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 特殊处理CPU负载
|
2025-09-03 08:49:38 +08:00
|
|
|
|
result.CpuLoad = processCpuLoad(result.CpuLoad);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 打印解析结果(实际应用中可替换为其他处理逻辑)
|
2025-09-03 08:49:38 +08:00
|
|
|
|
std::cout << "Device Running Information (" << mac << "):\n"
|
|
|
|
|
|
<< " Time: " << result.Time << "\n"
|
|
|
|
|
|
<< " CPU Load: " << result.CpuLoad << "\n"
|
|
|
|
|
|
<< " Memory: " << result.FreeMemory << "/" << result.TotalMemory << " MB\n"
|
|
|
|
|
|
<< " Storage: " << result.FreeStorage << "/" << result.TotalStorage << " GB\n"
|
|
|
|
|
|
<< " Time Sync: Hard=" << result.HardTimeSync
|
|
|
|
|
|
<< ", SNTP=" << result.SntpTimeSync
|
|
|
|
|
|
<< ", Cloud=" << result.CloudTimeSync << "\n"
|
|
|
|
|
|
<< " Signal: " << result.SignalStrength << std::endl;
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//读取装置运行信息(主动触发)成功,调整为空闲,处理后续工作。
|
2025-09-03 08:49:38 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 装置答非所问异常
|
|
|
|
|
|
// 读取装置运行信息(定时触发)失败,调整为空闲状态,处理下一项工作。
|
2025-09-03 08:49:38 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case DeviceState::READING_DEVVERSION:
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//读取装置版本配置信息(功能码同运行信息读取)(运维协议确认对时版本,电度与高频谐波开关,稳态间隔获取,版本配置上送)
|
2025-09-03 08:49:38 +08:00
|
|
|
|
if (udata[8] == static_cast<unsigned char>(MsgResponseType::Response_Read_RunningInformation)) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 获取解析后的数据体
|
2025-09-03 08:49:38 +08:00
|
|
|
|
std::vector<uint8_t>& recvData = parser.RecvData;
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 检查数据长度是否足够
|
2025-09-03 08:49:38 +08:00
|
|
|
|
if (recvData.size() < 2) {
|
|
|
|
|
|
std::cerr << "Invalid running information data: too short ("
|
|
|
|
|
|
<< recvData.size() << " bytes)" << std::endl;
|
|
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 提取有效载荷长度
|
2025-09-03 08:49:38 +08:00
|
|
|
|
size_t payloadLength = recvData.size() - 2;
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 复制有效载荷数据
|
2025-09-03 08:49:38 +08:00
|
|
|
|
std::vector<uint8_t> payloadBytes(payloadLength);
|
|
|
|
|
|
if (recvData.size() >= 2 + payloadLength) {
|
|
|
|
|
|
std::copy(recvData.begin() + 2, recvData.begin() + 2 + payloadLength, payloadBytes.begin());
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
std::cerr << "Invalid payload length: " << payloadLength
|
|
|
|
|
|
<< ", available: " << (recvData.size() - 2) << std::endl;
|
|
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 转换为UTF-8字符串
|
2025-09-03 08:49:38 +08:00
|
|
|
|
std::string payload(payloadBytes.begin(), payloadBytes.end());
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 定义存储装置版本信息的结构体
|
2025-09-03 08:49:38 +08:00
|
|
|
|
struct DeviceVersionInfo {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
std::string BaseModel; // 1: 装置基础型号
|
|
|
|
|
|
std::string CloudProtocolVer; // 2: 云服务协议版本
|
|
|
|
|
|
std::string AppVersion; // 3: 应用程序版本号
|
|
|
|
|
|
std::string AppDate; // 4: 应用程序版本日期
|
|
|
|
|
|
std::string AppChecksum; // 5: 应用程序校验码
|
|
|
|
|
|
std::string VoltageWiring; // 6: 电压接线方式
|
|
|
|
|
|
std::string CurrentBSynthetic; // 7: 电流B相是否合成
|
|
|
|
|
|
int DataStatInterval = 0; // 8: 数据统计时间间隔(分钟)
|
|
|
|
|
|
float RatedVoltage = 0.0f; // 9: 额定电压(二次值,单位V)
|
|
|
|
|
|
float PTRatio = 0.0f; // 10: PT变比
|
|
|
|
|
|
float CTRatio = 0.0f; // 11: CT变比
|
|
|
|
|
|
std::string SntpIP; // 12: sntp对时IP
|
|
|
|
|
|
int SntpPort = 0; // 13: sntp对时端口
|
|
|
|
|
|
int SntpInterval = 0; // 14: sntp对时间隔(分钟)
|
|
|
|
|
|
int WebPort = 0; // 15: Web端口
|
|
|
|
|
|
int FtpPort = 0; // 16: ftp端口
|
|
|
|
|
|
int PqdifInterval = 0; // 17: Pqdif文件时间间隔(小时)
|
|
|
|
|
|
int WaveFileTypeCount = 0; // 18: 录波文件包含文件类型数
|
|
|
|
|
|
std::string SpecialVersion; // 19: 特殊程序版本信息
|
|
|
|
|
|
std::string DeviceModel; // 20: 装置型号
|
|
|
|
|
|
int HarmonicEnergyFlag = 0; // 21: 谐波电度版本标志
|
|
|
|
|
|
std::string PhysicalName; // 22: 物理设备名称
|
|
|
|
|
|
std::string WaveLDName; // 23: 录波LD名称
|
|
|
|
|
|
int HighFreqHarmonicFlag = 0; // 24: 高频谐波功能标志
|
|
|
|
|
|
unsigned int CommProtocols = 0; // 51: 投入的通讯协议
|
|
|
|
|
|
unsigned int TimeSyncMethods = 0;// 52: 投入的对时方式
|
|
|
|
|
|
unsigned int DeviceFunctions = 0;// 53: 装置功能配置
|
2025-09-03 08:49:38 +08:00
|
|
|
|
} versionInfo;
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 分割字段
|
2025-09-03 08:49:38 +08:00
|
|
|
|
std::vector<std::string> fields;
|
|
|
|
|
|
size_t start = 0;
|
|
|
|
|
|
while (start < payload.length()) {
|
|
|
|
|
|
size_t end = payload.find(',', start);
|
|
|
|
|
|
if (end == std::string::npos) {
|
|
|
|
|
|
fields.push_back(payload.substr(start));
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
fields.push_back(payload.substr(start, end - start));
|
|
|
|
|
|
start = end + 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 处理每个字段
|
2025-09-03 08:49:38 +08:00
|
|
|
|
for (const auto& field : fields) {
|
|
|
|
|
|
if (field.empty()) continue;
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 分割键值对
|
2025-09-03 08:49:38 +08:00
|
|
|
|
size_t colonPos = field.find(':');
|
|
|
|
|
|
if (colonPos == std::string::npos || colonPos == 0) continue;
|
|
|
|
|
|
|
|
|
|
|
|
std::string key = field.substr(0, colonPos);
|
|
|
|
|
|
std::string value = field.substr(colonPos + 1);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 去除键值两端的空白和引号
|
2025-09-03 08:49:38 +08:00
|
|
|
|
auto trim = [](std::string str) -> std::string {
|
|
|
|
|
|
size_t start = str.find_first_not_of(" \t\"");
|
|
|
|
|
|
size_t end = str.find_last_not_of(" \t\"");
|
|
|
|
|
|
return (start == std::string::npos) ? "" : str.substr(start, end - start + 1);
|
|
|
|
|
|
};
|
|
|
|
|
|
key = trim(key);
|
|
|
|
|
|
value = trim(value);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 转换为信息编码ID
|
2025-09-03 08:49:38 +08:00
|
|
|
|
try {
|
|
|
|
|
|
int fieldId = std::stoi(key);
|
|
|
|
|
|
switch (fieldId) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 字符串类型字段
|
2025-09-03 08:49:38 +08:00
|
|
|
|
case 1: versionInfo.BaseModel = value; break;
|
|
|
|
|
|
case 2: versionInfo.CloudProtocolVer = value; break;
|
|
|
|
|
|
case 3: versionInfo.AppVersion = value; break;
|
|
|
|
|
|
case 4: versionInfo.AppDate = value; break;
|
|
|
|
|
|
case 5: versionInfo.AppChecksum = value; break;
|
|
|
|
|
|
case 6: versionInfo.VoltageWiring = value; break;
|
|
|
|
|
|
case 7: versionInfo.CurrentBSynthetic = value; break;
|
|
|
|
|
|
case 12: versionInfo.SntpIP = value; break;
|
|
|
|
|
|
case 19: versionInfo.SpecialVersion = value; break;
|
|
|
|
|
|
case 20: versionInfo.DeviceModel = value; break;
|
|
|
|
|
|
case 22: versionInfo.PhysicalName = value; break;
|
|
|
|
|
|
case 23: versionInfo.WaveLDName = value; break;
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 数值类型字段
|
2025-09-03 08:49:38 +08:00
|
|
|
|
case 8: versionInfo.DataStatInterval = std::stoi(value); break;
|
|
|
|
|
|
case 9: versionInfo.RatedVoltage = std::stof(value); break;
|
|
|
|
|
|
case 10: versionInfo.PTRatio = std::stof(value); break;
|
|
|
|
|
|
case 11: versionInfo.CTRatio = std::stof(value); break;
|
|
|
|
|
|
case 13: versionInfo.SntpPort = std::stoi(value); break;
|
|
|
|
|
|
case 14: versionInfo.SntpInterval = std::stoi(value); break;
|
|
|
|
|
|
case 15: versionInfo.WebPort = std::stoi(value); break;
|
|
|
|
|
|
case 16: versionInfo.FtpPort = std::stoi(value); break;
|
|
|
|
|
|
case 17: versionInfo.PqdifInterval = std::stoi(value); break;
|
|
|
|
|
|
case 18: versionInfo.WaveFileTypeCount = std::stoi(value); break;
|
|
|
|
|
|
case 21: versionInfo.HarmonicEnergyFlag = std::stoi(value); break;
|
|
|
|
|
|
case 24: versionInfo.HighFreqHarmonicFlag = std::stoi(value); break;
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 十六进制字段(51+)
|
2025-09-03 08:49:38 +08:00
|
|
|
|
case 51:
|
|
|
|
|
|
case 52:
|
|
|
|
|
|
case 53: {
|
|
|
|
|
|
if (value.size() > 2 && value.substr(0, 2) == "0x") {
|
|
|
|
|
|
unsigned int hexValue = std::stoul(value.substr(2), nullptr, 16);
|
|
|
|
|
|
switch (fieldId) {
|
|
|
|
|
|
case 51: versionInfo.CommProtocols = hexValue; break;
|
|
|
|
|
|
case 52: versionInfo.TimeSyncMethods = hexValue; break;
|
|
|
|
|
|
case 53: versionInfo.DeviceFunctions = hexValue; break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (const std::exception& e) {
|
|
|
|
|
|
std::cerr << "Error parsing field: " << field
|
|
|
|
|
|
<< ", error: " << e.what() << std::endl;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//云协议版本非空则赋值,未赋值则使用默认的V1.0
|
2025-09-04 15:37:26 +08:00
|
|
|
|
if (!versionInfo.CloudProtocolVer.empty()) {
|
|
|
|
|
|
ClientManager::instance().set_versioninformation(id, versionInfo.CloudProtocolVer);
|
|
|
|
|
|
}
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 打印解析结果
|
2025-09-08 14:37:39 +08:00
|
|
|
|
std::cout << "Device Version Info (" << mac << "):\n"
|
2025-09-03 08:49:38 +08:00
|
|
|
|
<< " Base Model: " << versionInfo.BaseModel << "\n"
|
|
|
|
|
|
<< " Cloud Protocol: " << versionInfo.CloudProtocolVer << "\n"
|
|
|
|
|
|
<< " App Version: " << versionInfo.AppVersion << "\n"
|
|
|
|
|
|
<< " App Date: " << versionInfo.AppDate << "\n"
|
|
|
|
|
|
<< " PT Ratio: " << versionInfo.PTRatio << "\n"
|
|
|
|
|
|
<< " CT Ratio: " << versionInfo.CTRatio << "\n"
|
|
|
|
|
|
<< " Wave File Types: " << versionInfo.WaveFileTypeCount << "\n"
|
|
|
|
|
|
<< " Comm Protocols: 0x" << std::hex << versionInfo.CommProtocols << "\n"
|
|
|
|
|
|
<< " Time Sync Methods: 0x" << versionInfo.TimeSyncMethods << "\n"
|
2025-09-08 14:37:39 +08:00
|
|
|
|
<< " Device Functions: 0x" << versionInfo.DeviceFunctions << std::dec << "\n";
|
2025-09-03 08:49:38 +08:00
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//读取装置版本配置信息成功,调整为空闲,处理后续工作。
|
2025-09-03 08:49:38 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 装置答非所问异常
|
|
|
|
|
|
// 读取装置版本配置信息失败,调整为空闲状态,处理下一项工作。
|
2025-09-03 08:49:38 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
2025-09-04 15:37:26 +08:00
|
|
|
|
case DeviceState::SET_RIGHTTIME:
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//设置装置对时
|
2025-09-04 15:37:26 +08:00
|
|
|
|
if (udata[8] == static_cast<unsigned char>(MsgResponseType::Response_NewACK)) {
|
|
|
|
|
|
std::cout << "set success" << mac << std::endl;
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//对时设置成功,调整为空闲,处理后续工作。
|
2025-09-04 15:37:26 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (udata[8] == static_cast<unsigned char>(MsgResponseType::Response_NewNACK)) {
|
|
|
|
|
|
std::cout << "set error" << mac << std::endl;
|
|
|
|
|
|
|
|
|
|
|
|
std::cout << "reason code: " << static_cast<int>(udata[8]) << "-" << static_cast<int>(udata[9]) << "-" << static_cast<int>(udata[10]) << "-" << static_cast<int>(udata[11]) << std::endl;
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 装置否定应答,对时设置失败
|
|
|
|
|
|
// 设置对时失败,调整为空闲状态,处理下一项工作。
|
2025-09-04 15:37:26 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 装置答非所问异常
|
|
|
|
|
|
// 设置对时失败,调整为空闲状态,处理下一项工作。
|
2025-09-04 15:37:26 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
2025-09-08 14:37:39 +08:00
|
|
|
|
case DeviceState::READING_EVENTLOG:
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//补招装置日志
|
2025-09-08 14:37:39 +08:00
|
|
|
|
if (udata[8] == static_cast<unsigned char>(MsgResponseType::Response_Read_Event)) {
|
|
|
|
|
|
std::cout << "set success" << mac << std::endl;
|
|
|
|
|
|
|
|
|
|
|
|
std::cout << "reason code: " << static_cast<int>(udata[8]) << "-" << static_cast<int>(udata[9]) << "-" << static_cast<int>(udata[10]) << "-" << static_cast<int>(udata[11]) << std::endl;
|
|
|
|
|
|
|
|
|
|
|
|
if (parser.RecvData.size() >= 14) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 提取当前帧
|
2025-09-08 14:37:39 +08:00
|
|
|
|
int current_frame = 0;
|
|
|
|
|
|
if (parser.RecvData.size() >= 4) {
|
|
|
|
|
|
std::vector<unsigned char> frame_data(parser.RecvData.begin(), parser.RecvData.begin() + 4);
|
2025-09-23 14:03:11 +08:00
|
|
|
|
std::reverse(frame_data.begin(), frame_data.end()); // 字节反转
|
2025-09-08 14:37:39 +08:00
|
|
|
|
current_frame = *reinterpret_cast<int*>(frame_data.data());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 提取总帧数
|
2025-09-08 14:37:39 +08:00
|
|
|
|
int total_frames = 0;
|
|
|
|
|
|
if (parser.RecvData.size() >= 8) {
|
|
|
|
|
|
std::vector<unsigned char> total_frame_data(parser.RecvData.begin() + 4, parser.RecvData.begin() + 8);
|
2025-09-23 14:03:11 +08:00
|
|
|
|
std::reverse(total_frame_data.begin(), total_frame_data.end()); // 字节反转
|
2025-09-08 14:37:39 +08:00
|
|
|
|
total_frames = *reinterpret_cast<int*>(total_frame_data.data());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 提取文件总大小
|
2025-09-08 14:37:39 +08:00
|
|
|
|
int file_size = 0;
|
|
|
|
|
|
if (parser.RecvData.size() >= 12) {
|
|
|
|
|
|
std::vector<unsigned char> size_data(parser.RecvData.begin() + 8, parser.RecvData.begin() + 12);
|
2025-09-23 14:03:11 +08:00
|
|
|
|
std::reverse(size_data.begin(), size_data.end()); // 字节反转
|
2025-09-08 14:37:39 +08:00
|
|
|
|
file_size = *reinterpret_cast<int*>(size_data.data());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 提取CRC校验码
|
2025-09-08 14:37:39 +08:00
|
|
|
|
uint16_t crc = 0;
|
|
|
|
|
|
if (parser.RecvData.size() >= 14) {
|
|
|
|
|
|
std::vector<unsigned char> crc_data(parser.RecvData.begin() + 12, parser.RecvData.begin() + 14);
|
2025-09-23 14:03:11 +08:00
|
|
|
|
std::reverse(crc_data.begin(), crc_data.end()); // 字节反转
|
2025-09-08 14:37:39 +08:00
|
|
|
|
crc = *reinterpret_cast<uint16_t*>(crc_data.data());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 提取文件数据
|
2025-09-08 14:37:39 +08:00
|
|
|
|
std::vector<unsigned char> file_data;
|
|
|
|
|
|
if (parser.RecvData.size() > 14) {
|
|
|
|
|
|
file_data.assign(parser.RecvData.begin() + 14, parser.RecvData.end());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 将数据添加到缓存(使用类似READING_STATS的逻辑)
|
2025-09-08 14:37:39 +08:00
|
|
|
|
bool complete = ClientManager::instance().add_eventlog_packet_to_device(
|
|
|
|
|
|
id, file_data, current_frame, total_frames
|
|
|
|
|
|
);
|
|
|
|
|
|
std::cout << "event log:" << current_frame << "/" << total_frames << std::endl;
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 检查是否收全所有帧
|
2025-09-08 14:37:39 +08:00
|
|
|
|
if (complete) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 1. 获取并清空缓存数据包
|
2025-09-08 14:37:39 +08:00
|
|
|
|
auto packets = ClientManager::instance().get_and_clear_event_packets(id);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 2. 按帧序号排序
|
2025-09-08 14:37:39 +08:00
|
|
|
|
std::sort(packets.begin(), packets.end(),
|
|
|
|
|
|
[](const ClientContext::StatPacket& a, const ClientContext::StatPacket& b) {
|
|
|
|
|
|
return a.packet_index < b.packet_index;
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 3. 解析每帧数据并提取数据体
|
2025-09-08 14:37:39 +08:00
|
|
|
|
std::vector<unsigned char> full_data;
|
|
|
|
|
|
|
|
|
|
|
|
for (const auto& packet : packets) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 将数据体添加到完整序列
|
2025-09-08 14:37:39 +08:00
|
|
|
|
full_data.insert(full_data.end(),
|
|
|
|
|
|
packet.data.begin(),
|
|
|
|
|
|
packet.data.end());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//确认待补招序号 // 获取测点参数
|
2025-09-08 14:37:39 +08:00
|
|
|
|
int event_lineid = 0;
|
2025-09-23 14:03:11 +08:00
|
|
|
|
std::string strScale;//电压等级
|
|
|
|
|
|
int nPTType;//接线方式
|
2025-09-08 14:37:39 +08:00
|
|
|
|
float fPT = 1.0f;
|
|
|
|
|
|
float fCT = 1.0f;
|
|
|
|
|
|
|
|
|
|
|
|
if (!ClientManager::instance().get_event_lineid(id, event_lineid)) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//取出补招序号失败!暂态补招结束
|
|
|
|
|
|
//补招装置日志获取完毕,调整为空闲状态,处理下一项工作。
|
2025-09-08 14:37:39 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!ClientManager::instance().get_point_scale_and_pttype(
|
|
|
|
|
|
id,
|
|
|
|
|
|
event_lineid,
|
|
|
|
|
|
strScale,
|
|
|
|
|
|
nPTType) || !ClientManager::instance().get_pt_ct_ratio(id, event_lineid, fPT, fCT)) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//取出解析方式,PTCT,电压等级失败!暂态补招结束
|
|
|
|
|
|
//补招装置日志获取完毕,调整为空闲状态,处理下一项工作。
|
2025-09-08 14:37:39 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// ========== 新增:解析full_data中的NewTaglogbuffer对象列表 ==========
|
2025-09-08 14:37:39 +08:00
|
|
|
|
std::list<NewTaglogbuffer> eventList;
|
|
|
|
|
|
size_t offset = 0;
|
|
|
|
|
|
const size_t headSize = sizeof(NewHeadTaglogbuffer);
|
|
|
|
|
|
const size_t bodyItemSize = sizeof(NewBodyTaglogbuffer);
|
|
|
|
|
|
|
|
|
|
|
|
while (offset + headSize <= full_data.size()) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 读取头部
|
2025-09-08 14:37:39 +08:00
|
|
|
|
NewHeadTaglogbuffer head;
|
|
|
|
|
|
memcpy(&head, full_data.data() + offset, headSize);
|
2025-09-23 14:03:11 +08:00
|
|
|
|
head.convertByteOrder(); // 转换字节序
|
2025-09-08 14:37:39 +08:00
|
|
|
|
|
|
|
|
|
|
uint32_t logParaNum = head.LogParaNum;
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 计算身体部分在full_data中占用的空间(最少4个身体项的空间)
|
2025-09-08 14:37:39 +08:00
|
|
|
|
size_t bodySpace;
|
|
|
|
|
|
if (logParaNum <= 4) {
|
|
|
|
|
|
bodySpace = 4 * bodyItemSize;
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
bodySpace = logParaNum * bodyItemSize;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 检查剩余数据是否足够
|
2025-09-08 14:37:39 +08:00
|
|
|
|
if (offset + headSize + bodySpace > full_data.size()) {
|
|
|
|
|
|
std::cerr << "Insufficient data for event body at offset " << offset << std::endl;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 创建事件对象并设置头部
|
2025-09-08 14:37:39 +08:00
|
|
|
|
NewTaglogbuffer event;
|
|
|
|
|
|
event.head = head;
|
|
|
|
|
|
event.bodyList.resize(logParaNum);
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 解析身体部分
|
2025-09-08 14:37:39 +08:00
|
|
|
|
const uint8_t* bodyData = full_data.data() + offset + headSize;
|
|
|
|
|
|
for (uint32_t i = 0; i < logParaNum; ++i) {
|
|
|
|
|
|
memcpy(&event.bodyList[i], bodyData, bodyItemSize);
|
|
|
|
|
|
event.bodyList[i].convertByteOrder();
|
|
|
|
|
|
bodyData += bodyItemSize;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//当前解析事件和待补招测点一致,则加入队列
|
2025-09-08 14:37:39 +08:00
|
|
|
|
if (event.head.name == event_lineid) {
|
|
|
|
|
|
eventList.push_back(event);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 移动偏移量,跳过头部和身体占用空间(包括填充)
|
2025-09-08 14:37:39 +08:00
|
|
|
|
offset += headSize + bodySpace;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 现在eventList中包含所有解析的事件对象,可以在这里进行处理
|
2025-09-08 14:37:39 +08:00
|
|
|
|
std::cout << "Parsed " << eventList.size() << " events from event log." << std::endl;
|
|
|
|
|
|
|
|
|
|
|
|
std::list<QVVRRecord> recordlist;
|
|
|
|
|
|
for (const auto& event : eventList) {
|
|
|
|
|
|
|
|
|
|
|
|
QVVRRecord record = DynamicLog_GetQVVRRecordFromLogBuffer(
|
|
|
|
|
|
strScale, nPTType, fPT, event);
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 使用记录数据(示例:打印到控制台)
|
|
|
|
|
|
std::cout << "事件类型: " << record.nType
|
|
|
|
|
|
<< ", 持续时间: " << record.fPersisstime << "s"
|
|
|
|
|
|
<< ", 特征幅值: " << record.fMagntitude << " pu"
|
|
|
|
|
|
<< ", 时间戳: " << record.triggerTimeMs << "ms" << std::endl;
|
2025-09-08 14:37:39 +08:00
|
|
|
|
|
2025-10-30 20:57:19 +08:00
|
|
|
|
//记录补招上来的暂态事件
|
|
|
|
|
|
append_qvvr_event(id,event.head.name,
|
|
|
|
|
|
record.nType,record.fPersisstime,record.fMagntitude,record.triggerTimeMs,record.phase);
|
2025-10-22 15:57:50 +08:00
|
|
|
|
//直接发走暂态事件
|
|
|
|
|
|
transfer_json_qvvr_data(id,event.head.name,
|
|
|
|
|
|
record.fMagntitude,record.fPersisstime,record.triggerTimeMs,record.nType,record.phase,"");
|
|
|
|
|
|
|
|
|
|
|
|
//通知状态机补招暂态事件成功
|
|
|
|
|
|
on_device_response_minimal(static_cast<int>(ResponseCode::OK), id, 0, static_cast<int>(DeviceState::READING_EVENTLOG));
|
|
|
|
|
|
|
2025-09-08 14:37:39 +08:00
|
|
|
|
recordlist.push_back(record);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//暂时移除CRC校验相关
|
|
|
|
|
|
//// ========== 新增 CRC 验证 ==========
|
2025-09-08 14:37:39 +08:00
|
|
|
|
//if (!full_data.empty()) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// // 计算接收数据的 CRC
|
2025-09-08 14:37:39 +08:00
|
|
|
|
// uint16_t calculated_crc = crc_16_new(full_data.data(), full_data.size());
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// // 比较计算出的 CRC 和从报文中提取的 CRC
|
2025-09-08 14:37:39 +08:00
|
|
|
|
// if (calculated_crc == crc) {
|
|
|
|
|
|
// std::cout << "CRC verification passed for event log data." << std::endl;
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// // 这里可以继续处理完整数据
|
2025-09-08 14:37:39 +08:00
|
|
|
|
// }
|
|
|
|
|
|
// else {
|
|
|
|
|
|
// std::cerr << "CRC verification failed! Expected: " << crc
|
|
|
|
|
|
// << ", Calculated: " << calculated_crc << std::endl;
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// // 处理 CRC 校验失败的情况
|
2025-09-08 14:37:39 +08:00
|
|
|
|
// }
|
|
|
|
|
|
//}
|
|
|
|
|
|
//else {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// //收取缓存文件异常,结束补招处理
|
2025-09-08 14:37:39 +08:00
|
|
|
|
// std::cerr << "No data received for event log." << std::endl;
|
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//未收全则直接结束处理,等待后续报文应答
|
2025-09-08 14:37:39 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//补招装置日志获取完毕,调整为空闲状态,处理下一项工作。
|
2025-09-08 14:37:39 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (udata[8] == static_cast<unsigned char>(MsgResponseType::Response_NewNACK)) {
|
|
|
|
|
|
std::cout << "set error" << mac << std::endl;
|
|
|
|
|
|
|
|
|
|
|
|
std::cout << "reason code: " << static_cast<int>(udata[8]) << "-" << static_cast<int>(udata[9]) << "-" << static_cast<int>(udata[10]) << "-" << static_cast<int>(udata[11]) << std::endl;
|
|
|
|
|
|
|
|
|
|
|
|
if (udata[10] == static_cast<unsigned char>(0x0c)) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//0x0c错误码代表询问暂态数据不存在,通知前台当前时间段无暂态
|
2025-09-08 14:37:39 +08:00
|
|
|
|
std::cout << "not find event " << mac << std::endl;
|
2025-10-24 08:50:54 +08:00
|
|
|
|
//lnk20251023
|
|
|
|
|
|
on_device_response_minimal(static_cast<int>(ResponseCode::NOT_FOUND), id, 0, static_cast<int>(DeviceState::READING_EVENTLOG));
|
2025-09-08 14:37:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
else if (udata[10] == static_cast<unsigned char>(0x06)) {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//0x0c错误码代表补招方法参数错误,通知前台参数异常
|
2025-10-24 08:50:54 +08:00
|
|
|
|
//lnk20251023
|
|
|
|
|
|
on_device_response_minimal(static_cast<int>(ResponseCode::FORBIDDEN), id, 0, static_cast<int>(DeviceState::READING_EVENTLOG));
|
2025-09-08 14:37:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
else {
|
2025-09-23 14:03:11 +08:00
|
|
|
|
//其余错误码代表异常情况
|
2025-10-24 08:50:54 +08:00
|
|
|
|
//lnk20251023
|
2025-10-28 20:59:05 +08:00
|
|
|
|
on_device_response_minimal(static_cast<int>(ResponseCode::BAD_REQUEST), id, 0, static_cast<int>(DeviceState::READING_EVENTLOG));
|
2025-09-08 14:37:39 +08:00
|
|
|
|
}
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 装置否定
|
|
|
|
|
|
// 补招装置日志失败,调整为空闲状态,处理下一项工作。
|
2025-09-08 14:37:39 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
std::cout << "set unknow error" << mac << std::endl;
|
|
|
|
|
|
|
|
|
|
|
|
std::cout << "reason code: " << static_cast<int>(udata[8]) << "-" << static_cast<int>(udata[9]) << "-" << static_cast<int>(udata[10]) << "-" << static_cast<int>(udata[11]) << std::endl;
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 装置答非所问异常
|
|
|
|
|
|
// 补招装置日志失败,调整为空闲状态,处理下一项工作。
|
2025-09-08 14:37:39 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
2025-07-03 11:13:16 +08:00
|
|
|
|
case DeviceState::CUSTOM_ACTION:
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 自定义动作状态
|
2025-07-03 11:13:16 +08:00
|
|
|
|
std::cout << "CUSTOM_ACTION state: Processing custom response from " << mac << std::endl;
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 这里添加处理自定义动作响应的逻辑
|
2025-07-03 11:13:16 +08:00
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 处理完成后标记状态完成
|
2025-07-03 11:13:16 +08:00
|
|
|
|
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
std::cerr << "Unknown state: " << static_cast<int>(currentState)
|
|
|
|
|
|
<< " for device " << id << std::endl;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:03:11 +08:00
|
|
|
|
// 无论何种状态,处理完成后触发后续状态处理
|
2025-07-03 11:13:16 +08:00
|
|
|
|
ClientManager::instance().post_message_processing(id);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
2025-06-20 09:25:17 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|