This repository has been archived on 2025-10-29. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
FPGA_WebLab/server/src/UdpClientPool.cs

404 lines
15 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Net;
using System.Net.Sockets;
using System.Text;
using DotNext;
using WebProtocol;
/// <summary>
/// UDP客户端发送池
/// </summary>
public class UDPClientPool
{
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
private static IPAddress localhost = IPAddress.Parse("127.0.0.1");
/// <summary>
/// 发送字符串
/// </summary>
/// <param name="endPoint">IP端点IP地址与端口</param>
/// <param name="stringArray">字符串数组</param>
/// <returns>是否成功</returns>
public static bool SendString(IPEndPoint endPoint, string[] stringArray)
{
var isSuccessful = true;
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
foreach (var str in stringArray)
{
byte[] sendbuf = Encoding.ASCII.GetBytes(str);
var sendLen = socket.SendTo(sendbuf, endPoint);
if (str.Length != sendLen) isSuccessful = false;
}
socket.Close();
if (isSuccessful) { return true; }
else { return false; }
}
/// <summary>
/// 异步发送字符串
/// </summary>
/// <param name="endPoint">IP端点IP地址与端口</param>
/// <param name="stringArray">字符串数组</param>
/// <returns>是否成功</returns>
public async static ValueTask<bool> SendStringAsync(IPEndPoint endPoint, string[] stringArray)
{
return await Task.Run(() => { return SendString(endPoint, stringArray); });
}
/// <summary>
/// 发送二进制字节
/// </summary>
/// <param name="endPoint">IP端点IP地址与端口</param>
/// <param name="buf">二进制字节</param>
/// <returns>是否成功</returns>
public static bool SendBytes(IPEndPoint endPoint, byte[] buf)
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
var sendLen = socket.SendTo(buf, endPoint);
socket.Close();
logger.Debug($"UDP socket send bytes to device {endPoint.Address.ToString()}:{endPoint.Port.ToString()}:");
logger.Debug($" Original Data: {BitConverter.ToString(buf).Replace("-", " ")}");
if (sendLen == buf.Length) { return true; }
else { return false; }
}
/// <summary>
/// 异步发送二进制字节
/// </summary>
/// <param name="endPoint">IP端点IP地址与端口</param>
/// <param name="buf">二进制字节</param>
/// <returns>是否成功</returns>
public async static ValueTask<bool> SendBytesAsync(IPEndPoint endPoint, byte[] buf)
{
return await Task.Run(() => { return SendBytes(endPoint, buf); });
}
/// <summary>
/// 发送地址包
/// </summary>
/// <param name="endPoint">IP端点IP地址与端口</param>
/// <param name="pkg">地址包</param>
/// <returns>是否成功</returns>
public static bool SendAddrPack(IPEndPoint endPoint, WebProtocol.SendAddrPackage pkg)
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
var sendBytes = pkg.ToBytes();
var sendLen = socket.SendTo(sendBytes, endPoint);
socket.Close();
logger.Debug($"UDP socket send address package to device {endPoint.Address.ToString()}:{endPoint.Port.ToString()}:");
logger.Debug($" Original Data: {BitConverter.ToString(pkg.ToBytes()).Replace("-", " ")}");
logger.Debug($" Decoded Data: {pkg.ToString()}");
if (sendLen == sendBytes.Length) { return true; }
else { return false; }
}
/// <summary>
/// 异步发送地址包
/// </summary>
/// <param name="endPoint">IP端点IP地址与端口</param>
/// <param name="pkg">地址包</param>
/// <returns>是否成功</returns>
public async static ValueTask<bool> SendAddrPackAsync(IPEndPoint endPoint, WebProtocol.SendAddrPackage pkg)
{
return await Task.Run(() => { return SendAddrPack(endPoint, pkg); });
}
/// <summary>
/// 发送数据包
/// </summary>
/// <param name="endPoint">IP端点IP地址与端口</param>
/// <param name="pkg">数据包</param>
/// <returns>是否成功</returns>
public static bool SendDataPack(IPEndPoint endPoint, WebProtocol.SendDataPackage pkg)
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
var sendBytes = pkg.ToBytes();
var sendLen = socket.SendTo(sendBytes, endPoint);
socket.Close();
logger.Debug($"UDP socket send data package to device {endPoint.Address.ToString()}:{endPoint.Port.ToString()}:");
logger.Debug($" Original Data: {BitConverter.ToString(pkg.ToBytes()).Replace("-", " ")}");
if (sendLen == sendBytes.Length) { return true; }
else { return false; }
}
/// <summary>
/// 异步发送数据包
/// </summary>
/// <param name="endPoint">IP端点IP地址与端口</param>
/// <param name="pkg">数据包</param>
/// <returns>是否成功</returns>
public async static ValueTask<bool> SendDataPackAsync(IPEndPoint endPoint, WebProtocol.SendDataPackage pkg)
{
return await Task.Run(() => { return SendDataPack(endPoint, pkg); });
}
/// <summary>
/// 发送字符串到本地
/// </summary>
/// <param name="port">端口</param>
/// <param name="stringArray">字符串数组</param>
/// <returns>是否成功</returns>
public static bool SendStringLocalHost(int port, string[] stringArray)
{
return SendString(new IPEndPoint(localhost, port), stringArray);
}
/// <summary>
/// 循环发送字符串到本地
/// </summary>
/// <param name="times">发送总次数</param>
/// <param name="sleepMilliSeconds">间隔时间</param>
/// <param name="port">端口</param>
/// <param name="stringArray">字符串数组</param>
/// <returns>是否成功</returns>
public static bool CycleSendStringLocalHost(int times, int sleepMilliSeconds, int port, string[] stringArray)
{
var isSuccessful = true;
while (times-- >= 0)
{
isSuccessful = SendStringLocalHost(port, stringArray);
if (!isSuccessful) break;
Thread.Sleep(sleepMilliSeconds);
}
return isSuccessful;
}
/// <summary>
/// [TODO:description]
/// </summary>
/// <param name="endPoint">[TODO:parameter]</param>
/// <param name="devAddr">[TODO:parameter]</param>
/// <param name="timeout">[TODO:parameter]</param>
/// <returns>[TODO:return]</returns>
public static async ValueTask<Result<RecvDataPackage>> ReadAddr(
IPEndPoint endPoint, int taskID, uint devAddr, int timeout = 1000)
{
var ret = false;
var opts = new SendAddrPackOptions();
opts.BurstType = BurstType.FixedBurst;
opts.BurstLength = 0;
opts.CommandID = Convert.ToByte(taskID);
opts.Address = devAddr;
// Read Jtag State Register
opts.IsWrite = false;
ret = await UDPClientPool.SendAddrPackAsync(endPoint, new SendAddrPackage(opts));
if (!ret) return new(new Exception("Send Address Package Failed!"));
// Wait for Read Ack
if (!MsgBus.IsRunning)
return new(new Exception("Message Bus not Working!"));
var retPack = await MsgBus.UDPServer.WaitForDataAsync(
endPoint.Address.ToString(), taskID, endPoint.Port, timeout);
if (!retPack.IsSuccessful) return new(retPack.Error);
else if (!retPack.Value.IsSuccessful)
return new(new Exception("Send address package failed"));
var retPackOpts = retPack.Value.Options;
if (retPackOpts.Data is null)
return new(new Exception($"Data is Null, package: {retPackOpts.ToString()}"));
return retPack;
}
/// <summary>
/// [TODO:description]
/// </summary>
/// <param name="endPoint">[TODO:parameter]</param>
/// <param name="devAddr">[TODO:parameter]</param>
/// <param name="result">[TODO:parameter]</param>
/// <param name="resultMask">[TODO:parameter]</param>
/// <param name="timeout">[TODO:parameter]</param>
/// <returns>[TODO:return]</returns>
public static async ValueTask<Result<bool>> ReadAddr(
IPEndPoint endPoint, int taskID, uint devAddr, UInt32 result, UInt32 resultMask, int timeout = 1000)
{
var address = endPoint.Address.ToString();
var ret = await ReadAddr(endPoint, taskID, devAddr, timeout);
if (!ret.IsSuccessful) return new(ret.Error);
if (!ret.Value.IsSuccessful)
return new(new Exception($"Read device {address} address {devAddr} failed"));
var retData = ret.Value.Options.Data;
if (retData is null)
return new(new Exception($"Device {address} receive none"));
if (retData.Length != 4)
return new(new Exception(
$"Device {address} receive data is {retData.Length} bytes instead of 4 bytes"));
// Check result
try
{
var retCode = Convert.ToUInt32(Common.Number.BytesToUInt64(retData).Value);
return Common.Number.BitsCheck(retCode, result, resultMask);
}
catch (Exception error)
{
return new(error);
}
}
/// <summary>
/// [TODO:description]
/// </summary>
/// <param name="endPoint">[TODO:parameter]</param>
/// <param name="devAddr">[TODO:parameter]</param>
/// <param name="result">[TODO:parameter]</param>
/// <param name="resultMask">[TODO:parameter]</param>
/// <param name="timeout">[TODO:parameter]</param>
/// <returns>[TODO:return]</returns>
public static async ValueTask<Result<bool>> ReadAddrWithWait(
IPEndPoint endPoint, int taskID, uint devAddr, UInt32 result, UInt32 resultMask, int timeout = 1000)
{
var address = endPoint.Address.ToString();
var startTime = DateTime.Now;
while (true)
{
var elapsed = DateTime.Now - startTime;
if (elapsed >= TimeSpan.FromMilliseconds(timeout)) break;
var timeleft = TimeSpan.FromMilliseconds(timeout) - elapsed;
try
{
var ret = await ReadAddr(endPoint, taskID, devAddr, Convert.ToInt32(timeleft.TotalMilliseconds));
if (!ret.IsSuccessful) return new(ret.Error);
if (!ret.Value.IsSuccessful)
return new(new Exception($"Read device {address} address {devAddr} failed"));
var retData = ret.Value.Options.Data;
if (retData is null)
return new(new Exception($"Device {address} receive none"));
if (retData.Length != 4)
return new(new Exception(
$"Device {address} receive data is {retData.Length} bytes instead of 4 bytes"));
// Check result
var retCode = Convert.ToUInt32(Common.Number.BytesToUInt64(retData).Value);
if (Common.Number.BitsCheck(retCode, result, resultMask)) return true;
}
catch (Exception error)
{
return new(error);
}
}
return false;
}
/// <summary>
/// [TODO:description]
/// </summary>
/// <param name="endPoint">[TODO:parameter]</param>
/// <param name="devAddr">[TODO:parameter]</param>
/// <param name="data">[TODO:parameter]</param>
/// <param name="timeout">[TODO:parameter]</param>
/// <returns>[TODO:return]</returns>
public static async ValueTask<Result<bool>> WriteAddr(
IPEndPoint endPoint, int taskID, UInt32 devAddr, UInt32 data, int timeout = 1000)
{
var ret = false;
var opts = new SendAddrPackOptions();
opts.BurstType = BurstType.FixedBurst;
opts.BurstLength = 0;
opts.CommandID = Convert.ToByte(taskID);
opts.Address = devAddr;
// Write Jtag State Register
opts.IsWrite = true;
ret = await UDPClientPool.SendAddrPackAsync(endPoint, new SendAddrPackage(opts));
if (!ret) return new(new Exception("Send 1st address package failed!"));
// Send Data Package
ret = await UDPClientPool.SendDataPackAsync(endPoint,
new SendDataPackage(Common.Number.NumberToBytes(data, 4).Value));
if (!ret) return new(new Exception("Send data package failed!"));
// Check Msg Bus
if (!MsgBus.IsRunning)
return new(new Exception("Message bus not working!"));
// Wait for Write Ack
var udpWriteAck = await MsgBus.UDPServer.WaitForAckAsync(
endPoint.Address.ToString(), taskID, endPoint.Port, timeout);
if (!udpWriteAck.IsSuccessful) return new(udpWriteAck.Error);
return udpWriteAck.Value.IsSuccessful;
}
/// <summary>
/// [TODO:description]
/// </summary>
/// <param name="endPoint">[TODO:parameter]</param>
/// <param name="devAddr">[TODO:parameter]</param>
/// <param name="dataArray">[TODO:parameter]</param>
/// <param name="timeout">[TODO:parameter]</param>
/// <returns>[TODO:return]</returns>
public static async ValueTask<Result<bool>> WriteAddr(
IPEndPoint endPoint, int taskID, UInt32 devAddr, byte[] dataArray, int timeout = 1000)
{
var ret = false;
var opts = new SendAddrPackOptions();
opts.BurstType = BurstType.FixedBurst;
opts.CommandID = Convert.ToByte(taskID);
opts.Address = devAddr;
// Check Msg Bus
if (!MsgBus.IsRunning)
return new(new Exception("Message bus not working!"));
opts.IsWrite = true;
var hasRest = dataArray.Length % (256 * (32 / 8)) != 0;
var writeTimes = hasRest ?
dataArray.Length / (256 * (32 / 8)) + 1 :
dataArray.Length / (256 * (32 / 8));
for (var i = 0; i < writeTimes; i++)
{
// Sperate Data Array
var isLastData = i == writeTimes - 1;
var sendDataArray =
isLastData ?
dataArray[(i * (256 * (32 / 8)))..] :
dataArray[(i * (256 * (32 / 8)))..((i + 1) * (256 * (32 / 8)))];
// Write Jtag State Register
opts.BurstLength = ((byte)(sendDataArray.Length / 4 - 1));
ret = await UDPClientPool.SendAddrPackAsync(endPoint, new SendAddrPackage(opts));
if (!ret) return new(new Exception("Send 1st address package failed!"));
// Send Data Package
ret = await UDPClientPool.SendDataPackAsync(endPoint, new SendDataPackage(sendDataArray));
if (!ret) return new(new Exception("Send data package failed!"));
// Wait for Write Ack
var udpWriteAck = await MsgBus.UDPServer.WaitForAckAsync(endPoint.Address.ToString(), taskID, endPoint.Port, timeout);
if (!udpWriteAck.IsSuccessful) return new(udpWriteAck.Error);
if (!udpWriteAck.Value.IsSuccessful)
return false;
}
return true;
}
}