feat: 更新通信协议

This commit is contained in:
SikongJueluo 2025-07-16 20:25:43 +08:00
parent 822091243e
commit d551cbe793
No known key found for this signature in database
4 changed files with 227 additions and 141 deletions

View File

@ -406,15 +406,17 @@ public class Jtag
async ValueTask<Result<uint>> ReadFIFO(uint devAddr) async ValueTask<Result<uint>> ReadFIFO(uint devAddr)
{ {
var ret = false; var ret = false;
var opts = new SendAddrPackOptions(); var opts = new SendAddrPackOptions()
{
BurstType = BurstType.FixedBurst,
BurstLength = 0,
CommandID = 0,
Address = devAddr,
IsWrite = false,
};
opts.BurstType = BurstType.FixedBurst;
opts.BurstLength = 0;
opts.CommandID = 0;
opts.Address = devAddr;
// Read Jtag State Register // Read Jtag State Register
opts.IsWrite = false;
ret = await UDPClientPool.SendAddrPackAsync(ep, new SendAddrPackage(opts)); ret = await UDPClientPool.SendAddrPackAsync(ep, new SendAddrPackage(opts));
if (!ret) return new(new Exception("Send Address Package Failed!")); if (!ret) return new(new Exception("Send Address Package Failed!"));

View File

@ -228,15 +228,17 @@ public class UDPClientPool
IPEndPoint endPoint, int taskID, uint devAddr, int timeout = 1000) IPEndPoint endPoint, int taskID, uint devAddr, int timeout = 1000)
{ {
var ret = false; var ret = false;
var opts = new SendAddrPackOptions(); var opts = new SendAddrPackOptions()
{
BurstType = BurstType.FixedBurst,
BurstLength = 0,
CommandID = Convert.ToByte(taskID),
Address = devAddr,
IsWrite = false,
};
opts.BurstType = BurstType.FixedBurst;
opts.BurstLength = 0;
opts.CommandID = Convert.ToByte(taskID);
opts.Address = devAddr;
// Read Jtag State Register // Read Register
opts.IsWrite = false;
ret = await UDPClientPool.SendAddrPackAsync(endPoint, new SendAddrPackage(opts)); ret = await UDPClientPool.SendAddrPackAsync(endPoint, new SendAddrPackage(opts));
if (!ret) return new(new Exception("Send Address Package Failed!")); if (!ret) return new(new Exception("Send Address Package Failed!"));
@ -358,12 +360,16 @@ public class UDPClientPool
IPEndPoint endPoint, int taskID, UInt32 devAddr, int dataLength, int timeout = 1000) IPEndPoint endPoint, int taskID, UInt32 devAddr, int dataLength, int timeout = 1000)
{ {
var ret = false; var ret = false;
var opts = new SendAddrPackOptions(); var opts = new SendAddrPackOptions()
{
BurstLength = 0,
Address = 0,
BurstType = BurstType.FixedBurst,
CommandID = Convert.ToByte(taskID),
IsWrite = false,
};
var resultData = new List<byte>(); var resultData = new List<byte>();
opts.BurstType = BurstType.FixedBurst;
opts.CommandID = Convert.ToByte(taskID);
opts.IsWrite = false;
// Check Msg Bus // Check Msg Bus
if (!MsgBus.IsRunning) if (!MsgBus.IsRunning)
@ -544,15 +550,17 @@ public class UDPClientPool
IPEndPoint endPoint, int taskID, UInt32 devAddr, UInt32 data, int timeout = 1000) IPEndPoint endPoint, int taskID, UInt32 devAddr, UInt32 data, int timeout = 1000)
{ {
var ret = false; var ret = false;
var opts = new SendAddrPackOptions(); var opts = new SendAddrPackOptions()
{
BurstType = BurstType.FixedBurst,
BurstLength = 0,
CommandID = Convert.ToByte(taskID),
Address = devAddr,
IsWrite = true,
};
opts.BurstType = BurstType.FixedBurst;
opts.BurstLength = 0;
opts.CommandID = Convert.ToByte(taskID);
opts.Address = devAddr;
// Write Jtag State Register // Write Register
opts.IsWrite = true;
ret = await UDPClientPool.SendAddrPackAsync(endPoint, new SendAddrPackage(opts)); ret = await UDPClientPool.SendAddrPackAsync(endPoint, new SendAddrPackage(opts));
if (!ret) return new(new Exception("Send 1st address package failed!")); if (!ret) return new(new Exception("Send 1st address package failed!"));
// Send Data Package // Send Data Package
@ -585,18 +593,21 @@ public class UDPClientPool
IPEndPoint endPoint, int taskID, UInt32 devAddr, byte[] dataArray, int timeout = 1000) IPEndPoint endPoint, int taskID, UInt32 devAddr, byte[] dataArray, int timeout = 1000)
{ {
var ret = false; var ret = false;
var opts = new SendAddrPackOptions(); var opts = new SendAddrPackOptions()
{
BurstType = BurstType.FixedBurst,
CommandID = Convert.ToByte(taskID),
Address = devAddr,
BurstLength = 0,
IsWrite = true,
};
opts.BurstType = BurstType.FixedBurst;
opts.CommandID = Convert.ToByte(taskID);
opts.Address = devAddr;
// Check Msg Bus // Check Msg Bus
if (!MsgBus.IsRunning) if (!MsgBus.IsRunning)
return new(new Exception("Message bus not working!")); return new(new Exception("Message bus not working!"));
opts.IsWrite = true;
var hasRest = dataArray.Length % (256 * (32 / 8)) != 0; var hasRest = dataArray.Length % (256 * (32 / 8)) != 0;
var writeTimes = hasRest ? var writeTimes = hasRest ?
dataArray.Length / (256 * (32 / 8)) + 1 : dataArray.Length / (256 * (32 / 8)) + 1 :

View File

@ -4,6 +4,7 @@ using System.Net.NetworkInformation; // 添加这个引用
using System.Net.Sockets; using System.Net.Sockets;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Text; using System.Text;
using Common;
using DotNext; using DotNext;
using Newtonsoft.Json; using Newtonsoft.Json;
using WebProtocol; using WebProtocol;
@ -16,6 +17,10 @@ public class UDPData
/// </summary> /// </summary>
public required DateTime DateTime { get; set; } public required DateTime DateTime { get; set; }
/// <summary> /// <summary>
/// 数据包时间戳
/// </summary>
public required UInt32 Timestamp { get; set; }
/// <summary>
/// 发送来源的IP地址 /// 发送来源的IP地址
/// </summary> /// </summary>
public required string Address { get; set; } public required string Address { get; set; }
@ -48,6 +53,7 @@ public class UDPData
return new UDPData() return new UDPData()
{ {
DateTime = this.DateTime, DateTime = this.DateTime,
Timestamp = this.Timestamp,
Address = new string(this.Address), Address = new string(this.Address),
Port = this.Port, Port = this.Port,
TaskID = this.TaskID, TaskID = this.TaskID,
@ -69,24 +75,26 @@ public class UDPData
/// <summary> /// <summary>
/// UDP 服务器 /// UDP 服务器
/// </summary> /// </summary>
public class UDPServer : IDisposable public class UDPServer
{ {
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
private ConcurrentDictionary<string, SortedList<DateTime, UDPData>> udpData = new ConcurrentDictionary<string, SortedList<DateTime, UDPData>>(); private ConcurrentDictionary<string, SortedList<UInt32, UDPData>> udpData
= new ConcurrentDictionary<string, SortedList<UInt32, UDPData>>();
private readonly ReaderWriterLockSlim udpDataLock = new ReaderWriterLockSlim(); private readonly ReaderWriterLockSlim udpDataLock = new ReaderWriterLockSlim();
private int listenPort; private int listenPort;
private List<UdpClient> listeners = new List<UdpClient>(); private List<UdpClient> listeners = new List<UdpClient>();
private List<Task> tasks = new List<Task>();
private IPEndPoint groupEP; private IPEndPoint groupEP;
private bool isRunning = false; private CancellationTokenSource? cancellationTokenSource;
private bool disposed = false; private bool disposed = false;
/// <summary> /// <summary>
/// 是否正在工作 /// 是否正在工作
/// </summary> /// </summary>
public bool IsRunning { get { return isRunning; } } public bool IsRunning => cancellationTokenSource?.Token.IsCancellationRequested == false;
/// <summary> UDP 服务器的错误代码 </summary> /// <summary> UDP 服务器的错误代码 </summary>
public enum ErrorCode public enum ErrorCode
@ -415,27 +423,29 @@ public class UDPServer : IDisposable
var remotePort = remoteEP.Port; var remotePort = remoteEP.Port;
var data = new UDPData() var data = new UDPData()
{ {
DateTime = time,
Timestamp = Number.BytesToUInt32(bytes[..4]).Value,
Address = remoteAddress, Address = remoteAddress,
Port = remotePort, Port = remotePort,
TaskID = taskID, TaskID = taskID,
Data = bytes, Data = bytes,
DateTime = time,
HasRead = false, HasRead = false,
}; };
var key = $"{remoteAddress}-{taskID}";
udpDataLock.EnterWriteLock(); udpDataLock.EnterWriteLock();
try try
{ {
var key = $"{remoteAddress}-{taskID}"; var sortedList = udpData.GetOrAdd(key, _ => new SortedList<UInt32, UDPData>());
var sortedList = udpData.GetOrAdd(key, _ => new SortedList<DateTime, UDPData>());
// 处理相同时间戳的情况,添加微小的时间差 // 处理相同时间戳的情况,添加微小的时间差
var uniqueTime = time; var uniqueTime = data.Timestamp;
while (sortedList.ContainsKey(uniqueTime)) while (sortedList.ContainsKey(uniqueTime))
{ {
logger.Warn( logger.Warn(
$"Duplicate timestamp detected for {remoteAddress}:{remotePort} at {uniqueTime}."); $"Duplicate timestamp detected for {remoteAddress}:{remotePort} at {uniqueTime}.");
uniqueTime = uniqueTime.AddTicks(1); uniqueTime += 1;
} }
sortedList.Add(uniqueTime, data); sortedList.Add(uniqueTime, data);
@ -491,7 +501,7 @@ public class UDPServer : IDisposable
recvData = Encoding.ASCII.GetString(bytes, 0, bytes.Length); recvData = Encoding.ASCII.GetString(bytes, 0, bytes.Length);
} }
logger.Debug($"Receive Data from {data.Address}:{data.Port} at {data.DateTime.ToString()}:"); logger.Debug($"Receive Data from {data.Address}:{data.Port} at {data.DateTime.ToString()} - {data.Timestamp}:");
logger.Debug($" Original Data : {BitConverter.ToString(bytes).Replace("-", " ")}"); logger.Debug($" Original Data : {BitConverter.ToString(bytes).Replace("-", " ")}");
if (recvData.Length != 0) logger.Debug($" Decoded Data : {recvData}"); if (recvData.Length != 0) logger.Debug($" Decoded Data : {recvData}");
return $@" return $@"
@ -580,8 +590,7 @@ public class UDPServer : IDisposable
return; return;
} }
// 异步执行ARP刷新避免阻塞主线程 ExecuteArpFlush(ipAddr);
Task.Run(() => ExecuteArpFlush(ipAddr));
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -633,7 +642,7 @@ public class UDPServer : IDisposable
/// 执行ARP刷新流程先删除ARP条目再用ping重新刷新 /// 执行ARP刷新流程先删除ARP条目再用ping重新刷新
/// </summary> /// </summary>
/// <param name="ipAddr">目标IP地址</param> /// <param name="ipAddr">目标IP地址</param>
private async void ExecuteArpFlush(string ipAddr) private void ExecuteArpFlush(string ipAddr)
{ {
try try
{ {
@ -806,33 +815,57 @@ public class UDPServer : IDisposable
/// <returns>None</returns> /// <returns>None</returns>
public void Start() public void Start()
{ {
this.isRunning = true; if (cancellationTokenSource != null && !cancellationTokenSource.Token.IsCancellationRequested)
{
logger.Warn("UDP Server is already running");
return;
}
cancellationTokenSource = new CancellationTokenSource();
var cancellationToken = cancellationTokenSource.Token;
try try
{ {
foreach (var client in listeners) foreach (var client in listeners)
{ {
Task.Run(() => tasks.Add(Task.Run(async () =>
{ {
while (this.isRunning) while (!cancellationToken.IsCancellationRequested)
{ {
try try
{ {
var ep = new IPEndPoint(IPAddress.Any, listenPort); // 使用 CancellationToken 来取消接收操作
var result = client.Receive(ref ep); var result = await client.ReceiveAsync(cancellationToken);
_ = ReceiveHandler(result, ep, DateTime.Now); _ = ReceiveHandler(result.Buffer, result.RemoteEndPoint, DateTime.Now);
}
catch (OperationCanceledException)
{
logger.Debug("UDP receive operation was cancelled");
break;
}
catch (ObjectDisposedException)
{
logger.Debug("UDP client was disposed");
break;
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine($"Error: {ex.Message}"); if (!cancellationToken.IsCancellationRequested)
{
logger.Error($"Error in UDP receive: {ex.Message}");
} }
} }
});
} }
}, cancellationToken));
}
logger.Info("UDP Server started successfully");
} }
catch (Exception e) catch (Exception e)
{ {
Console.WriteLine(e.ToString()); logger.Error($"Failed to start UDP server: {e}");
this.isRunning = false; cancellationTokenSource?.Cancel();
throw;
} }
} }
@ -842,39 +875,71 @@ public class UDPServer : IDisposable
/// <returns>None</returns> /// <returns>None</returns>
public void Stop() public void Stop()
{ {
foreach (var item in listeners) if (cancellationTokenSource == null || cancellationTokenSource.Token.IsCancellationRequested)
{ {
item.Close(); logger.Warn("UDP Server is not running or already stopped");
return;
} }
this.isRunning = false;
try
{
logger.Info("Stopping UDP Server...");
// 取消所有操作
cancellationTokenSource.Cancel();
// 等待所有任务完成,设置超时时间
var waitTasks = Task.WhenAll(tasks);
if (!waitTasks.Wait(TimeSpan.FromSeconds(5)))
{
logger.Warn("Some tasks did not complete within timeout period");
}
// 关闭所有UDP客户端
foreach (var client in listeners)
{
try
{
client.Close();
}
catch (Exception ex)
{
logger.Warn($"Error closing UDP client: {ex.Message}");
}
}
// 清理任务列表
tasks.Clear();
logger.Info("UDP Server stopped successfully");
}
catch (Exception ex)
{
logger.Error($"Error stopping UDP server: {ex.Message}");
}
finally
{
cancellationTokenSource?.Dispose();
cancellationTokenSource = null;
}
} }
/// <summary> /// <summary>
/// 释放资源 /// 实现IDisposable接口确保资源正确释放
/// </summary> /// </summary>
public void Dispose() public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{ {
if (!disposed) if (!disposed)
{
if (disposing)
{ {
Stop(); Stop();
udpDataLock?.Dispose();
foreach (var client in listeners)
{
client?.Dispose();
} }
udpDataLock?.Dispose();
disposed = true; disposed = true;
} }
} }
~UDPServer()
{
Dispose(false);
} }
}

View File

@ -1,3 +1,4 @@
using Common;
using DotNext; using DotNext;
using Newtonsoft.Json; using Newtonsoft.Json;
@ -35,32 +36,32 @@ namespace WebProtocol
/// 突发类型 /// 突发类型
/// </summary> /// </summary>
/// <example>0</example> /// <example>0</example>
public BurstType BurstType { get; set; } public required BurstType BurstType { get; set; }
/// <summary> /// <summary>
/// 任务ID /// 任务ID
/// </summary> /// </summary>
/// <example>1</example> /// <example>1</example>
public byte CommandID { get; set; } public required byte CommandID { get; set; }
/// <summary> /// <summary>
/// 标识写入还是读取 /// 标识写入还是读取
/// </summary> /// </summary>
/// <example>true</example> /// <example>true</example>
public bool IsWrite { get; set; } public required bool IsWrite { get; set; }
/// <summary> /// <summary>
/// 突发长度0是32bits255是32bits x 256 /// 突发长度0是32bits255是32bits x 256
/// </summary> /// </summary>
/// <example>255</example> /// <example>255</example>
public byte BurstLength { get; set; } public required byte BurstLength { get; set; }
/// <summary> /// <summary>
/// 目标地址 /// 目标地址
/// </summary> /// </summary>
/// <example>0</example> /// <example>0</example>
public UInt32 Address { get; set; } public required UInt32 Address { get; set; }
/// <summary> /// <summary>
/// 转换为Json格式字符串 /// 转换为Json格式字符串
@ -84,23 +85,29 @@ namespace WebProtocol
WriteResp WriteResp
}; };
/// <summary>
/// 时间戳
/// </summary>
/// <example>1234567</example>
public required UInt32 Timestamp { get; set; }
/// <summary> /// <summary>
/// 数据包类型 /// 数据包类型
/// </summary> /// </summary>
/// <example>0</example> /// <example>0</example>
public PackType Type { get; set; } public required PackType Type { get; set; }
/// <summary> /// <summary>
/// Task ID /// Task ID
/// </summary> /// </summary>
/// <example>0</example> /// <example>0</example>
public byte CommandID { get; set; } public required byte CommandID { get; set; }
/// <summary> /// <summary>
/// Whether is succeed to finish command /// Whether is succeed to finish command
/// </summary> /// </summary>
/// <example>true</example> /// <example>true</example>
public bool IsSuccess { get; set; } public required bool IsSuccess { get; set; }
/// <summary> /// <summary>
/// Return Data /// Return Data
@ -214,12 +221,14 @@ namespace WebProtocol
/// <returns> 字符串 </returns> /// <returns> 字符串 </returns>
public override string ToString() public override string ToString()
{ {
var opts = new SendAddrPackOptions(); var opts = new SendAddrPackOptions()
opts.BurstType = (BurstType)(commandType >> 6); {
opts.CommandID = Convert.ToByte((commandType >> 4) & 0b0011); BurstType = (BurstType)(commandType >> 6),
opts.IsWrite = Convert.ToBoolean(commandType & 0x01); CommandID = Convert.ToByte((commandType >> 4) & 0b0011),
opts.BurstLength = burstLength; IsWrite = Convert.ToBoolean(commandType & 0x01),
opts.Address = address; BurstLength = burstLength,
Address = address,
};
return JsonConvert.SerializeObject(opts); return JsonConvert.SerializeObject(opts);
} }
@ -297,8 +306,9 @@ namespace WebProtocol
} }
/// <summary> FPGA->Server 读响应包 </summary> /// <summary> FPGA->Server 读响应包 </summary>
public struct RecvDataPackage public class RecvDataPackage
{ {
readonly UInt32 timestamp;
readonly byte sign = (byte)PackSign.RecvData; readonly byte sign = (byte)PackSign.RecvData;
readonly byte commandID; readonly byte commandID;
readonly byte resp; readonly byte resp;
@ -309,11 +319,13 @@ namespace WebProtocol
/// FPGA->Server 读响应包 /// FPGA->Server 读响应包
/// 构造函数 /// 构造函数
/// </summary> /// </summary>
/// <param name="timestamp"> 时间戳 </param>
/// <param name="commandID"> 任务ID号 </param> /// <param name="commandID"> 任务ID号 </param>
/// <param name="resp"> 读响应包响应 </param> /// <param name="resp"> 读响应包响应 </param>
/// <param name="bodyData"> 数据 </param> /// <param name="bodyData"> 数据 </param>
public RecvDataPackage(byte commandID, byte resp, byte[] bodyData) public RecvDataPackage(UInt32 timestamp, byte commandID, byte resp, byte[] bodyData)
{ {
this.timestamp = timestamp;
this.commandID = commandID; this.commandID = commandID;
this.resp = resp; this.resp = resp;
this.bodyData = bodyData; this.bodyData = bodyData;
@ -322,26 +334,13 @@ namespace WebProtocol
_ = this._reserved; _ = this._reserved;
} }
/// <summary>
/// FPGA->Server 读响应包
/// 构造函数
/// </summary>
/// <param name="commandID"> 任务ID号 </param>
/// <param name="isSuccess">是否读取成功</param>
/// <param name="bodyData"> 数据 </param>
public RecvDataPackage(byte commandID, bool isSuccess, byte[] bodyData)
{
this.commandID = commandID;
this.resp = Convert.ToByte(isSuccess);
this.bodyData = bodyData;
}
/// <summary> /// <summary>
/// 通过接受包选项构建读响应包 /// 通过接受包选项构建读响应包
/// </summary> /// </summary>
/// <param name="opts">接收包(读响应包和写响应包)选项</param> /// <param name="opts">接收包(读响应包和写响应包)选项</param>
public RecvDataPackage(RecvPackOptions opts) public RecvDataPackage(RecvPackOptions opts)
{ {
this.timestamp = opts.Timestamp;
this.commandID = opts.CommandID; this.commandID = opts.CommandID;
this.resp = Convert.ToByte(opts.IsSuccess ? 0b10 : 0b00); this.resp = Convert.ToByte(opts.IsSuccess ? 0b10 : 0b00);
this.bodyData = opts.Data ?? (byte[])[0, 0, 0, 0]; this.bodyData = opts.Data ?? (byte[])[0, 0, 0, 0];
@ -354,11 +353,14 @@ namespace WebProtocol
{ {
get get
{ {
var opts = new RecvPackOptions(); var opts = new RecvPackOptions()
opts.Type = RecvPackOptions.PackType.ReadResp; {
opts.CommandID = commandID; Timestamp = this.timestamp,
opts.IsSuccess = Convert.ToBoolean((resp >> 1) == 0b01 ? false : true); Type = RecvPackOptions.PackType.ReadResp,
opts.Data = bodyData; CommandID = this.commandID,
IsSuccess = Convert.ToBoolean((resp >> 1) == 0b01 ? false : true),
Data = this.bodyData,
};
return opts; return opts;
} }
@ -369,7 +371,7 @@ namespace WebProtocol
/// </summary> /// </summary>
public bool IsSuccessful public bool IsSuccessful
{ {
get { return Convert.ToBoolean((resp >> 1) == 0b01 ? false : true); } get { return Convert.ToBoolean((this.resp >> 1) == 0b01 ? false : true); }
} }
/// <summary> /// <summary>
@ -379,12 +381,16 @@ namespace WebProtocol
/// <returns>读响应包</returns> /// <returns>读响应包</returns>
public static Result<RecvDataPackage> FromBytes(byte[] bytes) public static Result<RecvDataPackage> FromBytes(byte[] bytes)
{ {
if (bytes[0] != (byte)PackSign.RecvData) if (bytes[4] != (byte)PackSign.RecvData)
return new(new ArgumentException( return new(new ArgumentException(
$"The sign of bytes is not RecvData Package, Sign: 0x{BitConverter.ToString([bytes[0]])}", $"The sign of bytes is not RecvData Package, Sign: 0x{BitConverter.ToString([bytes[0]])}",
nameof(bytes) nameof(bytes)
)); ));
return new RecvDataPackage(bytes[1], bytes[2], bytes[4..]); return new RecvDataPackage(
Number.BytesToUInt32(bytes[..4]).Value,
bytes[5],
bytes[6],
bytes[8..]);
} }
/// <summary> /// <summary>
@ -394,13 +400,16 @@ namespace WebProtocol
public byte[] ToBytes() public byte[] ToBytes()
{ {
var bodyDataLen = bodyData.Length; var bodyDataLen = bodyData.Length;
var arr = new byte[4 + bodyDataLen]; var arr = new byte[8 + bodyDataLen];
arr[0] = this.sign; Buffer.BlockCopy(
arr[1] = this.commandID; Number.UInt32ArrayToBytes([this.timestamp]).Value, 0, arr, 0, 4);
arr[2] = this.resp; arr[4] = this.sign;
arr[5] = this.commandID;
arr[6] = this.resp;
arr[7] = this.resp;
Array.Copy(bodyData, 0, arr, 4, bodyDataLen); Array.Copy(bodyData, 0, arr, 8, bodyDataLen);
return arr; return arr;
} }
@ -408,8 +417,9 @@ namespace WebProtocol
} }
/// <summary> 写响应包 </summary> /// <summary> 写响应包 </summary>
public struct RecvRespPackage public class RecvRespPackage
{ {
readonly UInt32 timestamp;
readonly byte sign = (byte)PackSign.RecvResp; readonly byte sign = (byte)PackSign.RecvResp;
readonly byte commandID; readonly byte commandID;
readonly byte resp; readonly byte resp;
@ -418,10 +428,12 @@ namespace WebProtocol
/// <summary> /// <summary>
/// 构建写响应包 /// 构建写响应包
/// </summary> /// </summary>
/// <param name="timestamp">时间戳</param>
/// <param name="commandID">任务ID</param> /// <param name="commandID">任务ID</param>
/// <param name="resp">写响应</param> /// <param name="resp">写响应</param>
public RecvRespPackage(byte commandID, byte resp) public RecvRespPackage(UInt32 timestamp, byte commandID, byte resp)
{ {
this.timestamp = timestamp;
this.commandID = commandID; this.commandID = commandID;
this.resp = resp; this.resp = resp;
@ -429,23 +441,13 @@ namespace WebProtocol
_ = this._reserved; _ = this._reserved;
} }
/// <summary>
/// 构建写响应包
/// </summary>
/// <param name="commandID">任务ID</param>
/// <param name="isSuccess">是否写成功</param>
public RecvRespPackage(byte commandID, bool isSuccess)
{
this.commandID = commandID;
this.resp = Convert.ToByte(isSuccess);
}
/// <summary> /// <summary>
/// 通过接受包选项构建写响应包 /// 通过接受包选项构建写响应包
/// </summary> /// </summary>
/// <param name="opts">接收包(读响应包和写响应包)选项</param> /// <param name="opts">接收包(读响应包和写响应包)选项</param>
public RecvRespPackage(RecvPackOptions opts) public RecvRespPackage(RecvPackOptions opts)
{ {
this.timestamp = opts.Timestamp;
this.commandID = opts.CommandID; this.commandID = opts.CommandID;
this.resp = Convert.ToByte(opts.IsSuccess ? 0b10 : 0b00); this.resp = Convert.ToByte(opts.IsSuccess ? 0b10 : 0b00);
} }
@ -457,11 +459,14 @@ namespace WebProtocol
{ {
get get
{ {
var opts = new RecvPackOptions(); var opts = new RecvPackOptions()
opts.Type = RecvPackOptions.PackType.WriteResp; {
opts.CommandID = commandID; Timestamp = this.timestamp,
opts.IsSuccess = Convert.ToBoolean((resp >> 1) == 0b01 ? false : true); Type = RecvPackOptions.PackType.WriteResp,
opts.Data = null; CommandID = commandID,
IsSuccess = Convert.ToBoolean((resp >> 1) == 0b01 ? false : true),
Data = null,
};
return opts; return opts;
} }
@ -472,7 +477,7 @@ namespace WebProtocol
/// </summary> /// </summary>
public bool IsSuccessful public bool IsSuccessful
{ {
get { return Convert.ToBoolean((resp >> 1) == 0b01 ? false : true); } get { return Convert.ToBoolean((this.resp >> 1) == 0b01 ? false : true); }
} }
/// <summary> /// <summary>
@ -482,12 +487,13 @@ namespace WebProtocol
/// <returns>写响应包</returns> /// <returns>写响应包</returns>
public static Result<RecvRespPackage> FromBytes(byte[] bytes) public static Result<RecvRespPackage> FromBytes(byte[] bytes)
{ {
if (bytes[0] != (byte)PackSign.RecvResp) if (bytes[4] != (byte)PackSign.RecvResp)
return new(new ArgumentException( return new(new ArgumentException(
$"The sign of bytes is not RecvResp Package, Sign: 0x{BitConverter.ToString([bytes[0]])}", $"The sign of bytes is not RecvResp Package, Sign: 0x{BitConverter.ToString([bytes[4]])}",
nameof(bytes) nameof(bytes)
)); ));
return new RecvRespPackage(bytes[1], bytes[2]); var timestamp = Number.BytesToUInt32(bytes[..4]).Value;
return new RecvRespPackage(timestamp, bytes[5], bytes[6]);
} }
/// <summary> /// <summary>
@ -496,11 +502,13 @@ namespace WebProtocol
/// <returns>字节数组</returns> /// <returns>字节数组</returns>
public byte[] ToBytes() public byte[] ToBytes()
{ {
var arr = new byte[4]; var arr = new byte[8];
Buffer.BlockCopy(
arr[0] = this.sign; Number.UInt32ArrayToBytes([this.timestamp]).Value, 0, arr, 0, 4);
arr[1] = this.commandID; arr[4] = this.sign;
arr[2] = this.resp; arr[5] = this.commandID;
arr[6] = this.resp;
arr[7] = this._reserved;
return arr; return arr;
} }