Files
front_linux/LFtid1056/PQSMsg.cpp
2025-09-02 14:58:19 +08:00

634 lines
20 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 <vector>
#include <cstdint>
#include <cstring>
#include <string>
#include <stdexcept>
#include <algorithm>
#include <cctype>
#include <cstdlib>
#include "client2.h"
#include <iostream>
// 辅助转换函数
float IntToFloat(int num) {
return static_cast<float>(num) / 65536.0f;
}
float ShorToFloat100(short num) {
return static_cast<float>(num) / 100.0f;
}
float ShorToFloat1000(short num) {
return static_cast<float>(num) / 1000.0f;
}
float ShorToFloat10000(short num) {
return static_cast<float>(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地址并填充到缓冲区
//lnk20250808
static inline int hex_nibble(char c) {
if (c >= '0' && c <= '9') return c - '0';
c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
if (c >= 'a' && c <= 'f') return 10 + (c - 'a');
return -1;
}
// 安全版:不抛异常,返回 true/false
bool GetMAC(const std::string& strMAC,
std::vector<unsigned char>& packet,
size_t startIndex,
std::string* err = nullptr) {
// 1) 规范化:去掉 '-', ':', ' '
std::string s;
s.reserve(strMAC.size());
for (char c : strMAC) {
if (c == '-' || c == ':' || c == ' ') continue;
s.push_back(c);
}
// 2) 长度校验
if (s.size() != 12) {
if (err) *err = "MAC长度必须为12个十六进制字符";
return false;
}
// 3) 十六进制校验 + 解析
std::array<unsigned char, 6> mac{};
for (int i = 0; i < 6; ++i) {
int hi = hex_nibble(s[2*i]);
int lo = hex_nibble(s[2*i + 1]);
if (hi < 0 || lo < 0) {
if (err) *err = "MAC含非法字符(必须是0-9或A-F)";
return false;
}
mac[i] = static_cast<unsigned char>((hi << 4) | lo);
}
// 4) 确保缓冲区足够写入64字节MAC 6字节 + 其后补零)
const size_t need = startIndex + 64;
if (packet.size() < need) packet.resize(need, 0);
// 5) 写入MAC
for (int i = 0; i < 6; ++i) {
packet[startIndex + i] = mac[i];
}
// 6) 其余位置补零(若 resize 过这里基本已是0但保证一下
for (size_t i = 6; i < 64; ++i) {
packet[startIndex + i] = 0;
}
return true;
}
/*void GetMAC(const std::string& strMAC, std::vector<unsigned char>& packet, size_t startIndex) {
// 移除所有空格和短横线
std::string cleanedMAC = strMAC;
cleanedMAC.erase(std::remove(cleanedMAC.begin(), cleanedMAC.end(), ' '), cleanedMAC.end());
cleanedMAC.erase(std::remove(cleanedMAC.begin(), cleanedMAC.end(), '-'), cleanedMAC.end());
// 验证长度
if (cleanedMAC.length() != 12) {
throw std::invalid_argument("MAC地址长度必须为12个字符");
}
try {
// 解析每两个字符作为十六进制字节
for (int i = 0; i < 6; i++) {
// 提取两个字符的子串
std::string byteStr = cleanedMAC.substr(i * 2, 2);
// 转换为十六进制字节
unsigned char byte = static_cast<unsigned char>(
std::stoi(byteStr, nullptr, 16)
);
// 填充到指定位置
if (startIndex + i < packet.size()) {
packet[startIndex + i] = byte;
}
}
// 剩余部分填0 (总共需要64字节但MAC只占6字节)
for (int i = 6; i < 64; i++) {
if (startIndex + i < packet.size()) {
packet[startIndex + i] = 0;
}
}
}
catch (const std::exception& e) {
throw std::invalid_argument("无效的MAC地址: " + std::string(e.what()));
}
}*/
// CRC计算函数
unsigned char GetCrcSum(const std::vector<unsigned char>& Check, int nOffset, int nLen) {
unsigned char reg_b = 0x00;
for (int i = 0; i < nLen; ++i) {
if (static_cast<size_t>(i + nOffset) >= Check.size()) {
throw std::out_of_range("Index out of range in GetCrcSum");
}
reg_b += Check[i + nOffset];
}
return reg_b;
}
// 时间转换函数TagMsTime -> 毫秒时间戳)
uint64_t convertTagMsTimeToMsTimestamp(const TagMsTime& t) {
struct tm tm_time = {};
tm_time.tm_year = t.Year - 1900;
tm_time.tm_mon = t.Month - 1;
tm_time.tm_mday = t.Day;
tm_time.tm_hour = t.Hour;
tm_time.tm_min = t.Min;
tm_time.tm_sec = t.Sec;
tm_time.tm_isdst = -1; // 自动判断夏令时
// 转换为时间戳(秒)
time_t seconds = mktime(&tm_time);
if (seconds == -1) return 0;
// 加上毫秒
return static_cast<uint64_t>(seconds) * 1000 + t.Ms;
}
// 解析日志生成QVVRRecord
QVVRRecord DynamicLog_GetQVVRRecordFromLogBuffer(
const std::string& strScale,
uint32_t nPTType,
float fPT,
const NewTaglogbuffer& log) {
QVVRRecord record;
try {
// 转换时间
record.triggerTimeMs = convertTagMsTimeToMsTimestamp(log.head.Devtime);
// 提取参数
float fParam1 = 0.0f; // 持续时间
float fParam2 = 0.0f; // 特征幅值
float fParam3 = 0.0f; // 浮动门槛值
for (const auto& body : log.bodyList) {
switch (body.ParaCode) {
case 0: // 特征幅值(暂态单独使用)
fParam2 = static_cast<float>(body.ParaValue) / 65536.0f;
break;
case 1: // 持续时间(瞬态和暂态公用)
fParam1 = static_cast<float>(body.ParaValue) / 65536.0f;
break;
case 25: // 浮动门槛值(瞬态和暂态公用)
fParam3 = static_cast<float>(body.ParaValue) / 65536.0f;
break;
case 3: //电压幅度(瞬态单独使用)
record.fMagntitude = (static_cast<float>(body.ParaValue) / 65536.0f) / 100.0f;
break;
case 5: //相别(瞬态单独使用)
record.phase = static_cast<float>(body.ParaValue) / 65536.0f;
break;
case 6: //瞬变幅度(瞬态单独使用)
record.transientValue = (static_cast<float>(body.ParaValue) / 65536.0f) / 100.0f;
break;
default:
break;
}
}
record.fPersisstime = fParam1;
// 计算基准值fBase
float fBase = 0.0f;
if (fParam3 < 50.0f) { // 未上送浮动门槛
if (fPT != 1.0f) { // 变比不为1
fBase = (nPTType == 0) ? 57.74f : 100.0f;
}
else {
std::string strTemp = strScale;
std::transform(strTemp.begin(), strTemp.end(), strTemp.begin(), ::tolower);
size_t pos = strTemp.find('k');
if (pos != std::string::npos) {
std::string numPart = strTemp.substr(0, pos);
try {
float fTemp = std::stof(numPart) * 1000.0f;
fBase = (nPTType == 0) ? (fTemp / std::sqrt(3.0f)) : fTemp;
}
catch (...) {
fBase = (nPTType == 0) ? 57.74f : 100.0f;
}
}
else {
fBase = (nPTType == 0) ? 57.74f : 100.0f;
}
}
}
else {
fBase = fParam3; // 使用浮动门槛值
}
// 设置事件类型
switch (log.head.LogCode) {
case 0: case 26: case 40: case 54: case 68: case 82:
record.nType = 3;
break;
case 1: case 27: case 41: case 55: case 69: case 83:
record.nType = 1;
break;
case 13: case 36: case 50: case 64: case 78: case 92:
record.nType = 2;
break;
case 24:
// 手动启动录波保持默认类型0
break;
case 100:
record.nType = 1; // 模拟电压暂降
break;
case 3:
record.nType = 4; // 瞬态事件
default:
// 未知类型保持0
break;
}
// 特殊处理:中断事件且幅值较大
if (record.nType == 3 && fParam2 > fBase * 0.1f) {
fParam2 /= 100.0f;
}
// 计算特征幅值(标幺值)
record.fMagntitude = fParam2 / fBase;
}
catch (...) {
// 异常时返回空记录
record = QVVRRecord{};
}
return record;
}
// 主函数:组装二进制报文
std::vector<unsigned char> GetMsg(const std::vector<unsigned char>& SrcData, unsigned char nType) {
// 参数检查
if (SrcData.empty() ||
((nType < 0x01 || nType > 0xA4) && nType != 0xFF)) {
return {};
}
try {
// 计算总长度:报文头(6) + 额外字段(2) + 功能码(1) + 数据体 + CRC+结束符(2)
const size_t total_len = 6 + 2 + 1 + SrcData.size() + 2;
std::vector<unsigned char> msg(total_len);
// 组装报文头 (6字节)
msg[0] = 0xEB; // 报文头
msg[1] = 0x90; // 报文头
msg[2] = 0x00; // 备用
msg[3] = 0x00; // 备用
// 设置长度字段(数据体长度+功能码)
uint16_t data_len = static_cast<uint16_t>(SrcData.size() + 1);
msg[4] = static_cast<unsigned char>(data_len >> 8); // 长度高字节
msg[5] = static_cast<unsigned char>(data_len & 0xFF); // 长度低字节
// 额外字段 (2字节)
msg[6] = 0x00; // 备用
msg[7] = 0xFF; // 备用
// 功能码
msg[8] = nType;
// 复制数据体
if (!SrcData.empty()) {
std::copy(SrcData.begin(), SrcData.end(), msg.begin() + 9);
}
// 计算CRC从索引8开始长度 = 功能码+数据体)
unsigned char crc = GetCrcSum(msg, 8, 1 + SrcData.size());
msg[msg.size() - 2] = crc;
msg[msg.size() - 1] = 0x16; // 结束符
return msg;
}
catch (const std::exception& ex) {
throw std::runtime_error(std::string("Exception in GetMsg: ") + ex.what());
}
catch (...) {
throw std::runtime_error("Unknown exception in GetMsg");
}
}
// 生成装置云服务登录报文
std::vector<unsigned char> generate_frontlogin_message(const std::string& strMac)
{
const size_t packetSize = 150; // 报文总长150 数据体+帧序号140
std::vector<unsigned char> packet(packetSize, 0); // 初始化为全0
// 协议头
packet[0] = 0xEB; // 起始标志1
packet[1] = 0x90;
packet[2] = 0xEB; // 起始标志2
packet[3] = 0x90;
packet[4] = 0x8C; // 数据体长度 (140 = 0x008C)
packet[5] = 0x00;
// [6-7] 随机码 (保持为0)
// [8-9] 功能码 (保持为0)
// [10-11] 帧序号 (保持为0)
// 数据体1
packet[12] = 'F';
packet[13] = 'T';
packet[14] = 'I';
packet[15] = 'D';
// [16-19] 数据体2 (保持为0)
// 填充MAC地址 (从位置20开始64字节)
//GetMAC(strMac, packet, 20);
//lnk20250808
std::string err;
if (!GetMAC(strMac, packet, 20, &err)) {
std::cerr << "[GetMAC] parse failed: " << err << "\n";
// 做降级或返回
}
// 计算校验和 (从偏移8到137)
unsigned char checksum = 0;
for (size_t i = 8; i < packetSize - 2; i++) {
checksum += packet[i];
}
packet[packetSize - 2] = checksum;
// 结束符
packet[packetSize - 1] = 0x16;
//lnk20250808
// ======= 调试输出报文 =======
std::cout << "[generate_frontlogin_message] Packet (" << packet.size() << " bytes):\n";
for (size_t i = 0; i < packet.size(); ++i) {
printf("%02X ", packet[i]);
if ((i + 1) % 16 == 0) printf("\n");
}
if (packet.size() % 16 != 0) printf("\n");
return packet;
}
//询问统计数据时间报文
std::vector<unsigned char> generate_statequerytime_message() {
// 创建2字节数据缓冲区初始化为0
std::vector<unsigned char> DataBuf(2, 0x00);
// 调用GetMsg生成完整报文
return GetMsg(DataBuf, static_cast<unsigned char>(MsgRequestType::Request_StatTime));
}
//询问统计数据报文
std::vector<unsigned char> generate_statequerystat_message(tagTime time, uint16_t nDeviceNo, uint16_t nDataType) {
// 计算总大小3(备用) + 2(nDeviceNo) + 2(nDataType) + time结构大小
const size_t totalSize = 3 + 2 * sizeof(uint16_t) + time.GetSize();
std::vector<unsigned char> DataBuf(totalSize, 0x00); // 初始化为全0
size_t offset = 0;
// 1. 跳过3字节备用区已初始化为0
offset += 3;
// 2. 写入nDeviceNo网络字节序
uint16_t netDeviceNo = htons(nDeviceNo);
memcpy(DataBuf.data() + offset, &netDeviceNo, sizeof(uint16_t));
offset += sizeof(uint16_t);
// 3. 写入nDataType网络字节序
uint16_t netDataType = htons(nDataType);
memcpy(DataBuf.data() + offset, &netDataType, sizeof(uint16_t));
offset += sizeof(uint16_t);
// 4. 写入time结构内部已处理网络字节序
time.GetStructBuf(DataBuf.data(), DataBuf.size(), offset);
// 生成完整报文
return GetMsg(DataBuf, static_cast<unsigned char>(MsgRequestType::Request_Stat));
}
//询问实时数据报文 测点1-6 数据类型1-11 谐波次数0-2
std::vector<unsigned char> generate_realstat_message(unsigned char nCpuNo,
unsigned char StaTtype,
unsigned char flag)
{
// 计算总大小3(备用) + 1(nCpuNo) + 1(StaTtype) + 1(固定值) + 1(flag)
const size_t totalSize = 7;
std::vector<unsigned char> DataBuf(totalSize, 0x00); // 初始化为全0
size_t offset = 0;
// 1. 跳过3字节备用区已初始化为0
offset += 3;
// 2. 写入nCpuNo1字节 监测点序号 1-6
memcpy(DataBuf.data() + offset, &nCpuNo, sizeof(unsigned char));
offset += sizeof(unsigned char);
// 3. 写入StaTtype1字节 数据类型 1-11 一般仅读 1-6
memcpy(DataBuf.data() + offset, &StaTtype, sizeof(unsigned char));
offset += sizeof(unsigned char);
// 4. 写入固定值11字节 3秒实时数据仅有1 表示平均值
const unsigned char fixedValue = 1;
memcpy(DataBuf.data() + offset, &fixedValue, sizeof(unsigned char));
offset += sizeof(unsigned char);
// 5. 写入flag1字节 标志位 0-2 谐波次数 25 50 100次
memcpy(DataBuf.data() + offset, &flag, sizeof(unsigned char));
// 生成完整报文
return GetMsg(DataBuf, static_cast<unsigned char>(MsgRequestType::Request_New_3S));
}
// 生成文件下载请求报文 当前帧序号+文件名
std::vector<unsigned char> generate_downloadfile_message(int frameIndex, const std::string& fileName) {
// 数据体大小: 3(备用) + 4(帧序号) + 128(文件名) = 135字节
std::vector<unsigned char> dataBuf(135, 0x00);
// 写入帧序号 (4字节大端序)
//uint32_t netFrameIndex = htonl(static_cast<uint32_t>(frameIndex));
//memcpy(dataBuf.data() + 3, &netFrameIndex, sizeof(uint32_t));
// 移除htonl转换直接使用原始帧序号(小端序)
uint32_t rawFrameIndex = static_cast<uint32_t>(frameIndex);
memcpy(dataBuf.data() + 3, &rawFrameIndex, sizeof(uint32_t));
// 写入文件名 (最多128字节)
size_t copyLen = std::min(fileName.size(), static_cast<size_t>(128));
if (copyLen > 0) {
memcpy(dataBuf.data() + 7, fileName.c_str(), copyLen);
}
// 调用GetMsg生成完整报文
return GetMsg(dataBuf, static_cast<unsigned char>(MsgRequestType::Request_File_Download));
}
//文件目录读取报文 传入需要读取的文件路径
std::vector<unsigned char> generate_getfilemenu_message(const std::string& filedir) {
// 创建固定131字节缓冲区 (3 + 128)初始化为0
std::vector<unsigned char> dataBuf(131, 0x00);
// 复制文件名到缓冲区偏移量3开始
size_t copyLen = std::min(filedir.size(), static_cast<size_t>(128));
if (copyLen > 0) {
memcpy(dataBuf.data() + 3, filedir.c_str(), copyLen);
}
// 调用GetMsg生成完整报文
return GetMsg(dataBuf, static_cast<unsigned char>(MsgRequestType::Request_FileDir));
}
// 请求定值报文 传入测点号
std::vector<unsigned char> generate_requestFixValue_message(unsigned char nCpuNo) {
// 参数检查
if (nCpuNo < 1 || nCpuNo > 6)
return std::vector<unsigned char>();
// 创建4字节缓冲区并初始化
std::vector<unsigned char> DataBuf(4, 0x00);
DataBuf[3] = nCpuNo; // CPU编号放在第4字节
// 生成完整报文
return GetMsg(DataBuf, static_cast<unsigned char>(MsgRequestType::Request_FixValue));
}
// 请求定值描述报文
std::vector<unsigned char> generate_requestFixDes_message() {
// 创建3字节缓冲区并初始化
std::vector<unsigned char> DataBuf(3, 0x00);
// 生成完整报文
return GetMsg(DataBuf, static_cast<unsigned char>(MsgRequestType::Request_FixDes));
}
// 设置定值报文 传入测点号+修改的定值数据队列
std::vector<unsigned char> generate_requestSetFixValue_message(
unsigned char nCpuNo,
const std::vector<float>& value)
{
// 参数检查
if (nCpuNo < 1 || nCpuNo > 6)
return std::vector<unsigned char>();
// 计算缓冲区大小: 4(头部) + 浮点数组长度*4
const size_t bufSize = 4 + value.size() * 4;
std::vector<unsigned char> 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<unsigned char>(MsgRequestType::Request_Set_Fix));
}
/**
* @brief 生成请求装置内部定值的报文
* @return 包含完整报文的字节向量
*/
std::vector<unsigned char> generate_requestinterfixvalue_message()
{
// 创建3字节数据缓冲区并初始化为0
std::vector<unsigned char> dataBuf(3, 0x00);
// 调用通用报文生成函数
return GetMsg(dataBuf, static_cast<unsigned char>(MsgRequestType::Request_Read_InterFix));
}
/**
* @brief 生成请求装置内部定值描述的报文
* @param nDesCW 描述类型 (1-内部定值描述, 2-控制字描述)
* @return 包含完整报文的字节向量,参数无效时返回空向量
*/
std::vector<unsigned char> generate_requestinterfixdes_message(unsigned char nDesCW)
{
// 参数有效性检查
if (nDesCW < 1 || nDesCW > 2) {
return std::vector<unsigned char>();
}
// 创建3字节数据缓冲区
std::vector<unsigned char> dataBuf(3, 0x00);
// 设置描述类型
dataBuf[0] = nDesCW;
// 调用通用报文生成函数
return GetMsg(dataBuf, static_cast<unsigned char>(MsgRequestType::Request_Read_InterFixDes));
}
/**
* @brief 生成设置装置内部定值的报文
* @param values 要设置的定值数组 (ushort值)
* @return 包含完整报文的字节向量
*/
std::vector<unsigned char> generate_requestsetinterfixvalue_message(const std::vector<uint16_t>& values)
{
// 计算缓冲区大小: 3字节头部 + 每个值占2字节
const size_t bufSize = 3 + values.size() * 2;
std::vector<unsigned char> 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<unsigned char>(MsgRequestType::Request_Set_InterFix));
}
/**
* @brief 生成设置装置内部定值的报文
* @param values 要设置的定值数组 (ushort值)
* @return 包含完整报文的字节向量
*/
std::vector<unsigned char> generate_requestsetinterfixvalue_message_new(const std::vector<uint16_t>& value)
{
// 计算缓冲区大小: 3字节头部 + 每个值占2字节
const size_t bufSize = 3 + value.size() * 2;
std::vector<unsigned char> dataBuf(bufSize, 0x00);
// 填充定值数据
for (size_t i = 0; i < value.size(); i++) {
// 将值转换为字节数组
uint16_t rawValue = value[i];
unsigned char* bytes = reinterpret_cast<unsigned char*>(&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<unsigned char>(MsgRequestType::Request_Set_InterFix));
}