C00225155-02/C00225155/MegaRobo.C00225155/MegaRobo.C00225155.ControlD.../TemperatureControl/LowTemperatureUartHCM.cs

853 lines
37 KiB
C#
Raw Normal View History

2026-04-13 09:12:49 +00:00
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
{
/// <summary>
/// 高温温度模块 485 uart 定制HCM通信协议封装类PC→主控板指令构建 + 主控板→PC指令解析
/// </summary>
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 6n-18
/// <summary>
/// 计算帧的校验和核心前length字节之和的低8位
/// </summary>
/// <param name="data">待计算的帧数据</param>
/// <param name="length">参与计算的字节数前n-1字节</param>
/// <returns>校验和字节</returns>
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 线
/// <summary>
/// 指令序号自增0-255自动溢出确保除溢出外无重复指令
/// </summary>
private static void IncrementCmdSequence()
{
lock (_lock)
{
_cmdSequence++; // 字节类型自动溢出255→0
// 确保序号不超过0x7F避免下发指令CMD被误认为上传指令
if (_cmdSequence >= 0x80)
_cmdSequence = 0;
}
}
/// <summary>
/// 获取当前指令序号(带线程安全)
/// </summary>
private static byte GetCurrentCmdSequence()
{
lock (_lock)
{
return _cmdSequence;
}
}
#endregion
#region PCbyte[]
/// <summary>
/// 握手指令(系统开机必发)
/// </summary>
/// <param name="deviceId">设备ID0-255默认0</param>
/// <returns>握手指令帧5字节</returns>
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;
}
/// <summary>
/// 读取报错状态指令
/// </summary>
/// <param name="deviceId">设备ID0-255默认0</param>
/// <returns>报错状态指令帧5字节</returns>
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;
}
/// <summary>
/// 温度控制指令(下发后主控板直接执行温度控制)
/// </summary>
/// <param name="targetTemp">目标温度10.0-180.0℃精度0.1</param>
/// <param name="deviceId">设备ID0-255默认0</param>
/// <param name="releaseControl">是否释放控制true=0xFFFF关断功率关闭温度</param>
/// <returns>温度控制指令帧7字节</returns>
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;
}
/// <summary>
/// 电机控制指令(设置电机转速)
/// </summary>
/// <param name="motorSpeed">电机转速200-150016位参数</param>
/// <param name="deviceId">设备ID0-255默认0</param>
/// <returns>电机控制指令帧11字节0x0B=11</returns>
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]; // 帧长固定0x0B11字节
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;
}
/// <summary>
/// 读取温度指令(获取设置温度、实际温度、到温标志)
/// </summary>
/// <param name="deviceId">设备ID0-255默认0</param>
/// <returns>读取温度指令帧5字节</returns>
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;
}
/// <summary>
/// 读取传感器AD指令获取AD值
/// </summary>
/// <param name="deviceId">设备ID0-255默认0</param>
/// <returns>读取AD指令帧5字节</returns>
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;
}
/// <summary>
/// 读取EEPROM指令获取指定地址的硬件/调试信息)
/// </summary>
/// <param name="addrHigh">地址高位字节</param>
/// <param name="addrMid">地址中位字节</param>
/// <param name="addrLow">地址低位字节</param>
/// <param name="readLength">读取长度(字节数)</param>
/// <param name="deviceId">设备ID0-255默认0</param>
/// <returns>读取EEPROM指令帧变长9 + readLength字节</returns>
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;
}
/// <summary>
/// 写入EEPROM指令写入硬件/调试/标定参数)
/// </summary>
/// <param name="addrHigh">地址高位字节</param>
/// <param name="addrMid">地址中位字节</param>
/// <param name="addrLow">地址低位字节</param>
/// <param name="writeData">待写入的数据(字节数组)</param>
/// <param name="deviceId">设备ID0-255默认0</param>
/// <returns>写入EEPROM指令帧变长9 + writeData.Length字节</returns>
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;
}
/// <summary>
/// 获取实际转速指令
/// </summary>
/// <param name="deviceId">设备ID0-255默认0</param>
/// <returns>获取转速指令帧5字节</returns>
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;
}
/// <summary>
/// 获取开关盖状态指令
/// </summary>
/// <param name="deviceId">设备ID0-255默认0</param>
/// <returns>获取开关盖状态指令帧5字节</returns>
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;
}
/// <summary>
/// 校准温度指令设置温度校准B值
/// </summary>
/// <param name="calibBValue">校准B值16位B=(实际温度-目标温度)×100</param>
/// <param name="deviceId">设备ID0-255默认0</param>
/// <returns>校准温度指令帧7字节</returns>
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;
}
/// <summary>
/// 加热温度控制
/// </summary>
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;
}
/// <summary>
/// 电磁阀控制指令
/// </summary>
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
/// <summary>
/// 解析主控板返回的帧数据(入口方法)
/// </summary>
/// <param name="receivedFrame">主控板返回的原始字节数组</param>
/// <returns>解析结果(结构化对象,包含指令类型、状态、数据)</returns>
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
/// <summary>
/// 解析握手响应
/// </summary>
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<string, object>
{
{ "设备ID", deviceId },
{ "状态码", status },
{ "状态描述", status == 0 ? "握手成功" : $"握手失败(错误码:{status}" }
};
return new ParseResult(true, "握手响应解析成功", data);
}
/// <summary>
/// 解析报错状态响应
/// </summary>
private static ParseResult ParseStatusResponse(byte[] frame, byte deviceId)
{
// 响应帧长固定8字节协议3.2
if (frame.Length != 8)
return new ParseResult(false, "报错状态响应帧长错误需8字节", null);
// 提取Error2字节Bit0-11和状态位
ushort error = (ushort)((frame[4] << 8) | frame[5]);
byte status = frame[6];
// 解析Error按位含义协议3.2
var errorDesc = new Dictionary<string, bool>
{
{ "测温传感器故障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<string, object>
{
{ "设备ID", deviceId },
{ "状态码", status },
{ "状态描述", status == 0 ? "读取报错状态成功" : $"读取失败(错误码:{status}" },
{ "报错详情", errorDesc },
{ "原始Error值", $"0x{error:X4}" }
};
return new ParseResult(true, "报错状态响应解析成功", data);
}
/// <summary>
/// 解析温度控制响应
/// </summary>
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<string, object>
{
{ "设备ID", deviceId },
{ "状态码", status },
{ "状态描述", status == 0 ? "温度控制指令接收成功" : $"接收失败(错误码:{status}" }
};
return new ParseResult(true, "温度控制响应解析成功", data);
}
/// <summary>
/// 解析电机控制响应
/// </summary>
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<string, object>
{
{ "设备ID", deviceId },
{ "状态码", status },
{ "状态描述", status == 0 ? "电机控制指令接收成功" : $"接收失败(错误码:{status}" }
};
return new ParseResult(true, "电机控制响应解析成功", data);
}
/// <summary>
/// 解析读取温度响应
/// </summary>
private static ParseResult ParseReadTempResponse(byte[] frame, byte deviceId)
{
// 响应帧长固定0x0D13字节协议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<string, object>
{
{ "设备ID", deviceId },
{ "状态码", status },
{ "状态描述", status == 0 ? "读取温度成功" : $"读取失败(错误码:{status}" },
{ "设置温度(℃)", setTemp },
{ "实际温度(℃)", actualTemp },
{ "到温标志", flag == 0 ? "未到温" : "已到温" },
{ "原始设置温度参数", $"0x{setTempParam:X4}" },
{ "原始实际温度参数", $"0x{actualTempParam:X4}" }
};
return new ParseResult(true, "读取温度响应解析成功", data);
}
/// <summary>
/// 解析读取AD响应
/// </summary>
private static ParseResult ParseReadAdcResponse(byte[] frame, byte deviceId)
{
// 响应帧长固定0x0D13字节协议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<string, object>
{
{ "设备ID", deviceId },
{ "状态码", status },
{ "状态描述", status == 0 ? "读取AD成功" : $"读取失败(错误码:{status}" },
{ "AD值", adcValue },
{ "原始AD参数", $"0x{adcValue:X4}" }
};
return new ParseResult(true, "读取AD响应解析成功", data);
}
/// <summary>
/// 解析读取EEPROM响应
/// </summary>
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~参数n5到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<string, object>
{
{ "设备ID", deviceId },
{ "状态码", status },
{ "状态描述", status == 0 ? "读取EEPROM成功" : $"读取失败(错误码:{status}" },
{ "读取数据长度(字节)", dataLength },
{ "读取数据(十六进制)", BitConverter.ToString(eepromData).Replace("-", " ") },
{ "原始数据数组", eepromData }
};
return new ParseResult(true, "读取EEPROM响应解析成功", data);
}
/// <summary>
/// 解析写入EEPROM响应
/// </summary>
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<string, object>
{
{ "设备ID", deviceId },
{ "状态码", status },
{ "状态描述", status == 0 ? "写入EEPROM成功" : $"写入失败(错误码:{status}" }
};
return new ParseResult(true, "写入EEPROM响应解析成功", data);
}
/// <summary>
/// 解析获取实际转速响应
/// </summary>
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<string, object>
{
{ "设备ID", deviceId },
{ "状态码", status },
{ "状态描述", status == 0 ? "获取转速成功" : $"获取失败(错误码:{status}" },
{ "实际转速", speedParam },
{ "原始转速参数", $"0x{speedParam:X4}" }
};
return new ParseResult(true, "获取转速响应解析成功", data);
}
/// <summary>
/// 解析获取开关盖状态响应
/// </summary>
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<string, object>
{
{ "设备ID", deviceId },
{ "状态码", status },
{ "状态描述", status == 0 ? "获取开关盖状态成功" : $"获取失败(错误码:{status}" },
{ "开关盖状态", ioParam == 0 ? "关盖" : "开盖" },
{ "原始状态参数", $"0x{ioParam:X2}" }
};
return new ParseResult(true, "获取开关盖状态响应解析成功", data);
}
/// <summary>
/// 解析校准温度响应
/// </summary>
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<string, object>
{
{ "设备ID", deviceId },
{ "状态码", status },
{ "状态描述", status == 0 ? "温度校准指令接收成功" : $"接收失败(错误码:{status}" }
};
return new ParseResult(true, "校准温度响应解析成功", data);
}
/// <summary>
/// 加热温度控制响应解析
/// </summary>
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<string, object>
{
{ "设备ID", deviceId },
{ "状态码", status },
{ "状态描述", status == 0 ? "加热温度指令接收成功" : $"接收失败(错误码:{status}" }
};
return new ParseResult(true, "加热温度响应解析成功", data);
}
/// <summary>
/// 电磁阀控制响应解析
/// </summary>
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<string, object>
{
{ "设备ID", deviceId },
{ "状态码", status },
{ "状态描述", status == 0 ? "电磁阀指令接收成功" : $"接收失败(错误码:{status}" }
};
return new ParseResult(true, "电磁阀控制响应解析成功", data);
}
#endregion
#endregion
/// <summary>
/// 帧间隔时间(协议要求>2ms留3ms余量
/// </summary>
private static void AddFrameInterval()
{
Task.Delay(3);
}
/// <summary>
/// CRC16校验用户原类中定义协议未使用保留以备扩展
/// </summary>
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 };
}
}
}