diff --git a/server/Program.cs b/server/Program.cs index fa389c5..f14bda2 100644 --- a/server/Program.cs +++ b/server/Program.cs @@ -40,16 +40,17 @@ try Description = "Use FPGA in the cloud", Version = "v1" }); - // Generate Doc and Exam - var executingAssembly = Assembly.GetExecutingAssembly(); - var xmlFilename = $"{executingAssembly.GetName().Name}.xml"; - options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename)); - var referencedProjectsXmlDocPaths = - executingAssembly.GetReferencedAssemblies() - .Where(assembly => assembly.Name != null && assembly.Name.StartsWith("server", StringComparison.InvariantCultureIgnoreCase)) - .Select(assembly => Path.Combine(AppContext.BaseDirectory, $"{assembly.Name}.xml")) - .Where(path => File.Exists(path)); - foreach (var xmlDocPath in referencedProjectsXmlDocPaths) options.IncludeXmlComments(xmlDocPath); + // Generate Doc and Example + options.IncludeXmlComments(Assembly.GetExecutingAssembly()); + // var executingAssembly = Assembly.GetExecutingAssembly(); + // var xmlFilename = $"{executingAssembly.GetName().Name}.xml"; + // options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename)); + // var referencedProjectsXmlDocPaths = + // executingAssembly.GetReferencedAssemblies() + // .Where(assembly => assembly.Name != null && assembly.Name.StartsWith("server", StringComparison.InvariantCultureIgnoreCase)) + // .Select(assembly => Path.Combine(AppContext.BaseDirectory, $"{assembly.Name}.xml")) + // .Where(path => File.Exists(path)); + // foreach (var xmlDocPath in referencedProjectsXmlDocPaths) options.IncludeXmlComments(xmlDocPath); }); var app = builder.Build(); @@ -83,13 +84,13 @@ try // API Get app.MapGet("/", () => Results.Redirect("/swagger")); app.MapGet("/api/GetRecvDataArray", Router.API.GetRecvDataArray); - app.MapPut("/api/SendString", Router.API.SendString); + app.MapPost("/api/SendString", Router.API.SendString); // API Put - app.MapPut("/api/SendAddrPackage", Router.API.SendAddrPackage); - app.MapPut("/api/SendDataPackage", Router.API.SendDataPackage); - // API Jtag Put - app.MapPut("/api/jtag/RunCommand", Router.API.Jtag.RunCommand); - app.MapPut("/api/jtag/GetIDCode", Router.API.Jtag.GetDeviceIDCode); + app.MapPost("/api/SendAddrPackage", Router.API.SendAddrPackage); + app.MapPost("/api/SendDataPackage", Router.API.SendDataPackage); + // API Jtag + app.MapPost("/api/jtag/RunCommand", Router.API.Jtag.RunCommand); + app.MapGet("/api/jtag/GetIDCode", Router.API.Jtag.GetDeviceIDCode); app.Run("http://localhost:5000"); } diff --git a/server/src/JtagController.cs b/server/src/JtagController.cs index a206576..28d065e 100644 --- a/server/src/JtagController.cs +++ b/server/src/JtagController.cs @@ -235,13 +235,13 @@ class Jtag var ret = false; var opts = new SendAddrPackOptions(); - opts.burstType = BurstType.FixedBurst; - opts.burstLength = 0; - opts.commandID = 0; - opts.address = devAddr; + opts.BurstType = BurstType.FixedBurst; + opts.BurstLength = 0; + opts.CommandID = 0; + opts.Address = devAddr; // Read Jtag State Register - opts.isWrite = false; + opts.IsWrite = false; ret = await UDPClientPool.SendAddrPackAsync(ep, new SendAddrPackage(opts)); if (!ret) throw new Exception("Send Address Package Failed!"); @@ -249,26 +249,19 @@ class Jtag if (!MsgBus.IsRunning) throw new Exception("Message Bus not Working!"); - var data = await MsgBus.UDPServer.FindDataAsync(address); - if (!data.HasValue) - throw new Exception("Get None after Time out!"); + var retPack = await MsgBus.UDPServer.WaitForDataAsync(address, port); + if (!retPack.IsSuccessful || !retPack.Value.IsSuccessful) + throw new Exception("Send address package failed"); - var recvData = data.Value; - if (recvData.Address != address || recvData.Port != port) - throw new Exception("Receive Data From Wrong Board!"); + var retPackOpts = retPack.Value.Options; + if (retPackOpts.Data is null) + throw new Exception($"Data is Null, package: {retPackOpts.ToString()}"); - var retPack = RecvDataPackage.FromBytes(recvData.Data); - if (!retPack.IsSuccessful) - throw new Exception("Not RecvDataPackage!", retPack.Error); - - if (retPack.Value.Options.data is null) - throw new Exception($"Data is Null, package: {retPack.Value.Options.ToString()}"); - - var retPackLen = retPack.Value.Options.data.Length; + var retPackLen = retPackOpts.Data.Length; if (retPackLen != 4) throw new Exception($"RecvDataPackage BodyData Length not Equal to 4: Total {retPackLen} bytes"); - return (uint)(NumberProcessor.BytesToNumber(retPack.Value.Options.data)); + return (uint)(NumberProcessor.BytesToNumber(retPackOpts.Data)); } public async ValueTask> RunCommand(uint devAddr, uint command) @@ -276,59 +269,60 @@ class Jtag var ret = false; var opts = new SendAddrPackOptions(); - opts.burstType = BurstType.FixedBurst; - opts.burstLength = 0; - opts.commandID = 0; - opts.address = devAddr; + + opts.BurstType = BurstType.FixedBurst; + opts.BurstLength = 0; + opts.CommandID = 0; + opts.Address = devAddr; // Write Jtag State Register - opts.isWrite = true; + opts.IsWrite = true; ret = await UDPClientPool.SendAddrPackAsync(ep, new SendAddrPackage(opts)); - if (!ret) throw new Exception("Send 1st Address Package Failed!"); + if (!ret) throw new Exception("Send 1st address package failed!"); + // Check Msg Bus + if (!MsgBus.IsRunning) + throw new Exception("Message bus not working!"); + // Wait for Write Ack + { + var udpResp = await MsgBus.UDPServer.WaitForAckAsync(address, port); + if (!udpResp.IsSuccessful || !udpResp.Value.IsSuccessful) + throw new Exception("Send address package failed"); + } + // Send Data Package ret = await UDPClientPool.SendDataPackAsync(ep, new SendDataPackage(NumberProcessor.NumberToBytes(command, 4).Value)); - if (!ret) throw new Exception("Send Data Package Failed!"); + if (!ret) throw new Exception("Send data package failed!"); // Read Jtag State Register - opts.isWrite = false; - opts.address = JtagAddr.STATE; + opts.IsWrite = false; + opts.Address = JtagAddr.STATE; ret = await UDPClientPool.SendAddrPackAsync(ep, new SendAddrPackage(opts)); if (!ret) throw new Exception("Send 2rd Address Package Failed!"); + // Wait for Read Data + { + var udpResp = await MsgBus.UDPServer.WaitForDataAsync(address, port); + if (!udpResp.IsSuccessful || !udpResp.Value.IsSuccessful) + throw new Exception("Send address package failed"); - // Wait for Ack - if (!MsgBus.IsRunning) - throw new Exception("Message Bus not Working!"); - - var data = await MsgBus.UDPServer.FindDataAsync(address); - if (!data.HasValue) - throw new Exception("Get None after Time out!"); - - var recvData = data.Value; - if (recvData.Address != address || recvData.Port != port) - throw new Exception("Receive Data From Wrong Board!"); - - var retPack = RecvDataPackage.FromBytes(recvData.Data); - if (!retPack.IsSuccessful) - throw new Exception("Not RecvDataPackage!", retPack.Error); - - - return retPack; + return udpResp.Value; + } } - public async ValueTask> RunCommand(uint devAddr, uint command, uint result, uint resultMask = 0xFF_FF_FF_FF) + public async ValueTask> RunCommand + (uint devAddr, uint command, uint result, uint resultMask = 0xFF_FF_FF_FF) { var ret = false; var retPack = await RunCommand(devAddr, command); - if (retPack.Value.Options.data is null) + if (retPack.Value.Options.Data is null) throw new Exception($"Data is Null, package: {retPack.Value.Options.ToString()}"); - var retPackLen = retPack.Value.Options.data.Length; + var retPackLen = retPack.Value.Options.Data.Length; if (retPackLen != 4) throw new Exception($"RecvDataPackage BodyData Length not Equal to 4: Total {retPackLen} bytes"); if (NumberProcessor.BitsCheck( - NumberProcessor.BytesToNumber(retPack.Value.Options.data).Value, result, resultMask)) + NumberProcessor.BytesToNumber(retPack.Value.Options.Data).Value, result, resultMask)) ret = true; return ret; diff --git a/server/src/Router.cs b/server/src/Router.cs index dced8b8..fe7bc03 100644 --- a/server/src/Router.cs +++ b/server/src/Router.cs @@ -2,6 +2,7 @@ using System.Net; using Common; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; +using WebProtocol; namespace Router { @@ -54,28 +55,24 @@ namespace Router } - [HttpPost] + /// + /// 发送地址包 + /// + /// IP地址 + /// UDP 端口号 + /// 地址包选项 + [HttpPost("{address}/{port}")] + [ProducesResponseType(200)] + [ProducesResponseType(500)] public static async ValueTask SendAddrPackage( string address, int port, - // WebProtocol.BurstType burstType, - // byte commandID, - // bool isWrite, - // byte burstLength, - // UInt32 devAddress) - WebProtocol.SendAddrPackOptions opts) + [FromBody] SendAddrPackOptions opts) { - // WebProtocol.SendAddrPackOptions opts; - // opts.burstType = burstType; - // opts.commandID = commandID; - // opts.isWrite = isWrite; - // opts.burstLength = burstLength; - // opts.address = devAddress; - var endPoint = new IPEndPoint(IPAddress.Parse(address), port); var ret = await UDPClientPool.SendAddrPackAsync(endPoint, new WebProtocol.SendAddrPackage(opts)); - if (ret) { return Results.Json(new Response() { IsSuccess = true }); } - else { return Results.Json(new Response() { IsSuccess = false }); } + if (ret) { return TypedResults.Ok(); } + else { return TypedResults.InternalServerError(); } } public static async ValueTask SendDataPackage(string address, int port, string data) @@ -87,7 +84,7 @@ namespace Router else { return Results.Json(new Response() { IsSuccess = false }); } } - [HttpGet()] + [HttpGet("{address}")] public static async ValueTask GetRecvDataArray(string address) { var ret = await MsgBus.UDPServer.GetDataArrayAsync(address); diff --git a/server/src/UdpServer.cs b/server/src/UdpServer.cs index c050fb1..6c09b90 100644 --- a/server/src/UdpServer.cs +++ b/server/src/UdpServer.cs @@ -11,19 +11,23 @@ public class UDPData /// /// 接受到的时间 /// - public DateTime DateTime { get; set; } + public required DateTime DateTime { get; set; } /// /// 发送来源的IP地址 /// - public string Address { get; set; } + public required string Address { get; set; } /// /// 发送来源的端口号 /// - public int Port { get; set; } + public required int Port { get; set; } /// /// 接受到的数据 /// - public byte[] Data { get; set; } + public required byte[] Data { get; set; } + /// + /// 是否被读取过 + /// + public required bool HasRead { get; set; } /// /// 将UDP Data 转化为Json 格式字符串 @@ -94,6 +98,8 @@ public class UDPServer { data = udpData[ipAddr][0]; udpData[ipAddr].RemoveAt(0); + logger.Debug($"Find UDP Data: {data.ToString()}"); + break; } } @@ -103,6 +109,7 @@ public class UDPServer if (data == null) { + logger.Trace("Get nothing even after time out"); return Optional.None(); } else @@ -137,6 +144,8 @@ public class UDPServer { data = udpData[ipAddr][0]; udpData[ipAddr].RemoveAt(0); + logger.Debug($"Find UDP Data: {data.ToString()}"); + break; } } @@ -146,6 +155,7 @@ public class UDPServer if (data == null) { + logger.Trace("Get nothing even after time out"); return Optional.None(); } else @@ -154,6 +164,12 @@ public class UDPServer } } + /// + /// 获取还未被读取的数据列表 + /// + /// IP地址 + /// 超时时间 + /// 数据列表 public async ValueTask>> GetDataArrayAsync(string ipAddr, int timeout = 1000) { List? data = null; @@ -186,6 +202,56 @@ public class UDPServer } } + /// + /// 异步等待读响应或写响应 + /// + /// IP地址 + /// UDP 端口 + /// 超时时间范围 + /// 接收响应包 + public async ValueTask> WaitForAckAsync + (string address, int port, int timeout = 1000) + { + var data = await FindDataAsync(address, timeout); + if (!data.HasValue) + throw new Exception("Get None even after time out!"); + + var recvData = data.Value; + if (recvData.Address != address || recvData.Port != port) + throw new Exception("Receive Data From Wrong Board!"); + + var retPack = WebProtocol.RecvRespPackage.FromBytes(recvData.Data); + if (!retPack.IsSuccessful) + throw new Exception("Not RecvDataPackage!", retPack.Error); + + return retPack.Value; + } + + /// + /// 异步等待数据 + /// + /// IP地址 + /// UDP 端口 + /// 超时时间范围 + /// 接收数据包 + public async ValueTask> WaitForDataAsync + (string address, int port, int timeout = 1000) + { + var data = await FindDataAsync(address, timeout); + if (!data.HasValue) + throw new Exception("Get None even after time out!"); + + var recvData = data.Value; + if (recvData.Address != address || recvData.Port != port) + throw new Exception("Receive Data From Wrong Board!"); + + var retPack = WebProtocol.RecvDataPackage.FromBytes(recvData.Data); + if (!retPack.IsSuccessful) + throw new Exception("Not RecvDataPackage!", retPack.Error); + + return retPack.Value; + } + private void ReceiveHandler(IAsyncResult res) { var remoteEP = new IPEndPoint(IPAddress.Any, listenPort); @@ -210,17 +276,20 @@ public class UDPServer Port = remotePort, Data = bytes, DateTime = nowtime, + HasRead = false, }); logger.Trace("Receive data from old client"); } else { - udpData.Add(remoteAddress, new List([new UDPData(){ - Address = remoteAddress, - Port = remotePort, - Data = bytes, - DateTime = nowtime, - }])); + udpData.Add(remoteAddress, new List([new UDPData() + { + Address = remoteAddress, + Port = remotePort, + Data = bytes, + DateTime = nowtime, + HasRead = false, + }])); logger.Trace("Receive data from new client"); } @@ -268,7 +337,7 @@ public class UDPServer logger.Debug($"Receive Data from {remoteStr} at {nowtime.ToString()}:"); logger.Debug($"Original Data: {BitConverter.ToString(bytes).Replace("-", " ")}"); if (recvData.Length != 0) logger.Debug(recvData); - RecordAllData(); + // RecordAllData(); listener.BeginReceive(new AsyncCallback(ReceiveHandler), null); diff --git a/server/src/WebProtocol.cs b/server/src/WebProtocol.cs index b205df7..7401837 100644 --- a/server/src/WebProtocol.cs +++ b/server/src/WebProtocol.cs @@ -28,33 +28,44 @@ namespace WebProtocol /// Package options which to send address to read or write - /// - /// { - /// "burType":0, - /// "commandID":1, - /// } - /// - public struct SendAddrPackOptions + public class SendAddrPackOptions { - /// Package Burst Type - [JsonProperty("burstType")] - public BurstType burstType; - /// 1 - public byte commandID; - /// 标识写入还是读取 - /// true - public bool isWrite; - /// 突发长度:0是32bits,255是32bits x 256 - /// 255 - public byte burstLength; - /// 0x10_00_00_00 - public UInt32 address; + /// + /// 突发类型 + /// + /// 0 + public BurstType BurstType { get; set; } /// - /// Convert to Json String + /// 任务ID /// - /// Json String + /// 1 + public byte CommandID { get; set; } + + /// + /// 标识写入还是读取 + /// + /// true + public bool IsWrite { get; set; } + + /// + /// 突发长度:0是32bits,255是32bits x 256 + /// + /// 255 + public byte BurstLength { get; set; } + + + /// + /// 目标地址 + /// + /// 0 + public UInt32 Address { get; set; } + + /// + /// 转换为Json格式字符串 + /// + /// Json String public override string ToString() { return JsonConvert.SerializeObject(this); @@ -62,7 +73,7 @@ namespace WebProtocol } /// Package Options which to receive from boards - public struct RecvPackOptions + public class RecvPackOptions { /// 数据包类型 public enum PackType @@ -76,19 +87,26 @@ namespace WebProtocol /// /// 数据包类型 /// - public PackType type; + /// 0 + public PackType Type { get; set; } + /// /// Task ID /// - public byte commandID; + /// 0 + public byte CommandID { get; set; } + /// /// Whether is succeed to finish command /// - public bool isSuccess; + /// true + public bool IsSuccess { get; set; } + /// /// Return Data /// - public byte[]? data; + /// [] + public byte[]? Data { get; set; } /// /// Convert to Json String @@ -101,7 +119,7 @@ namespace WebProtocol } /// Server->FPGA 地址包 - public struct SendAddrPackage + public class SendAddrPackage { readonly byte sign = (byte)PackSign.SendAddr; readonly byte commandType; @@ -115,12 +133,12 @@ namespace WebProtocol /// 地址包选项 public SendAddrPackage(SendAddrPackOptions opts) { - byte byteBurstType = Convert.ToByte((byte)opts.burstType << 6); - byte byteCommandID = Convert.ToByte((opts.commandID & 0x03) << 4); - byte byteIsWrite = (opts.isWrite ? (byte)0x01 : (byte)0x00); + byte byteBurstType = Convert.ToByte((byte)opts.BurstType << 6); + byte byteCommandID = Convert.ToByte((opts.CommandID & 0x03) << 4); + byte byteIsWrite = (opts.IsWrite ? (byte)0x01 : (byte)0x00); this.commandType = Convert.ToByte(byteBurstType | byteCommandID | byteIsWrite); - this.burstLength = opts.burstLength; - this.address = opts.address; + this.burstLength = opts.BurstLength; + this.address = opts.Address; } /// @@ -178,12 +196,12 @@ namespace WebProtocol /// 字符串 public override string ToString() { - SendAddrPackOptions opts; - opts.burstType = (BurstType)(commandType >> 6); - opts.commandID = Convert.ToByte((commandType >> 4) & 0b0011); - opts.isWrite = Convert.ToBoolean(commandType & 0x01); - opts.burstLength = burstLength; - opts.address = address; + var opts = new SendAddrPackOptions(); + opts.BurstType = (BurstType)(commandType >> 6); + opts.CommandID = Convert.ToByte((commandType >> 4) & 0b0011); + opts.IsWrite = Convert.ToBoolean(commandType & 0x01); + opts.BurstLength = burstLength; + opts.Address = address; return JsonConvert.SerializeObject(opts); } @@ -287,16 +305,24 @@ namespace WebProtocol { get { - RecvPackOptions opts; - opts.type = RecvPackOptions.PackType.ReadResp; - opts.commandID = commandID; - opts.isSuccess = Convert.ToBoolean((resp >> 1) == 0b01 ? false : true); - opts.data = bodyData; + var opts = new RecvPackOptions(); + opts.Type = RecvPackOptions.PackType.ReadResp; + opts.CommandID = commandID; + opts.IsSuccess = Convert.ToBoolean((resp >> 1) == 0b01 ? false : true); + opts.Data = bodyData; return opts; } } + /// + /// 读取是否成功 + /// + public bool IsSuccessful + { + get { return Convert.ToBoolean((resp >> 1) == 0b01 ? false : true); } + } + /// /// 从字节数组构建读响应包 /// @@ -342,16 +368,24 @@ namespace WebProtocol { get { - RecvPackOptions opts; - opts.type = RecvPackOptions.PackType.WriteResp; - opts.commandID = commandID; - opts.isSuccess = Convert.ToBoolean((resp >> 1) == 0b01 ? false : true); - opts.data = null; + var opts = new RecvPackOptions(); + opts.Type = RecvPackOptions.PackType.WriteResp; + opts.CommandID = commandID; + opts.IsSuccess = Convert.ToBoolean((resp >> 1) == 0b01 ? false : true); + opts.Data = null; return opts; } } + /// + /// 写入是否成功 + /// + public bool IsSuccessful + { + get { return Convert.ToBoolean((resp >> 1) == 0b01 ? false : true); } + } + /// /// 从字节数组构建写响应包 ///