feat: 更新通信协议
This commit is contained in:
parent
822091243e
commit
d551cbe793
|
@ -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!"));
|
||||||
|
|
||||||
|
|
|
@ -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 :
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -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是32bits,255是32bits x 256
|
/// 突发长度:0是32bits,255是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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue