using System; using System.Collections.Generic; using System.IO.Ports; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace MegaRobo.C00225155.ControlDevices { /// /// 高温温度模块 485 uart 定制HCM通信协议封装类(PC→主控板指令构建 + 主控板→PC指令解析) /// public static class LowTemperatureUartHCM { #region 协议常量定义(码表及指令规范) private const byte ST = 0x5E; // 帧头 private const byte HELLO = 0x01; // 握手指令 private const byte STATUS = 0x05; // 读取报错状态 private const byte SETTEMP = 0x06; // 制冷温度控制 private const byte MOTOR = 0x07; // 电机控制 private const byte RDTEMP = 0x08; // 读取温度 private const byte RDADC = 0x09; // 读取传感器AD private const byte RDEE = 0x11; // 读取EEPROM private const byte WREE = 0x12; // 写入EEPROM private const byte RDMotSpeed = 0x13; // 获取实际转速 private const byte RDIOStatus = 0x14; // 获取开关盖状态 private const byte Calb = 0x15; // 校准温度 private const byte SETHOTTEMP = 0x16; // 加热温度控制(补充遗漏指令) private const byte RelayControl = 0x17; // 电磁阀控制(补充遗漏指令) private const byte RESPONSE_FLAG = 0x80; // 上传指令标志(指令码 | 0x80) #endregion #region private static byte _cmdSequence = 0; // 指令序号(0-255自动溢出) private static readonly object _lock = new object();// 线程安全锁(避免多线程序号混乱) #endregion #region 校验和计算(协议第6点:前n-1字节之和的低8位) /// /// 计算帧的校验和(核心:前length字节之和的低8位) /// /// 待计算的帧数据 /// 参与计算的字节数(前n-1字节) /// 校验和字节 private static byte CalculateChecksum(byte[] data, int length) { if (data == null || length <= 0 || length > data.Length) throw new ArgumentException("校验和计算参数无效"); int sum = 0; for (int i = 0; i < length; i++) sum += data[i]; return (byte)(sum & 0xFF); // 取低8位,确保是1字节 } #endregion #region 指令序号自增(线程安全) /// /// 指令序号自增(0-255自动溢出,确保除溢出外无重复指令) /// private static void IncrementCmdSequence() { lock (_lock) { _cmdSequence++; // 字节类型自动溢出(255→0) // 确保序号不超过0x7F(避免下发指令CMD被误认为上传指令) if (_cmdSequence >= 0x80) _cmdSequence = 0; } } /// /// 获取当前指令序号(带线程安全) /// private static byte GetCurrentCmdSequence() { lock (_lock) { return _cmdSequence; } } #endregion #region 下传指令构建(PC→主控板,返回byte[]帧) /// /// 握手指令(系统开机必发) /// /// 设备ID(0-255,默认0) /// 握手指令帧(5字节) public static byte[] SendHello(byte deviceId = 0) { byte[] frame = new byte[5]; // 帧长固定5字节 byte seq = GetCurrentCmdSequence(); // 按协议填充帧结构:ST → HELLO+序号 → 设备ID → LTH=5 → 校验和 frame[0] = ST; frame[1] = (byte)(HELLO | seq); frame[2] = deviceId; frame[3] = 5; // LTH固定为5 frame[4] = CalculateChecksum(frame, 4); // 前4字节求和取低8位 IncrementCmdSequence(); // 序号自增 AddFrameInterval(); // 帧间隔>2ms return frame; } /// /// 读取报错状态指令 /// /// 设备ID(0-255,默认0) /// 报错状态指令帧(5字节) public static byte[] SendStatusRequest(byte deviceId = 0) { byte[] frame = new byte[5]; // 帧长固定5字节 byte seq = GetCurrentCmdSequence(); // 帧结构:ST → STATUS+序号 → 设备ID → LTH=5 → 校验和 frame[0] = ST; frame[1] = (byte)(STATUS | seq); frame[2] = deviceId; frame[3] = 5; // LTH固定为5 frame[4] = CalculateChecksum(frame, 4); IncrementCmdSequence(); AddFrameInterval(); return frame; } /// /// 温度控制指令(下发后主控板直接执行温度控制) /// /// 目标温度(10.0-180.0℃,精度0.1) /// 设备ID(0-255,默认0) /// 是否释放控制(true=0xFFFF,关断功率)关闭温度 /// 温度控制指令帧(7字节) public static byte[] SendSetTemp(double targetTemp, byte deviceId = 0, bool releaseControl=false) { byte[] frame = new byte[7]; // 帧长固定7字节 byte seq = GetCurrentCmdSequence(); int tempParam = 0; // 温度参数(16位:高8位+低8位) // 处理参数:释放控制/正常温度 if (releaseControl) { tempParam = 0xFFFF; // 协议约定:释放控制=0xFFFF } else { // 参数校验:温度范围10.0-180.0℃(对应1000-18000) if (targetTemp < -50.0 || targetTemp > 50.0) throw new ArgumentOutOfRangeException(nameof(targetTemp), "温度必须在[-50 , 50]℃之间"); tempParam = (short)(targetTemp * 100); // 放大100倍(精度0.1) } // 帧结构:ST → SETTEMP+序号 → 设备ID → LTH=7 → 参数1(高8) → 参数2(低8) → 校验和 frame[0] = ST; frame[1] = (byte)(SETTEMP | seq); frame[2] = deviceId; frame[3] = 7; // LTH固定为7 frame[4] = (byte)(tempParam >> 8); // 参数1(高8位) frame[5] = (byte)(tempParam & 0xFF); // 参数2(低8位) frame[6] = CalculateChecksum(frame, 6); // 前6字节求和 IncrementCmdSequence(); AddFrameInterval(); return frame; } /// /// 电机控制指令(设置电机转速) /// /// 电机转速(200-1500,16位参数) /// 设备ID(0-255,默认0) /// 电机控制指令帧(11字节,0x0B=11) public static byte[] SendMotorControl(int motorSpeed, byte deviceId = 0) { // 参数校验:转速范围100-1500 if (motorSpeed < 100 || motorSpeed > 1500) throw new ArgumentOutOfRangeException(nameof(motorSpeed), "转速必须在100-1500之间"); byte[] frame = new byte[11]; // 帧长固定0x0B(11字节) byte seq = GetCurrentCmdSequence(); ushort speedParam = (ushort)motorSpeed; // 转速参数(16位) // 帧结构:ST → MOTOR+序号 → 设备ID → LTH=0x0B → 0x10 → 预留0×3 → 参数4(高8) → 参数5(低8) → 校验和 frame[0] = ST; frame[1] = (byte)(MOTOR | seq); frame[2] = deviceId; frame[3] = 0x0B; // LTH固定为11 frame[4] = 0x10; // 协议固定值 frame[5] = 0; // 预留位1 frame[6] = 0; // 预留位2 frame[7] = 0; // 预留位3 frame[8] = (byte)(speedParam >> 8); // 参数4(高8位) frame[9] = (byte)(speedParam & 0xFF); // 参数5(低8位) frame[10] = CalculateChecksum(frame, 10); // 前10字节求和 IncrementCmdSequence(); AddFrameInterval(); return frame; } /// /// 读取温度指令(获取设置温度、实际温度、到温标志) /// /// 设备ID(0-255,默认0) /// 读取温度指令帧(5字节) public static byte[] SendReadTempRequest(byte deviceId = 0) { byte[] frame = new byte[5]; // 帧长固定5字节 byte seq = GetCurrentCmdSequence(); // 帧结构:ST → RDTEMP+序号 → 设备ID → LTH=5 → 校验和 frame[0] = ST; frame[1] = (byte)(RDTEMP | seq); frame[2] = deviceId; frame[3] = 5; // LTH固定为5 frame[4] = CalculateChecksum(frame, 4); IncrementCmdSequence(); AddFrameInterval(); return frame; } /// /// 读取传感器AD指令(获取AD值) /// /// 设备ID(0-255,默认0) /// 读取AD指令帧(5字节) public static byte[] SendReadAdcRequest(byte deviceId = 0) { byte[] frame = new byte[5]; // 帧长固定5字节(协议3.6) byte seq = GetCurrentCmdSequence(); // 帧结构:ST → RDADC+序号 → 设备ID → LTH=5 → 校验和 frame[0] = ST; frame[1] = (byte)(RDADC | seq); frame[2] = deviceId; frame[3] = 5; // LTH固定为5 frame[4] = CalculateChecksum(frame, 4); IncrementCmdSequence(); AddFrameInterval(); return frame; } /// /// 读取EEPROM指令(获取指定地址的硬件/调试信息) /// /// 地址高位字节 /// 地址中位字节 /// 地址低位字节 /// 读取长度(字节数) /// 设备ID(0-255,默认0) /// 读取EEPROM指令帧(变长,9 + readLength字节) public static byte[] SendReadEepromRequest(byte addrHigh, byte addrMid, byte addrLow, int readLength, byte deviceId = 0) { // 参数校验:读取长度≥1(避免空数据) if (readLength < 1) throw new ArgumentOutOfRangeException(nameof(readLength), "读取长度必须≥1"); int frameLength = 9 + readLength; // 帧长N=9(固定段)+ 读取长度 byte[] frame = new byte[frameLength]; byte seq = GetCurrentCmdSequence(); // 帧结构:ST → RDEE+序号 → 设备ID → LTH=N → 地址高→中→低 → 读取长度 → 校验和 frame[0] = ST; frame[1] = (byte)(RDEE | seq); frame[2] = deviceId; frame[3] = (byte)frameLength; // LTH=N(实际帧长) frame[4] = addrHigh; // 地址高位 frame[5] = addrMid; // 地址中位 frame[6] = addrLow; // 地址低位 frame[7] = (byte)readLength; // 读取长度 // 校验和:前(frameLength-1)字节求和(帧长-1 = 8 + readLength) frame[frameLength - 1] = CalculateChecksum(frame, frameLength - 1); IncrementCmdSequence(); AddFrameInterval(); return frame; } /// /// 写入EEPROM指令(写入硬件/调试/标定参数) /// /// 地址高位字节 /// 地址中位字节 /// 地址低位字节 /// 待写入的数据(字节数组) /// 设备ID(0-255,默认0) /// 写入EEPROM指令帧(变长,9 + writeData.Length字节) public static byte[] SendWriteEepromRequest(byte addrHigh, byte addrMid, byte addrLow, byte[] writeData, byte deviceId = 0) { // 参数校验:写入数据非空 if (writeData == null || writeData.Length == 0) throw new ArgumentException("写入数据不能为空", nameof(writeData)); int frameLength = 9 + writeData.Length; // 帧长N=9(固定段)+ 数据长度 byte[] frame = new byte[frameLength]; byte seq = GetCurrentCmdSequence(); // 帧结构:ST → WREE+序号 → 设备ID → LTH=N → 地址高→中→低 → 写入数据 → 校验和 frame[0] = ST; frame[1] = (byte)(WREE | seq); frame[2] = deviceId; frame[3] = (byte)frameLength; // LTH=N(实际帧长) frame[4] = addrHigh; // 地址高位 frame[5] = addrMid; // 地址中位 frame[6] = addrLow; // 地址低位 // 填充写入数据(从第8字节开始,索引7) Array.Copy(writeData, 0, frame, 7, writeData.Length); // 校验和:前(frameLength-1)字节求和 frame[frameLength - 1] = CalculateChecksum(frame, frameLength - 1); IncrementCmdSequence(); AddFrameInterval(); return frame; } /// /// 获取实际转速指令 /// /// 设备ID(0-255,默认0) /// 获取转速指令帧(5字节) public static byte[] SendReadMotorSpeedRequest(byte deviceId = 0) { byte[] frame = new byte[5]; // 帧长固定5字节 byte seq = GetCurrentCmdSequence(); // 帧结构:ST → RDMotSpeed+序号 → 设备ID → LTH=5 → 校验和 frame[0] = ST; frame[1] = (byte)(RDMotSpeed | seq); frame[2] = deviceId; frame[3] = 5; // LTH固定为5 frame[4] = CalculateChecksum(frame, 4); IncrementCmdSequence(); AddFrameInterval(); return frame; } /// /// 获取开关盖状态指令 /// /// 设备ID(0-255,默认0) /// 获取开关盖状态指令帧(5字节) public static byte[] SendReadIoStatusRequest(byte deviceId = 0) { byte[] frame = new byte[5]; // 帧长固定5字节 byte seq = GetCurrentCmdSequence(); // 帧结构:ST → RDIOStatus+序号 → 设备ID → LTH=5 → 校验和 frame[0] = ST; frame[1] = (byte)(RDIOStatus | seq); frame[2] = deviceId; frame[3] = 5; // LTH固定为5 frame[4] = CalculateChecksum(frame, 4); IncrementCmdSequence(); AddFrameInterval(); return frame; } /// /// 校准温度指令(设置温度校准B值) /// /// 校准B值(16位:B=(实际温度-目标温度)×100) /// 设备ID(0-255,默认0) /// 校准温度指令帧(7字节) public static byte[] SendCalibrateTempRequest(int calibBValue, byte deviceId = 0) { // 参数校验:B值为16位有符号范围(-32768~32767) if (calibBValue < short.MinValue || calibBValue > short.MaxValue) throw new ArgumentOutOfRangeException(nameof(calibBValue), "校准B值必须在-32768~32767之间"); byte[] frame = new byte[7]; // 帧长固定7字节 byte seq = GetCurrentCmdSequence(); ushort bParam = (ushort)calibBValue; // 转换为16位无符号(高位在前) // 帧结构:ST → Calb+序号 → 设备ID → LTH=7 → 参数1(高8) → 参数2(低8) → 校验和 frame[0] = ST; frame[1] = (byte)(Calb | seq); frame[2] = deviceId; frame[3] = 7; // LTH固定为7 frame[4] = (byte)(bParam >> 8); // 参数1(高8位) frame[5] = (byte)(bParam & 0xFF); // 参数2(低8位) frame[6] = CalculateChecksum(frame, 6); // 前6字节求和 IncrementCmdSequence(); AddFrameInterval(); return frame; } /// /// 加热温度控制 /// public static byte[] SendSetHotTemp(double targetTemp, byte deviceId = 0, bool releaseControl = false) { byte[] frame = new byte[7]; byte seq = GetCurrentCmdSequence(); ushort tempParam; if (releaseControl) { tempParam = 0xFFFF; // 释放控制 } else { // 协议范围:室温~100℃(对应室温*100~10000) if (targetTemp < 20.0 || targetTemp > 100.0) // 室温暂以20℃为参考下限 throw new ArgumentOutOfRangeException(nameof(targetTemp), "温度必须在[20.0 , 100]℃之间(参考室温)"); tempParam = (ushort)(targetTemp * 100); } frame[0] = ST; frame[1] = (byte)(SETHOTTEMP | seq); frame[2] = deviceId; frame[3] = 7; // LTH=7 frame[4] = (byte)(tempParam >> 8); frame[5] = (byte)(tempParam & 0xFF); frame[6] = CalculateChecksum(frame, 6); IncrementCmdSequence(); AddFrameInterval(); return frame; } /// /// 电磁阀控制指令 /// public static byte[] SendRelayControl(bool isOpen, byte deviceId = 0) { byte[] frame = new byte[6]; byte seq = GetCurrentCmdSequence(); byte param = (byte)(isOpen ? 1 : 0); // 1=开启,0=关闭 frame[0] = ST; frame[1] = (byte)(RelayControl | seq); frame[2] = deviceId; frame[3] = 6; // LTH=6 frame[4] = param; frame[5] = CalculateChecksum(frame, 5); IncrementCmdSequence(); AddFrameInterval(); return frame; } #endregion #region 指令解析(主控板→PC,返回结构化结果) /// /// 解析主控板返回的帧数据(入口方法) /// /// 主控板返回的原始字节数组 /// 解析结果(结构化对象,包含指令类型、状态、数据) public static ParseResult ParseReceivedFrame(byte[] receivedFrame) { // 基础校验:帧非空、帧长≥5(最短帧为5字节) if (receivedFrame == null || receivedFrame.Length < 5) return new ParseResult(false, "无效帧:数据为空或长度不足", null); // 1. 校验帧头(必须为ST=0x5E) if (receivedFrame[0] != ST) return new ParseResult(false, $"帧头错误:实际0x{receivedFrame[0]:X2},期望0x{ST:X2}", null); // 2. 提取核心字段 byte cmdWithFlag = receivedFrame[1]; // 带0x80标志的指令码 byte deviceId = receivedFrame[2]; // 设备ID byte frameLength = receivedFrame[3]; // 帧长LTH byte checksum = receivedFrame[frameLength - 1]; // 帧中校验和 // 3. 校验帧长(实际长度必须等于帧长字段) if (receivedFrame.Length != frameLength) return new ParseResult(false, $"帧长不匹配:实际{receivedFrame.Length}字节,期望{frameLength}字节", null); // 4. 校验和验证 byte calculatedChecksum = CalculateChecksum(receivedFrame, frameLength - 1); if (calculatedChecksum != checksum) return new ParseResult(false, $"校验和错误:实际0x{checksum:X2},计算0x{calculatedChecksum:X2}", null); // 5. 去除响应标志,获取原始指令码 byte originalCmd = (byte)(cmdWithFlag & ~RESPONSE_FLAG); // 6. 按指令类型分发解析 switch (originalCmd) { case HELLO: return ParseHelloResponse(receivedFrame, deviceId); case STATUS: return ParseStatusResponse(receivedFrame, deviceId); case SETTEMP: return ParseSetTempResponse(receivedFrame, deviceId); case MOTOR: return ParseMotorResponse(receivedFrame, deviceId); case RDTEMP: return ParseReadTempResponse(receivedFrame, deviceId); case RDADC: return ParseReadAdcResponse(receivedFrame, deviceId); case RDEE: return ParseReadEepromResponse(receivedFrame, deviceId); case WREE: return ParseWriteEepromResponse(receivedFrame, deviceId); case RDMotSpeed: return ParseReadMotorSpeedResponse(receivedFrame, deviceId); case RDIOStatus: return ParseReadIoStatusResponse(receivedFrame, deviceId); case Calb: return ParseCalibrateTempResponse(receivedFrame, deviceId); case SETHOTTEMP: return ParseSetHotTempResponse(receivedFrame, deviceId); case RelayControl: return ParseRelayControlResponse(receivedFrame, deviceId); default: return new ParseResult(false, $"未知指令:0x{originalCmd:X2}", null); } } #region 各指令解析实现 /// /// 解析握手响应 /// private static ParseResult ParseHelloResponse(byte[] frame, byte deviceId) { // 响应帧长固定6字节(协议3.1) if (frame.Length != 6) return new ParseResult(false, "握手响应帧长错误(需6字节)", null); byte status = frame[4]; // 状态位(0=成功) var data = new Dictionary { { "设备ID", deviceId }, { "状态码", status }, { "状态描述", status == 0 ? "握手成功" : $"握手失败(错误码:{status})" } }; return new ParseResult(true, "握手响应解析成功", data); } /// /// 解析报错状态响应 /// private static ParseResult ParseStatusResponse(byte[] frame, byte deviceId) { // 响应帧长固定8字节(协议3.2) if (frame.Length != 8) return new ParseResult(false, "报错状态响应帧长错误(需8字节)", null); // 提取Error(2字节:Bit0-11)和状态位 ushort error = (ushort)((frame[4] << 8) | frame[5]); byte status = frame[6]; // 解析Error按位含义(协议3.2) var errorDesc = new Dictionary { { "测温传感器故障(Bit0)", (error & (1 << 0)) != 0 }, { "温度过高>200℃(Bit1)", (error & (1 << 1)) != 0 }, { "温度过低≤0℃(Bit2)", (error & (1 << 2)) != 0 }, { "电机故障(Bit3)", (error & (1 << 3)) != 0 }, { "预留Bit4", (error & (1 << 4)) != 0 }, { "预留Bit5", (error & (1 << 5)) != 0 } }; var data = new Dictionary { { "设备ID", deviceId }, { "状态码", status }, { "状态描述", status == 0 ? "读取报错状态成功" : $"读取失败(错误码:{status})" }, { "报错详情", errorDesc }, { "原始Error值", $"0x{error:X4}" } }; return new ParseResult(true, "报错状态响应解析成功", data); } /// /// 解析温度控制响应 /// private static ParseResult ParseSetTempResponse(byte[] frame, byte deviceId) { // 响应帧长固定6字节(协议3.3) if (frame.Length != 6) return new ParseResult(false, "温度控制响应帧长错误(需6字节)", null); byte status = frame[4]; // 状态位(0=成功) var data = new Dictionary { { "设备ID", deviceId }, { "状态码", status }, { "状态描述", status == 0 ? "温度控制指令接收成功" : $"接收失败(错误码:{status})" } }; return new ParseResult(true, "温度控制响应解析成功", data); } /// /// 解析电机控制响应 /// private static ParseResult ParseMotorResponse(byte[] frame, byte deviceId) { // 响应帧长固定6字节(协议3.4) if (frame.Length != 6) return new ParseResult(false, "电机控制响应帧长错误(需6字节)", null); byte status = frame[4]; // 状态位(0=成功) var data = new Dictionary { { "设备ID", deviceId }, { "状态码", status }, { "状态描述", status == 0 ? "电机控制指令接收成功" : $"接收失败(错误码:{status})" } }; return new ParseResult(true, "电机控制响应解析成功", data); } /// /// 解析读取温度响应 /// private static ParseResult ParseReadTempResponse(byte[] frame, byte deviceId) { // 响应帧长固定0x0D(13字节,协议3.5) if (frame.Length != 0x0D) return new ParseResult(false, $"读取温度响应帧长错误(需13字节,实际{frame.Length}字节)", null); // 提取数据:设置温度(5-6字节)、实际温度(7-8字节)、预留(9-10)、标志位(11)、状态位(12) ushort setTempParam = (ushort)((frame[4] << 8) | frame[5]); ushort actualTempParam = (ushort)((frame[6] << 8) | frame[7]); byte flag = frame[10]; // 0=未到温,1=到温 byte status = frame[11]; // 转换为实际温度(除以100,精度0.1) double setTemp = setTempParam / 100.0; double actualTemp = actualTempParam / 100.0; var data = new Dictionary { { "设备ID", deviceId }, { "状态码", status }, { "状态描述", status == 0 ? "读取温度成功" : $"读取失败(错误码:{status})" }, { "设置温度(℃)", setTemp }, { "实际温度(℃)", actualTemp }, { "到温标志", flag == 0 ? "未到温" : "已到温" }, { "原始设置温度参数", $"0x{setTempParam:X4}" }, { "原始实际温度参数", $"0x{actualTempParam:X4}" } }; return new ParseResult(true, "读取温度响应解析成功", data); } /// /// 解析读取AD响应 /// private static ParseResult ParseReadAdcResponse(byte[] frame, byte deviceId) { // 响应帧长固定0x0D(13字节,协议3.6) if (frame.Length != 0x0D) return new ParseResult(false, $"读取AD响应帧长错误(需13字节,实际{frame.Length}字节)", null); // 提取数据:AD值(5-6字节)、预留(7-8)、状态位(9) ushort adcValue = (ushort)((frame[4] << 8) | frame[5]); byte status = frame[8]; var data = new Dictionary { { "设备ID", deviceId }, { "状态码", status }, { "状态描述", status == 0 ? "读取AD成功" : $"读取失败(错误码:{status})" }, { "AD值", adcValue }, { "原始AD参数", $"0x{adcValue:X4}" } }; return new ParseResult(true, "读取AD响应解析成功", data); } /// /// 解析读取EEPROM响应 /// private static ParseResult ParseReadEepromResponse(byte[] frame, byte deviceId) { // 响应帧长N≥6(协议3.7:返回长度-6为数据字节数) if (frame.Length < 6) return new ParseResult(false, "读取EEPROM响应帧长不足(需≥6字节)", null); // 提取数据:参数1~参数n(5到N-2字节)、状态位(N-2字节) int dataLength = frame.Length - 6; // 数据字节数(N-6) byte[] eepromData = new byte[dataLength]; Array.Copy(frame, 4, eepromData, 0, dataLength); // 从第5字节(索引4)开始复制 byte status = frame[frame.Length - 2]; // 状态位(N-2字节) var data = new Dictionary { { "设备ID", deviceId }, { "状态码", status }, { "状态描述", status == 0 ? "读取EEPROM成功" : $"读取失败(错误码:{status})" }, { "读取数据长度(字节)", dataLength }, { "读取数据(十六进制)", BitConverter.ToString(eepromData).Replace("-", " ") }, { "原始数据数组", eepromData } }; return new ParseResult(true, "读取EEPROM响应解析成功", data); } /// /// 解析写入EEPROM响应 /// private static ParseResult ParseWriteEepromResponse(byte[] frame, byte deviceId) { // 响应帧长固定6字节(协议3.8) if (frame.Length != 6) return new ParseResult(false, "写入EEPROM响应帧长错误(需6字节)", null); byte status = frame[4]; // 状态位(0=成功) var data = new Dictionary { { "设备ID", deviceId }, { "状态码", status }, { "状态描述", status == 0 ? "写入EEPROM成功" : $"写入失败(错误码:{status})" } }; return new ParseResult(true, "写入EEPROM响应解析成功", data); } /// /// 解析获取实际转速响应 /// private static ParseResult ParseReadMotorSpeedResponse(byte[] frame, byte deviceId) { // 响应帧长固定8字节(协议3.9) if (frame.Length != 8) return new ParseResult(false, "获取转速响应帧长错误(需8字节)", null); // 提取数据:转速参数(5-6字节)、状态位(7字节) ushort speedParam = (ushort)((frame[4] << 8) | frame[5]); byte status = frame[6]; var data = new Dictionary { { "设备ID", deviceId }, { "状态码", status }, { "状态描述", status == 0 ? "获取转速成功" : $"获取失败(错误码:{status})" }, { "实际转速", speedParam }, { "原始转速参数", $"0x{speedParam:X4}" } }; return new ParseResult(true, "获取转速响应解析成功", data); } /// /// 解析获取开关盖状态响应 /// private static ParseResult ParseReadIoStatusResponse(byte[] frame, byte deviceId) { // 响应帧长固定7字节(协议3.10) if (frame.Length != 7) return new ParseResult(false, "获取开关盖状态响应帧长错误(需7字节)", null); // 提取数据:开关盖参数(5字节)、状态位(6字节) byte ioParam = frame[4]; // 0=关盖,1=开盖 byte status = frame[5]; var data = new Dictionary { { "设备ID", deviceId }, { "状态码", status }, { "状态描述", status == 0 ? "获取开关盖状态成功" : $"获取失败(错误码:{status})" }, { "开关盖状态", ioParam == 0 ? "关盖" : "开盖" }, { "原始状态参数", $"0x{ioParam:X2}" } }; return new ParseResult(true, "获取开关盖状态响应解析成功", data); } /// /// 解析校准温度响应 /// private static ParseResult ParseCalibrateTempResponse(byte[] frame, byte deviceId) { // 响应帧长固定6字节(协议3.11) if (frame.Length != 6) return new ParseResult(false, "校准温度响应帧长错误(需6字节)", null); byte status = frame[4]; // 状态位(0=成功) var data = new Dictionary { { "设备ID", deviceId }, { "状态码", status }, { "状态描述", status == 0 ? "温度校准指令接收成功" : $"接收失败(错误码:{status})" } }; return new ParseResult(true, "校准温度响应解析成功", data); } /// /// 加热温度控制响应解析 /// private static ParseResult ParseSetHotTempResponse(byte[] frame, byte deviceId) { if (frame.Length != 6) return new ParseResult(false, "加热温度响应帧长错误(需6字节)", null); byte status = frame[4]; var data = new Dictionary { { "设备ID", deviceId }, { "状态码", status }, { "状态描述", status == 0 ? "加热温度指令接收成功" : $"接收失败(错误码:{status})" } }; return new ParseResult(true, "加热温度响应解析成功", data); } /// /// 电磁阀控制响应解析 /// private static ParseResult ParseRelayControlResponse(byte[] frame, byte deviceId) { if (frame.Length != 6) return new ParseResult(false, "电磁阀控制响应帧长错误(需6字节)", null); byte status = frame[4]; var data = new Dictionary { { "设备ID", deviceId }, { "状态码", status }, { "状态描述", status == 0 ? "电磁阀指令接收成功" : $"接收失败(错误码:{status})" } }; return new ParseResult(true, "电磁阀控制响应解析成功", data); } #endregion #endregion /// /// 帧间隔时间(协议要求>2ms,留3ms余量) /// private static void AddFrameInterval() { Task.Delay(3); } /// /// CRC16校验(用户原类中定义,协议未使用,保留以备扩展) /// public static byte[] CRC16(byte[] data) { int len = data.Length; if (len <= 0) return new byte[] { 0, 0 }; ushort crc = 0xFFFF; for (int i = 0; i < len; i++) { crc = (ushort)(crc ^ data[i]); for (int j = 0; j < 8; j++) { crc = (crc & 1) != 0 ? (ushort)((crc >> 1) ^ 0xA001) : (ushort)(crc >> 1); } } byte hi = (byte)((crc & 0xFF00) >> 8); byte lo = (byte)(crc & 0x00FF); return BitConverter.IsLittleEndian ? new byte[] { lo, hi } : new byte[] { hi, lo }; } } }