Files
front_linux/LFtid1056/PQSMsg.cpp

393 lines
12 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"
// 辅助转换函数
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;
}
// 辅助函数解析MAC地址并填充到缓冲区
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);
// 计算校验和 (从偏移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;
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));
}