From 98a5dbe7f3a3937a63602fb8760d37e5d15adf7e Mon Sep 17 00:00:00 2001 From: SikongJueluo <selfconfusion@gmail.com> Date: Tue, 22 Apr 2025 17:24:46 +0800 Subject: [PATCH] try to fix server bug: couldn't download bitstream --- server.test/.gitignore | 1 + server/.gitignore | 1 + server/Program.cs | 6 +- server/src/Controllers.cs | 94 +++++++++++++----- server/src/JtagClient.cs | 203 +++++++++++++++++++------------------- server/src/UdpServer.cs | 28 +++--- 6 files changed, 192 insertions(+), 141 deletions(-) diff --git a/server.test/.gitignore b/server.test/.gitignore index 1746e32..d676866 100644 --- a/server.test/.gitignore +++ b/server.test/.gitignore @@ -1,2 +1,3 @@ bin obj +bitstream diff --git a/server/.gitignore b/server/.gitignore index 501ec83..096eec5 100644 --- a/server/.gitignore +++ b/server/.gitignore @@ -1,3 +1,4 @@ obj bin +bitstream diff --git a/server/Program.cs b/server/Program.cs index 2a3902a..9e111eb 100644 --- a/server/Program.cs +++ b/server/Program.cs @@ -65,7 +65,11 @@ try // Application Settings var app = builder.Build(); // Configure the HTTP request pipeline. - app.UseExceptionHandler("/Home/Error"); + // app.UseExceptionHandler(new ExceptionHandlerOptions() + // { + // AllowStatusCode404Response = true, + // ExceptionHandlingPath = "/error" + // }); // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); app.UseHttpsRedirection(); diff --git a/server/src/Controllers.cs b/server/src/Controllers.cs index ecd5411..399e7c6 100644 --- a/server/src/Controllers.cs +++ b/server/src/Controllers.cs @@ -139,6 +139,8 @@ public class UDPController : ControllerBase [Route("api/[controller]")] public class JtagController : ControllerBase { + private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); + /// <summary> /// 页面 /// </summary> @@ -184,48 +186,92 @@ public class JtagController : ControllerBase else { return TypedResults.InternalServerError(ret.Error); } } + /// <summary> + /// 上传比特流文件 + /// </summary> + /// <param name="address"> 设备地址 </param> + /// <param name="file">比特流文件</param> + [HttpPost("UploadBitstream")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + public async ValueTask<IResult> UploadBitstream(string address, IFormFile file) + { + if (file == null || file.Length == 0) + return TypedResults.BadRequest("未选择文件"); + + // 生成安全的文件名(避免路径遍历攻击) + var fileName = Path.GetRandomFileName(); + var uploadsFolder = Path.Combine(Environment.CurrentDirectory, $"bitstream/{address}"); + + // 如果存在文件,则删除原文件再上传 + if (Directory.Exists(uploadsFolder)) + { + Directory.Delete(uploadsFolder, true); + } + Directory.CreateDirectory(uploadsFolder); + + var filePath = Path.Combine(uploadsFolder, fileName); + + using (var stream = new FileStream(filePath, FileMode.Create)) + { + await file.CopyToAsync(stream); + } + + return TypedResults.Ok("文件上传成功"); + } + /// <summary> /// 通过Jtag下载比特流文件 /// </summary> /// <param name="address"> 设备地址 </param> /// <param name="port"> 设备端口 </param> - /// <param name="file">比特流文件(最大32MB)</param> - [HttpGet("DownloadBitstream")] + [HttpPost("DownloadBitstream")] [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async ValueTask<IResult> DownloadBitstream(string address, int port, IFormFile file) + public async ValueTask<IResult> DownloadBitstream(string address, int port) { // 检查文件 - if (file is null || file.Length <= 0) - throw new ArgumentException("Empty file", nameof(file)); + var fileDir = Path.Combine(Environment.CurrentDirectory, $"bitstream/{address}"); + if (!Directory.Exists(fileDir)) + return TypedResults.BadRequest("Empty bitstream, Please upload it first"); - // 定义缓冲区大小(例如:1MB) - const int bufferSize = 1024 * 1024; // 1MB - byte[] buffer = new byte[bufferSize]; - long totalBytesRead = 0; - - // 使用异步流读取文件 - using (var memoryStream = new MemoryStream()) + try { - using (var stream = file.OpenReadStream()) + // 读取文件 + var filePath = Directory.GetFiles(fileDir)[0]; + var fileStream = System.IO.File.Open(filePath, System.IO.FileMode.Open); + if (fileStream is null || fileStream.Length <= 0) + return TypedResults.BadRequest("Wrong bitstream, Please upload it again"); + + // 定义缓冲区大小: 32KB + byte[] buffer = new byte[32 * 1024]; + long totalBytesRead = 0; + + // 使用异步流读取文件 + using (var memoryStream = new MemoryStream()) { int bytesRead; - while ((bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length)) > 0) + while ((bytesRead = await fileStream.ReadAsync(buffer, 0, buffer.Length)) > 0) { await memoryStream.WriteAsync(buffer, 0, bytesRead); totalBytesRead += bytesRead; } + + // 将所有数据转换为字节数组(注意:如果文件非常大,可能不适合完全加载到内存) + var fileBytes = memoryStream.ToArray(); + + // 下载比特流 + var jtagCtrl = new JtagClient.Jtag(address, port); + var ret = await jtagCtrl.DownloadBitstream(fileBytes); + + if (ret.IsSuccessful) { return TypedResults.Ok(ret.Value); } + else { return TypedResults.InternalServerError(ret.Error); } } - - // 将所有数据转换为字节数组(注意:如果文件非常大,可能不适合完全加载到内存) - byte[] fileBytes = memoryStream.ToArray(); - - // 下载比特流 - var jtagCtrl = new JtagClient.Jtag(address, port); - var ret = await jtagCtrl.DownloadBitstream(fileBytes); - - if (ret.IsSuccessful) { return TypedResults.Ok(ret.Value); } - else { return TypedResults.InternalServerError(ret.Error); } + } + catch (Exception error) + { + return TypedResults.InternalServerError(error); } } } diff --git a/server/src/JtagClient.cs b/server/src/JtagClient.cs index 9119f25..a724b18 100644 --- a/server/src/JtagClient.cs +++ b/server/src/JtagClient.cs @@ -287,11 +287,10 @@ class Jtag 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"); - } + var udpWriteAck = await MsgBus.UDPServer.WaitForAckAsync(address, port); + if (!udpWriteAck.IsSuccessful) throw udpWriteAck.Error; + else if (!udpWriteAck.Value.IsSuccessful) + throw new Exception("Send address package failed"); // Read Jtag State Register opts.IsWrite = false; @@ -299,13 +298,12 @@ class Jtag 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"); + var udpDataResp = await MsgBus.UDPServer.WaitForDataAsync(address, port); + if (!udpDataResp.IsSuccessful) throw udpDataResp.Error; + else if (!udpDataResp.Value.IsSuccessful) + throw new Exception("Send address package failed"); - return udpResp.Value; - } + return udpDataResp.Value; } public async ValueTask<Result<RecvDataPackage>> WriteFIFO(UInt32 devAddr, byte[] dataArray) @@ -342,11 +340,10 @@ class Jtag if (!ret) throw new Exception("Send data package failed!"); // 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"); - } + var udpWriteAck = await MsgBus.UDPServer.WaitForAckAsync(address, port); + if (!udpWriteAck.IsSuccessful) throw udpWriteAck.Error; + else if (!udpWriteAck.Value.IsSuccessful) + throw new Exception("Send address package failed"); } // Read Jtag State Register @@ -356,13 +353,12 @@ class Jtag 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"); + var udpDataResp = await MsgBus.UDPServer.WaitForDataAsync(address, port); + if (!udpDataResp.IsSuccessful) throw udpDataResp.Error; + else if (!udpDataResp.Value.IsSuccessful) + throw new Exception("Send address package failed"); - return udpResp.Value; - } + return udpDataResp.Value; } public async ValueTask<Result<bool>> WriteFIFO @@ -370,6 +366,7 @@ class Jtag { var ret = false; var retPack = await WriteFIFO(devAddr, data); + if (!retPack.IsSuccessful) throw retPack.Error; if (retPack.Value.Options.Data is null) throw new Exception($"Data is Null, package: {retPack.Value.Options.ToString()}"); @@ -507,27 +504,31 @@ class Jtag // Clear Data await MsgBus.UDPServer.ClearUDPData(this.address); + Result<bool> ret; + + ret = await ClearAllRegisters(); + if (!ret.IsSuccessful) throw ret.Error; + else if (!ret.Value) throw new Exception("Jtag Clear All Registers Failed"); + + ret = await RunTest(); + if (!ret.IsSuccessful) throw ret.Error; + else if (!ret.Value) throw new Exception("Jtag Run Test Failed"); + + ret = await ExecRDCmd(JtagCmd.JTAG_DR_IDCODE); + if (!ret.IsSuccessful) throw ret.Error; + else if (!ret.Value) throw new Exception("Jtag Execute Command JTAG_DR_IDCODE Failed"); + + ret = await ClearWriteDataReg(); + if (!ret.IsSuccessful) throw ret.Error; + else if (!ret.Value) throw new Exception("Jtag Clear Write Registers Failed"); + + var retData = await LoadDRCareOutput(4); + if (!retData.IsSuccessful) { - var ret = await ClearAllRegisters(); - if (!ret.IsSuccessful) throw ret.Error; - else if (!ret.Value) throw new Exception("Jtag Clear All Registers Failed"); + throw new Exception("Get ID Code Failed"); } - { - var ret = await RunTest(); - if (!ret.IsSuccessful) throw ret.Error; - else if (!ret.Value) throw new Exception("Jtag Run Test Failed"); - } - { - var ret = await ExecRDCmd(JtagCmd.JTAG_DR_IDCODE); - if (!ret.IsSuccessful) throw ret.Error; - else if (!ret.Value) throw new Exception("Jtag Execute Command JTAG_DR_IDCODE Failed"); - } - { - var ret = await ClearWriteDataReg(); - if (!ret.IsSuccessful) throw ret.Error; - else if (!ret.Value) throw new Exception("Jtag Clear Write Registers Failed"); - } - return (await LoadDRCareOutput(1)).Value; + + return retData.Value; } public async ValueTask<Result<bool>> DownloadBitstream(byte[] bitstream) @@ -535,66 +536,66 @@ class Jtag // Clear Data await MsgBus.UDPServer.ClearUDPData(this.address); - { - var ret = await CloseTest(); - if (!ret.IsSuccessful) throw ret.Error; - else if (!ret.Value) throw new Exception("Jtag Close Test Failed"); - } - { - var ret = await RunTest(); - if (!ret.IsSuccessful) throw ret.Error; - else if (!ret.Value) throw new Exception("Jtag Run Test Failed"); - } - { - var ret = await ExecRDCmd(JtagCmd.JTAG_DR_JRST); - if (!ret.IsSuccessful) throw ret.Error; - else if (!ret.Value) throw new Exception("Jtag Execute Command JTAG_DR_JRST Failed"); - } - { - var ret = await RunTest(); - if (!ret.IsSuccessful) throw ret.Error; - else if (!ret.Value) throw new Exception("Jtag Run Test Failed"); - } - { - var ret = await ExecRDCmd(JtagCmd.JTAG_DR_CFGI); - if (!ret.IsSuccessful) throw ret.Error; - else if (!ret.Value) throw new Exception("Jtag Execute Command JTAG_DR_CFGI Failed"); - } - { - var ret = await IdleDelay(75000); - if (!ret.IsSuccessful) throw ret.Error; - else if (!ret.Value) throw new Exception("Jtag IDLE Delay Failed"); - } - { - var ret = await LoadDRCareInput(bitstream); - if (!ret.IsSuccessful) throw ret.Error; - else if (!ret.Value) throw new Exception("Jtag Load Data Failed"); - } - { - var ret = await CloseTest(); - if (!ret.IsSuccessful) throw ret.Error; - else if (!ret.Value) throw new Exception("Jtag Close Test Failed"); - } - { - var ret = await RunTest(); - if (!ret.IsSuccessful) throw ret.Error; - else if (!ret.Value) throw new Exception("Jtag Run Test Failed"); - } - { - var ret = await ExecRDCmd(JtagCmd.JTAG_DR_JWAKEUP); - if (!ret.IsSuccessful) throw ret.Error; - else if (!ret.Value) throw new Exception("Jtag Execute Command JTAG_DR_JWAKEUP Failed"); - } - { - var ret = await IdleDelay(1000); - if (!ret.IsSuccessful) throw ret.Error; - else if (!ret.Value) throw new Exception("Jtag IDLE Delay Failed"); - } - { - var ret = await CloseTest(); - if (!ret.IsSuccessful) throw ret.Error; - else if (!ret.Value) throw new Exception("Jtag Close Test Failed"); - } + Result<bool> ret; + + ret = await CloseTest(); + if (!ret.IsSuccessful) throw ret.Error; + else if (!ret.Value) throw new Exception("Jtag Close Test Failed"); + + + ret = await RunTest(); + if (!ret.IsSuccessful) throw ret.Error; + else if (!ret.Value) throw new Exception("Jtag Run Test Failed"); + + + ret = await ExecRDCmd(JtagCmd.JTAG_DR_JRST); + if (!ret.IsSuccessful) throw ret.Error; + else if (!ret.Value) throw new Exception("Jtag Execute Command JTAG_DR_JRST Failed"); + + + ret = await RunTest(); + if (!ret.IsSuccessful) throw ret.Error; + else if (!ret.Value) throw new Exception("Jtag Run Test Failed"); + + + ret = await ExecRDCmd(JtagCmd.JTAG_DR_CFGI); + if (!ret.IsSuccessful) throw ret.Error; + else if (!ret.Value) throw new Exception("Jtag Execute Command JTAG_DR_CFGI Failed"); + + + ret = await IdleDelay(75000); + if (!ret.IsSuccessful) throw ret.Error; + else if (!ret.Value) throw new Exception("Jtag IDLE Delay Failed"); + + + ret = await LoadDRCareInput(bitstream); + if (!ret.IsSuccessful) throw ret.Error; + else if (!ret.Value) throw new Exception("Jtag Load Data Failed"); + + + ret = await CloseTest(); + if (!ret.IsSuccessful) throw ret.Error; + else if (!ret.Value) throw new Exception("Jtag Close Test Failed"); + + + ret = await RunTest(); + if (!ret.IsSuccessful) throw ret.Error; + else if (!ret.Value) throw new Exception("Jtag Run Test Failed"); + + + ret = await ExecRDCmd(JtagCmd.JTAG_DR_JWAKEUP); + if (!ret.IsSuccessful) throw ret.Error; + else if (!ret.Value) throw new Exception("Jtag Execute Command JTAG_DR_JWAKEUP Failed"); + + + ret = await IdleDelay(1000); + if (!ret.IsSuccessful) throw ret.Error; + else if (!ret.Value) throw new Exception("Jtag IDLE Delay Failed"); + + + ret = await CloseTest(); + if (!ret.IsSuccessful) throw ret.Error; + else if (!ret.Value) throw new Exception("Jtag Close Test Failed"); return true; } diff --git a/server/src/UdpServer.cs b/server/src/UdpServer.cs index 1295bbe..e5f15f2 100644 --- a/server/src/UdpServer.cs +++ b/server/src/UdpServer.cs @@ -136,11 +136,11 @@ public class UDPServer using (await udpData.AcquireWriteLockAsync(timeleft)) { - if (udpData.TryGetValue(ipAddr, out var dataQueue) && dataQueue != null && dataQueue.Count > 0) + if (udpData.ContainsKey(ipAddr) && + udpData.TryGetValue(ipAddr, out var dataQueue) && + dataQueue.Count > 0) { data = dataQueue.Dequeue(); - // data = dataList[0].DeepClone(); - // dataList.RemoveAt(0); logger.Debug($"Find UDP Data: {data.ToString()}"); break; } @@ -150,7 +150,7 @@ public class UDPServer if (data is null) { logger.Trace("Get nothing even after time out"); - return Optional.None<UDPData>(); + return Optional<UDPData>.None; } else { @@ -179,7 +179,9 @@ public class UDPServer using (await udpData.AcquireReadLockAsync(timeleft)) { - if (udpData.TryGetValue(ipAddr, out var dataQueue) && dataQueue != null && dataQueue.Count > 0) + if (udpData.ContainsKey(ipAddr) && + udpData.TryGetValue(ipAddr, out var dataQueue) && + dataQueue.Count > 0) { data = dataQueue.ToList(); logger.Debug($"Find UDP Data Array: {JsonConvert.SerializeObject(data)}"); @@ -191,7 +193,7 @@ public class UDPServer if (data is null) { logger.Trace("Get nothing even after time out"); - return Optional.None<List<UDPData>>(); + return Optional<List<UDPData>>.None; } else { @@ -214,7 +216,7 @@ public class UDPServer throw new Exception("Get None even after time out!"); var recvData = data.Value; - if (recvData.Address != address || (port >= 0 && recvData.Port != port)) + if (recvData.Address != address || (port > 0 && recvData.Port != port)) throw new Exception("Receive Data From Wrong Board!"); var retPack = WebProtocol.RecvRespPackage.FromBytes(recvData.Data); @@ -305,19 +307,13 @@ public class UDPServer using (udpData.AcquireWriteLock()) { // Record UDP Receive Data - // if (udpData.ContainsKey(remoteAddress)) - if (udpData.TryGetValue(remoteAddress, out var dataQueue)) + if (udpData.ContainsKey(remoteAddress) && udpData.TryGetValue(remoteAddress, out var dataQueue)) { - // var listData = udpData[remoteAddress]; - // listData.Add(data); dataQueue.Enqueue(data); logger.Trace("Receive data from old client"); } else { - // var list = new List<UDPData>(); - // list.Add(data); - // udpData.Add(remoteAddress, list); var queue = new Queue<UDPData>(); queue.Enqueue(data); udpData.Add(remoteAddress, queue); @@ -401,7 +397,9 @@ public class UDPServer { using (await udpData.AcquireWriteLockAsync()) { - if (udpData.TryGetValue(ipAddr, out var dataQueue) && dataQueue.Count > 0) + if (udpData.ContainsKey(ipAddr) && + udpData.TryGetValue(ipAddr, out var dataQueue) && + dataQueue.Count > 0) { dataQueue.Clear(); }