Files
front_linux/LFtid1056/dealMsg.cpp
2025-10-28 20:59:05 +08:00

2189 lines
117 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>
#include <queue>
#include <vector>
#include <atomic>
#include <fstream>
#include <sys/stat.h> // 用于mkdir
#include <iostream>
#include "cloudfront/code/interface.h" //lnk20250708
#include "cloudfront/code/rocketmq.h" //lnk20250708
#include "cloudfront/code/log4.h" //lnk20250924
#include "client2.h"
#include "cloudfront/code/log4.h"
using namespace std;
SafeMessageQueue message_queue; // 全局消息队列
//时间转换函数
time_t ConvertToTimestamp(const tagTime& time) {
struct tm t = {};
t.tm_year = time.DeviceYear - 1900; // tm_year 从 1900 开始计
t.tm_mon = time.DeviceMonth - 1; // tm_mon 从 01月开始
t.tm_mday = time.DeviceDay;
t.tm_hour = time.DeviceHour;
t.tm_min = time.DeviceMinute;
t.tm_sec = time.DeviceSecond;
// 返回时间戳(本地时间)
return mktime(&t);
}
//文件分割取字段
std::string extract_filename(const std::string& path) {
// 查找最后一个'/'的位置
size_t last_slash = path.find_last_of('/');
// 如果找到'/',则返回'/'之后的部分
if (last_slash != std::string::npos) {
return path.substr(last_slash + 1);
}
// 如果没有'/',直接返回原字符串
return path;
}
//文件crc校验函数
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;
}
//消息处理逻辑
void process_received_message(string mac, string id,const char* data, size_t length) {
// 实际的消息处理逻辑
std::cout << "Active connections: " << mac << " id:" << id << " size:" << length << std::endl;
// 接收到消息后,先找到指定装置刷新对应最新通讯时间戳
ClientManager::instance().set_cloudmessage_time(id);
//数据处理逻辑
if (length > 0) {
// 将数据转为无符号类型以便处理二进制值
const unsigned char* udata = reinterpret_cast<const unsigned char*>(data);
//对数据消息的初步处理--登录报文格式解析不出来
MessageParser parser;
bool bool_msgset = parser.SetMsg(udata, length);
//云服务登录报文
if (udata[0] == 0xEB && udata[1] == 0x90 && udata[2] == 0xEB && udata[3] == 0x90) {
//通讯状态报文
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;
//装置登录成功
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
//std::tm start_time = {};
//start_time.tm_year = 2025 - 1900; // 年份从1900开始计算
//start_time.tm_mon = 8 - 1; // 月份从0开始 (0=一月)
//start_time.tm_mday = 20;
//start_time.tm_hour = 1;
//start_time.tm_min = 1;
//start_time.tm_sec = 1;
//// 设置结束时间: 2025年9月4日 12:15:30
//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);
/*DIY_ERRORLOG_CODE("111", 0, static_cast<int>(LogCode::LOG_CODE_OTHER), "【ERROR】测试告警发送 前置");
DIY_ERRORLOG_CODE(id, 1, static_cast<int>(LogCode::LOG_CODE_OTHER), "【ERROR】测试告警发送 设备");
std::string mpid;
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】测试告警发送 测点");
}*/
}
if (udata[19] == 0x00) {
std::cout << "cloud login: " << mac << " state: fail!" << std::endl;
//装置登录失败 关闭客户端连接 等待20秒重新登录
ClientManager::instance().restart_device(id);
}
}
else {
std::cout << "cloud login: " << mac << " state: error!"<< std::endl;
//装置登录失败 关闭客户端连接 等待20秒重新登录
ClientManager::instance().restart_device(id);
}
//登录报文处理完毕,当前报文处理逻辑结束并返回
return;
}
//装置主动上送报文 暂态事件报文/暂态波形文件报文
if (udata[8] == static_cast<unsigned char>(MsgResponseType::Response_Event)) {
//处理主动上送的暂态事件报文
NewTaglogbuffer event = NewTaglogbuffer::createFromData(parser.RecvData.data(), parser.RecvData.size());
//获取测点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;//接线方式
float fPT = 1.0f;
float fCT = 1.0f;
if (ClientManager::instance().get_point_scale_and_pttype(
id, // 或使用id
event.head.name, // 从报文中解析出的测点序号
strScale,
nPTType) && ClientManager::instance().get_pt_ct_ratio(id, event.head.name, fPT, fCT))
{
// 使用获取的参数解析事件记录
QVVRRecord record = DynamicLog_GetQVVRRecordFromLogBuffer(
strScale, nPTType, fPT, event);
// 使用记录数据(示例:打印到控制台)
std::cout << "事件类型: " << record.nType
<< ", 持续时间: " << record.fPersisstime << "s"
<< ", 特征幅值: " << record.fMagntitude << " pu"
<< ", 时间戳: " << record.triggerTimeMs << "ms" << std::endl;
//lnk20250805 事件上送先记录,录波文件上传结束后再更新文件
append_qvvr_event(id,event.head.name,
record.nType,record.fPersisstime,record.fMagntitude,record.triggerTimeMs,record.phase);
transfer_json_qvvr_data(id,event.head.name,
record.fMagntitude,record.fPersisstime,record.triggerTimeMs,record.nType,record.phase,
"");
//事件主动上送处理完成,不需要通知状态机
}
else {
// 处理获取失败的情况
std::cerr << "Failed to get point parameters for: " << mac << std::endl;
}
//处理完毕主动上送报文后直接退出,不要干扰装置正常应答
return;
}
else if (udata[8] == static_cast<unsigned char>(MsgResponseType::Response_ActiveSOEInfo)) {
//处理主动上送的波形文件信息报文
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;//数据体去除前两位
size_t data_size = parser.RecvData.size() - 2;
// 直接构造字符串(避免额外拷贝)
std::string tempfilename(
reinterpret_cast<const char*>(data_ptr),
data_size
);
// ========== 新增:处理终止符 ==========
// 查找字符串中的第一个空字符或其他终止符
size_t terminator_pos = tempfilename.find_first_of("\0\r\n", 0, 3);
if (terminator_pos != std::string::npos) {
// 如果找到终止符,截断字符串
tempfilename.resize(terminator_pos);
std::cout << "Found terminator at position: " << terminator_pos
<< ", truncated filename to: " << tempfilename << std::endl;
}
// ========== 新增文件路径处理逻辑 ==========
// 1. 分割原始文件名和后缀
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 = "";
}
// 2. 确定大小写风格
bool isUppercase = false;
if (!originalExt.empty()) {
isUppercase = true;
for (char c : originalExt) {
if (std::isalpha(c) && std::islower(c)) {
isUppercase = false;
break;
}
}
}
// 3. 生成需要的后缀列表
std::vector<std::string> requiredExts;
if (file_type == 3) { // 需要三个文件
requiredExts = { ".cfg", ".dat", ".hdr" };
}
else { // 默认需要两个文件
requiredExts = { ".cfg", ".dat" };
//requiredExts = { ".dat" };
}
// 4. 调整后缀大小写
if (isUppercase) {
for (auto& ext : requiredExts) {
for (char& c : ext) {
if (std::isalpha(c)) c = std::toupper(c);
}
}
}
// 5. 构建完整路径列表
std::vector<std::string> fullFilenames;
for (const auto& ext : requiredExts) {
fullFilenames.push_back(baseName + ext);
}
// 6. 打印结果(实际使用中可能需要替换这里的打印逻辑)
std::cout << "Generated filenames: ";
for (const auto& name : fullFilenames) {
std::cout << name << " ";
}
std::cout << std::endl;
//lnk20250805录波文件目录接口
assign_qvvr_file_list(id, line_id, fullFilenames);
// ========== 新增:为每个文件生成下载请求 ==========
for (const auto& filename : fullFilenames) {
// 生成下载请求报文 (帧序号固定为1代表开始新文件的下载)
auto downloadMsg = generate_downloadfile_message(1, filename);
// 将下载动作添加到设备队列
ClientManager::instance().add_action_to_device(
id,
DeviceState::READING_EVENTFILE,
downloadMsg
);
std::cout << "Added download request for: " << filename << std::endl;
}
//最后报文收发处理逻辑(如果当前装置空闲则尝试执行后续动作)(如果当前装置存在其他状态则直接退出,不要干扰装置后续执行)
DeviceState currentState = DeviceState::IDLE;//获取当前装置的状态
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:
//当前装置空闲中,可以执行后续动作
ClientManager::instance().post_message_processing(id);
break;
default:
//非空闲的其他状态直接退出即可,等待后续处理完毕后再尝试获取波形文件
break;
}
//处理完毕主动上送报文后直接退出,不要干扰装置正常应答
return;
}
//常规通讯报文
{
DeviceState currentState = DeviceState::IDLE;//获取当前装置的状态
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:
// 空闲状态下收到报文,可能是主动上报数据
std::cout << "IDLE state: Received active report from " << mac << std::endl;
// 这里可以添加处理主动上报数据的逻辑
break;
case DeviceState::READING_STATS:
// 读取统计数据状态
if (udata[8] == static_cast<unsigned char>(MsgResponseType::Response_Stat)) {
// 一发多收,需要在这里等待所有报文收全再组装相应数据 一帧1K 直到所有数据传送完毕
//当前帧未收全,直接退出消息处理,等待后续帧
std::cout << "mac: " << mac << " count" << static_cast<int>(udata[10]) << std::endl;
// 解析帧信息 (根据实际协议调整)
int current_packet = static_cast<int>(udata[10]); // 当前帧序号
int total_packets = Stat_PacketNum; // 总帧数
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
);
//判断是否收全
if (complete) {
// 1. 获取并清空缓存数据包
auto packets = ClientManager::instance().get_and_clear_stat_packets(id);
// 2. 按帧序号排序
std::sort(packets.begin(), packets.end(),
[](const ClientContext::StatPacket& a, const ClientContext::StatPacket& b) {
return a.packet_index < b.packet_index;
});
// 3. 解析每帧数据并提取数据体
std::vector<unsigned char> full_data;
MessageParser parser;
for (const auto& packet : packets) {
// 解析单帧报文
if (!parser.SetMsg(packet.data.data(), packet.data.size())) {
std::cerr << "Failed to parse packet " << packet.packet_index
<< " for device " << id << std::endl;
continue;
}
// 将数据体添加到完整序列
full_data.insert(full_data.end(),
parser.RecvData.begin(),
parser.RecvData.end());
}
// 4. 组装 tagPqData 对象
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 {
// 成功组装,可以在这里使用 pq_data 对象
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)) {
// 使用获取的变比值进行数据转换
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;
// 将浮点数据添加到缓存
// 添加到缓存并检查是否收全
bool complete = ClientManager::instance().add_float_data_to_device(
id, pq_data.name, pq_data.Data_Type, float_data);
if (complete) {
// 如果收全,立即取出处理
std::array<tagPqData_Float, 4> all_data =
ClientManager::instance().get_and_clear_float_data(id, pq_data.name);
if (!all_data.empty()) {
//单个测点 4组数据处理逻辑
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];
std::string strScale;//电压等级
int nPTType = 0;//接线方式
ClientManager::instance().get_point_scale_and_pttype(
id, // 或使用id
pq_data.name, // 从报文中解析出的测点序号
strScale,
nPTType);
// 转换为Base64字符串
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;
//lnk20250708使用接口发送
time_t data_time = ConvertToTimestamp(avg_data.time);
enqueue_stat_pq(max_base64Str,
min_base64Str,
avg_base64Str,
cp95_base64Str,
data_time,
mac,
avg_data.name);
}
}
}
else {
// 处理获取变比值失败的情况
std::cerr << "Failed to get PT/CT ratio for device: "
<< mac << " lineno: " << pq_data.name << std::endl;
}
}
//数据组装完毕,修改为空闲状态等待下一项工作
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
}
else {
//未收全则直接结束处理,等待后续报文应答
return;
}
}
else {
// 装置答非所问异常
// 接收统计数据错误,调整为空闲状态,处理下一项工作。
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
}
break;
case DeviceState::READING_STATS_TIME:
// 读取统计时间状态
if (udata[8] == static_cast<unsigned char>(MsgResponseType::Response_StatTime)) {
std::vector<PointInfo> points;//装置测点信息
if (ClientManager::instance().get_device_points(mac, points)) {
// 成功获取测点信息
// 处理接收装置的时标
tagTime t3;
t3.SetStructBuf(parser.RecvData.data(), parser.RecvData.size());
int first = 0;//第一次标记
for (const auto& point : points) {
for (ushort i = 0; i < 4; i++)//每个测点需要单独召唤最大最小平均95概率值
{
auto sendbuff = generate_statequerystat_message(t3, point.nCpuNo, i);//组装询问统计数据报文
if (first == 0) {
//首次尝试组装报文 直接将当前状态调整 并等待最后启动发送
first++;
ClientManager::instance().change_device_state(id, DeviceState::READING_STATS, sendbuff);
}
else {
//非首次进入,将动作传入队列等待
ClientManager::instance().add_action_to_device(id, DeviceState::READING_STATS, sendbuff);
}
}
}
}
else {
// 未找到装置下属测点异常
// 接收统计数据时间错误,调整为空闲状态,处理下一项工作。
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
}
}
else {
// 装置答非所问异常
// 接收统计数据时间错误,调整为空闲状态,处理下一项工作。
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
}
break;
case DeviceState::READING_REALSTAT:
//读取实时数据状态
if (udata[8] == static_cast<unsigned char>(MsgResponseType::Response_New_3S)) {
unsigned char packet_type = udata[13];
//取监测点号
unsigned char cid = udata[12];
// 将数据添加到缓存
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
);
// 如果不是最后一个包,请求下一个包
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 {
// 获取并清空缓存
auto packets = ClientManager::instance().get_and_clear_realtime_packets(id);
// 按包类型排序01-06
std::sort(packets.begin(), packets.end(),
[](const ClientContext::RealtimePacket& a,
const ClientContext::RealtimePacket& b) {
return a.packet_type < b.packet_type;
});
RealtagPqDate_float realdata;
// 按顺序解析每个包
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;
}
}
std::string strScale;//电压等级
int nPTType = 0;//接线方式
ClientManager::instance().get_point_scale_and_pttype(
id, // 或使用id
static_cast<unsigned char>(udata[12]), // 从报文中解析出的测点序号
strScale,
nPTType);
// 转换为Base64字符串并发送lnk20250924
enqueue_realtime_pq(realdata, nPTType, cid, mac, id);
// 处理完成后重置状态
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
}
}
else {
// 装置答非所问异常
on_device_response_minimal(static_cast<int>(ResponseCode::INTERNAL_ERROR), id,0, static_cast<int>(DeviceState::READING_REALSTAT));
// 接收实时数据错误,调整为空闲状态,处理下一项工作。
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
}
break;
case DeviceState::READING_EVENTFILE:
// 暂态波形文件下载
if (udata[8] == static_cast<unsigned char>(MsgResponseType::Response_File_Download)) {
// 提取当前帧序号12-15字节大端序
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]);
// 提取总帧数16-19字节大端序
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;
// 将数据添加到缓存 去除数据体前14位 (逻辑稍后编写)
const uint8_t* data_ptr = parser.RecvData.data() + 14;
size_t data_size = parser.RecvData.size() - 14;
// 如果是第一帧,记录文件名
if (current_frame == 1) {
ClientManager::DownloadInfo info;
if (ClientManager::instance().parse_download_packet(id, info)) {
ClientManager::instance().update_current_filename(id, info.filename);
}
}
// 获取文件名
std::string filename = ClientManager::instance().get_current_filename(id);
// 添加到缓存
ClientManager::instance().add_file_packet_to_device(id, current_frame, data_ptr, data_size);
//std::cout << "fileinfo: " << info.filename << "/" << info.current_frame << std::endl;
//判断是否收全,未收全则继续发送报文,收全则取出所有缓存组装文件并保存至本地,推送消息
if (current_frame < total_frames) {
// 未收全,更新帧序号并保持状态,等待后续自动发送已修改的新报文
int nextframe = current_frame + 1;
auto downloadMsg = generate_downloadfile_message(nextframe, filename);
ClientManager::instance().change_device_state(id, DeviceState::READING_EVENTFILE, downloadMsg);
}
else {
// 已收全,在此处处理文件
std::cout << "mac: " << mac << " fileinfo: " << filename <<std::endl;
// 获取缓存中的所有分片
auto packets = ClientManager::instance().get_and_clear_file_packets(id);
// 合并文件内容
std::vector<unsigned char> file_data;
for (const auto& packet : packets) {
file_data.insert(file_data.end(), packet.begin(), packet.end());
}
// 保存文件
std::string wavefile = "wave"; // 使用MAC地址作为目录名
// 创建目录(如果不存在)
if (mkdir(wavefile.c_str(), 0777) != 0 && errno != EEXIST) {
std::cerr << "Failed to create directory: " << wavefile << std::endl;
}
// 保存文件
std::string mac_dir = wavefile + "/" + mac; // 使用MAC地址作为目录名
// 创建目录(如果不存在)
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;
//lnk20250805文件保存成功调用录波文件上送接口
update_qvvr_file_download(file_path, id);
}
else {
std::cerr << "Failed to save file: " << file_path
<< ", Error: " << strerror(errno) << std::endl;
// 文件保存失败,通知云端
/*on_device_response_minimal(static_cast<int>(ResponseCode::BAD_REQUEST),
id, 0, static_cast<int>(DeviceState::READING_EVENTFILE));*/
}
//当前文件下载完毕,调整为空闲处理下一项工作(如果这里后续有新文件等待下载,一般已经存入等待队列等候处理了,调成空闲状态后直接就会开始新文件的下载工作)
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
}
}
else {
// 装置答非所问异常
//on_device_response_minimal(static_cast<int>(ResponseCode::INTERNAL_ERROR), id, 0, static_cast<int>(DeviceState::READING_EVENTFILE));
// 接收波形文件数据错误,调整为空闲状态,处理下一项工作。
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
}
break;
case DeviceState::READING_FILEMENU:
//读取文件目录
if (udata[8] == static_cast<unsigned char>(MsgResponseType::Response_FileDir)) {
// 计算结构体大小
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;
// 遍历接收到的数据
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);
// 字节序转换 (大端 -> 小端)
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)));
// 打印文件名
std::cout << "file name:" << gbk_name << std::endl;
// 添加到文件列表
FileList.push_back(dir_info);
}
// 这里可以添加发送文件列表的逻辑
//send_file_list(id,FileList);//lnk20250813
filemenu_cache_put(id,FileList);
on_device_response_minimal(static_cast<int>(ResponseCode::OK), id, 0, static_cast<int>(DeviceState::READING_FILEMENU));
// 处理完成后重置状态
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
}
else {
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;
// 装置答非所问异常
on_device_response_minimal(static_cast<int>(ResponseCode::INTERNAL_ERROR), id, 0, static_cast<int>(DeviceState::READING_FILEMENU));
// 接收目录数据错误,调整为空闲状态,处理下一项工作。
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
}
break;
case DeviceState::READING_FILEDATA:
//下载文件数据 和暂态文件下载共用同一功能码
if (udata[8] == static_cast<unsigned char>(MsgResponseType::Response_File_Download))
{
// 提取当前帧序号12-15字节大端序
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]);
// 提取总帧数16-19字节大端序
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]);
//提取数据
const uint8_t* data_ptr = parser.RecvData.data() + 14;
size_t data_size = parser.RecvData.size() - 14;
// 如果是第一帧,记录文件名
if (current_frame == 1) {
ClientManager::DownloadInfo info;
if (ClientManager::instance().parse_download_packet(id, info)) {
ClientManager::instance().update_current_filename(id, info.filename);
}
}
// 获取文件名
std::string filename = ClientManager::instance().get_current_filename(id);
// 添加到缓存
ClientManager::instance().add_file_packet_to_device(id, current_frame, data_ptr, data_size);
//判断是否收全,未收全则继续发送报文,收全则取出所有缓存组装文件并保存至本地,推送消息
if (current_frame < total_frames) {
// 未收全,更新帧序号并保持状态,等待后续自动发送已修改的新报文
int nextframe = current_frame + 1;
auto downloadMsg = generate_downloadfile_message(nextframe, filename);
ClientManager::instance().change_device_state(id, DeviceState::READING_FILEDATA, downloadMsg);
}
else {
// 已收全,在此处处理文件
std::cout << "mac: " << mac << " fileinfo: " << filename << std::endl;
// 获取缓存中的所有分片
auto packets = ClientManager::instance().get_and_clear_file_packets(id);
// 合并文件内容
std::vector<unsigned char> file_data;
for (const auto& packet : packets) {
file_data.insert(file_data.end(), packet.begin(), packet.end());
}
// 保存文件
std::string wavefile = "download"; // 使用MAC地址作为目录名
// 创建目录(如果不存在)
if (mkdir(wavefile.c_str(), 0777) != 0 && errno != EEXIST) {
std::cerr << "Failed to create directory: " << wavefile << std::endl;
}
// 保存文件
std::string mac_dir = wavefile + "/" + mac; // 使用MAC地址作为目录名
// 创建目录(如果不存在)
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;
//使用接口上送文件lnk20250826
std::string filename;
SendFileWebAuto(id, file_path, file_path, filename);//如果是补招文件的下载,下载后也是直接上传,上传成功后更新补招状态即可
std::cout << "File upload: " << filename << std::endl;
//通知文件上传
on_device_response_minimal(static_cast<int>(ResponseCode::OK), id, 0, static_cast<int>(DeviceState::READING_FILEDATA));
}
else {
on_device_response_minimal(static_cast<int>(ResponseCode::INTERNAL_ERROR), id, 0, static_cast<int>(DeviceState::READING_FILEDATA));
std::cerr << "Failed to save file: " << file_path
<< ", Error: " << strerror(errno) << std::endl;
}
//当前文件下载完毕,调整为空闲处理下一项工作(如果这里后续有新文件等待下载,一般已经存入等待队列等候处理了,调成空闲状态后直接就会开始新文件的下载工作)
ClientManager::instance().change_device_state(id, DeviceState::READING_FILEDATA);
}
}
else {
// 装置答非所问异常
on_device_response_minimal(static_cast<int>(ResponseCode::INTERNAL_ERROR), id, 0, static_cast<int>(DeviceState::READING_FILEDATA));
// 下载文件数据错误,调整为空闲状态,处理下一项工作。
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
}
break;
case DeviceState::READING_FIXEDVALUE:
//读取指定测点定值数据
if (udata[8] == static_cast<unsigned char>(MsgResponseType::Response_FixValue)) {
// 确保数据长度足够包含测点序号
if (parser.RecvData.size() < 1) {
std::cout << "Invalid fix value data length" << std::endl;
on_device_response_minimal(static_cast<int>(ResponseCode::INTERNAL_ERROR), id, 0, static_cast<int>(DeviceState::READING_FIXEDVALUE));
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
break;
}
// 提取测点序号 (第一个字节)
uint8_t monitor_index = parser.RecvData[0];
std::cout << "Monitor Index: " << static_cast<int>(monitor_index) << std::endl;
// 计算有效数据长度 (排除测点序号)
size_t bufflen = parser.RecvData.size() - 1;
const size_t structlen = 4; // 每个浮点数占4字节
// 检查数据长度是否合法
if (bufflen % structlen != 0) {
std::cout << "Invalid fix value data length: " << bufflen
<< " (not multiple of 4)" << std::endl;
on_device_response_minimal(static_cast<int>(ResponseCode::INTERNAL_ERROR), id, 0, static_cast<int>(DeviceState::READING_FIXEDVALUE));
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
break;
}
// 存储浮点值的容器
std::vector<float> fList;
fList.reserve(bufflen / structlen); // 预分配空间
// 解析浮点数据 (从第二个字节开始)
for (size_t i = 1; i < parser.RecvData.size(); i += structlen) {
// 复制4字节数据
uint8_t bytes[4] = {
parser.RecvData[i],
parser.RecvData[i + 1],
parser.RecvData[i + 2],
parser.RecvData[i + 3]
};
// 翻转字节序 (大端转小端)
std::swap(bytes[0], bytes[3]);
std::swap(bytes[1], bytes[2]);
// 转换为float
float value;
memcpy(&value, bytes, sizeof(float));
fList.push_back(value);
}
// 打印解析结果
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;
}
//存储定值lnk20250827
save_set_value(id, monitor_index, fList);
//测试定值修改功能
//ClientManager::instance().set_fixedvalue_action_to_device(id, monitor_index, fList);
//定值读取完毕,调整为空闲,处理后续工作。
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
}
else {
// 装置答非所问异常
on_device_response_minimal(static_cast<int>(ResponseCode::INTERNAL_ERROR), id, 0, static_cast<int>(DeviceState::READING_FIXEDVALUE));
// 读取定值错误,调整为空闲状态,处理下一项工作。
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
}
break;
case DeviceState::READING_FIXEDVALUEDES:
//读取指定测点定值描述
if (udata[8] == static_cast<unsigned char>(MsgResponseType::Response_FixDes)) {
// 计算结构体大小
const size_t structlen = sizeof(DZ_TAB_STRUCT);
const size_t bufflen = parser.RecvData.size();
// 检查数据长度是否有效
if (bufflen == 0 || bufflen % structlen != 0) {
std::cerr << "Invalid fixdes data length: " << bufflen
<< " (expected multiple of " << structlen << ")" << std::endl;
on_device_response_minimal(static_cast<int>(ResponseCode::INTERNAL_ERROR), id, 0, static_cast<int>(DeviceState::READING_FIXEDVALUEDES));
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
break;
}
// 存储所有解析出的定值描述
std::vector<DZ_TAB_STRUCT> dz_list;
dz_list.reserve(bufflen / structlen);
// 遍历所有定值描述结构体
for (size_t i = 0, j = 1; i < bufflen; i += structlen, j++) {
// 复制数据到临时缓冲区
std::vector<uint8_t> buff(structlen);
memcpy(buff.data(), parser.RecvData.data() + i, structlen);
// 执行字节序转换与C#相同)
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
// 解析为结构体
DZ_TAB_STRUCT dz_info;
memcpy(&dz_info, buff.data(), structlen);
// 正确处理字符串 - 查找第一个'\0'作为结束符
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;
};
// 提取原始GBK字符串
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));
// 转换为可打印字符串(可选)(GBK编码)
std::string dz_name(dz_info.DZ_Name, name_len);
std::string dz_unit(dz_info.DZ_UNIT, unit_len);
// 保存到上下文
dz_list.push_back(dz_info);
// 调试输出(可选)
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;
}
//lnk20250828
// 提取测点序号 (第一个字节)
uint8_t monitor_index = parser.RecvData[0];
std::cout << "Monitor Index: " << static_cast<int>(monitor_index) << std::endl;
send_set_value_reply(id, monitor_index, dz_list);
on_device_response_minimal(static_cast<int>(ResponseCode::OK), id, 0, static_cast<int>(DeviceState::READING_FIXEDVALUE));
//定值描述读取完毕,调整为空闲,处理后续工作。
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
}
else {
// 装置答非所问异常
on_device_response_minimal(static_cast<int>(ResponseCode::INTERNAL_ERROR),id,0,static_cast<int>(DeviceState::READING_FIXEDVALUEDES));
// 读取定值描述,调整为空闲状态,处理下一项工作。
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
}
break;
case DeviceState::SET_FIXEDVALUE:
//设置装置定值
if (udata[8] == static_cast<unsigned char>(MsgResponseType::Response_NewACK)) {
std::cout << "set success" << mac << std::endl;
//响应lnk20250828
on_device_response_minimal(static_cast<int>(ResponseCode::OK),id,0,static_cast<int>(DeviceState::SET_FIXEDVALUE));
//定值设置成功,调整为空闲,处理后续工作。
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;
// 装置否定应答,定值设置失败
//响应lnk20250828
on_device_response_minimal(static_cast<int>(ResponseCode::BAD_REQUEST),id,0,static_cast<int>(DeviceState::SET_FIXEDVALUE));
// 设置装置定值失败,调整为空闲状态,处理下一项工作。
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
}
else {
// 装置答非所问异常
// 设置装置定值失败,调整为空闲状态,处理下一项工作。
//响应lnk20250828
on_device_response_minimal(static_cast<int>(ResponseCode::INTERNAL_ERROR),id,0,static_cast<int>(DeviceState::SET_FIXEDVALUE));
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
}
break;
case DeviceState::READING_INTERFIXEDVALUE:
//读取内部定值
if (udata[8] == static_cast<unsigned char>(MsgResponseType::Response_Read_InterFix)) {
// 获取数据长度
size_t bufflen = parser.RecvData.size();
const size_t structlen = 2; // 每个ushort占2字节
// 存储解析结果的容器
std::vector<ushort> fList;
fList.reserve(bufflen / structlen); // 预分配空间
// 解析每个ushort数据
for (size_t i = 0; i < bufflen; i += structlen) {
// 复制2字节数据
uint8_t bytes[2] = {
parser.RecvData[i],
parser.RecvData[i + 1]
};
// 翻转字节序 (大端转小端)
std::swap(bytes[0], bytes[1]);
// 转换为ushort - 使用memcpy确保正确处理字节序
ushort value;
memcpy(&value, bytes, sizeof(ushort));
fList.push_back(value);
}
// 打印解析结果(调试用)
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;
}
//存储定值lnk20250827
save_internal_value(id, fList);
//内部定值修改测试
//ClientManager::instance().set_interfixedvalue_action_to_device(id, fList);
//内部定值获取完毕,调整为空闲,处理后续工作。
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
}
else {
// 装置答非所问异常
on_device_response_minimal(static_cast<int>(ResponseCode::INTERNAL_ERROR), id, 0, static_cast<int>(DeviceState::READING_INTERFIXEDVALUE));
// 读取装置内部定值失败,调整为空闲状态,处理下一项工作。
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
}
break;
case DeviceState::READING_INTERFIXEDVALUEDES:
//读取内部定值描述
if (udata[8] == static_cast<unsigned char>(MsgResponseType::Response_Read_InterFixDes)) {
// 获取接收数据
std::vector<uint8_t>& recvData = parser.RecvData;
size_t bufflen = recvData.size();
const size_t structlen = sizeof(NameFixValue);
// 存储解析结果的向量
std::vector<NameFixValue> fixValueList;
// 检查数据长度是否合法
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);
on_device_response_minimal(static_cast<int>(ResponseCode::INTERNAL_ERROR), id, 0, static_cast<int>(DeviceState::READING_INTERFIXEDVALUEDES));
break;
}
else
{
// 计算结构体数量
size_t structCount = bufflen / structlen;
fixValueList.reserve(structCount);
// 遍历所有结构体
for (size_t i = 0, k = 1; i < bufflen; i += structlen, k++)
{
// 复制当前结构体数据到缓冲区
std::vector<uint8_t> buff(structlen);
memcpy(buff.data(), recvData.data() + i, structlen);
// 翻转数据类型DataType (偏移22, 2字节)
ReversalBuff(buff.data(), 22, 2);
// 翻转最小值MinValue (偏移24, 2字节)
ReversalBuff(buff.data(), 24, 2);
// 翻转最大值MaxValue (偏移26, 2字节)
ReversalBuff(buff.data(), 26, 2);
// 翻转缺省值DefaultValue (偏移28, 2字节)
ReversalBuff(buff.data(), 28, 2);
// 解析为结构体
NameFixValue dz_info;
memcpy(&dz_info, buff.data(), structlen);
// 添加到结果列表
fixValueList.push_back(dz_info);
// 调试输出
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;
}
}
//lnk20250905
save_internal_info(id, fixValueList);
//内部定值描述获取完毕,调整为空闲状态,处理下一项工作。
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
}
else {
// 装置答非所问异常
on_device_response_minimal(static_cast<int>(ResponseCode::INTERNAL_ERROR), id, 0, static_cast<int>(DeviceState::READING_INTERFIXEDVALUEDES));
// 读取装置内部定值描述失败,调整为空闲状态,处理下一项工作。
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
}
break;
case DeviceState::READING_CONTROLWORD:
//读取控制字描述
if (udata[8] == static_cast<unsigned char>(MsgResponseType::Response_Read_InterFixDes)) {
// 计算结构体大小
const size_t structlen = sizeof(DZ_kzz_bit);
const size_t bufflen = parser.RecvData.size();
// 检查数据长度是否有效
if (bufflen == 0 || bufflen % structlen != 0) {
std::cerr << "Invalid control word data length: " << bufflen
<< " (expected multiple of " << structlen << ")" << std::endl;
on_device_response_minimal(static_cast<int>(ResponseCode::INTERNAL_ERROR), id, 0, static_cast<int>(DeviceState::READING_CONTROLWORD));
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
break;
}
// 存储解析结果
std::vector<DZ_kzz_bit> control_words;
control_words.reserve(bufflen / structlen);
// 遍历所有控制字描述结构体
for (size_t i = 0; i < bufflen; i += structlen) {
// 复制数据到临时缓冲区
std::vector<uint8_t> buff(structlen);
memcpy(buff.data(), parser.RecvData.data() + i, structlen);
// 解析为结构体
DZ_kzz_bit dz_info;
memcpy(&dz_info, buff.data(), structlen);
// 正确处理字符串 - 查找第一个'\0'作为结束符
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;
};
// 提取原始GBK字符串
size_t name_len = find_string_end(dz_info.kzz_bit, sizeof(dz_info.kzz_bit));
// 直接存储原始GBK数据不转换UTF-8
control_words.push_back(dz_info);
// 调试输出(可选)
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;
}
send_internal_value_reply(id, control_words);
on_device_response_minimal(static_cast<int>(ResponseCode::OK), id, 0, static_cast<int>(DeviceState::READING_INTERFIXEDVALUE));
// 控制字描述读取完毕,调整为空闲,处理后续工作
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
}
else {
// 装置答非所问异常
on_device_response_minimal(static_cast<int>(ResponseCode::INTERNAL_ERROR), id, 0, static_cast<int>(DeviceState::READING_CONTROLWORD));
// 读取装置控制字描述失败,调整为空闲状态,处理下一项工作。
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
}
break;
case DeviceState::SET_INTERFIXEDVALUE:
//设置内部定值
if (udata[8] == static_cast<unsigned char>(MsgResponseType::Response_NewACK)) {
std::cout << "set success" << mac << std::endl;
//内部定值设置成功,调整为空闲,处理后续工作。
on_device_response_minimal(static_cast<int>(ResponseCode::OK), id, 0, static_cast<int>(DeviceState::SET_INTERFIXEDVALUE));
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;
// 装置否定应答,内部定值设置失败
on_device_response_minimal(static_cast<int>(ResponseCode::BAD_REQUEST), id, 0, static_cast<int>(DeviceState::SET_INTERFIXEDVALUE));
// 设置装置内部定值失败,调整为空闲状态,处理下一项工作。
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
}
else {
// 装置答非所问异常
on_device_response_minimal(static_cast<int>(ResponseCode::INTERNAL_ERROR), id, 0, static_cast<int>(DeviceState::SET_INTERFIXEDVALUE));
// 设置装置内部定值失败,调整为空闲状态,处理下一项工作。
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
}
break;
case DeviceState::READING_RUNNINGINFORMATION_1:
//读取装置运行信息(主动触发)
if (udata[8] == static_cast<unsigned char>(MsgResponseType::Response_Read_RunningInformation)) {
// 获取解析后的数据体
std::vector<uint8_t>& recvData = parser.RecvData;
// 检查数据长度是否足够
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;
}
// 提取有效载荷长度
size_t payloadLength = recvData.size() - 2;
// 复制有效载荷数据
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;
}
// 转换为UTF-8字符串
std::string payload(payloadBytes.begin(), payloadBytes.end());
// 定义类似New_MachMessage的结构体
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;
// 辅助函数:去除字符串两端的引号
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;
};
// 辅助函数处理CPU负载值
auto processCpuLoad = [](const std::string& cpuValue) -> std::string {
if (cpuValue.empty()) return cpuValue;
// 处理多核格式(如"39_38"
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;
}
cores.push_back(cpuValue.substr(start)); // 添加最后一部分
for (auto& core : cores) {
// 手动转换整数替代std::stoi
const char* str = core.c_str();
char* endptr = nullptr;
long value = strtol(str, &endptr, 10);
// 检查转换是否有效
if (endptr != str && *endptr == '\0') {
// 校正超范围值
if (value > 100) value /= 100;
core = std::to_string(value);
}
// 转换失败保持原值
}
std::string result;
for (size_t i = 0; i < cores.size(); ++i) {
if (i > 0) result += '_';
result += cores[i];
}
return result;
}
// 处理单核格式
else {
const char* str = cpuValue.c_str();
char* endptr = nullptr;
long value = strtol(str, &endptr, 10);
// 检查转换是否有效
if (endptr != str && *endptr == '\0') {
if (value > 100) value /= 100;
return std::to_string(value);
}
return cpuValue;
}
};
// 分割字段并处理
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) {
// 跳过空字段
if (field.empty()) continue;
// 查找冒号位置
size_t colonPos = field.find(':');
if (colonPos == std::string::npos || colonPos == 0 || colonPos == field.length() - 1) {
continue;
}
// 分割键值对
std::string key = field.substr(0, colonPos);
std::string value = field.substr(colonPos + 1);
// 去除键的空白
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);
}
// 去除值的空白
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);
}
// 去除值两端的引号
if (value.size() >= 2 && value.front() == '"' && value.back() == '"') {
value = value.substr(1, value.size() - 2);
}
// 尝试将键转换为整数
const char* keyStr = key.c_str();
char* endPtr = nullptr;
long fieldId = strtol(keyStr, &endPtr, 10);
// 检查转换是否有效
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;
}
}
}
// 特殊处理CPU负载
result.CpuLoad = processCpuLoad(result.CpuLoad);
// 打印解析结果(实际应用中可替换为其他处理逻辑)
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;
//读取装置运行信息(主动触发)成功,调整为空闲,处理后续工作。
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
}
else {
// 装置答非所问异常
// 读取装置运行信息(主动触发)失败,调整为空闲状态,处理下一项工作。
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
}
break;
case DeviceState::READING_RUNNINGINFORMATION_2:
//读取装置运行信息(定时触发) 接收与解析和主动触发一致,仅修改数据发送部分
if (udata[8] == static_cast<unsigned char>(MsgResponseType::Response_Read_RunningInformation)) {
// 获取解析后的数据体
std::vector<uint8_t>& recvData = parser.RecvData;
// 检查数据长度是否足够
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;
}
// 提取有效载荷长度
size_t payloadLength = recvData.size() - 2;
// 复制有效载荷数据
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;
}
// 转换为UTF-8字符串
std::string payload(payloadBytes.begin(), payloadBytes.end());
// 定义类似New_MachMessage的结构体
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;
// 辅助函数:去除字符串两端的引号
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;
};
// 辅助函数处理CPU负载值
auto processCpuLoad = [](const std::string& cpuValue) -> std::string {
if (cpuValue.empty()) return cpuValue;
// 处理多核格式(如"39_38"
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;
}
cores.push_back(cpuValue.substr(start)); // 添加最后一部分
for (auto& core : cores) {
// 手动转换整数替代std::stoi
const char* str = core.c_str();
char* endptr = nullptr;
long value = strtol(str, &endptr, 10);
// 检查转换是否有效
if (endptr != str && *endptr == '\0') {
// 校正超范围值
if (value > 100) value /= 100;
core = std::to_string(value);
}
// 转换失败保持原值
}
std::string result;
for (size_t i = 0; i < cores.size(); ++i) {
if (i > 0) result += '_';
result += cores[i];
}
return result;
}
// 处理单核格式
else {
const char* str = cpuValue.c_str();
char* endptr = nullptr;
long value = strtol(str, &endptr, 10);
// 检查转换是否有效
if (endptr != str && *endptr == '\0') {
if (value > 100) value /= 100;
return std::to_string(value);
}
return cpuValue;
}
};
// 分割字段并处理
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) {
// 跳过空字段
if (field.empty()) continue;
// 查找冒号位置
size_t colonPos = field.find(':');
if (colonPos == std::string::npos || colonPos == 0 || colonPos == field.length() - 1) {
continue;
}
// 分割键值对
std::string key = field.substr(0, colonPos);
std::string value = field.substr(colonPos + 1);
// 去除键的空白
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);
}
// 去除值的空白
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);
}
// 去除值两端的引号
if (value.size() >= 2 && value.front() == '"' && value.back() == '"') {
value = value.substr(1, value.size() - 2);
}
// 尝试将键转换为整数
const char* keyStr = key.c_str();
char* endPtr = nullptr;
long fieldId = strtol(keyStr, &endPtr, 10);
// 检查转换是否有效
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;
}
}
}
// 特殊处理CPU负载
result.CpuLoad = processCpuLoad(result.CpuLoad);
// 打印解析结果(实际应用中可替换为其他处理逻辑)
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;
//读取装置运行信息(主动触发)成功,调整为空闲,处理后续工作。
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
}
else {
// 装置答非所问异常
// 读取装置运行信息(定时触发)失败,调整为空闲状态,处理下一项工作。
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
}
break;
case DeviceState::READING_DEVVERSION:
//读取装置版本配置信息(功能码同运行信息读取)(运维协议确认对时版本,电度与高频谐波开关,稳态间隔获取,版本配置上送)
if (udata[8] == static_cast<unsigned char>(MsgResponseType::Response_Read_RunningInformation)) {
// 获取解析后的数据体
std::vector<uint8_t>& recvData = parser.RecvData;
// 检查数据长度是否足够
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;
}
// 提取有效载荷长度
size_t payloadLength = recvData.size() - 2;
// 复制有效载荷数据
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;
}
// 转换为UTF-8字符串
std::string payload(payloadBytes.begin(), payloadBytes.end());
// 定义存储装置版本信息的结构体
struct DeviceVersionInfo {
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: 装置功能配置
} versionInfo;
// 分割字段
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) {
if (field.empty()) continue;
// 分割键值对
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);
// 去除键值两端的空白和引号
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);
// 转换为信息编码ID
try {
int fieldId = std::stoi(key);
switch (fieldId) {
// 字符串类型字段
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;
// 数值类型字段
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;
// 十六进制字段51+
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;
}
}
//云协议版本非空则赋值未赋值则使用默认的V1.0
if (!versionInfo.CloudProtocolVer.empty()) {
ClientManager::instance().set_versioninformation(id, versionInfo.CloudProtocolVer);
}
// 打印解析结果
std::cout << "Device Version Info (" << mac << "):\n"
<< " 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"
<< " Device Functions: 0x" << versionInfo.DeviceFunctions << std::dec << "\n";
//读取装置版本配置信息成功,调整为空闲,处理后续工作。
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
}
else {
// 装置答非所问异常
// 读取装置版本配置信息失败,调整为空闲状态,处理下一项工作。
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
}
break;
case DeviceState::SET_RIGHTTIME:
//设置装置对时
if (udata[8] == static_cast<unsigned char>(MsgResponseType::Response_NewACK)) {
std::cout << "set success" << mac << std::endl;
//对时设置成功,调整为空闲,处理后续工作。
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;
// 装置否定应答,对时设置失败
// 设置对时失败,调整为空闲状态,处理下一项工作。
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
}
else {
// 装置答非所问异常
// 设置对时失败,调整为空闲状态,处理下一项工作。
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
}
break;
case DeviceState::READING_EVENTLOG:
//补招装置日志
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) {
// 提取当前帧
int current_frame = 0;
if (parser.RecvData.size() >= 4) {
std::vector<unsigned char> frame_data(parser.RecvData.begin(), parser.RecvData.begin() + 4);
std::reverse(frame_data.begin(), frame_data.end()); // 字节反转
current_frame = *reinterpret_cast<int*>(frame_data.data());
}
// 提取总帧数
int total_frames = 0;
if (parser.RecvData.size() >= 8) {
std::vector<unsigned char> total_frame_data(parser.RecvData.begin() + 4, parser.RecvData.begin() + 8);
std::reverse(total_frame_data.begin(), total_frame_data.end()); // 字节反转
total_frames = *reinterpret_cast<int*>(total_frame_data.data());
}
// 提取文件总大小
int file_size = 0;
if (parser.RecvData.size() >= 12) {
std::vector<unsigned char> size_data(parser.RecvData.begin() + 8, parser.RecvData.begin() + 12);
std::reverse(size_data.begin(), size_data.end()); // 字节反转
file_size = *reinterpret_cast<int*>(size_data.data());
}
// 提取CRC校验码
uint16_t crc = 0;
if (parser.RecvData.size() >= 14) {
std::vector<unsigned char> crc_data(parser.RecvData.begin() + 12, parser.RecvData.begin() + 14);
std::reverse(crc_data.begin(), crc_data.end()); // 字节反转
crc = *reinterpret_cast<uint16_t*>(crc_data.data());
}
// 提取文件数据
std::vector<unsigned char> file_data;
if (parser.RecvData.size() > 14) {
file_data.assign(parser.RecvData.begin() + 14, parser.RecvData.end());
}
// 将数据添加到缓存使用类似READING_STATS的逻辑
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;
// 检查是否收全所有帧
if (complete) {
// 1. 获取并清空缓存数据包
auto packets = ClientManager::instance().get_and_clear_event_packets(id);
// 2. 按帧序号排序
std::sort(packets.begin(), packets.end(),
[](const ClientContext::StatPacket& a, const ClientContext::StatPacket& b) {
return a.packet_index < b.packet_index;
});
// 3. 解析每帧数据并提取数据体
std::vector<unsigned char> full_data;
for (const auto& packet : packets) {
// 将数据体添加到完整序列
full_data.insert(full_data.end(),
packet.data.begin(),
packet.data.end());
}
//确认待补招序号 // 获取测点参数
int event_lineid = 0;
std::string strScale;//电压等级
int nPTType;//接线方式
float fPT = 1.0f;
float fCT = 1.0f;
if (!ClientManager::instance().get_event_lineid(id, event_lineid)) {
//取出补招序号失败!暂态补招结束
//补招装置日志获取完毕,调整为空闲状态,处理下一项工作。
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)) {
//取出解析方式PTCT,电压等级失败!暂态补招结束
//补招装置日志获取完毕,调整为空闲状态,处理下一项工作。
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
break;
}
// ========== 新增解析full_data中的NewTaglogbuffer对象列表 ==========
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()) {
// 读取头部
NewHeadTaglogbuffer head;
memcpy(&head, full_data.data() + offset, headSize);
head.convertByteOrder(); // 转换字节序
uint32_t logParaNum = head.LogParaNum;
// 计算身体部分在full_data中占用的空间最少4个身体项的空间
size_t bodySpace;
if (logParaNum <= 4) {
bodySpace = 4 * bodyItemSize;
}
else {
bodySpace = logParaNum * bodyItemSize;
}
// 检查剩余数据是否足够
if (offset + headSize + bodySpace > full_data.size()) {
std::cerr << "Insufficient data for event body at offset " << offset << std::endl;
break;
}
// 创建事件对象并设置头部
NewTaglogbuffer event;
event.head = head;
event.bodyList.resize(logParaNum);
// 解析身体部分
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;
}
//当前解析事件和待补招测点一致,则加入队列
if (event.head.name == event_lineid) {
eventList.push_back(event);
}
// 移动偏移量,跳过头部和身体占用空间(包括填充)
offset += headSize + bodySpace;
}
// 现在eventList中包含所有解析的事件对象可以在这里进行处理
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);
// 使用记录数据(示例:打印到控制台)
std::cout << "事件类型: " << record.nType
<< ", 持续时间: " << record.fPersisstime << "s"
<< ", 特征幅值: " << record.fMagntitude << " pu"
<< ", 时间戳: " << record.triggerTimeMs << "ms" << std::endl;
//记录补招上来的暂态事件,如果需要前置自行下载波形才需要这个接口
/*append_qvvr_event(id,event.head.name,
record.nType,record.fPersisstime,record.fMagntitude,record.triggerTimeMs,record.phase);*/
//直接发走暂态事件
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));
recordlist.push_back(record);
}
//暂时移除CRC校验相关
//// ========== 新增 CRC 验证 ==========
//if (!full_data.empty()) {
// // 计算接收数据的 CRC
// uint16_t calculated_crc = crc_16_new(full_data.data(), full_data.size());
// // 比较计算出的 CRC 和从报文中提取的 CRC
// if (calculated_crc == crc) {
// std::cout << "CRC verification passed for event log data." << std::endl;
// // 这里可以继续处理完整数据
// }
// else {
// std::cerr << "CRC verification failed! Expected: " << crc
// << ", Calculated: " << calculated_crc << std::endl;
// // 处理 CRC 校验失败的情况
// }
//}
//else {
// //收取缓存文件异常,结束补招处理
// std::cerr << "No data received for event log." << std::endl;
//}
}
else {
//未收全则直接结束处理,等待后续报文应答
return;
}
}
//补招装置日志获取完毕,调整为空闲状态,处理下一项工作。
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)) {
//0x0c错误码代表询问暂态数据不存在通知前台当前时间段无暂态
std::cout << "not find event " << mac << std::endl;
//lnk20251023
on_device_response_minimal(static_cast<int>(ResponseCode::NOT_FOUND), id, 0, static_cast<int>(DeviceState::READING_EVENTLOG));
}
else if (udata[10] == static_cast<unsigned char>(0x06)) {
//0x0c错误码代表补招方法参数错误通知前台参数异常
//lnk20251023
on_device_response_minimal(static_cast<int>(ResponseCode::FORBIDDEN), id, 0, static_cast<int>(DeviceState::READING_EVENTLOG));
}
else {
//其余错误码代表异常情况
//lnk20251023
on_device_response_minimal(static_cast<int>(ResponseCode::BAD_REQUEST), id, 0, static_cast<int>(DeviceState::READING_EVENTLOG));
}
// 装置否定
// 补招装置日志失败,调整为空闲状态,处理下一项工作。
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;
// 装置答非所问异常
// 补招装置日志失败,调整为空闲状态,处理下一项工作。
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
}
break;
case DeviceState::CUSTOM_ACTION:
// 自定义动作状态
std::cout << "CUSTOM_ACTION state: Processing custom response from " << mac << std::endl;
// 这里添加处理自定义动作响应的逻辑
// 处理完成后标记状态完成
ClientManager::instance().change_device_state(id, DeviceState::IDLE);
break;
default:
std::cerr << "Unknown state: " << static_cast<int>(currentState)
<< " for device " << id << std::endl;
break;
}
// 无论何种状态,处理完成后触发后续状态处理
ClientManager::instance().post_message_processing(id);
}
}
}