first
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
using System.Net;
|
||||
using UdpServer = Common.Net.Udp.UdpServer;
|
||||
|
||||
namespace FASS.Extend.Master
|
||||
{
|
||||
public class Command
|
||||
{
|
||||
public UdpServer Server { get; private set; }
|
||||
|
||||
public EndPoint Remote { get => Server.RemoteEndPoint; set => Server.RemoteEndPoint = value; }
|
||||
|
||||
public Command(IPEndPoint local)
|
||||
{
|
||||
Server = new UdpServer()
|
||||
{
|
||||
LocalEndPoint = local
|
||||
};
|
||||
}
|
||||
|
||||
public void SendState(byte command, byte state, ulong timeSpan, IPEndPoint remote)
|
||||
{
|
||||
var sendMessage = new SendQueryMessage().SetMessage(command, state, timeSpan);
|
||||
var sendByteArray = sendMessage.GetByteArray();
|
||||
Server.Send(sendByteArray, remote);
|
||||
}
|
||||
public static ReceiveStateMessage GetReceiveStateMessage(byte[] byteArray) => new ReceiveStateMessage().GetMessage(byteArray);
|
||||
public static byte[] GetReceiveStateByteArray(ReceiveStateMessage message) => message.GetByteArray();
|
||||
|
||||
public void SendLightControls(byte taskNo, byte sectionCount, LightControlMessage[] lightControlMessages, ulong timeStamp, IPEndPoint remote)
|
||||
{
|
||||
var sendMessage = new SendControlMessage().SetMessage(taskNo, sectionCount, lightControlMessages, timeStamp);
|
||||
var sendByteArray = sendMessage.GetByteArray();
|
||||
Server.Send(sendByteArray, remote);
|
||||
}
|
||||
public static ReceiveControlRespMessage GetReceiveControlRespMessage(byte[] byteArray) => new ReceiveControlRespMessage().GetMessage(byteArray);
|
||||
public static byte[] GetSendControlByteArray(SendControlMessage message) => message.GetByteArray();
|
||||
|
||||
|
||||
public void SendPressedStateResponse(byte command, byte taskNo, byte lightNo, byte state, uint led, ulong timeSpan, IPEndPoint remote)
|
||||
{
|
||||
var sendMessage = new SendPressedStateRespMessage().SetMessage(command, taskNo, lightNo, state, led, timeSpan);
|
||||
var sendByteArray = sendMessage.GetByteArray();
|
||||
Server.Send(sendByteArray, remote);
|
||||
}
|
||||
|
||||
public static SendPressedStateRespMessage GetPressedStateResponseMessage(byte[] byteArray) => new SendPressedStateRespMessage().GetMessage(byteArray);
|
||||
|
||||
public static byte[] GetPressedStateResponseByteArray(SendPressedStateRespMessage message) => message.GetByteArray();
|
||||
|
||||
public static ReceivePressedStateMessage GetReceivePressedStateMessage(byte[] byteArray) => new ReceivePressedStateMessage().GetMessage(byteArray);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
namespace FASS.Extend.Master
|
||||
{
|
||||
public static class Crc32
|
||||
{
|
||||
private static readonly uint[] Table;
|
||||
|
||||
static Crc32()
|
||||
{
|
||||
// 初始化CRC32查找表
|
||||
Table = new uint[256];
|
||||
const uint poly = 0xEDB88320; // 标准CRC32多项式
|
||||
|
||||
for (uint i = 0; i < 256; i++)
|
||||
{
|
||||
var crc = i;
|
||||
for (var j = 0; j < 8; j++)
|
||||
{
|
||||
crc = (crc & 1) == 1
|
||||
? (crc >> 1) ^ poly
|
||||
: crc >> 1;
|
||||
}
|
||||
Table[i] = crc;
|
||||
}
|
||||
}
|
||||
|
||||
public static uint Compute(byte[] data)
|
||||
{
|
||||
uint crc = 0xFFFFFFFF; // 初始值
|
||||
foreach (byte b in data)
|
||||
{
|
||||
// 查表更新CRC值
|
||||
crc = (crc >> 8) ^ Table[(crc ^ b) & 0xFF];
|
||||
}
|
||||
return crc ^ 0xFFFFFFFF; // 最终异或处理
|
||||
}
|
||||
|
||||
public static byte[] LittleEndianComputeBytes(byte[] data)
|
||||
{
|
||||
uint crc = Compute(data);
|
||||
return BitConverter.GetBytes(crc);
|
||||
}
|
||||
|
||||
public static byte[] BigEndianComputeBytes(byte[] data)
|
||||
{
|
||||
uint crc = Compute(data);
|
||||
var result = BitConverter.GetBytes(crc);
|
||||
Array.Reverse(result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Version>2.4.2</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Common.Net" Version="2.4.2" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,49 @@
|
||||
namespace FASS.Extend.Master
|
||||
{
|
||||
public class LightControlMessage
|
||||
{
|
||||
public byte StartLightNo { get; set; }
|
||||
public byte EndLightNo { get; set; }
|
||||
public byte State { get; set; } = 0;
|
||||
public uint Led { get; set; }
|
||||
public byte Reserve { get; set; }
|
||||
|
||||
|
||||
public LightControlMessage SetMessage(
|
||||
byte startLightNo,
|
||||
byte endLightNo,
|
||||
byte state,
|
||||
uint led)
|
||||
{
|
||||
StartLightNo = startLightNo;
|
||||
EndLightNo = endLightNo;
|
||||
State = state;
|
||||
Led = led;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LightControlMessage GetMessage(byte[] byteArray)
|
||||
{
|
||||
if (byteArray == null || byteArray.Length != 8) throw new Exception($"数据长度错误:{Utility.ByteArrayToHexString(byteArray)}");
|
||||
StartLightNo = byteArray[0];
|
||||
EndLightNo = byteArray[1];
|
||||
State = byteArray[2];
|
||||
Led = BitConverter.ToUInt32(byteArray[3..7]);
|
||||
return this;
|
||||
}
|
||||
|
||||
public byte[] GetByteArray()
|
||||
{
|
||||
var byteArray = new byte[8];
|
||||
byteArray[0] = StartLightNo;
|
||||
byteArray[1] = EndLightNo;
|
||||
byteArray[2] = State;
|
||||
var ledArr = BitConverter.GetBytes(Led);
|
||||
byteArray[3] = ledArr[0];
|
||||
byteArray[4] = ledArr[1];
|
||||
byteArray[5] = ledArr[2];
|
||||
byteArray[6] = ledArr[3];
|
||||
return byteArray;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
namespace FASS.Extend.Master
|
||||
{
|
||||
public class LightStateMessage
|
||||
{
|
||||
public byte Alarm { get; set; }
|
||||
public byte State { get; set; }
|
||||
|
||||
public LightStateMessage SetMessage(
|
||||
byte alarm,
|
||||
byte state)
|
||||
{
|
||||
Alarm = alarm;
|
||||
State = state;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LightStateMessage GetMessage(byte[] byteArray)
|
||||
{
|
||||
if (byteArray == null || byteArray.Length < 2) throw new Exception($"数据长度错误:{Utility.ByteArrayToHexString(byteArray)}");
|
||||
Alarm = byteArray[0];
|
||||
State = byteArray[1];
|
||||
return this;
|
||||
}
|
||||
|
||||
public byte[] GetByteArray()
|
||||
{
|
||||
var byteArray = new byte[2];
|
||||
byteArray[0] = Alarm;
|
||||
byteArray[1] = State;
|
||||
return byteArray;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
namespace FASS.Extend.Master
|
||||
{
|
||||
public class ReceiveControlRespMessage
|
||||
{
|
||||
public byte Begin { get; set; } = 0xBB;
|
||||
public byte Command { get; set; }
|
||||
public string? Uuid { get; set; }
|
||||
public byte TaskNo { get; set; }
|
||||
public byte[] Reserve { get; set; } = new byte[6];
|
||||
public byte[] Check { get; set; } = new byte[4];
|
||||
public byte[] End { get; set; } = { 0xEE, 0xEE, 0xEE };
|
||||
|
||||
public ReceiveControlRespMessage SetMessage(
|
||||
byte command,
|
||||
string uuid,
|
||||
byte taskNo)
|
||||
{
|
||||
Command = command;
|
||||
Uuid = uuid;
|
||||
TaskNo = taskNo;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ReceiveControlRespMessage GetMessage(byte[] byteArray)
|
||||
{
|
||||
if (byteArray == null || byteArray.Length < 24) throw new Exception($"数据长度错误:{Utility.ByteArrayToHexString(byteArray)}");
|
||||
//if (byteArray[98] != Utility.XOR(byteArray[1..^2])) throw new Exception($"数据校验错误:{Utility.ByteArrayToHexString(byteArray)}");
|
||||
//if (byteArray[0] != 0xBB || byteArray[99] != 0xEE) throw new Exception($"数据帧头尾错误:{Utility.ByteArrayToHexString(byteArray)}");
|
||||
Begin = byteArray[0];
|
||||
Command = byteArray[1];
|
||||
Uuid = Utility.ByteArrayToHexString(byteArray[2..10]).ToLower();
|
||||
TaskNo = byteArray[10];
|
||||
Reserve = byteArray[11..17];
|
||||
Check = byteArray[17..21];
|
||||
End = byteArray[21..24];
|
||||
return this;
|
||||
}
|
||||
|
||||
public byte[] GetByteArray()
|
||||
{
|
||||
var byteArray = new byte[24];
|
||||
byteArray[0] = Begin;
|
||||
byteArray[1] = Command;
|
||||
var uuid = Utility.HexStringToBytes(Uuid!);
|
||||
Array.Copy(uuid, 0, byteArray, 2, uuid.Length);
|
||||
byteArray[10] = TaskNo;
|
||||
Array.Copy(Reserve, 0, byteArray, 11, Reserve.Length);
|
||||
var crc32Check = Crc32.LittleEndianComputeBytes(byteArray[1..^7]);
|
||||
Array.Copy(crc32Check, 0, byteArray, 17, crc32Check.Length);
|
||||
Array.Copy(End, 0, byteArray, 21, End.Length);
|
||||
return byteArray;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
namespace FASS.Extend.Master
|
||||
{
|
||||
public class ReceivePressedStateMessage
|
||||
{
|
||||
public byte Begin { get; set; } = 0xBB;
|
||||
public byte Command { get; set; }
|
||||
public string? Uuid { get; set; }
|
||||
public byte TaskNo { get; set; }
|
||||
public byte LightNo { get; set; }
|
||||
public byte[] Reserve { get; set; } = new byte[6];
|
||||
public byte[] Check { get; set; } = new byte[4];
|
||||
public byte[] End { get; set; } = { 0xEE, 0xEE, 0xEE };
|
||||
|
||||
public ReceivePressedStateMessage SetMessage(
|
||||
byte command,
|
||||
string uuid,
|
||||
byte taskNo,
|
||||
byte lightNo)
|
||||
{
|
||||
Command = command;
|
||||
Uuid = uuid;
|
||||
TaskNo = taskNo;
|
||||
LightNo = lightNo;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ReceivePressedStateMessage GetMessage(byte[] byteArray)
|
||||
{
|
||||
if (byteArray == null || byteArray.Length < 24) throw new Exception($"数据长度错误:{Utility.ByteArrayToHexString(byteArray)}");
|
||||
//if (byteArray[98] != Utility.XOR(byteArray[1..^2])) throw new Exception($"数据校验错误:{Utility.ByteArrayToHexString(byteArray)}");
|
||||
//if (byteArray[0] != 0xBB || byteArray[99] != 0xEE) throw new Exception($"数据帧头尾错误:{Utility.ByteArrayToHexString(byteArray)}");
|
||||
Begin = byteArray[0];
|
||||
Command = byteArray[1];
|
||||
Uuid = Utility.ByteArrayToHexString(byteArray[2..10]).ToLower();
|
||||
TaskNo = byteArray[10];
|
||||
LightNo = byteArray[11];
|
||||
Reserve = byteArray[12..17];
|
||||
Check = byteArray[17..21];
|
||||
End = byteArray[21..24];
|
||||
return this;
|
||||
}
|
||||
|
||||
public byte[] GetByteArray()
|
||||
{
|
||||
var byteArray = new byte[24];
|
||||
byteArray[0] = Begin;
|
||||
byteArray[1] = Command;
|
||||
var uuid = Utility.HexStringToBytes(Uuid!);
|
||||
Array.Copy(uuid, 0, byteArray, 2, uuid.Length);
|
||||
byteArray[10] = TaskNo;
|
||||
byteArray[11] = LightNo;
|
||||
Array.Copy(Reserve, 0, byteArray, 12, Reserve.Length);
|
||||
var crc32Check = Crc32.LittleEndianComputeBytes(byteArray[1..^7]);
|
||||
Array.Copy(crc32Check, 0, byteArray, 17, crc32Check.Length);
|
||||
Array.Copy(End, 0, byteArray, 21, End.Length);
|
||||
return byteArray;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
namespace FASS.Extend.Master
|
||||
{
|
||||
public class ReceiveStateMessage
|
||||
{
|
||||
public byte Begin { get; set; } = 0xBB;
|
||||
public byte Command { get; set; }
|
||||
public string? Uuid { get; set; }
|
||||
public string? SoftwareVersion { get; set; }
|
||||
public string? HardwareVersion { get; set; }
|
||||
public uint Alarm { get; set; }
|
||||
public byte Count { get; set; }
|
||||
public LightStateMessage[] LightMessages { get; set; } = new LightStateMessage[128];
|
||||
public byte[] Reserve { get; set; } = new byte[14];
|
||||
public byte[] Check { get; set; } = new byte[4];
|
||||
public byte[] End { get; set; } = { 0xEE, 0xEE, 0xEE };
|
||||
|
||||
public ReceiveStateMessage SetMessage(
|
||||
byte command,
|
||||
string uuid,
|
||||
string softwareVersion,
|
||||
string hardwareVersion,
|
||||
uint alarm,
|
||||
byte count,
|
||||
LightStateMessage[] lightMessages)
|
||||
{
|
||||
Command = command;
|
||||
Uuid = uuid;
|
||||
SoftwareVersion = softwareVersion;
|
||||
HardwareVersion = hardwareVersion;
|
||||
Alarm = alarm;
|
||||
Count = count;
|
||||
Array.Copy(lightMessages, 0, LightMessages, 0, lightMessages.Length);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ReceiveStateMessage GetMessage(byte[] byteArray)
|
||||
{
|
||||
if (byteArray == null || byteArray.Length < 300) throw new Exception($"数据长度错误:{Utility.ByteArrayToHexString(byteArray)}");
|
||||
//if (byteArray[98] != Utility.XOR(byteArray[1..^2])) throw new Exception($"数据校验错误:{Utility.ByteArrayToHexString(byteArray)}");
|
||||
//if (byteArray[0] != 0xBB || byteArray[99] != 0xEE) throw new Exception($"数据帧头尾错误:{Utility.ByteArrayToHexString(byteArray)}");
|
||||
Begin = byteArray[0];
|
||||
Command = byteArray[1];
|
||||
Uuid = Utility.ByteArrayToHexString(byteArray[2..10]).ToLower();
|
||||
HardwareVersion = $"{byteArray[11]}.{byteArray[12]}.{byteArray[13]}";
|
||||
SoftwareVersion = $"{byteArray[15]}.{byteArray[16]}.{byteArray[17]}";
|
||||
Alarm = BitConverter.ToUInt32(byteArray[18..22]);
|
||||
Count = byteArray[22];
|
||||
for (var i = 0; i < 128; i++)
|
||||
{
|
||||
var start = i * 2 + 23;
|
||||
var end = start + 2;
|
||||
LightMessages[i] = new LightStateMessage().GetMessage(byteArray[start..end]);
|
||||
}
|
||||
Reserve = byteArray[279..293];
|
||||
Check = byteArray[293..297];
|
||||
End = byteArray[297..300];
|
||||
return this;
|
||||
}
|
||||
|
||||
public byte[] GetByteArray()
|
||||
{
|
||||
var byteArray = new byte[300];
|
||||
byteArray[0] = Begin;
|
||||
byteArray[1] = Command;
|
||||
var uuid = Utility.HexStringToBytes(Uuid!);
|
||||
Array.Copy(uuid, 0, byteArray, 2, uuid.Length);
|
||||
//硬件版本
|
||||
var hardVersion = HardwareVersion!.Split('.');
|
||||
byteArray[11] = byte.Parse(hardVersion[0]);
|
||||
byteArray[12] = byte.Parse(hardVersion[1]);
|
||||
byteArray[13] = byte.Parse(hardVersion[2]);
|
||||
//软件版本
|
||||
var softVersion = SoftwareVersion!.Split('.');
|
||||
byteArray[15] = byte.Parse(softVersion[0]);
|
||||
byteArray[16] = byte.Parse(softVersion[1]);
|
||||
byteArray[17] = byte.Parse(softVersion[2]);
|
||||
var alarm = BitConverter.GetBytes(Alarm);
|
||||
byteArray[18] = alarm[0];
|
||||
byteArray[19] = alarm[1];
|
||||
byteArray[20] = alarm[2];
|
||||
byteArray[21] = alarm[3];
|
||||
var count = Count;
|
||||
var ligthMessages = LightMessages.SelectMany(e => e.GetByteArray()).ToArray();
|
||||
Array.Copy(ligthMessages, 0, byteArray, 23, ligthMessages.Length);
|
||||
Array.Copy(Reserve, 0, byteArray, 279, Reserve.Length);
|
||||
var crc32Check = Crc32.LittleEndianComputeBytes(byteArray[1..^7]);
|
||||
Array.Copy(crc32Check, 0, byteArray, 293, crc32Check.Length);
|
||||
Array.Copy(End, 0, byteArray, 297, End.Length);
|
||||
return byteArray;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
namespace FASS.Extend.Master
|
||||
{
|
||||
public class SendControlMessage
|
||||
{
|
||||
public byte Begin { get; set; } = 0xBB;
|
||||
public byte Command { get; set; } = 0x01;
|
||||
public byte TaskNo { get; set; }
|
||||
public byte SectionCount { get; set; }
|
||||
|
||||
public List<LightControlMessage> LightControlMessages { get; set; } = new List<LightControlMessage>();
|
||||
public ulong TimeStamp { get; set; }
|
||||
public byte[] Reserve { get; set; } = new byte[5];
|
||||
public byte[] Check { get; set; } = new byte[4];
|
||||
public byte[] End { get; set; } = { 0xEE, 0xEE, 0xEE };
|
||||
|
||||
public SendControlMessage SetMessage(
|
||||
byte taskNo,
|
||||
byte sectionCount,
|
||||
LightControlMessage[] lightControlMessages,
|
||||
ulong timeStamp)
|
||||
{
|
||||
TaskNo = taskNo;
|
||||
SectionCount = sectionCount;
|
||||
TimeStamp = timeStamp;
|
||||
LightControlMessages.AddRange(lightControlMessages);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SendControlMessage GetMessage(byte[] byteArray)
|
||||
{
|
||||
//最少一个灯范围控制
|
||||
if (byteArray == null || byteArray.Length < 32) throw new Exception($"数据长度错误:{Utility.ByteArrayToHexString(byteArray)}");
|
||||
//if (byteArray[298] != Utility.XOR(byteArray[1..^2])) throw new Exception($"数据校验错误:{Utility.ByteArrayToHexString(byteArray)}");
|
||||
Begin = byteArray[0];
|
||||
Command = byteArray[1];
|
||||
TaskNo = byteArray[2];
|
||||
SectionCount = byteArray[3];
|
||||
if (SectionCount == 0)
|
||||
{
|
||||
throw new Exception($"数据长度错误,控制段个数错误:{Utility.ByteArrayToHexString(byteArray)}");
|
||||
}
|
||||
if (SectionCount > 60)
|
||||
{
|
||||
throw new Exception($"数据长度错误,控制段个数超出限制:{Utility.ByteArrayToHexString(byteArray)}");
|
||||
}
|
||||
var length = SectionCount * 8 + 24;
|
||||
if (byteArray.Length != length) throw new Exception($"数据长度错误:{Utility.ByteArrayToHexString(byteArray)}");
|
||||
for (var i = 0; i < SectionCount; i++)
|
||||
{
|
||||
var start = i * 8 + 4;
|
||||
var end = start + 8;
|
||||
LightControlMessages.Add(new LightControlMessage().GetMessage(byteArray[start..end]));
|
||||
}
|
||||
Reserve = byteArray[(4 + 8 * SectionCount)..(9 + 8 * SectionCount)];
|
||||
TimeStamp = BitConverter.ToUInt64(byteArray[(9 + 8 * SectionCount)..(17 + 8 * SectionCount)]);
|
||||
Check = byteArray[(17 + 8 * SectionCount)..(21 + 8 * SectionCount)];
|
||||
End = byteArray[(21 + 8 * SectionCount)..(24 + 8 * SectionCount)];
|
||||
return this;
|
||||
}
|
||||
|
||||
public byte[] GetByteArray()
|
||||
{
|
||||
var length = 24 + 8 * SectionCount;
|
||||
var byteArray = new byte[length];
|
||||
byteArray[0] = Begin;
|
||||
byteArray[1] = Command;
|
||||
byteArray[2] = TaskNo;
|
||||
byteArray[3] = SectionCount;
|
||||
var lightControlMessages = LightControlMessages.SelectMany(e => e.GetByteArray()).ToArray();
|
||||
Array.Copy(lightControlMessages, 0, byteArray, 4, lightControlMessages.Length);
|
||||
Array.Copy(Reserve, 0, byteArray, 4 + 8 * SectionCount, Reserve.Length);
|
||||
var date = new DateTime(1970, 1, 1, 8, 0, 0).AddMilliseconds(TimeStamp);
|
||||
byteArray[9 + 8 * SectionCount] = (byte)(date.Year - 1970);
|
||||
byteArray[10 + 8 * SectionCount] = (byte)(date.Month);
|
||||
byteArray[11 + 8 * SectionCount] = (byte)(date.Day);
|
||||
byteArray[12 + 8 * SectionCount] = (byte)(date.Hour);
|
||||
byteArray[13 + 8 * SectionCount] = (byte)(date.Minute);
|
||||
byteArray[14 + 8 * SectionCount] = (byte)(date.Second);
|
||||
var millisecond = BitConverter.GetBytes((ushort)(date.Millisecond));
|
||||
byteArray[15 + 8 * SectionCount] = millisecond[0];
|
||||
byteArray[16 + 8 * SectionCount] = millisecond[1];
|
||||
var crc32Check = Crc32.LittleEndianComputeBytes(byteArray[1..^7]);
|
||||
Array.Copy(crc32Check, 0, byteArray, 17 + 8 * SectionCount, crc32Check.Length);
|
||||
Array.Copy(End, 0, byteArray, 21 + 8 * SectionCount, End.Length);
|
||||
return byteArray;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
namespace FASS.Extend.Master
|
||||
{
|
||||
public class SendPressedStateRespMessage
|
||||
{
|
||||
public byte Begin { get; set; } = 0xBB;
|
||||
public byte Command { get; set; } = 0x82;
|
||||
public byte TaskNo { get; set; }
|
||||
public byte LightNo { get; set; }
|
||||
public byte State { get; set; }
|
||||
public uint Led { get; set; }
|
||||
public ulong TimeStamp { get; set; }
|
||||
public byte[] Check { get; set; } = new byte[4];
|
||||
public byte[] End { get; set; } = { 0xEE, 0xEE, 0xEE };
|
||||
|
||||
public SendPressedStateRespMessage SetMessage(
|
||||
byte command,
|
||||
byte taskNo,
|
||||
byte lightNo,
|
||||
byte state,
|
||||
uint led,
|
||||
ulong param)
|
||||
{
|
||||
Command = command;
|
||||
TaskNo = taskNo;
|
||||
LightNo = lightNo;
|
||||
State = state;
|
||||
Led = led;
|
||||
TimeStamp = param;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SendPressedStateRespMessage GetMessage(byte[] byteArray)
|
||||
{
|
||||
if (byteArray == null || byteArray.Length != 24) throw new Exception($"数据长度错误:{Utility.ByteArrayToHexString(byteArray)}");
|
||||
//if (byteArray[98] != Utility.XOR(byteArray[1..^2])) throw new Exception($"数据校验错误:{Utility.ByteArrayToHexString(byteArray)}");
|
||||
//if (byteArray[0] != 0xBB || byteArray[99] != 0xEE) throw new Exception($"数据帧头尾错误:{Utility.ByteArrayToHexString(byteArray)}");
|
||||
Begin = byteArray[0];
|
||||
Command = byteArray[1];
|
||||
TaskNo = byteArray[2];
|
||||
LightNo = byteArray[3];
|
||||
State = byteArray[4];
|
||||
Led = BitConverter.ToUInt32(byteArray[5..9]);
|
||||
TimeStamp = BitConverter.ToUInt64(byteArray[9..17]);
|
||||
Check = byteArray[17..21];
|
||||
End = byteArray[21..24];
|
||||
return this;
|
||||
}
|
||||
|
||||
public byte[] GetByteArray()
|
||||
{
|
||||
var byteArray = new byte[24];
|
||||
byteArray[0] = Begin;
|
||||
byteArray[1] = Command;
|
||||
byteArray[2] = TaskNo;
|
||||
byteArray[3] = LightNo;
|
||||
byteArray[4] = State;
|
||||
var ledArr = BitConverter.GetBytes(Led);
|
||||
byteArray[5] = ledArr[0];
|
||||
byteArray[6] = ledArr[1];
|
||||
byteArray[7] = ledArr[2];
|
||||
byteArray[8] = ledArr[3];
|
||||
var date = new DateTime(1970, 1, 1, 8, 0, 0).AddMilliseconds(TimeStamp);
|
||||
byteArray[9] = (byte)(date.Year - 1970);
|
||||
byteArray[10] = (byte)(date.Month);
|
||||
byteArray[11] = (byte)(date.Day);
|
||||
byteArray[12] = (byte)(date.Hour);
|
||||
byteArray[13] = (byte)(date.Minute);
|
||||
byteArray[14] = (byte)(date.Second);
|
||||
var millisecond = BitConverter.GetBytes((ushort)(date.Millisecond));
|
||||
byteArray[15] = millisecond[0];
|
||||
byteArray[16] = millisecond[1];
|
||||
var crc32Check = Crc32.LittleEndianComputeBytes(byteArray[1..^7]);
|
||||
Array.Copy(crc32Check, 0, byteArray, 17, crc32Check.Length);
|
||||
Array.Copy(End, 0, byteArray, 21, End.Length);
|
||||
return byteArray;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
namespace FASS.Extend.Master
|
||||
{
|
||||
public class SendQueryMessage
|
||||
{
|
||||
public byte Begin { get; set; } = 0xBB;
|
||||
public byte Command { get; set; } = 0x00;
|
||||
public byte State { get; set; } = 0x00;
|
||||
public byte[] Reserve { get; set; } = new byte[6];
|
||||
public ulong TimeStamp { get; set; }
|
||||
public byte[] Check { get; set; } = new byte[4];
|
||||
public byte[] End { get; set; } = { 0xEE, 0xEE, 0xEE };
|
||||
|
||||
public SendQueryMessage SetMessage(
|
||||
byte command,
|
||||
byte state,
|
||||
ulong param)
|
||||
{
|
||||
Command = command;
|
||||
TimeStamp = param;
|
||||
State = state;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SendQueryMessage GetMessage(byte[] byteArray)
|
||||
{
|
||||
if (byteArray is null || byteArray.Length < 24) throw new Exception($"数据长度错误: {Utility.ByteArrayToHexString(byteArray)}");
|
||||
//if (byteArray[48] != Utility.XOR(byteArray[1..^2])) throw new Exception($"数据校验错误:{Utility.ByteArrayToHexString(byteArray)}");
|
||||
Begin = byteArray[0];
|
||||
Command = byteArray[1];
|
||||
State = byteArray[2];
|
||||
Reserve = byteArray[3..9];
|
||||
TimeStamp = BitConverter.ToUInt64(byteArray[9..17]);
|
||||
Check = byteArray[17..21];
|
||||
End = byteArray[21..24];
|
||||
return this;
|
||||
}
|
||||
|
||||
public byte[] GetByteArray()
|
||||
{
|
||||
var byteArray = new byte[24];
|
||||
byteArray[0] = Begin;
|
||||
byteArray[1] = Command;
|
||||
byteArray[2] = State;
|
||||
Array.Copy(Reserve, 0, byteArray, 3, Reserve.Length);
|
||||
var date = new DateTime(1970, 1, 1, 8, 0, 0).AddMilliseconds(TimeStamp);
|
||||
byteArray[9] = (byte)(date.Year - 1970);
|
||||
byteArray[10] = (byte)(date.Month);
|
||||
byteArray[11] = (byte)(date.Day);
|
||||
byteArray[12] = (byte)(date.Hour);
|
||||
byteArray[13] = (byte)(date.Minute);
|
||||
byteArray[14] = (byte)(date.Second);
|
||||
var millisecond = BitConverter.GetBytes((ushort)(date.Millisecond));
|
||||
byteArray[15] = millisecond[0];
|
||||
byteArray[16] = millisecond[1];
|
||||
var crc32Check = Crc32.LittleEndianComputeBytes(byteArray[1..^7]);
|
||||
Array.Copy(crc32Check, 0, byteArray, 17, crc32Check.Length);
|
||||
Array.Copy(End, 0, byteArray, 21, End.Length);
|
||||
return byteArray;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,328 @@
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace FASS.Extend.Master
|
||||
{
|
||||
public static class Utility
|
||||
{
|
||||
public static string ByteArrayToHexString(byte[]? byteArray, string separator = "")
|
||||
{
|
||||
if (byteArray is null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
return string.Join(separator, byteArray.Select(t => t.ToString("X2")));
|
||||
}
|
||||
|
||||
public static byte XOR(byte[] byteArray)
|
||||
{
|
||||
byte xor = 0;
|
||||
for (int i = 0; i < byteArray.Length; i++)
|
||||
{
|
||||
xor ^= byteArray[i];
|
||||
}
|
||||
return xor;
|
||||
}
|
||||
|
||||
public static byte[] GetCRC16(byte[] data)
|
||||
{
|
||||
byte b = byte.MaxValue;
|
||||
byte b2 = byte.MaxValue;
|
||||
byte b3 = 1;
|
||||
byte b4 = 160;
|
||||
for (int i = 0; i < data.Length; i++)
|
||||
{
|
||||
b = (byte)(b ^ data[i]);
|
||||
for (int j = 0; j <= 7; j++)
|
||||
{
|
||||
byte b5 = b2;
|
||||
byte b6 = b;
|
||||
b2 = (byte)(b2 >> 1);
|
||||
b = (byte)(b >> 1);
|
||||
if ((b5 & 1) == 1)
|
||||
{
|
||||
b = (byte)(b | 0x80u);
|
||||
}
|
||||
if ((b6 & 1) == 1)
|
||||
{
|
||||
b2 = (byte)(b2 ^ b4);
|
||||
b = (byte)(b ^ b3);
|
||||
}
|
||||
}
|
||||
}
|
||||
return new byte[2]
|
||||
{
|
||||
b,b2
|
||||
};
|
||||
}
|
||||
|
||||
public static byte[] HexStringToBytes(string hex)
|
||||
{
|
||||
if (string.IsNullOrEmpty(hex))
|
||||
throw new ArgumentException("输入字符串不能为空");
|
||||
|
||||
// 清理字符串中的非十六进制字符
|
||||
string cleanHex = Regex.Replace(hex, "[^0-9A-Fa-f]", "");
|
||||
|
||||
if (cleanHex.Length % 2 != 0)
|
||||
throw new FormatException("十六进制字符串长度必须为偶数");
|
||||
|
||||
return Convert.FromHexString(cleanHex);
|
||||
}
|
||||
|
||||
public static List<byte[]> SplitByMarkers(byte[] source, byte head, byte[] tail)
|
||||
{
|
||||
List<byte[]> result = new List<byte[]>();
|
||||
int startIndex = 0;
|
||||
int tailLength = tail.Length;
|
||||
|
||||
if (tailLength != 3)
|
||||
throw new ArgumentException("Tail marker must be 3 bytes");
|
||||
|
||||
while (startIndex < source.Length)
|
||||
{
|
||||
// 查找头字节
|
||||
int headPos = Array.IndexOf(source, head, startIndex);
|
||||
if (headPos == -1) break;
|
||||
|
||||
// 检查尾部空间是否足够
|
||||
int minTailStart = headPos + 1;
|
||||
int maxPossibleTailStart = source.Length - tailLength;
|
||||
|
||||
bool tailFound = false;
|
||||
int tailStart = minTailStart;
|
||||
|
||||
// 从最小可能位置开始查找尾部
|
||||
while (tailStart <= maxPossibleTailStart)
|
||||
{
|
||||
// 检查连续三个字节是否匹配尾部
|
||||
if (source[tailStart] == tail[0] &&
|
||||
source[tailStart + 1] == tail[1] &&
|
||||
source[tailStart + 2] == tail[2] && ((tailStart + 2 == source.Length-1) ||(source[tailStart + 3] == head)))//找到尾部是整条报文的末尾、或者是下一帧报文的包头
|
||||
{
|
||||
tailFound = true;
|
||||
break;
|
||||
}
|
||||
tailStart++;
|
||||
}
|
||||
|
||||
if (!tailFound) break;
|
||||
|
||||
// 计算完整数据块(包含头尾)
|
||||
int chunkEnd = tailStart + tailLength - 1;
|
||||
int chunkSize = chunkEnd - headPos + 1;
|
||||
|
||||
byte[] chunk = new byte[chunkSize];
|
||||
Array.Copy(source, headPos, chunk, 0, chunkSize);
|
||||
result.Add(chunk);
|
||||
|
||||
// 更新起始点为尾部之后
|
||||
startIndex = chunkEnd + 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static bool[] ByteToBoolArray(byte b)
|
||||
{
|
||||
// 创建长度为8的布尔数组(一个字节=8位)
|
||||
bool[] result = new bool[8];
|
||||
|
||||
// 从高位到低位遍历(索引0对应最高位,索引7对应最低位)
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
// 通过位掩码检查每一位的值
|
||||
result[i] = (b & (1 << (7 - i))) != 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static byte BoolArrayToByte(bool[] bools)
|
||||
{
|
||||
if (bools.Length != 8)
|
||||
throw new ArgumentException("数组长度必须为 8");
|
||||
|
||||
byte result = 0;
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
if (bools[i])
|
||||
{
|
||||
// 选择位序:
|
||||
// 低位优先(第一个元素对应 byte 的最低位,即 bit0)
|
||||
//result |= (byte)(1 << i);
|
||||
|
||||
// 高位优先(第一个元素对应 byte 的最高位,即 bit7)
|
||||
result |= (byte)(1 << (7 - i));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public static byte SetLightColour(string value, bool ledOpen)
|
||||
{
|
||||
var lightValue = byte.Parse(value);
|
||||
var boolArr = ByteToBoolArray(lightValue);
|
||||
boolArr[1] = ledOpen;
|
||||
return BoolArrayToByte(boolArr);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置红灯
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static byte SetLightRed()
|
||||
{
|
||||
return LightStateControl(false, false, false, true, false, false, false, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置红灯闪烁
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static byte SetLightRedWithFlash()
|
||||
{
|
||||
return LightStateControl(false, false, true, true, false, false, false, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置绿灯+数显
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static byte SetLightGreenWithLed()
|
||||
{
|
||||
return LightStateControl(false, true, false, false, false, true, false, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置绿灯
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static byte SetLightGreen()
|
||||
{
|
||||
return LightStateControl(false, false, false, false, false, true, false, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置黄灯
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static byte SetLightYellow()
|
||||
{
|
||||
return LightStateControl(false, false, false, true, false, true, false, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置洋红色灯
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static byte SetLightMagenta()
|
||||
{
|
||||
return LightStateControl(false, false, false, true, false, false, false, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置洋红灯+数显
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static byte SetLightMagentaWithLed()
|
||||
{
|
||||
return LightStateControl(false, true, false, true, false, false, false, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 灭灯
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static byte SetLightOff()
|
||||
{
|
||||
return LightStateControl(false, false, false, false, false, false, false, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置显示灯地址
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static byte SetDisplayLightAddress()
|
||||
{
|
||||
return LightStateControl(true, false, false, false, false, false, false, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置灯状态
|
||||
/// </summary>
|
||||
/// <param name="fd">数码管闪烁</param>
|
||||
/// <param name="sd">数码管开关</param>
|
||||
/// <param name="fr">红色闪烁</param>
|
||||
/// <param name="sr">红</param>
|
||||
/// <param name="fg">绿色闪烁</param>
|
||||
/// <param name="sg">绿</param>
|
||||
/// <param name="fb">蓝色闪烁</param>
|
||||
/// <param name="sb">蓝</param>
|
||||
/// <returns></returns>
|
||||
public static byte LightStateControl(bool fd = false, bool sd = false, bool fr = false, bool sr = false, bool fg = false, bool sg = false, bool fb = false, bool sb = false)
|
||||
{
|
||||
bool[] bools = new bool[8] { fd, sd, fr, sr, fg, sg, fb, sb };
|
||||
return BoolArrayToByte(bools);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 十进制转bcb
|
||||
/// </summary>
|
||||
/// <param name="decimalNumber"></param>
|
||||
/// <returns></returns>
|
||||
public static byte DecimalToBcd(byte decimalNumber)
|
||||
{
|
||||
int tens = decimalNumber / 10; // 获取十位数字
|
||||
int ones = decimalNumber % 10; // 获取个位数字
|
||||
return (byte)((tens << 4) | ones); // 合并为BCD码
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置数码管显示值
|
||||
/// </summary>
|
||||
/// <param name="maxTaskNum">最大合单数</param>
|
||||
/// <param name="list">各包车的数值</param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ArgumentException"></exception>
|
||||
public static byte[] GetLedBytes(int maxTaskNum, List<int> list)
|
||||
{
|
||||
var byteArr = new byte[4];
|
||||
if (list.Count < maxTaskNum)
|
||||
{
|
||||
throw new ArgumentException();
|
||||
}
|
||||
if (maxTaskNum == 1)
|
||||
{
|
||||
byteArr[1] = DecimalToBcd((byte)list[0]);
|
||||
}
|
||||
else if (maxTaskNum == 2)
|
||||
{
|
||||
byteArr[1] = DecimalToBcd((byte)list[0]);
|
||||
byteArr[0] = DecimalToBcd((byte)list[1]);
|
||||
}
|
||||
else if (maxTaskNum == 3)
|
||||
{
|
||||
string str1 = DecimalToBcd((byte)list[0]).ToString("X2");
|
||||
string str2 = DecimalToBcd((byte)list[1]).ToString("X2");
|
||||
string str3 = DecimalToBcd((byte)list[2]).ToString("X2");
|
||||
var appedStr = str1.Substring(str1.Length - 1) + str2.Substring(str2.Length - 1) + str3.Substring(str3.Length - 1) + "0";
|
||||
byte[] hexArr = HexStringToBytes(appedStr);
|
||||
byteArr[1] = hexArr[0];
|
||||
byteArr[0] = hexArr[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
string str1 = DecimalToBcd((byte)list[0]).ToString("X2");
|
||||
string str2 = DecimalToBcd((byte)list[1]).ToString("X2");
|
||||
string str3 = DecimalToBcd((byte)list[2]).ToString("X2");
|
||||
string str4 = DecimalToBcd((byte)list[3]).ToString("X2");
|
||||
var appedStr = str1.Substring(str1.Length - 1) + str2.Substring(str2.Length - 1) + str3.Substring(str3.Length - 1) + str4.Substring(str4.Length - 1);
|
||||
byte[] hexArr = HexStringToBytes(appedStr);
|
||||
byteArr[1] = hexArr[0];
|
||||
byteArr[0] = hexArr[1];
|
||||
}
|
||||
return byteArr;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user