From 5539c10c0de1e4172c33738b5ccbdcf8e3399301 Mon Sep 17 00:00:00 2001 From: zw <3466561528@qq.com> Date: Tue, 5 Aug 2025 15:41:04 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9A=E5=80=BC=E4=B8=8E=E5=86=85=E9=83=A8?= =?UTF-8?q?=E5=AE=9A=E5=80=BC=E4=BF=AE=E6=94=B9=E5=AE=8C=E6=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LFtid1056/PQSMsg.cpp | 154 +++++++++++++++ LFtid1056/PQSMsg.h | 94 +++++++++- LFtid1056/client2.cpp | 170 +++++++++++++++++ LFtid1056/client2.h | 39 +++- LFtid1056/dealMsg.cpp | 386 +++++++++++++++++++++++++++++++++++++- LFtid1056/main_thread.cpp | 2 +- 6 files changed, 827 insertions(+), 18 deletions(-) diff --git a/LFtid1056/PQSMsg.cpp b/LFtid1056/PQSMsg.cpp index cb30432..51e94ba 100644 --- a/LFtid1056/PQSMsg.cpp +++ b/LFtid1056/PQSMsg.cpp @@ -23,6 +23,14 @@ float ShorToFloat1000(short num) { float ShorToFloat10000(short num) { return static_cast(num) / 10000.0f; } + +// 字节序转换函数 +void ReversalBuff(uint8_t* buff, int start, int length) { + for (int i = 0; i < length / 2; i++) { + std::swap(buff[start + i], buff[start + length - 1 - i]); + } +} + // 辅助函数:解析MAC地址并填充到缓冲区 void GetMAC(const std::string& strMAC, std::vector& packet, size_t startIndex) { // 移除所有空格和短横线 @@ -405,4 +413,150 @@ std::vector generate_getfilemenu_message(const std::string& filed // 调用GetMsg生成完整报文 return GetMsg(dataBuf, static_cast(MsgRequestType::Request_FileDir)); +} + +// 请求定值报文 传入测点号 +std::vector generate_requestFixValue_message(unsigned char nCpuNo) { + // 参数检查 + if (nCpuNo < 1 || nCpuNo > 6) + return std::vector(); + + // 创建4字节缓冲区并初始化 + std::vector DataBuf(4, 0x00); + DataBuf[3] = nCpuNo; // CPU编号放在第4字节 + + // 生成完整报文 + return GetMsg(DataBuf, static_cast(MsgRequestType::Request_FixValue)); +} + +// 请求定值描述报文 +std::vector generate_requestFixDes_message() { + // 创建3字节缓冲区并初始化 + std::vector DataBuf(3, 0x00); + + // 生成完整报文 + return GetMsg(DataBuf, static_cast(MsgRequestType::Request_FixDes)); +} + +// 设置定值报文 传入测点号+修改的定值数据队列 +std::vector generate_requestSetFixValue_message( + unsigned char nCpuNo, + const std::vector& value) +{ + // 参数检查 + if (nCpuNo < 1 || nCpuNo > 6) + return std::vector(); + + // 计算缓冲区大小: 4(头部) + 浮点数组长度*4 + const size_t bufSize = 4 + value.size() * 4; + std::vector DataBuf(bufSize, 0x00); + DataBuf[3] = nCpuNo; // CPU编号放在第4字节 + + // 处理每个浮点值 + for (size_t i = 0; i < value.size(); i++) { + // 将float转换为网络字节序 + uint32_t intValue; + memcpy(&intValue, &value[i], sizeof(float)); + uint32_t netValue = htonl(intValue); + + // 将转换后的值复制到缓冲区 + unsigned char* dest = DataBuf.data() + 4 + i * 4; + memcpy(dest, &netValue, sizeof(uint32_t)); + } + + // 生成完整报文 + return GetMsg(DataBuf, static_cast(MsgRequestType::Request_Set_Fix)); +} + +/** + * @brief 生成请求装置内部定值的报文 + * @return 包含完整报文的字节向量 + */ +std::vector generate_requestinterfixvalue_message() +{ + // 创建3字节数据缓冲区并初始化为0 + std::vector dataBuf(3, 0x00); + + // 调用通用报文生成函数 + return GetMsg(dataBuf, static_cast(MsgRequestType::Request_Read_InterFix)); +} + +/** + * @brief 生成请求装置内部定值描述的报文 + * @param nDesCW 描述类型 (1-内部定值描述, 2-控制字描述) + * @return 包含完整报文的字节向量,参数无效时返回空向量 + */ +std::vector generate_requestinterfixdes_message(unsigned char nDesCW) +{ + // 参数有效性检查 + if (nDesCW < 1 || nDesCW > 2) { + return std::vector(); + } + + // 创建3字节数据缓冲区 + std::vector dataBuf(3, 0x00); + + // 设置描述类型 + dataBuf[0] = nDesCW; + + // 调用通用报文生成函数 + return GetMsg(dataBuf, static_cast(MsgRequestType::Request_Read_InterFixDes)); +} + +/** + * @brief 生成设置装置内部定值的报文 + * @param values 要设置的定值数组 (ushort值) + * @return 包含完整报文的字节向量 + */ +std::vector generate_requestsetinterfixvalue_message(const std::vector& values) +{ + // 计算缓冲区大小: 3字节头部 + 每个值占2字节 + const size_t bufSize = 3 + values.size() * 2; + std::vector dataBuf(bufSize, 0x00); + + // 填充定值数据 + for (size_t i = 0; i < values.size(); i++) { + // 将ushort值转换为网络字节序 (大端) + uint16_t netValue = htons(values[i]); + + // 计算目标位置偏移量 (跳过3字节头部) + unsigned char* dest = dataBuf.data() + 3 + i * 2; + + // 复制转换后的值到缓冲区 + memcpy(dest, &netValue, sizeof(uint16_t)); + } + + // 调用通用报文生成函数 + return GetMsg(dataBuf, static_cast(MsgRequestType::Request_Set_InterFix)); +} + +/** + * @brief 生成设置装置内部定值的报文 + * @param values 要设置的定值数组 (ushort值) + * @return 包含完整报文的字节向量 + */ +std::vector generate_requestsetinterfixvalue_message_new(const std::vector& value) +{ + // 计算缓冲区大小: 3字节头部 + 每个值占2字节 + const size_t bufSize = 3 + value.size() * 2; + std::vector dataBuf(bufSize, 0x00); + + // 填充定值数据 + for (size_t i = 0; i < value.size(); i++) { + // 将值转换为字节数组 + uint16_t rawValue = value[i]; + unsigned char* bytes = reinterpret_cast(&rawValue); + + // 反转字节序(模拟C#的ReversalBuff) + std::swap(bytes[0], bytes[1]); + + // 计算目标位置偏移量 (跳过3字节头部) + unsigned char* dest = dataBuf.data() + 3 + i * 2; + + // 复制转换后的值到缓冲区 + memcpy(dest, bytes, sizeof(uint16_t)); + } + + // 调用通用报文生成函数 + return GetMsg(dataBuf, static_cast(MsgRequestType::Request_Set_InterFix)); } \ No newline at end of file diff --git a/LFtid1056/PQSMsg.h b/LFtid1056/PQSMsg.h index 9bc59f3..71b9f8a 100644 --- a/LFtid1056/PQSMsg.h +++ b/LFtid1056/PQSMsg.h @@ -27,7 +27,19 @@ enum class MsgRequestType : unsigned char { //下载装置文件 Request_File_Download = 0x07, //询问文件目录 - Request_FileDir = 0x02 + Request_FileDir = 0x02, + //询问装置定值 + Request_FixValue = 0x20, + //询问装置定值描述 + Request_FixDes = 0x21, + //设置装置定值 + Request_Set_Fix = 0x22, + //询问内部定值 + Request_Read_InterFix = 0x23, + //询问内部定值描述 内部定值or控制字 + Request_Read_InterFixDes = 0x24, + //设置内部定值 + Request_Set_InterFix = 0x25 }; // 接收报文功能码枚举 enum class MsgResponseType : unsigned char { @@ -44,7 +56,23 @@ enum class MsgResponseType : unsigned char { //下载装置文件 Response_File_Download = 0x87, //询问文件目录 - Response_FileDir = 0x82 + Response_FileDir = 0x82, + //询问装置定值 + Response_FixValue = 0xA0, + //询问装置定值描述 + Response_FixDes = 0xA1, + //设置装置定值(未使用,采用默认肯定与否定应答) + Response_Set_Fix = 0xA2, + //询问内部定值 + Response_Read_InterFix = 0xA3, + //询问内部定值描述 + Response_Read_InterFixDes = 0xA4, + //设置内部定值(未使用,采用默认肯定与否定应答) + Response_Set_InterFix = 0xA5, + //默认肯定应答 + Response_NewACK = 0x40, + //默认否定应答 + Response_NewNACK = 0x41 }; //基础消息结构 class MessageParser { @@ -2061,6 +2089,42 @@ struct tag_dir_info { }; #pragma pack(pop) +// 定值描述文件 +struct DZ_TAB_STRUCT { + short LN_Num; // 监测点 + short DZ_Num; // 序号 + char DZ_Name[66]; // 名称 + short DZ_Type; // 定值类型 + float DZ_Min; // 最小值 + float DZ_Max; // 最大值 + float DZ_Default; // 缺省值 + char DZ_UNIT[10]; // 量纲 +}; + +// 控制字描述结构体定义 +#pragma pack(push, 1) // 确保内存紧凑布局 +struct DZ_kzz_bit { + char kzz_bit[40]; // 名称,固定40字节 + char bit_enable; // 是否使用标志(1字节) +}; +#pragma pack(pop) // 恢复默认对齐 + +// 单个内部定值描述结构体 +struct NameFixValue +{ + char uNumber; // 序号 + char sFixValueName[20]; // 名称 (固定20字节) + char uBY; // 备用 + uint16_t DataType; // 数据类型 + uint16_t MinValue; // 最小值 + uint16_t MaxValue; // 最大值 + uint16_t DefaultValue; // 缺省值 + char sDimension[4]; // 单位 (固定4字节) +}; + +// 字节序转换函数 +void ReversalBuff(uint8_t* buff, int start, int length); + // 生成带协议头的二进制报文 std::vector generate_binary_message( uint16_t msg_type, @@ -2077,4 +2141,28 @@ std::vector generate_realstat_message(unsigned char nCpuNo, unsig //生成文件下载请求报文 当前帧序号+文件名 std::vector generate_downloadfile_message(int frameIndex, const std::string& fileName); //文件目录读取报文 传入需要读取的文件路径 -std::vector generate_getfilemenu_message(const std::string& filedir); \ No newline at end of file +std::vector generate_getfilemenu_message(const std::string& filedir); +// 请求定值报文 传入测点号 +std::vector generate_requestFixValue_message(unsigned char nCpuNo); +// 请求定值描述报文 +std::vector generate_requestFixDes_message(); +// 设置定值报文 传入测点号+修改的定值数据队列 +std::vector generate_requestSetFixValue_message(unsigned char nCpuNo, const std::vector& value); +/** + * @brief 生成请求装置内部定值的报文 + * @return 包含完整报文的字节向量 + */ +std::vector generate_requestinterfixvalue_message(); +/** + * @brief 生成请求装置内部定值描述的报文 + * @param nDesCW 描述类型 (1-内部定值描述, 2-控制字描述) + * @return 包含完整报文的字节向量,参数无效时返回空向量 + */ +std::vector generate_requestinterfixdes_message(unsigned char nDesCW); +/** + * @brief 生成设置装置内部定值的报文 + * @param values 要设置的定值数组 (ushort值) + * @return 包含完整报文的字节向量 + */ +std::vector generate_requestsetinterfixvalue_message(const std::vector& values); +std::vector generate_requestsetinterfixvalue_message_new(const std::vector& value); \ No newline at end of file diff --git a/LFtid1056/client2.cpp b/LFtid1056/client2.cpp index d84d416..eea3622 100644 --- a/LFtid1056/client2.cpp +++ b/LFtid1056/client2.cpp @@ -1081,6 +1081,176 @@ bool ClientManager::add_file_download_action_to_device( return false; // 璁惧鏈壘鍒 } +//鑾峰彇鎸囧畾瑁呯疆鎸囧畾娴嬬偣涓嬬殑瀹氬兼暟鎹 +bool ClientManager::get_fixedvalue_action_to_device(const std::string& identifier, ushort point_id) { + std::lock_guard lock(mutex_); + + // 鏌ユ壘鍖归厤鐨勮澶 + for (auto& pair : clients_) { + auto& ctx = pair.second; + if (ctx->device_info.device_id == identifier || + ctx->device_info.mac == identifier) + { + // 鐢熸垚瀹氬兼暟鎹姤鏂 + auto packet = generate_requestFixValue_message(point_id); + + // 娣诲姞鍔ㄤ綔鍒伴槦鍒 (鐘舵: 璇诲彇鏂囦欢鐩綍) + ctx->add_action(DeviceState::READING_FIXEDVALUE, packet); + + // 濡傛灉褰撳墠绌洪棽鍒欑珛鍗虫墽琛 + if (ctx->current_state_ == DeviceState::IDLE) { + ctx->process_next_action(); + } + + return true; // 鎴愬姛娣诲姞 + } + } + return false; // 璁惧鏈壘鍒 +} + +//鑾峰彇鎸囧畾瑁呯疆鐨勫畾鍊兼弿杩 +bool ClientManager::get_fixedvaluedes_action_to_device(const std::string& identifier) { + std::lock_guard lock(mutex_); + + // 鏌ユ壘鍖归厤鐨勮澶 + for (auto& pair : clients_) { + auto& ctx = pair.second; + if (ctx->device_info.device_id == identifier || + ctx->device_info.mac == identifier) + { + // 鐢熸垚瀹氬兼弿杩版姤鏂 + auto packet = generate_requestFixDes_message(); + + // 娣诲姞鍔ㄤ綔鍒伴槦鍒 (鐘舵: 璇诲彇鏂囦欢鐩綍) + ctx->add_action(DeviceState::READING_FIXEDVALUEDES, packet); + + // 濡傛灉褰撳墠绌洪棽鍒欑珛鍗虫墽琛 + if (ctx->current_state_ == DeviceState::IDLE) { + ctx->process_next_action(); + } + + return true; // 鎴愬姛娣诲姞 + } + } + return false; // 璁惧鏈壘鍒 +} + +//璁剧疆鎸囧畾娴嬬偣瀹氬奸厤缃 +bool ClientManager::set_fixedvalue_action_to_device(const std::string& identifier, ushort point_id, const std::vector& value) { + std::lock_guard lock(mutex_); + + // 鏌ユ壘鍖归厤鐨勮澶 + for (auto& pair : clients_) { + auto& ctx = pair.second; + if (ctx->device_info.device_id == identifier || + ctx->device_info.mac == identifier) + { + // 鐢熸垚瀹氬兼弿杩版姤鏂 + auto packet = generate_requestSetFixValue_message(point_id, value); + + // 娣诲姞鍔ㄤ綔鍒伴槦鍒 (鐘舵: 璇诲彇鏂囦欢鐩綍) + ctx->add_action(DeviceState::SET_FIXEDVALUE, packet); + + // 濡傛灉褰撳墠绌洪棽鍒欑珛鍗虫墽琛 + if (ctx->current_state_ == DeviceState::IDLE) { + ctx->process_next_action(); + } + + return true; // 鎴愬姛娣诲姞 + } + } + return false; // 璁惧鏈壘鍒 +} + +//鑾峰彇瑁呯疆鍐呴儴瀹氬 +bool ClientManager::get_interfixedvalue_action_to_device(const std::string& identifier) { + std::lock_guard lock(mutex_); + + // 鏌ユ壘鍖归厤鐨勮澶 + for (auto& pair : clients_) { + auto& ctx = pair.second; + if (ctx->device_info.device_id == identifier || + ctx->device_info.mac == identifier) + { + // 鐢熸垚瀹氬兼弿杩版姤鏂 + auto packet = generate_requestinterfixvalue_message(); + + // 娣诲姞鍔ㄤ綔鍒伴槦鍒 (鐘舵: 璇诲彇鏂囦欢鐩綍) + ctx->add_action(DeviceState::READING_INTERFIXEDVALUE, packet); + + // 濡傛灉褰撳墠绌洪棽鍒欑珛鍗虫墽琛 + if (ctx->current_state_ == DeviceState::IDLE) { + ctx->process_next_action(); + } + + return true; // 鎴愬姛娣诲姞 + } + } + return false; // 璁惧鏈壘鍒 +} + +//鑾峰彇瑁呯疆鍐呴儴瀹氬兼帶鍒跺瓧鎻忚堪or鍐呴儴瀹氬兼弿杩 1-鍐呴儴瀹氬兼弿杩帮紝2-鎺у埗瀛椾綅鎻忚堪 +bool ClientManager::get_fixedvalucontrolword_action_to_device(const std::string& identifier, unsigned char nDesCW) { + std::lock_guard lock(mutex_); + + // 鏌ユ壘鍖归厤鐨勮澶 + for (auto& pair : clients_) { + auto& ctx = pair.second; + if (ctx->device_info.device_id == identifier || + ctx->device_info.mac == identifier) + { + // 鐢熸垚瀹氬兼弿杩版姤鏂 + auto packet = generate_requestinterfixdes_message(nDesCW); + + if (nDesCW == 1) { + // 娣诲姞鍐呴儴瀹氬兼弿杩 + ctx->add_action(DeviceState::READING_INTERFIXEDVALUEDES, packet); + } + else { + // 娣诲姞鎺у埗瀛楁弿杩 + ctx->add_action(DeviceState::READING_CONTROLWORD, packet); + } + + // 濡傛灉褰撳墠绌洪棽鍒欑珛鍗虫墽琛 + if (ctx->current_state_ == DeviceState::IDLE) { + ctx->process_next_action(); + } + + return true; // 鎴愬姛娣诲姞 + } + } + return false; // 璁惧鏈壘鍒 +} + +//璁剧疆瑁呯疆鍐呴儴瀹氬奸厤缃 +bool ClientManager::set_interfixedvalue_action_to_device(const std::string& identifier, const std::vector& values) { + std::lock_guard lock(mutex_); + + // 鏌ユ壘鍖归厤鐨勮澶 + for (auto& pair : clients_) { + auto& ctx = pair.second; + if (ctx->device_info.device_id == identifier || + ctx->device_info.mac == identifier) + { + // 鐢熸垚瀹氬兼弿杩版姤鏂 + auto packet = generate_requestsetinterfixvalue_message(values); + //auto packet = generate_requestsetinterfixvalue_message_new(values); + + // 娣诲姞鍔ㄤ綔鍒伴槦鍒 (鐘舵: 璇诲彇鏂囦欢鐩綍) + ctx->add_action(DeviceState::SET_INTERFIXEDVALUE, packet); + + // 濡傛灉褰撳墠绌洪棽鍒欑珛鍗虫墽琛 + if (ctx->current_state_ == DeviceState::IDLE) { + ctx->process_next_action(); + } + + return true; // 鎴愬姛娣诲姞 + } + } + return false; // 璁惧鏈壘鍒 +} + +//鑾峰彇鎸囧畾瑁呯疆娴嬬偣鐨勭數鍘嬬瓑绾т笌鎺ョ嚎鏂瑰紡 bool ClientManager::get_point_scale_and_pttype(const std::string& identifier, ushort nCpuNo, std::string& out_scale, diff --git a/LFtid1056/client2.h b/LFtid1056/client2.h index 8047255..8605ca9 100644 --- a/LFtid1056/client2.h +++ b/LFtid1056/client2.h @@ -42,13 +42,20 @@ enum class ConnectionState { // 添加的状态枚举 enum class DeviceState { - IDLE, // 空闲状态 - READING_STATS, // 读取统计数据 - READING_STATS_TIME, // 读取统计时间 - READING_REALSTAT, // 读取实时数据 - READING_EVENTFILE, // 暂态波形文件下载 - READING_FILEMENU, // 读取文件目录 - READING_FILEDATA, // 下载文件数据 + IDLE, // 空闲状态 + READING_STATS, // 读取统计数据 + READING_STATS_TIME, // 读取统计时间 + READING_REALSTAT, // 读取实时数据 + READING_EVENTFILE, // 暂态波形文件下载 + READING_FILEMENU, // 读取文件目录 + READING_FILEDATA, // 下载文件数据 + READING_FIXEDVALUE, // 读取测点定值 + READING_FIXEDVALUEDES, // 读取测点定值描述 + SET_FIXEDVALUE, // 设置测点定值 + READING_INTERFIXEDVALUE, // 读取内部定值 + READING_INTERFIXEDVALUEDES, // 读取内部定值描述 + READING_CONTROLWORD, // 读取控制字描述 + SET_INTERFIXEDVALUE, // 设置内部定值 // 可根据需要添加更多状态 CUSTOM_ACTION // 自定义动作 }; @@ -370,6 +377,24 @@ public: //文件下载调用 传入mac/id + 文件位置 bool add_file_download_action_to_device(const std::string& identifier, const std::string& file_path); + + //获取指定装置指定测点下的定值数据 传入mac/id + 测点序号 + bool get_fixedvalue_action_to_device(const std::string& identifier, ushort point_id); + + //获取指定装置定值描述 传入mac/id + bool get_fixedvaluedes_action_to_device(const std::string& identifier); + + //设置指定测点的定值配置 传入mac/id + 测点序号 + 定时队列 + bool set_fixedvalue_action_to_device(const std::string& identifier, ushort point_id, const std::vector& value); + + //获取装置内部定值 传入mac/id + bool get_interfixedvalue_action_to_device(const std::string& identifier); + + //获取装置内部定值控制字描述or内部定值描述 1-内部定值描述,2-控制字位描述 + bool get_fixedvalucontrolword_action_to_device(const std::string& identifier, unsigned char nDesCW); + + //设置装置内部定值 传入mac/id + 内部定值序列 + bool set_interfixedvalue_action_to_device(const std::string& identifier, const std::vector& values); private: ClientManager() : loop_(nullptr) {} std::unordered_map> clients_; diff --git a/LFtid1056/dealMsg.cpp b/LFtid1056/dealMsg.cpp index 6ecc25e..058cd82 100644 --- a/LFtid1056/dealMsg.cpp +++ b/LFtid1056/dealMsg.cpp @@ -46,6 +46,8 @@ std::string extract_filename(const std::string& path) { // 如果没有'/',直接返回原字符串 return path; } + +//消息处理逻辑 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; @@ -71,6 +73,12 @@ void process_received_message(string mac, string id,const char* data, size_t len //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();装置修改内部定值测试(参数由外部提供) } if (udata[19] == 0x00) { std::cout << "cloud login: " << mac << " state: fail!" << std::endl; @@ -240,8 +248,6 @@ void process_received_message(string mac, string id,const char* data, size_t len case DeviceState::READING_STATS: // 读取统计数据状态 - std::cout << "READING_STATS state: Processing stats data from " << mac << std::endl; - // 这里添加处理统计数据报文的逻辑 if (udata[8] == static_cast(MsgResponseType::Response_Stat)) { // 一发多收,需要在这里等待所有报文收全再组装相应数据 一帧1K 直到所有数据传送完毕 //当前帧未收全,直接退出消息处理,等待后续帧 @@ -412,7 +418,6 @@ void process_received_message(string mac, string id,const char* data, size_t len case DeviceState::READING_STATS_TIME: // 读取统计时间状态 - std::cout << "READING_STATS_TIME state: Processing stats time from " << mac << std::endl; if (udata[8] == static_cast(MsgResponseType::Response_StatTime)) { std::vector points;//装置测点信息 if (ClientManager::instance().get_device_points(mac, points)) { @@ -452,7 +457,6 @@ void process_received_message(string mac, string id,const char* data, size_t len case DeviceState::READING_REALSTAT: //读取实时数据状态 - std::cout << "READING_REALSTAT state: Processing stats data from " << mac << std::endl; if (udata[8] == static_cast(MsgResponseType::Response_New_3S)) { unsigned char packet_type = udata[13]; @@ -568,7 +572,6 @@ void process_received_message(string mac, string id,const char* data, size_t len case DeviceState::READING_EVENTFILE: // 暂态波形文件下载 - std::cout << "READING_EVENTFILE state: Processing stats time from " << mac << std::endl; if (udata[8] == static_cast(MsgResponseType::Response_File_Download)) { // 提取当前帧序号(12-15字节,大端序) int current_frame = (static_cast(udata[12]) << 24) | @@ -660,7 +663,6 @@ void process_received_message(string mac, string id,const char* data, size_t len case DeviceState::READING_FILEMENU: //读取文件目录 - std::cout << "READING_FILEMENU state: Processing stats time from " << mac << std::endl; if (udata[8] == static_cast(MsgResponseType::Response_FileDir)) { // 计算结构体大小 const size_t struct_size = sizeof(tag_dir_info); @@ -704,7 +706,6 @@ void process_received_message(string mac, string id,const char* data, size_t len case DeviceState::READING_FILEDATA: //下载文件数据 和暂态文件下载共用同一功能码 - std::cout << "READING_FILEDATA state: Processing stats time from " << mac << std::endl; if (udata[8] == static_cast(MsgResponseType::Response_File_Download)) { // 提取当前帧序号(12-15字节,大端序) @@ -794,6 +795,377 @@ void process_received_message(string mac, string id,const char* data, size_t len } break; + case DeviceState::READING_FIXEDVALUE: + //读取指定测点定值数据 + if (udata[8] == static_cast(MsgResponseType::Response_FixValue)) { + // 确保数据长度足够包含测点序号 + if (parser.RecvData.size() < 1) { + std::cout << "Invalid fix value data length" << std::endl; + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + break; + } + + // 提取测点序号 (第一个字节) + uint8_t monitor_index = parser.RecvData[0]; + std::cout << "Monitor Index: " << static_cast(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; + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + break; + } + + // 存储浮点值的容器 + std::vector 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; + } + + //测试定值修改功能 + //ClientManager::instance().set_fixedvalue_action_to_device(id, monitor_index, fList); + + //定值读取完毕,调整为空闲,处理后续工作。 + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + } + else { + // 装置答非所问异常 + // 读取定值错误,调整为空闲状态,处理下一项工作。 + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + } + break; + + case DeviceState::READING_FIXEDVALUEDES: + //读取指定测点定值描述 + if (udata[8] == static_cast(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; + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + break; + } + + // 存储所有解析出的定值描述 + std::vector dz_list; + dz_list.reserve(bufflen / structlen); + + // 遍历所有定值描述结构体 + for (size_t i = 0, j = 1; i < bufflen; i += structlen, j++) { + // 复制数据到临时缓冲区 + std::vector 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; + } + + + //定值描述读取完毕,调整为空闲,处理后续工作。 + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + } + else { + // 装置答非所问异常 + // 读取定值描述,调整为空闲状态,处理下一项工作。 + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + } + break; + + case DeviceState::SET_FIXEDVALUE: + //设置装置定值 + if (udata[8] == static_cast(MsgResponseType::Response_NewACK)) { + std::cout << "set success" << mac << std::endl; + //定值设置成功,调整为空闲,处理后续工作。 + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + } + else if (udata[8] == static_cast(MsgResponseType::Response_NewNACK)) { + std::cout << "set error" << mac << std::endl; + // 装置否定应答,定值设置失败 + // 设置装置定值失败,调整为空闲状态,处理下一项工作。 + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + } + else { + // 装置答非所问异常 + // 设置装置定值失败,调整为空闲状态,处理下一项工作。 + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + } + break; + + case DeviceState::READING_INTERFIXEDVALUE: + //读取内部定值 + if (udata[8] == static_cast(MsgResponseType::Response_Read_InterFix)) { + // 获取数据长度 + size_t bufflen = parser.RecvData.size(); + const size_t structlen = 2; // 每个ushort占2字节 + + // 存储解析结果的容器 + std::vector 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; + } + + //内部定值修改测试 + //ClientManager::instance().set_interfixedvalue_action_to_device(id, fList); + + //内部定值获取完毕,调整为空闲,处理后续工作。 + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + } + else { + // 装置答非所问异常 + // 读取装置内部定值失败,调整为空闲状态,处理下一项工作。 + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + } + break; + + case DeviceState::READING_INTERFIXEDVALUEDES: + //读取内部定值描述 + if (udata[8] == static_cast(MsgResponseType::Response_Read_InterFixDes)) { + // 获取接收数据 + std::vector& recvData = parser.RecvData; + size_t bufflen = recvData.size(); + const size_t structlen = sizeof(NameFixValue); + + // 存储解析结果的向量 + std::vector 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); + break; + } + else + { + // 计算结构体数量 + size_t structCount = bufflen / structlen; + fixValueList.reserve(structCount); + + // 遍历所有结构体 + for (size_t i = 0, k = 1; i < bufflen; i += structlen, k++) + { + // 复制当前结构体数据到缓冲区 + std::vector 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; + } + } + + //内部定值描述获取完毕,调整为空闲状态,处理下一项工作。 + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + } + else { + // 装置答非所问异常 + // 读取装置内部定值描述失败,调整为空闲状态,处理下一项工作。 + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + } + break; + + case DeviceState::READING_CONTROLWORD: + //读取控制字描述 + if (udata[8] == static_cast(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; + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + break; + } + + // 存储解析结果 + std::vector control_words; + control_words.reserve(bufflen / structlen); + + // 遍历所有控制字描述结构体 + for (size_t i = 0; i < bufflen; i += structlen) { + // 复制数据到临时缓冲区 + std::vector 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(dz_info.bit_enable) << std::endl; + } + + // 控制字描述读取完毕,调整为空闲,处理后续工作 + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + } + else { + // 装置答非所问异常 + // 读取装置控制字描述失败,调整为空闲状态,处理下一项工作。 + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + } + break; + + case DeviceState::SET_INTERFIXEDVALUE: + //设置内部定值 + if (udata[8] == static_cast(MsgResponseType::Response_NewACK)) { + std::cout << "set success" << mac << std::endl; + //内部定值设置成功,调整为空闲,处理后续工作。 + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + } + else if (udata[8] == static_cast(MsgResponseType::Response_NewNACK)) { + std::cout << "set error" << mac << std::endl; + + std::cout << "reason code: " << static_cast(udata[8]) << "-" << static_cast(udata[9]) << "-" << static_cast(udata[10]) << "-" << static_cast(udata[11]) << std::endl; + + // 装置否定应答,内部定值设置失败 + // 设置装置内部定值失败,调整为空闲状态,处理下一项工作。 + ClientManager::instance().change_device_state(id, DeviceState::IDLE); + } + else { + // 装置答非所问异常 + // 设置装置内部定值失败,调整为空闲状态,处理下一项工作。 + 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; diff --git a/LFtid1056/main_thread.cpp b/LFtid1056/main_thread.cpp index 8ebaf0b..f3c17c1 100644 --- a/LFtid1056/main_thread.cpp +++ b/LFtid1056/main_thread.cpp @@ -131,7 +131,7 @@ void* client_manager_thread(void* arg) { std::vector points2 = { {"P101", "Generator Output", "D002",1 ,1, 1, 1, 1,"0.38k",0} }; - //00-B7-8D-A8-00-D6 00-B7-8D-01-79-06 + //00B78DA800D6 00-B7-8D-01-79-06 // 创建装置列表 std::vector devices = { {