From f35a295af28f323f2b8e64d62d8fe596136d6213 Mon Sep 17 00:00:00 2001 From: SikongJueluo Date: Fri, 25 Apr 2025 21:53:56 +0800 Subject: [PATCH 1/8] add remote update but not finished --- server/src/RemoteUpdate.cs | 166 ++++++++++++++++++++++++++++++++++++ server/src/UdpClientPool.cs | 88 +++++++++++++++++++ 2 files changed, 254 insertions(+) create mode 100644 server/src/RemoteUpdate.cs diff --git a/server/src/RemoteUpdate.cs b/server/src/RemoteUpdate.cs new file mode 100644 index 0000000..a302c68 --- /dev/null +++ b/server/src/RemoteUpdate.cs @@ -0,0 +1,166 @@ +using System.Net; +using DotNext; +namespace RemoteUpdate; + +static class Global +{ + /// + /// FPGA 远程更新器地址 + /// + public class RemoteUpdaterAddr + { + /// + /// 基地址 + /// + public const UInt32 BaseAddr = 0x3000_0000; + /// + /// 写比特流-读写地址——控制位 + /// [31:24]: 保留 + /// [23:17]: 保留 + /// [16: 8]: 保留 + /// [ 7: 0]: {-, -, -, -, -,{bitstream_wr_num}, flash_wr_en} + /// + public const UInt32 WriteCtrl = 0x3000_0000; + /// + /// 写比特流-只写地址——FIFO入口 + /// [31:0]: 写比特流数据入口 + /// + public const UInt32 WriteFIFO = 0x3000_0001; + /// + /// 写比特流-只读地址——标志位 + /// [31:24]: {-, -, -, -, -, -, -, wr_fifo_full} + /// [23:17]: {-, -, -, -, -, -, -, wr_fifo_empty} + /// [16: 8]: {-, -, -, -, -, -, -, bitstream_wr_done} + /// [ 7: 0]: {-, -, -, -, -, -, -, clear_bs_done} + /// + public const UInt32 WriteSign = 0x3000_0002; + /// + /// 读比特流-读写地址——控制位 + /// [31:24]: {-, -, -, -, -, -,{ bs_crc32_ok }} + /// [23:17]: {-, -, -, -, -, -, -, crc_check_en} + /// [16: 8]: {-, -, -, -, -, -, -, bitstream_up2cpu_en} + /// [ 7: 0]: {-, -, -, -, -,{bitstream_rd_num},flash_rd_en} + /// + public const UInt32 ReadCtrl = 0x3000_0003; + /// + /// 读比特流-只读地址——FIFO出口 + /// [31:0]: 读比特流数据出口 + /// + public const UInt32 ReadFIFO = 0x3000_0004; + /// + /// 读比特流-只读地址——CRC校验值 + /// [31:0]: CRC校验值 bs_readback_crc + /// + public const UInt32 ReadCRC = 0x3000_0005; + /// + /// 读比特流-只读地址——标志位 + /// [31:24]: {-, -, -, -, -, -, -, rd_fifo_afull} + /// [23:17]: {-, -, -, -, -, -, -, rd_fifo_empty} + /// [16: 8]: {-, -, -, -, -, -, -, bitstream_rd_done} + /// [ 7: 0]: {-, -, -, -, -, -, -, bs_readback_crc_valid} + /// + public const UInt32 ReadSign = 0x3000_0006; + /// + /// 单独擦除开关-读写地址——控制位 + /// [31:24]: {-, -, -, -, -, -, -, - } + /// [23:17]: {-, -, -, -, -, -, -, - } + /// [16: 8]: {-, -, -, -, -, -, -, - } + /// [ 7: 0]: {-, -, -, -, -, -, -, clear_sw_en} + /// + public const UInt32 ClearCtrl = 0x3000_0007; + /// + /// 单独擦除开关-只读地址——标志位 + /// [31:24]: {-, -, -, -, -, -, -, time_out_reg} + /// [23:17]: { flash_flag_status[15:8]} + /// [16: 8]: { flash_flag_status[7:0]} + /// [ 7: 0]: {-, -, -, -, -, -, -, clear_sw_done} + /// + public const UInt32 ClearSign = 0x3000_0008; + /// + /// 写开关-读写地址——标志位 + /// [31:24]: {-, -, -, -, -, -, -, - } + /// [23:17]: {-, -, -, -, -, -, -, - } + /// [16: 8]: {-, -, -, -, -, -, { open_sw_num}} + /// [ 7: 0]: {-, -, -, -, -, -, -, write_sw_code_en} + /// + public const UInt32 WriteSwitchSign = 0x3000_0009; + /// + /// 写开关-只读地址——控制位 + /// [31:24]: {-, -, -, -, -, -, -, - } + /// [23:17]: {-, -, -, -, -, -, -, - } + /// [16: 8]: {-, -, -, -, -, -, -, ipal_busy} + /// [ 7: 0]: {-, -, -, -, -, -, -, open_sw_code_done} + /// + public const UInt32 WriteSwitchCtrl = 0x3000_0010; + /// + /// 热启动开关-读写地址——控制位 + /// [31:24]: {-, -, -, -, -, -, -, - } + /// [23:17]: {-, -, -, -, -, -, -, - } + /// [16: 8]: {-, -, -, -, -, -, } + /// [ 7: 0]: {-, -, -, -, -, -, -, hotreset_en} + /// + public const UInt32 HotResetCtrl = 0x3000_0011; + } + +} + +/// +/// FPGA远程更新 +/// +public class RemoteUpdater +{ + private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); + + const int timeout = 1000; + + int port { get; } + string address { get; } + private IPEndPoint remoteEP; + + /// + /// 初始化 FPGA 远程更新器 + /// + /// 目标设备的 IP 地址 + /// 目标设备的端口号 + public RemoteUpdater(string address, int port) + { + this.address = address; + this.port = port; + this.remoteEP = new IPEndPoint(IPAddress.Parse(address), port); + } + + public async ValueTask> UpdateBitstream(int bitstreamNum, byte[] bitstream) + { + if (bitstreamNum < 0 || bitstreamNum > 0b11) + return new(new ArgumentException( + "The number of bitstream can't be negative or over 3(0b11)", nameof(bitstreamNum))); + + if (bitstream.Length % (4 * 1024) != 0) + return new(new ArgumentException( + "Bitstream doesn't match 4KB align, which should be divided by 4 * 1024", nameof(bitstream))); + + // Clear Data + await MsgBus.UDPServer.ClearUDPData(this.address); + + logger.Trace($"Clear up udp server {this.address} receive data"); + + + { + var ret = await UDPClientPool.WriteAddr( + this.remoteEP, Global.RemoteUpdaterAddr.WriteCtrl, (UInt32)((bitstreamNum << 1) | 0b1), timeout); + if (!ret.IsSuccessful) return new(ret.Error); + else if (!ret.Value) return new(new Exception("Enable write flash failed")); + } + + { + var ret = await UDPClientPool.ReadAddr( + this.remoteEP, Global.RemoteUpdaterAddr.ClearSign, timeout); + if (!ret.IsSuccessful) return new(ret.Error); + else if (!ret.Value.IsSuccessful) return new(new Exception("Read clear switch sign failed")); + } + + + return true; + } + +} diff --git a/server/src/UdpClientPool.cs b/server/src/UdpClientPool.cs index c86aab2..25c3925 100644 --- a/server/src/UdpClientPool.cs +++ b/server/src/UdpClientPool.cs @@ -1,6 +1,8 @@ using System.Net; using System.Net.Sockets; using System.Text; +using DotNext; +using WebProtocol; /// /// UDP客户端发送池 @@ -161,4 +163,90 @@ public class UDPClientPool return isSuccessful; } + + /// + /// [TODO:description] + /// + /// [TODO:parameter] + /// [TODO:parameter] + /// [TODO:parameter] + /// [TODO:return] + public static async ValueTask> ReadAddr( + IPEndPoint endPoint, uint devAddr, int timeout = 1000) + { + var ret = false; + var opts = new SendAddrPackOptions(); + + opts.BurstType = BurstType.FixedBurst; + opts.BurstLength = 0; + opts.CommandID = 0; + 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(), 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; + } + + public static async ValueTask> ReadAddrWithCheck( + IPEndPoint endPoint, uint devAddr, int timeout = 1000) + { + } + + + /// + /// [TODO:description] + /// + /// [TODO:parameter] + /// [TODO:parameter] + /// [TODO:parameter] + /// [TODO:parameter] + /// [TODO:return] + public static async ValueTask> WriteAddr( + IPEndPoint endPoint, UInt32 devAddr, UInt32 data, int timeout = 1000) + { + var ret = false; + var opts = new SendAddrPackOptions(); + + opts.BurstType = BurstType.FixedBurst; + opts.BurstLength = 0; + opts.CommandID = 0; + 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(), endPoint.Port, timeout); + if (!udpWriteAck.IsSuccessful) return new(udpWriteAck.Error); + + return udpWriteAck.Value.IsSuccessful; + } } From 3f77a1a426ea8694cc32e8283fd3985d5aa9245a Mon Sep 17 00:00:00 2001 From: SikongJueluo Date: Sun, 27 Apr 2025 21:53:02 +0800 Subject: [PATCH 2/8] add remote update --- server/src/Common.cs | 83 +++++++++++++--- server/src/Controllers.cs | 131 ++++++++++++++++++++++++++ server/src/JtagClient.cs | 6 +- server/src/RemoteUpdate.cs | 183 +++++++++++++++++++++++++++--------- server/src/UdpClientPool.cs | 139 ++++++++++++++++++++++++++- server/src/WebProtocol.cs | 2 +- 6 files changed, 480 insertions(+), 64 deletions(-) diff --git a/server/src/Common.cs b/server/src/Common.cs index 194b409..a6b267b 100644 --- a/server/src/Common.cs +++ b/server/src/Common.cs @@ -44,12 +44,12 @@ namespace Common } /// - /// 二进制字节数组转成整数 + /// 二进制字节数组转成64bits整数 /// /// 二进制字节数组 /// 是否高位在右边 /// 整数 - public static Result BytesToNumber(byte[] bytes, bool isRightHigh = false) + public static Result BytesToUInt64(byte[] bytes, bool isRightHigh = false) { if (bytes.Length > 8) { @@ -59,27 +59,78 @@ namespace Common )); } - ulong num = 0; + UInt64 num = 0; int len = bytes.Length; - if (isRightHigh) + try { - for (var i = 0; i < len; i++) + if (isRightHigh) { - num += Convert.ToUInt64((UInt64)bytes[len - 1 - i] << (i << 3)); + for (var i = 0; i < len; i++) + { + num += Convert.ToUInt64((UInt64)bytes[len - 1 - i] << (i << 3)); + } } - } - else - { - for (var i = 0; i < len; i++) + else { - num += Convert.ToUInt64((UInt64)bytes[i] << ((int)(len - 1 - i) << 3)); + for (var i = 0; i < len; i++) + { + num += Convert.ToUInt64((UInt64)bytes[i] << ((int)(len - 1 - i) << 3)); + } } - } - return num; + return num; + } + catch (Exception error) + { + return new(error); + } } + /// + /// 二进制字节数组转成32bits整数 + /// + /// 二进制字节数组 + /// 是否高位在右边 + /// 整数 + public static Result BytesToUInt32(byte[] bytes, bool isRightHigh = false) + { + if (bytes.Length > 4) + { + return new(new ArgumentException( + "Unsigned long number can't over 4 bytes(32 bits).", + nameof(bytes) + )); + } + + UInt32 num = 0; + int len = bytes.Length; + + try + { + if (isRightHigh) + { + for (var i = 0; i < len; i++) + { + num += Convert.ToUInt32((UInt32)bytes[len - 1 - i] << (i << 3)); + } + } + else + { + for (var i = 0; i < len; i++) + { + num += Convert.ToUInt32((UInt32)bytes[i] << ((int)(len - 1 - i) << 3)); + } + } + + return num; + } + catch (Exception error) + { + return new(error); + } + + } /// @@ -152,6 +203,12 @@ namespace Common return (srcBits & mask) == dstBits; } + /// + /// 获取整型对应位置的比特 + /// + /// 整型数字 + /// 位置 + /// 比特 public static Result ToBit(UInt32 srcBits, int location) { if (location < 0) diff --git a/server/src/Controllers.cs b/server/src/Controllers.cs index 42405b2..e7cfe00 100644 --- a/server/src/Controllers.cs +++ b/server/src/Controllers.cs @@ -347,6 +347,137 @@ public class JtagController : ControllerBase } } +/// +/// 远程更新 +/// +[ApiController] +[Route("api/[controller]")] +public class RemoteUpdater : ControllerBase +{ + private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); + + /// + /// 上传远程更新比特流文件 + /// + /// 设备地址 + /// 比特流文件 + [HttpPost("UploadBitstream")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + public async ValueTask 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/RemoteUpdate/{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); + } + + logger.Info($"Device {address} Upload Bitstream Successfully"); + return TypedResults.Ok("Bitstream Upload Successfully"); + } + + /// + /// 远程更新比特流文件 + /// + /// 设备地址 + /// 设备端口 + /// 比特流位号 + [HttpPost("DownloadBitstream")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status500InternalServerError)] + public async ValueTask UpdateBitstream(string address, int port, int bitstreamNum) + { + // 检查文件 + var fileDir = Path.Combine(Environment.CurrentDirectory, $"bitstream/RemoteUpdate/{address}"); + if (!Directory.Exists(fileDir)) + return TypedResults.BadRequest("Empty bitstream, Please upload it first"); + + try + { + // 读取文件 + var filePath = Directory.GetFiles(fileDir)[0]; + + using (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]; + byte[] revBuffer = new byte[32 * 1024]; + long totalBytesRead = 0; + + // 使用异步流读取文件 + using (var memoryStream = new MemoryStream()) + { + int bytesRead; + while ((bytesRead = await fileStream.ReadAsync(buffer, 0, buffer.Length)) > 0) + { + // 反转 32bits + var retBuffer = Common.Number.ReverseBytes(buffer, 4); + if (!retBuffer.IsSuccessful) + return TypedResults.InternalServerError(retBuffer.Error); + revBuffer = retBuffer.Value; + for (int i = 0; i < buffer.Length; i++) + { + revBuffer[i] = BinaryPrimitives.ReverseEndianness(revBuffer[i]); + } + + await memoryStream.WriteAsync(revBuffer, 0, bytesRead); + totalBytesRead += bytesRead; + } + + // 将所有数据转换为字节数组(注意:如果文件非常大,可能不适合完全加载到内存) + var restStreamLen = memoryStream.Length % (4 * 1024); + if (restStreamLen != 0) + { + var appendLen = ((int)(4 * 1024 - restStreamLen)); + await memoryStream.WriteAsync(new byte[appendLen], 0, appendLen); + } + var fileBytes = memoryStream.ToArray(); + + // 下载比特流 + var remoteUpdater = new RemoteUpdate.RemoteUpdater(address, port); + var ret = await remoteUpdater.UpdateBitstream(bitstreamNum, fileBytes); + + if (ret.IsSuccessful) + { + logger.Info($"Device {address} Update bitstream successfully"); + return TypedResults.Ok(ret.Value); + } + else + { + logger.Error(ret.Error); + 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 cca5b27..b02ed6e 100644 --- a/server/src/JtagClient.cs +++ b/server/src/JtagClient.cs @@ -428,7 +428,7 @@ public class Jtag if (retPackLen != 4) return new(new Exception($"RecvDataPackage BodyData Length not Equal to 4: Total {retPackLen} bytes")); - return Convert.ToUInt32(Common.Number.BytesToNumber(retPackOpts.Data).Value); + return Convert.ToUInt32(Common.Number.BytesToUInt64(retPackOpts.Data).Value); } /// @@ -558,7 +558,7 @@ public class Jtag return new(new Exception($"RecvDataPackage BodyData Length not Equal to 4: Total {retPackLen} bytes")); if (Common.Number.BitsCheck( - Common.Number.BytesToNumber(retPack.Value.Options.Data).Value, result, resultMask)) + Common.Number.BytesToUInt64(retPack.Value.Options.Data).Value, result, resultMask)) ret = true; return ret; @@ -578,7 +578,7 @@ public class Jtag return new(new Exception($"RecvDataPackage BodyData Length not Equal to 4: Total {retPackLen} bytes")); if (Common.Number.BitsCheck( - Common.Number.BytesToNumber(retPack.Value.Options.Data).Value, result, resultMask)) + Common.Number.BytesToUInt64(retPack.Value.Options.Data).Value, result, resultMask)) ret = true; return ret; diff --git a/server/src/RemoteUpdate.cs b/server/src/RemoteUpdate.cs index a302c68..a1061f8 100644 --- a/server/src/RemoteUpdate.cs +++ b/server/src/RemoteUpdate.cs @@ -12,54 +12,54 @@ static class Global /// /// 基地址 /// - public const UInt32 BaseAddr = 0x3000_0000; + public const UInt32 BaseAddr = 0x2000_0000; /// - /// 写比特流-读写地址——控制位 - /// [31:24]: 保留 - /// [23:17]: 保留 - /// [16: 8]: 保留 - /// [ 7: 0]: {-, -, -, -, -,{bitstream_wr_num}, flash_wr_en} + /// 写比特流-读写地址——控制位
+ /// [31:24]: 保留
+ /// [23:17]: 保留
+ /// [16: 8]: 保留
+ /// [ 7: 0]: {-, -, -, -, -,{bitstream_wr_num}, flash_wr_en}
///
- public const UInt32 WriteCtrl = 0x3000_0000; + public const UInt32 WriteCtrl = 0x2000_0000; /// /// 写比特流-只写地址——FIFO入口 /// [31:0]: 写比特流数据入口 /// - public const UInt32 WriteFIFO = 0x3000_0001; + public const UInt32 WriteFIFO = 0x2000_0001; /// - /// 写比特流-只读地址——标志位 - /// [31:24]: {-, -, -, -, -, -, -, wr_fifo_full} - /// [23:17]: {-, -, -, -, -, -, -, wr_fifo_empty} - /// [16: 8]: {-, -, -, -, -, -, -, bitstream_wr_done} - /// [ 7: 0]: {-, -, -, -, -, -, -, clear_bs_done} + /// 写比特流-只读地址——标志位
+ /// [31:24]: {-, -, -, -, -, -, -, wr_fifo_full}
+ /// [23:17]: {-, -, -, -, -, -, -, wr_fifo_empty}
+ /// [16: 8]: {-, -, -, -, -, -, -, bitstream_wr_done}
+ /// [ 7: 0]: {-, -, -, -, -, -, -, clear_bs_done}
///
- public const UInt32 WriteSign = 0x3000_0002; + public const UInt32 WriteSign = 0x2000_0002; /// - /// 读比特流-读写地址——控制位 - /// [31:24]: {-, -, -, -, -, -,{ bs_crc32_ok }} - /// [23:17]: {-, -, -, -, -, -, -, crc_check_en} - /// [16: 8]: {-, -, -, -, -, -, -, bitstream_up2cpu_en} - /// [ 7: 0]: {-, -, -, -, -,{bitstream_rd_num},flash_rd_en} + /// 读比特流-读写地址——控制位
+ /// [31:24]: {-, -, -, -, -, -,{ bs_crc32_ok }}
+ /// [23:17]: {-, -, -, -, -, -, -, crc_check_en}
+ /// [16: 8]: {-, -, -, -, -, -, -, bitstream_up2cpu_en}
+ /// [ 7: 0]: {-, -, -, -, -,{bitstream_rd_num},flash_rd_en}
///
- public const UInt32 ReadCtrl = 0x3000_0003; + public const UInt32 ReadCtrl = 0x2000_0003; /// /// 读比特流-只读地址——FIFO出口 /// [31:0]: 读比特流数据出口 /// - public const UInt32 ReadFIFO = 0x3000_0004; + public const UInt32 ReadFIFO = 0x2000_0004; /// /// 读比特流-只读地址——CRC校验值 /// [31:0]: CRC校验值 bs_readback_crc /// - public const UInt32 ReadCRC = 0x3000_0005; + public const UInt32 ReadCRC = 0x2000_0005; /// - /// 读比特流-只读地址——标志位 - /// [31:24]: {-, -, -, -, -, -, -, rd_fifo_afull} - /// [23:17]: {-, -, -, -, -, -, -, rd_fifo_empty} - /// [16: 8]: {-, -, -, -, -, -, -, bitstream_rd_done} - /// [ 7: 0]: {-, -, -, -, -, -, -, bs_readback_crc_valid} + /// 读比特流-只读地址——标志位
+ /// [31:24]: {-, -, -, -, -, -, -, rd_fifo_afull}
+ /// [23:17]: {-, -, -, -, -, -, -, rd_fifo_empty}
+ /// [16: 8]: {-, -, -, -, -, -, -, bitstream_rd_done}
+ /// [ 7: 0]: {-, -, -, -, -, -, -, bs_readback_crc_valid}
///
- public const UInt32 ReadSign = 0x3000_0006; + public const UInt32 ReadSign = 0x2000_0006; /// /// 单独擦除开关-读写地址——控制位 /// [31:24]: {-, -, -, -, -, -, -, - } @@ -67,15 +67,15 @@ static class Global /// [16: 8]: {-, -, -, -, -, -, -, - } /// [ 7: 0]: {-, -, -, -, -, -, -, clear_sw_en} /// - public const UInt32 ClearCtrl = 0x3000_0007; + public const UInt32 ClearCtrl = 0x2000_0007; /// - /// 单独擦除开关-只读地址——标志位 - /// [31:24]: {-, -, -, -, -, -, -, time_out_reg} - /// [23:17]: { flash_flag_status[15:8]} - /// [16: 8]: { flash_flag_status[7:0]} - /// [ 7: 0]: {-, -, -, -, -, -, -, clear_sw_done} + /// 单独擦除开关-只读地址——标志位
+ /// [31:24]: {-, -, -, -, -, -, -, time_out_reg}
+ /// [23:17]: { flash_flag_status[15:8]}
+ /// [16: 8]: { flash_flag_status[7:0]}
+ /// [ 7: 0]: {-, -, -, -, -, -, -, clear_sw_done}
///
- public const UInt32 ClearSign = 0x3000_0008; + public const UInt32 ClearSign = 0x2000_0008; /// /// 写开关-读写地址——标志位 /// [31:24]: {-, -, -, -, -, -, -, - } @@ -83,7 +83,7 @@ static class Global /// [16: 8]: {-, -, -, -, -, -, { open_sw_num}} /// [ 7: 0]: {-, -, -, -, -, -, -, write_sw_code_en} /// - public const UInt32 WriteSwitchSign = 0x3000_0009; + public const UInt32 WriteSwitchSign = 0x2000_0009; /// /// 写开关-只读地址——控制位 /// [31:24]: {-, -, -, -, -, -, -, - } @@ -91,7 +91,7 @@ static class Global /// [16: 8]: {-, -, -, -, -, -, -, ipal_busy} /// [ 7: 0]: {-, -, -, -, -, -, -, open_sw_code_done} /// - public const UInt32 WriteSwitchCtrl = 0x3000_0010; + public const UInt32 WriteSwitchCtrl = 0x2000_0010; /// /// 热启动开关-读写地址——控制位 /// [31:24]: {-, -, -, -, -, -, -, - } @@ -99,7 +99,7 @@ static class Global /// [16: 8]: {-, -, -, -, -, -, } /// [ 7: 0]: {-, -, -, -, -, -, -, hotreset_en} /// - public const UInt32 HotResetCtrl = 0x3000_0011; + public const UInt32 HotResetCtrl = 0x2000_0011; } } @@ -111,7 +111,7 @@ public class RemoteUpdater { private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); - const int timeout = 1000; + readonly int timeout = 1000; int port { get; } string address { get; } @@ -129,7 +129,13 @@ public class RemoteUpdater this.remoteEP = new IPEndPoint(IPAddress.Parse(address), port); } - public async ValueTask> UpdateBitstream(int bitstreamNum, byte[] bitstream) + /// + /// [TODO:description] + /// + /// [TODO:parameter] + /// [TODO:parameter] + /// [TODO:return] + public async ValueTask> WriteBitstream(int bitstreamNum, byte[] bitstream) { if (bitstreamNum < 0 || bitstreamNum > 0b11) return new(new ArgumentException( @@ -149,18 +155,105 @@ public class RemoteUpdater var ret = await UDPClientPool.WriteAddr( this.remoteEP, Global.RemoteUpdaterAddr.WriteCtrl, (UInt32)((bitstreamNum << 1) | 0b1), timeout); if (!ret.IsSuccessful) return new(ret.Error); - else if (!ret.Value) return new(new Exception("Enable write flash failed")); + if (!ret.Value) return new(new Exception("Enable write flash failed")); } + // { + // var ret = await UDPClientPool.ReadAddrWithWait( + // this.remoteEP, Global.RemoteUpdaterAddr.ClearSign, 0x00_01, 0x00_01, 60 * 1000); + // if (!ret.IsSuccessful) return new(ret.Error); + // if (!ret.Value) return new(new Exception("Clear switch failed even over time")); + // } + { + var ret = await UDPClientPool.ReadAddrWithWait( + this.remoteEP, Global.RemoteUpdaterAddr.WriteSign, 0x00_01, 0x00_01, 60 * 1000); + if (!ret.IsSuccessful) return new(ret.Error); + if (!ret.Value) return new(new Exception("Clear bitstream failed even over time")); + } + logger.Trace($"Device {this.address} remote update init finished"); { - var ret = await UDPClientPool.ReadAddr( - this.remoteEP, Global.RemoteUpdaterAddr.ClearSign, timeout); + var ret = await UDPClientPool.WriteAddr(this.remoteEP, Global.RemoteUpdaterAddr.WriteFIFO, bitstream); if (!ret.IsSuccessful) return new(ret.Error); - else if (!ret.Value.IsSuccessful) return new(new Exception("Read clear switch sign failed")); + if (!ret.Value) return new(new Exception("Send bitstream failed")); } - + { + var ret = await UDPClientPool.ReadAddrWithWait( + this.remoteEP, Global.RemoteUpdaterAddr.WriteSign, 0x00_10, 0x00_10, timeout); + if (!ret.IsSuccessful) return new(ret.Error); + if (!ret.Value) return new(new Exception("Write bitstream failed even over time")); + } + logger.Trace($"Device {this.address} write bitstream finished"); return true; } + /// + /// [TODO:description] + /// + /// [TODO:parameter] + /// [TODO:parameter] + /// [TODO:return] + public async ValueTask> CheckBitstreamCRC(int bitstreamNum, UInt32 checkSum) + { + // Clear Data + await MsgBus.UDPServer.ClearUDPData(this.address); + + logger.Trace($"Clear up udp server {this.address} receive data"); + + + { + var ret = await UDPClientPool.WriteAddr( + this.remoteEP, Global.RemoteUpdaterAddr.ReadCtrl, + (UInt32)((bitstreamNum << 1) | 0b1), timeout); + if (!ret.IsSuccessful) return new(ret.Error); + if (!ret.Value) return new(new Exception("Enable read failed")); + } + { + var ret = await UDPClientPool.ReadAddrWithWait( + this.remoteEP, Global.RemoteUpdaterAddr.ReadSign, 0x00_11, 0x00_11, 60 * 1000); + if (!ret.IsSuccessful) return new(ret.Error); + if (!ret.Value) return new(new Exception("Read bitstream failed even over time")); + } + logger.Trace($"Device {this.address} remote update read bitstream finished"); + + { + var ret = await UDPClientPool.ReadAddr( + this.remoteEP, Global.RemoteUpdaterAddr.ReadSign, timeout); + if (!ret.IsSuccessful) return new(ret.Error); + if (ret.Value.Options.Data is null) return new(new Exception("Receive null when read sign")); + + // Check CRC + var crcCode = Common.Number.BytesToUInt32(ret.Value.Options.Data); + if (!crcCode.IsSuccessful) return new(crcCode.Error); + + var retCRC = crcCode.Value == checkSum; + logger.Trace($"Device {this.address} remote update check crc finished"); + + return retCRC; + } + } + + /// + /// [TODO:description] + /// + /// [TODO:parameter] + /// [TODO:parameter] + /// [TODO:return] + public async ValueTask> UpdateBitstream(int bitstreamNum, byte[] bitstream) + { + { + var ret = await WriteBitstream(bitstreamNum, bitstream); + if (!ret.IsSuccessful) return new(ret.Error); + if (!ret.Value) return new(new Exception("Write bitstream failed")); + } + { + var crc = new System.IO.Hashing.Crc32(); + crc.Append(bitstream); + var ret = await CheckBitstreamCRC(bitstreamNum, crc.GetCurrentHashAsUInt32()); + if (!ret.IsSuccessful) return new(ret.Error); + + return ret.Value; + } + } + } diff --git a/server/src/UdpClientPool.cs b/server/src/UdpClientPool.cs index 25c3925..b8891f7 100644 --- a/server/src/UdpClientPool.cs +++ b/server/src/UdpClientPool.cs @@ -204,9 +204,90 @@ public class UDPClientPool return retPack; } - public static async ValueTask> ReadAddrWithCheck( - IPEndPoint endPoint, uint devAddr, int timeout = 1000) + /// + /// [TODO:description] + /// + /// [TODO:parameter] + /// [TODO:parameter] + /// [TODO:parameter] + /// [TODO:parameter] + /// [TODO:parameter] + /// [TODO:return] + public static async ValueTask> ReadAddr( + IPEndPoint endPoint, uint devAddr, UInt32 result, UInt32 resultMask, int timeout = 1000) { + var address = endPoint.Address.ToString(); + + var ret = await ReadAddr(endPoint, 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); + } + } + + /// + /// [TODO:description] + /// + /// [TODO:parameter] + /// [TODO:parameter] + /// [TODO:parameter] + /// [TODO:parameter] + /// [TODO:parameter] + /// [TODO:return] + public static async ValueTask> ReadAddrWithWait( + IPEndPoint endPoint, 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, 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; } @@ -249,4 +330,58 @@ public class UDPClientPool return udpWriteAck.Value.IsSuccessful; } + + /// + /// [TODO:description] + /// + /// [TODO:parameter] + /// [TODO:parameter] + /// [TODO:parameter] + /// [TODO:parameter] + /// [TODO:return] + public static async ValueTask> WriteAddr(IPEndPoint endPoint, UInt32 devAddr, byte[] dataArray, int timeout = 1000) + { + var ret = false; + var opts = new SendAddrPackOptions(); + + + opts.BurstType = BurstType.FixedBurst; + opts.CommandID = 0; + opts.Address = devAddr; + + // Check Msg Bus + if (!MsgBus.IsRunning) + return new(new Exception("Message bus not working!")); + + opts.IsWrite = true; + var writeTimes = dataArray.Length / (256 * (32 / 8)) + 1; + 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(), endPoint.Port, timeout); + if (!udpWriteAck.IsSuccessful) return new(udpWriteAck.Error); + + if (!udpWriteAck.Value.IsSuccessful) + return false; + } + + return true; + } + } diff --git a/server/src/WebProtocol.cs b/server/src/WebProtocol.cs index 707a7e1..67f542a 100644 --- a/server/src/WebProtocol.cs +++ b/server/src/WebProtocol.cs @@ -248,7 +248,7 @@ namespace WebProtocol )); } - var address = Common.Number.BytesToNumber(bytes[4..]).Value; + var address = Common.Number.BytesToUInt64(bytes[4..]).Value; return new SendAddrPackage(bytes[1], bytes[2], Convert.ToUInt32(address)); } } From 210f6aa61c9f48c8da853a58566f7db9a6df5e7d Mon Sep 17 00:00:00 2001 From: SikongJueluo Date: Tue, 29 Apr 2025 21:13:38 +0800 Subject: [PATCH 3/8] add hot reset for remote update but no work --- server/Program.cs | 7 ++ server/server.csproj | 1 + server/src/RemoteUpdate.cs | 140 +++++++++++++++++++++++++----------- server/src/UdpClientPool.cs | 5 +- 4 files changed, 112 insertions(+), 41 deletions(-) diff --git a/server/Program.cs b/server/Program.cs index 02fd163..a3f8d0f 100644 --- a/server/Program.cs +++ b/server/Program.cs @@ -1,3 +1,4 @@ +using Honoo.IO.Hashing; using Microsoft.AspNetCore.Http.Features; using Newtonsoft.Json; using NLog; @@ -104,6 +105,12 @@ try app.MapGet("/", () => Results.Redirect("/swagger")); app.MapControllers(); + // { + // var crc = Crc.Create(CrcName.CRC32_MPEG_2); + // var checkSum = crc.ComputeFinal(new byte[] { 0x1C, 0xDF, 0x44, 0x21 }); + // logger.Info($"CRC: 0x{checkSum.ToString().PadLeft(8, '0')}"); + // } + app.Run("http://localhost:5000"); } catch (Exception exception) diff --git a/server/server.csproj b/server/server.csproj index dca031e..2ef7bc9 100644 --- a/server/server.csproj +++ b/server/server.csproj @@ -13,6 +13,7 @@ + diff --git a/server/src/RemoteUpdate.cs b/server/src/RemoteUpdate.cs index a1061f8..590096c 100644 --- a/server/src/RemoteUpdate.cs +++ b/server/src/RemoteUpdate.cs @@ -61,11 +61,11 @@ static class Global ///
public const UInt32 ReadSign = 0x2000_0006; /// - /// 单独擦除开关-读写地址——控制位 - /// [31:24]: {-, -, -, -, -, -, -, - } - /// [23:17]: {-, -, -, -, -, -, -, - } - /// [16: 8]: {-, -, -, -, -, -, -, - } - /// [ 7: 0]: {-, -, -, -, -, -, -, clear_sw_en} + /// 单独擦除开关-读写地址——控制位
+ /// [31:24]: {-, -, -, -, -, -, -, - }
+ /// [23:17]: {-, -, -, -, -, -, -, - }
+ /// [16: 8]: {-, -, -, -, -, -, -, - }
+ /// [ 7: 0]: {-, -, -, -, -, -, -, clear_sw_en}
///
public const UInt32 ClearCtrl = 0x2000_0007; /// @@ -77,29 +77,29 @@ static class Global /// public const UInt32 ClearSign = 0x2000_0008; /// - /// 写开关-读写地址——标志位 - /// [31:24]: {-, -, -, -, -, -, -, - } - /// [23:17]: {-, -, -, -, -, -, -, - } - /// [16: 8]: {-, -, -, -, -, -, { open_sw_num}} - /// [ 7: 0]: {-, -, -, -, -, -, -, write_sw_code_en} + /// 写开关-读写地址——控制位
+ /// [31:24]: {-, -, -, -, -, -, -, - }
+ /// [23:17]: {-, -, -, -, -, -, -, - }
+ /// [16: 8]: {-, -, -, -, -, -, { open_sw_num}}
+ /// [ 7: 0]: {-, -, -, -, -, -, -, write_sw_code_en}
///
- public const UInt32 WriteSwitchSign = 0x2000_0009; + public const UInt32 WriteSwitchCtrl = 0x2000_0009; /// - /// 写开关-只读地址——控制位 - /// [31:24]: {-, -, -, -, -, -, -, - } - /// [23:17]: {-, -, -, -, -, -, -, - } - /// [16: 8]: {-, -, -, -, -, -, -, ipal_busy} - /// [ 7: 0]: {-, -, -, -, -, -, -, open_sw_code_done} + /// 写开关-只读地址——标志位
+ /// [31:24]: {-, -, -, -, -, -, -, - }
+ /// [23:17]: {-, -, -, -, -, -, -, - }
+ /// [16: 8]: {-, -, -, -, -, -, -, ipal_busy}
+ /// [ 7: 0]: {-, -, -, -, -, -, -, open_sw_code_done}
///
- public const UInt32 WriteSwitchCtrl = 0x2000_0010; + public const UInt32 WriteSwitchSign = 0x2000_000A; /// - /// 热启动开关-读写地址——控制位 - /// [31:24]: {-, -, -, -, -, -, -, - } - /// [23:17]: {-, -, -, -, -, -, -, - } - /// [16: 8]: {-, -, -, -, -, -, } - /// [ 7: 0]: {-, -, -, -, -, -, -, hotreset_en} + /// 热启动开关-读写地址——控制位
+ /// [31:24]: {-, -, -, -, -, -, -, - }
+ /// [23:17]: {-, -, -, -, -, -, -, - }
+ /// [16: 8]: {-, -, -, -, -, -, }
+ /// [ 7: 0]: {-, -, -, -, -, -, -, hotreset_en}
///
- public const UInt32 HotResetCtrl = 0x2000_0011; + public const UInt32 HotResetCtrl = 0x2000_000B; } } @@ -130,11 +130,11 @@ public class RemoteUpdater } /// - /// [TODO:description] + /// Writes a bitstream to the FPGA device. /// - /// [TODO:parameter] - /// [TODO:parameter] - /// [TODO:return] + /// The bitstream number (0-3). + /// The bitstream data to write. + /// A result indicating success or failure. public async ValueTask> WriteBitstream(int bitstreamNum, byte[] bitstream) { if (bitstreamNum < 0 || bitstreamNum > 0b11) @@ -165,7 +165,7 @@ public class RemoteUpdater // } { var ret = await UDPClientPool.ReadAddrWithWait( - this.remoteEP, Global.RemoteUpdaterAddr.WriteSign, 0x00_01, 0x00_01, 60 * 1000); + this.remoteEP, Global.RemoteUpdaterAddr.WriteSign, 0x00_00_00_01, 0x00_00_00_01, 60 * 1000); if (!ret.IsSuccessful) return new(ret.Error); if (!ret.Value) return new(new Exception("Clear bitstream failed even over time")); } @@ -178,7 +178,7 @@ public class RemoteUpdater } { var ret = await UDPClientPool.ReadAddrWithWait( - this.remoteEP, Global.RemoteUpdaterAddr.WriteSign, 0x00_10, 0x00_10, timeout); + this.remoteEP, Global.RemoteUpdaterAddr.WriteSign, 0x00_00_01_00, 0x00_00_01_00, timeout); if (!ret.IsSuccessful) return new(ret.Error); if (!ret.Value) return new(new Exception("Write bitstream failed even over time")); } @@ -188,11 +188,11 @@ public class RemoteUpdater } /// - /// [TODO:description] + /// Checks the CRC of a bitstream on the FPGA device. /// - /// [TODO:parameter] - /// [TODO:parameter] - /// [TODO:return] + /// The bitstream number (0-3). + /// The expected CRC checksum value. + /// A result indicating whether the CRC matches. public async ValueTask> CheckBitstreamCRC(int bitstreamNum, UInt32 checkSum) { // Clear Data @@ -210,7 +210,7 @@ public class RemoteUpdater } { var ret = await UDPClientPool.ReadAddrWithWait( - this.remoteEP, Global.RemoteUpdaterAddr.ReadSign, 0x00_11, 0x00_11, 60 * 1000); + this.remoteEP, Global.RemoteUpdaterAddr.ReadSign, 0x00_00_01_00, 0x00_00_01_00, 60 * 1000); if (!ret.IsSuccessful) return new(ret.Error); if (!ret.Value) return new(new Exception("Read bitstream failed even over time")); } @@ -218,7 +218,7 @@ public class RemoteUpdater { var ret = await UDPClientPool.ReadAddr( - this.remoteEP, Global.RemoteUpdaterAddr.ReadSign, timeout); + this.remoteEP, Global.RemoteUpdaterAddr.ReadCRC, timeout); if (!ret.IsSuccessful) return new(ret.Error); if (ret.Value.Options.Data is null) return new(new Exception("Receive null when read sign")); @@ -229,6 +229,8 @@ public class RemoteUpdater var retCRC = crcCode.Value == checkSum; logger.Trace($"Device {this.address} remote update check crc finished"); + logger.Debug($"Expected CRC32/Mpeg Code: 0x{checkSum.ToString("X").PadLeft(8, '0')}"); + logger.Debug($"Actually CRC32/Mpeg Code: 0x{crcCode.Value.ToString("X").PadLeft(8, '0')}"); return retCRC; } } @@ -237,8 +239,60 @@ public class RemoteUpdater /// [TODO:description] ///
/// [TODO:parameter] - /// [TODO:parameter] /// [TODO:return] + public async ValueTask> HotReset(int bitstreamNum) + { + // Clear Data + await MsgBus.UDPServer.ClearUDPData(this.address); + + logger.Trace($"Clear up udp server {this.address} receive data"); + + + { + var ret = await UDPClientPool.WriteAddr( + this.remoteEP, Global.RemoteUpdaterAddr.ClearCtrl, + (UInt32)(0b1), timeout); + if (!ret.IsSuccessful) return new(ret.Error); + if (!ret.Value) return new(new Exception("Run clear failed")); + } + { + var ret = await UDPClientPool.ReadAddrWithWait( + this.remoteEP, Global.RemoteUpdaterAddr.ClearSign, 0x00_00_00_01, 0x00_00_00_01, 60 * 1000); + if (!ret.IsSuccessful) return new(ret.Error); + if (!ret.Value) return new(new Exception("Clear failed even over time")); + } + logger.Trace($"Device {this.address} remote update clear finished"); + + { + var ret = await UDPClientPool.WriteAddr( + this.remoteEP, Global.RemoteUpdaterAddr.WriteSwitchCtrl, + (UInt32)((bitstreamNum << 1) | 0b1), timeout); + if (!ret.IsSuccessful) return new(ret.Error); + if (!ret.Value) return new(new Exception("Run write switch code failed")); + } + { + var ret = await UDPClientPool.ReadAddrWithWait( + this.remoteEP, Global.RemoteUpdaterAddr.WriteSwitchSign, + 0x00_00_00_01, 0x00_00_00_01, 60 * 1000); + if (!ret.IsSuccessful) return new(ret.Error); + if (!ret.Value) return new(new Exception("Write switch code failed even over time")); + } + logger.Trace($"Device {this.address} remote update write switch open finished"); + + { + var ret = await UDPClientPool.WriteAddr( + this.remoteEP, Global.RemoteUpdaterAddr.HotResetCtrl, (UInt32)(0b1), timeout); + if (!ret.IsSuccessful) return new(ret.Error); + return ret.Value; + } + } + + /// + /// Updates the bitstream on the FPGA device. + /// + /// The bitstream number (0-3). + /// The bitstream data to update. + /// A result indicating success or failure. public async ValueTask> UpdateBitstream(int bitstreamNum, byte[] bitstream) { { @@ -247,11 +301,17 @@ public class RemoteUpdater if (!ret.Value) return new(new Exception("Write bitstream failed")); } { - var crc = new System.IO.Hashing.Crc32(); - crc.Append(bitstream); - var ret = await CheckBitstreamCRC(bitstreamNum, crc.GetCurrentHashAsUInt32()); - if (!ret.IsSuccessful) return new(ret.Error); + var crc = Honoo.IO.Hashing.Crc.Create(Honoo.IO.Hashing.CrcName.CRC32_MPEG_2); + var checkSum = crc.ComputeFinal(bitstream); + var ret = await CheckBitstreamCRC(bitstreamNum, checkSum.ToUInt32()); + if (!ret.IsSuccessful) return new(ret.Error); + // if (!ret.Value) return new(new Exception("Check bitstream crc32/mpeg-2 failed")); + } + { + var ret = await HotReset(bitstreamNum); + if (!ret.IsSuccessful) return new(ret.Error); + if (!ret.Value) return new(new Exception("Hot reset failed")); return ret.Value; } } diff --git a/server/src/UdpClientPool.cs b/server/src/UdpClientPool.cs index b8891f7..2c59a56 100644 --- a/server/src/UdpClientPool.cs +++ b/server/src/UdpClientPool.cs @@ -354,7 +354,10 @@ public class UDPClientPool return new(new Exception("Message bus not working!")); opts.IsWrite = true; - var writeTimes = dataArray.Length / (256 * (32 / 8)) + 1; + 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 From e6d177cf1599f0cc4e8c21eebcd6abc0b2deebe6 Mon Sep 17 00:00:00 2001 From: SikongJueluo Date: Fri, 2 May 2025 12:16:00 +0000 Subject: [PATCH 4/8] finish basic database --- flake.nix | 4 +- server/Program.cs | 18 ++---- server/server.csproj | 2 + server/src/Controllers.cs | 66 ++++++++++++++++++++++ server/src/Database.cs | 113 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 190 insertions(+), 13 deletions(-) create mode 100644 server/src/Database.cs diff --git a/flake.nix b/flake.nix index 542c239..b099c89 100644 --- a/flake.nix +++ b/flake.nix @@ -22,6 +22,7 @@ sqlite sqls sql-studio + zlib # Backend (dotnetCorePackages.combinePackages [ dotnetCorePackages.sdk_9_0 @@ -37,7 +38,8 @@ typescript-language-server ]; shellHook = '' - export PATH=$PATH:$HOME/.bun/bin + export PATH=$PATH: + export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${pkgs.zlib}/lib ''; }; diff --git a/server/Program.cs b/server/Program.cs index a3f8d0f..0b3c10c 100644 --- a/server/Program.cs +++ b/server/Program.cs @@ -1,4 +1,3 @@ -using Honoo.IO.Hashing; using Microsoft.AspNetCore.Http.Features; using Newtonsoft.Json; using NLog; @@ -38,16 +37,17 @@ try }); // Add CORS policy - builder.Services.AddCors(options => + if (builder.Environment.IsDevelopment()) { - options.AddPolicy("Development", policy => + builder.Services.AddCors(options => { - policy + options.AddPolicy("Development", policy => policy .AllowAnyOrigin() .AllowAnyMethod() - .AllowAnyHeader(); + .AllowAnyHeader() + ); }); - }); + } // Add Swagger builder.Services.AddControllers(); @@ -105,12 +105,6 @@ try app.MapGet("/", () => Results.Redirect("/swagger")); app.MapControllers(); - // { - // var crc = Crc.Create(CrcName.CRC32_MPEG_2); - // var checkSum = crc.ComputeFinal(new byte[] { 0x1C, 0xDF, 0x44, 0x21 }); - // logger.Info($"CRC: 0x{checkSum.ToString().PadLeft(8, '0')}"); - // } - app.Run("http://localhost:5000"); } catch (Exception exception) diff --git a/server/server.csproj b/server/server.csproj index 2ef7bc9..a6dc9b5 100644 --- a/server/server.csproj +++ b/server/server.csproj @@ -14,12 +14,14 @@ + + diff --git a/server/src/Controllers.cs b/server/src/Controllers.cs index e7cfe00..a1d31cf 100644 --- a/server/src/Controllers.cs +++ b/server/src/Controllers.cs @@ -1,6 +1,7 @@ using System.Buffers.Binary; using System.Net; using Common; +using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; using WebProtocol; @@ -478,6 +479,71 @@ public class RemoteUpdater : ControllerBase } } + +/// +/// 数据控制器 +/// +[ApiController] +[Route("api/[controller]")] +public class Data : ControllerBase +{ + private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); + + /// + /// 创建数据库表 + /// + /// 插入的记录数 + [EnableCors("Development")] + [HttpPost("CreateTable")] + public IResult CreateTables() + { + using var db = new Database.AppDataConnection(); + db.CreateAllTables(); + return TypedResults.Ok(); + } + + /// + /// 删除数据库表 + /// + /// 插入的记录数 + [EnableCors("Development")] + [HttpDelete("DropTables")] + public IResult DropTables() + { + using var db = new Database.AppDataConnection(); + db.DropAllTables(); + return TypedResults.Ok(); + } + + /// + /// 获取所有用户 + /// + /// 用户列表 + [HttpGet("AllUsers")] + public IResult AllUsers() + { + using var db = new Database.AppDataConnection(); + var ret = db.User.ToList(); + return TypedResults.Ok(ret); + } + + /// + /// 注册新用户 + /// + /// 用户名 + /// 操作结果 + [HttpPost("SignUpUser")] + public IResult SignUpUser(string name) + { + if (name.Length > 255) + return TypedResults.BadRequest("Name Couln't over 255 characters"); + + using var db = new Database.AppDataConnection(); + var ret = db.AddUser(name); + return TypedResults.Ok(ret); + } +} + /// /// 日志控制器 /// diff --git a/server/src/Database.cs b/server/src/Database.cs new file mode 100644 index 0000000..e54d831 --- /dev/null +++ b/server/src/Database.cs @@ -0,0 +1,113 @@ +using LinqToDB; +using LinqToDB.Data; +using LinqToDB.Mapping; + +namespace Database; + +/// +/// 用户类,表示用户信息 +/// +public class User +{ + /// + /// 用户的唯一标识符 + /// + [PrimaryKey] + public Guid ID { get; set; } = Guid.NewGuid(); + + /// + /// 用户的名称 + /// + [NotNull] + public required string Name { get; set; } +} + +/// +/// FPGA 板子类,表示板子信息 +/// +public class Board +{ + /// + /// FPGA 板子的唯一标识符 + /// + [PrimaryKey] + public Guid Id { get; set; } = Guid.NewGuid(); + + /// + /// FPGA 板子的名称 + /// + [NotNull] + public required string BoardName { get; set; } +} + +/// +/// 应用程序数据连接类,用于与数据库交互 +/// +public class AppDataConnection : DataConnection +{ + static readonly LinqToDB.DataOptions options = + new LinqToDB.DataOptions() + .UseSQLite($"Data Source={Environment.CurrentDirectory}/Database.sqlite"); + + /// + /// 初始化应用程序数据连接 + /// + public AppDataConnection() : base(options) { } + + + /// + /// 创建所有数据库表 + /// + public void CreateAllTables() + { + this.CreateTable(); + this.CreateTable(); + } + + /// + /// 删除所有数据库表 + /// + public void DropAllTables() + { + this.DropTable(); + this.DropTable(); + } + + /// + /// 添加一个新的用户到数据库 + /// + /// 用户的名称 + /// 插入的记录数 + public int AddUser(string name) + { + var user = new User() + { + Name = name + }; + return this.Insert(user); + } + + /// + /// 添加一块新的 FPGA 板子到数据库 + /// + /// FPGA 板子的名称 + /// 插入的记录数 + public int AddBoard(string name) + { + var board = new Board() + { + BoardName = name + }; + return this.Insert(board); + } + + /// + /// 用户表 + /// + public ITable User => this.GetTable(); + + /// + /// FPGA 板子表 + /// + public ITable Board => this.GetTable(); +} From c6b819f24f7d47ed1a16e6b10215833150775b90 Mon Sep 17 00:00:00 2001 From: SikongJueluo Date: Sun, 4 May 2025 16:38:40 +0800 Subject: [PATCH 5/8] fix: rewrite remote update --- server/src/Common.cs | 18 +- server/src/Controllers.cs | 6 +- server/src/RemoteUpdate.cs | 531 +++++++++++++++++++++---------------- 3 files changed, 310 insertions(+), 245 deletions(-) diff --git a/server/src/Common.cs b/server/src/Common.cs index a6b267b..46c0fcc 100644 --- a/server/src/Common.cs +++ b/server/src/Common.cs @@ -12,9 +12,9 @@ namespace Common ///
/// 整数 /// 整数长度 - /// 是否高位在右边 + /// 是否高位在数组索引低 /// 二进制字节数组 - public static Result NumberToBytes(ulong num, uint length, bool isRightHigh = false) + public static Result NumberToBytes(ulong num, uint length, bool isLowNumHigh = false) { if (length > 8) { @@ -26,7 +26,7 @@ namespace Common var arr = new byte[length]; - if (isRightHigh) + if (isLowNumHigh) { for (var i = 0; i < length; i++) { @@ -47,9 +47,9 @@ namespace Common /// 二进制字节数组转成64bits整数 /// /// 二进制字节数组 - /// 是否高位在右边 + /// 是否高位在数组索引低 /// 整数 - public static Result BytesToUInt64(byte[] bytes, bool isRightHigh = false) + public static Result BytesToUInt64(byte[] bytes, bool isLowNumHigh = false) { if (bytes.Length > 8) { @@ -64,7 +64,7 @@ namespace Common try { - if (isRightHigh) + if (isLowNumHigh) { for (var i = 0; i < len; i++) { @@ -91,9 +91,9 @@ namespace Common /// 二进制字节数组转成32bits整数 /// /// 二进制字节数组 - /// 是否高位在右边 + /// 是否高位在数组索引低 /// 整数 - public static Result BytesToUInt32(byte[] bytes, bool isRightHigh = false) + public static Result BytesToUInt32(byte[] bytes, bool isLowNumHigh = false) { if (bytes.Length > 4) { @@ -108,7 +108,7 @@ namespace Common try { - if (isRightHigh) + if (isLowNumHigh) { for (var i = 0; i < len; i++) { diff --git a/server/src/Controllers.cs b/server/src/Controllers.cs index a1d31cf..6124b2c 100644 --- a/server/src/Controllers.cs +++ b/server/src/Controllers.cs @@ -449,12 +449,14 @@ public class RemoteUpdater : ControllerBase if (restStreamLen != 0) { var appendLen = ((int)(4 * 1024 - restStreamLen)); - await memoryStream.WriteAsync(new byte[appendLen], 0, appendLen); + var bytesAppend = new byte[appendLen]; + Array.Fill(bytesAppend, 0xFF); + await memoryStream.WriteAsync(bytesAppend, 0, appendLen); } var fileBytes = memoryStream.ToArray(); // 下载比特流 - var remoteUpdater = new RemoteUpdate.RemoteUpdater(address, port); + var remoteUpdater = new RemoteUpdate.RemoteUpdateClient(address, port); var ret = await remoteUpdater.UpdateBitstream(bitstreamNum, fileBytes); if (ret.IsSuccessful) diff --git a/server/src/RemoteUpdate.cs b/server/src/RemoteUpdate.cs index 590096c..727f72b 100644 --- a/server/src/RemoteUpdate.cs +++ b/server/src/RemoteUpdate.cs @@ -2,236 +2,174 @@ using System.Net; using DotNext; namespace RemoteUpdate; -static class Global +static class RemoteUpdateClientAddr { - /// - /// FPGA 远程更新器地址 - /// - public class RemoteUpdaterAddr - { - /// - /// 基地址 - /// - public const UInt32 BaseAddr = 0x2000_0000; - /// - /// 写比特流-读写地址——控制位
- /// [31:24]: 保留
- /// [23:17]: 保留
- /// [16: 8]: 保留
- /// [ 7: 0]: {-, -, -, -, -,{bitstream_wr_num}, flash_wr_en}
- ///
- public const UInt32 WriteCtrl = 0x2000_0000; - /// - /// 写比特流-只写地址——FIFO入口 - /// [31:0]: 写比特流数据入口 - /// - public const UInt32 WriteFIFO = 0x2000_0001; - /// - /// 写比特流-只读地址——标志位
- /// [31:24]: {-, -, -, -, -, -, -, wr_fifo_full}
- /// [23:17]: {-, -, -, -, -, -, -, wr_fifo_empty}
- /// [16: 8]: {-, -, -, -, -, -, -, bitstream_wr_done}
- /// [ 7: 0]: {-, -, -, -, -, -, -, clear_bs_done}
- ///
- public const UInt32 WriteSign = 0x2000_0002; - /// - /// 读比特流-读写地址——控制位
- /// [31:24]: {-, -, -, -, -, -,{ bs_crc32_ok }}
- /// [23:17]: {-, -, -, -, -, -, -, crc_check_en}
- /// [16: 8]: {-, -, -, -, -, -, -, bitstream_up2cpu_en}
- /// [ 7: 0]: {-, -, -, -, -,{bitstream_rd_num},flash_rd_en}
- ///
- public const UInt32 ReadCtrl = 0x2000_0003; - /// - /// 读比特流-只读地址——FIFO出口 - /// [31:0]: 读比特流数据出口 - /// - public const UInt32 ReadFIFO = 0x2000_0004; - /// - /// 读比特流-只读地址——CRC校验值 - /// [31:0]: CRC校验值 bs_readback_crc - /// - public const UInt32 ReadCRC = 0x2000_0005; - /// - /// 读比特流-只读地址——标志位
- /// [31:24]: {-, -, -, -, -, -, -, rd_fifo_afull}
- /// [23:17]: {-, -, -, -, -, -, -, rd_fifo_empty}
- /// [16: 8]: {-, -, -, -, -, -, -, bitstream_rd_done}
- /// [ 7: 0]: {-, -, -, -, -, -, -, bs_readback_crc_valid}
- ///
- public const UInt32 ReadSign = 0x2000_0006; - /// - /// 单独擦除开关-读写地址——控制位
- /// [31:24]: {-, -, -, -, -, -, -, - }
- /// [23:17]: {-, -, -, -, -, -, -, - }
- /// [16: 8]: {-, -, -, -, -, -, -, - }
- /// [ 7: 0]: {-, -, -, -, -, -, -, clear_sw_en}
- ///
- public const UInt32 ClearCtrl = 0x2000_0007; - /// - /// 单独擦除开关-只读地址——标志位
- /// [31:24]: {-, -, -, -, -, -, -, time_out_reg}
- /// [23:17]: { flash_flag_status[15:8]}
- /// [16: 8]: { flash_flag_status[7:0]}
- /// [ 7: 0]: {-, -, -, -, -, -, -, clear_sw_done}
- ///
- public const UInt32 ClearSign = 0x2000_0008; - /// - /// 写开关-读写地址——控制位
- /// [31:24]: {-, -, -, -, -, -, -, - }
- /// [23:17]: {-, -, -, -, -, -, -, - }
- /// [16: 8]: {-, -, -, -, -, -, { open_sw_num}}
- /// [ 7: 0]: {-, -, -, -, -, -, -, write_sw_code_en}
- ///
- public const UInt32 WriteSwitchCtrl = 0x2000_0009; - /// - /// 写开关-只读地址——标志位
- /// [31:24]: {-, -, -, -, -, -, -, - }
- /// [23:17]: {-, -, -, -, -, -, -, - }
- /// [16: 8]: {-, -, -, -, -, -, -, ipal_busy}
- /// [ 7: 0]: {-, -, -, -, -, -, -, open_sw_code_done}
- ///
- public const UInt32 WriteSwitchSign = 0x2000_000A; - /// - /// 热启动开关-读写地址——控制位
- /// [31:24]: {-, -, -, -, -, -, -, - }
- /// [23:17]: {-, -, -, -, -, -, -, - }
- /// [16: 8]: {-, -, -, -, -, -, }
- /// [ 7: 0]: {-, -, -, -, -, -, -, hotreset_en}
- ///
- public const UInt32 HotResetCtrl = 0x2000_000B; - } + /// + /// ADDR: 0X00: 写Flash-读写地址——控制位
+ /// [31:16]: wr_sector_num
+ /// [15: 0]: {flash_wr_en,-,-,-, start_wr_sector}
+ ///
+ public const UInt32 WriteCtrl = 0x00; + + /// + /// ADDR: 0X01: 写Flash-只写地址——FIFO入口
+ /// [31:0]: 写比特流数据入口
+ ///
+ public const UInt32 WriteFIFO = 0x01; + + /// + /// ADDR: 0X02: 写Flash-只读地址——标志位
+ /// [31:24]: {-, -, -, -, -, -, -, wr_fifo_full}
+ /// [23:16]: {-, -, -, -, -, -, -, wr_fifo_empty}
+ /// [15: 8]: {-, -, -, -, -, -, -, flash_wr_done}
+ /// [ 7: 0]: {-, -, -, -, -, -, -, flash_clear_done}
+ ///
+ public const UInt32 WriteSign = 0x02; + + /// + /// ADDR: 0X03: 读Flash-读写地址——控制位1
+ /// [31:16]: rd_sector_num
+ /// [15: 0]: {flash_rd_en,-,-,-, start_rd_sub_sector}
+ ///
+ public const UInt32 ReadCtrl1 = 0x03; + + /// + /// ADDR: 0X04: 读Flash-读写地址——控制位2
+ /// [31:24]: { }
+ /// [23:16]: {-, -, -, -, -, -,{ bs_crc32_ok }}
+ /// [15: 8]: {-, -, -, -, -, -, -, crc_check_en}
+ /// [ 7: 0]: {-, -, -, -, -, -, -, bitstream_up2cpu_en}
+ ///
+ public const UInt32 ReadCtrl2 = 0x04; + + /// + /// ADDR: 0X05: 读Flash-只读地址——FIFO出口
+ /// [31:0]: 读比特流数据出口
+ ///
+ public const UInt32 ReadFIFO = 0x05; + + /// + /// ADDR: 0X06: 读Flash-只读地址——CRC校验值
+ /// [31:0]: CRC校验值 bs_readback_crc
+ ///
+ public const UInt32 ReadCRC = 0x06; + + /// + /// ADDR: 0X07: 读Flash-只读地址——标志位
+ /// [31:24]: {-, -, -, -, -, -, -, rd_fifo_afull}
+ /// [23:16]: {-, -, -, -, -, -, -, rd_fifo_empty}
+ /// [15: 8]: {-, -, -, -, -, -, -, flash_rd_done}
+ /// [ 7: 0]: {-, -, -, -, -, -, -, bs_readback_crc_valid}
+ ///
+ public const UInt32 ReadSign = 0x07; + + /// + /// ADDR: 0X08: 热启动开关-读写地址——控制位
+ /// [31: 8]: hotreset_addr
+ /// [ 7: 0]: {-, -, -, -, -, -, -, hotreset_en}
+ ///
+ public const UInt32 HotResetCtrl = 0x08; + + /// + /// ADDR: 0X09: 只读地址 版本号
+ /// [31: 0]: FPGA_VERSION[31:0]
+ ///
+ public const UInt32 Version = 0x09; } +static class FlashAddr +{ + public static readonly UInt32[] Switch = { 0x0000, 0x2000, 0x4000 }; + public static readonly UInt32[] Jump = { 0x1000, 0x3000, 0x5000 }; + public static readonly UInt32[] User = { 0x406000, 0x806000, 0xC06000 }; + + public const UInt32 Golden = 0x6000; +} + + + /// -/// FPGA远程更新 +/// [TODO:description] /// -public class RemoteUpdater +public class RemoteUpdateClient { private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); - readonly int timeout = 1000; + const int FLASH_SECTOR_LENGTH = 4 * 1024; - int port { get; } - string address { get; } - private IPEndPoint remoteEP; + readonly int timeout = 2000; + readonly int timeoutForWait = 60 * 1000; + + readonly int port; + readonly string address; + private IPEndPoint ep; /// - /// 初始化 FPGA 远程更新器 + /// [TODO:description] /// - /// 目标设备的 IP 地址 - /// 目标设备的端口号 - public RemoteUpdater(string address, int port) + /// [TODO:parameter] + /// [TODO:parameter] + /// [TODO:parameter] + /// [TODO:parameter] + /// [TODO:return] + public RemoteUpdateClient(string address, int port, int timeout = 2000, int timeoutForWait = 60 * 1000) { + if (timeout < 0) + throw new ArgumentException("Timeout couldn't be negative", nameof(timeout)); this.address = address; this.port = port; - this.remoteEP = new IPEndPoint(IPAddress.Parse(address), port); + this.ep = new IPEndPoint(IPAddress.Parse(address), port); + this.timeout = timeout; + this.timeoutForWait = timeoutForWait; } /// - /// Writes a bitstream to the FPGA device. + /// [TODO:description] /// - /// The bitstream number (0-3). - /// The bitstream data to write. - /// A result indicating success or failure. - public async ValueTask> WriteBitstream(int bitstreamNum, byte[] bitstream) + /// [TODO:parameter] + /// [TODO:parameter] + /// [TODO:parameter] + /// [TODO:return] + public async ValueTask> WriteFlash(UInt32 flashAddr, int writeSectorNum, byte[] bytesData) { - if (bitstreamNum < 0 || bitstreamNum > 0b11) + // Assert + if (writeSectorNum <= 0 || writeSectorNum >= FLASH_SECTOR_LENGTH) return new(new ArgumentException( - "The number of bitstream can't be negative or over 3(0b11)", nameof(bitstreamNum))); - - if (bitstream.Length % (4 * 1024) != 0) + $"Write sector num should be 1 ~ 4096, but given {writeSectorNum}", nameof(writeSectorNum))); + if (bytesData.Length % (4 * 1024) != 0) return new(new ArgumentException( - "Bitstream doesn't match 4KB align, which should be divided by 4 * 1024", nameof(bitstream))); - - // Clear Data - await MsgBus.UDPServer.ClearUDPData(this.address); - - logger.Trace($"Clear up udp server {this.address} receive data"); - + $"The length of data should be divided by 4096, bug given {bytesData.Length}", nameof(bytesData))); { var ret = await UDPClientPool.WriteAddr( - this.remoteEP, Global.RemoteUpdaterAddr.WriteCtrl, (UInt32)((bitstreamNum << 1) | 0b1), timeout); + this.ep, RemoteUpdateClientAddr.WriteCtrl, + Convert.ToUInt32((writeSectorNum << 16) | (1 << 15) | Convert.ToInt32(flashAddr / 4096)), this.timeout); if (!ret.IsSuccessful) return new(ret.Error); if (!ret.Value) return new(new Exception("Enable write flash failed")); } - // { - // var ret = await UDPClientPool.ReadAddrWithWait( - // this.remoteEP, Global.RemoteUpdaterAddr.ClearSign, 0x00_01, 0x00_01, 60 * 1000); - // if (!ret.IsSuccessful) return new(ret.Error); - // if (!ret.Value) return new(new Exception("Clear switch failed even over time")); - // } + { var ret = await UDPClientPool.ReadAddrWithWait( - this.remoteEP, Global.RemoteUpdaterAddr.WriteSign, 0x00_00_00_01, 0x00_00_00_01, 60 * 1000); + this.ep, RemoteUpdateClientAddr.WriteSign, + 0x00_00_00_01, 0x00_00_00_01, this.timeoutForWait); if (!ret.IsSuccessful) return new(ret.Error); - if (!ret.Value) return new(new Exception("Clear bitstream failed even over time")); + if (!ret.Value) return new(new Exception( + $"Flash clear failed after {this.timeoutForWait} milliseconds")); } - logger.Trace($"Device {this.address} remote update init finished"); { - var ret = await UDPClientPool.WriteAddr(this.remoteEP, Global.RemoteUpdaterAddr.WriteFIFO, bitstream); + var ret = await UDPClientPool.WriteAddr(this.ep, RemoteUpdateClientAddr.WriteFIFO, bytesData, this.timeout); if (!ret.IsSuccessful) return new(ret.Error); - if (!ret.Value) return new(new Exception("Send bitstream failed")); + if (!ret.Value) return new(new Exception("Send data to flash failed")); } + { var ret = await UDPClientPool.ReadAddrWithWait( - this.remoteEP, Global.RemoteUpdaterAddr.WriteSign, 0x00_00_01_00, 0x00_00_01_00, timeout); + this.ep, RemoteUpdateClientAddr.WriteSign, + 0x00_00_01_00, 0x00_00_01_00, this.timeoutForWait); if (!ret.IsSuccessful) return new(ret.Error); - if (!ret.Value) return new(new Exception("Write bitstream failed even over time")); - } - logger.Trace($"Device {this.address} write bitstream finished"); - - return true; - } - - /// - /// Checks the CRC of a bitstream on the FPGA device. - /// - /// The bitstream number (0-3). - /// The expected CRC checksum value. - /// A result indicating whether the CRC matches. - public async ValueTask> CheckBitstreamCRC(int bitstreamNum, UInt32 checkSum) - { - // Clear Data - await MsgBus.UDPServer.ClearUDPData(this.address); - - logger.Trace($"Clear up udp server {this.address} receive data"); - - - { - var ret = await UDPClientPool.WriteAddr( - this.remoteEP, Global.RemoteUpdaterAddr.ReadCtrl, - (UInt32)((bitstreamNum << 1) | 0b1), timeout); - if (!ret.IsSuccessful) return new(ret.Error); - if (!ret.Value) return new(new Exception("Enable read failed")); - } - { - var ret = await UDPClientPool.ReadAddrWithWait( - this.remoteEP, Global.RemoteUpdaterAddr.ReadSign, 0x00_00_01_00, 0x00_00_01_00, 60 * 1000); - if (!ret.IsSuccessful) return new(ret.Error); - if (!ret.Value) return new(new Exception("Read bitstream failed even over time")); - } - logger.Trace($"Device {this.address} remote update read bitstream finished"); - - { - var ret = await UDPClientPool.ReadAddr( - this.remoteEP, Global.RemoteUpdaterAddr.ReadCRC, timeout); - if (!ret.IsSuccessful) return new(ret.Error); - if (ret.Value.Options.Data is null) return new(new Exception("Receive null when read sign")); - - // Check CRC - var crcCode = Common.Number.BytesToUInt32(ret.Value.Options.Data); - if (!crcCode.IsSuccessful) return new(crcCode.Error); - - var retCRC = crcCode.Value == checkSum; - logger.Trace($"Device {this.address} remote update check crc finished"); - - logger.Debug($"Expected CRC32/Mpeg Code: 0x{checkSum.ToString("X").PadLeft(8, '0')}"); - logger.Debug($"Actually CRC32/Mpeg Code: 0x{crcCode.Value.ToString("X").PadLeft(8, '0')}"); - return retCRC; + return ret.Value; } } @@ -240,80 +178,205 @@ public class RemoteUpdater /// /// [TODO:parameter] /// [TODO:return] - public async ValueTask> HotReset(int bitstreamNum) + public async ValueTask> EnableBitstream(int bitstreamNum) { - // Clear Data - await MsgBus.UDPServer.ClearUDPData(this.address); + // Assert + if (bitstreamNum <= 0 || bitstreamNum > 3) + return new(new ArgumentException( + $"Bitsteam num should be 1 ~ 3, but given {bitstreamNum}", nameof(bitstreamNum))); - logger.Trace($"Clear up udp server {this.address} receive data"); + var bytesData = new byte[FLASH_SECTOR_LENGTH]; + Array.Fill(bytesData, 0xFF); + bytesData[FLASH_SECTOR_LENGTH - 1] = 0x01; + bytesData[FLASH_SECTOR_LENGTH - 2] = 0x33; + bytesData[FLASH_SECTOR_LENGTH - 3] = 0x2D; + bytesData[FLASH_SECTOR_LENGTH - 4] = 0x94; + var ret = await WriteFlash(FlashAddr.Switch[bitstreamNum], 1, bytesData); + if (!ret.IsSuccessful) return new(ret.Error); + return ret.Value; + } + + /// + /// [TODO:description] + /// + /// [TODO:parameter] + /// [TODO:return] + public async ValueTask> DisableBitstream(int bitstreamNum) + { + // Assert + if (bitstreamNum <= 0 || bitstreamNum > 3) + return new(new ArgumentException( + $"Bitsteam num should be 1 ~ 3, but given {bitstreamNum}", nameof(bitstreamNum))); + + var bytesData = new byte[FLASH_SECTOR_LENGTH]; + Array.Fill(bytesData, 0xFF); + + var ret = await WriteFlash(FlashAddr.Switch[bitstreamNum], 1, bytesData); + if (!ret.IsSuccessful) return new(ret.Error); + return ret.Value; + } + + + /// + /// [TODO:description] + /// + /// [TODO:parameter] + /// [TODO:return] + public async ValueTask> WriteJumpCmd(int bitstreamNum) + { + // Assert + if (bitstreamNum <= 0 || bitstreamNum > 3) + return new(new ArgumentException( + $"Bitsteam num should be 1 ~ 3, but given {bitstreamNum}", nameof(bitstreamNum))); + + // Init data + var bytesData = new byte[FLASH_SECTOR_LENGTH]; + for (int i = 0; i < FLASH_SECTOR_LENGTH; i += 4) + bytesData[i] = 0xA0; + + Buffer.BlockCopy(new byte[] { 0xAB, 0x00, 0x00, 0x01 }, 0, bytesData, 0x04, 4); + Buffer.BlockCopy(new byte[] { 0x00, 0x00, 0x00, 0x0B }, 0, bytesData, 0x08, 4); + Buffer.BlockCopy(new byte[] { 0xAB, 0xC0, 0x00, 0x01 }, 0, bytesData, 0x34, 4); + Buffer.BlockCopy(new byte[] { 0x00, 0x00, 0x00, 0x00 }, 0, bytesData, 0x38, 4); + Buffer.BlockCopy(new byte[] { 0xAC, 0x00, 0x00, 0x01 }, 0, bytesData, 0x3C, 4); + Buffer.BlockCopy(Common.Number.NumberToBytes(FlashAddr.User[bitstreamNum], 4).Value, 0, bytesData, 0x40, 4); + Buffer.BlockCopy(new byte[] { 0xA8, 0x80, 0x00, 0x01 }, 0, bytesData, 0x44, 4); + Buffer.BlockCopy(new byte[] { 0x00, 0x00, 0x00, 0x0F }, 0, bytesData, 0x48, 4); + + var ret = await WriteFlash(FlashAddr.Switch[bitstreamNum], 1, bytesData); + if (!ret.IsSuccessful) return new(ret.Error); + return ret.Value; + } + + /// + /// [TODO:description] + /// + /// [TODO:parameter] + /// [TODO:return] + public async ValueTask> InitRemoteUpdate(int bitstreamNum) + { + // Assert + if (bitstreamNum <= 0 || bitstreamNum > 3) + return new(new ArgumentException( + $"Bitsteam num should be 1 ~ 3, but given {bitstreamNum}", nameof(bitstreamNum))); + + for (int i = 0; i < 3; i++) + { + { + var ret = (i == bitstreamNum) ? await EnableBitstream(i) : await DisableBitstream(i); + if (!ret.IsSuccessful) return new(ret.Error); + if (!ret.Value) return new(new Exception($"Write switch {i} failed")); + } + + { + var ret = await WriteJumpCmd(i); + if (!ret.IsSuccessful) return new(ret.Error); + if (!ret.Value) return new(new Exception($"Write jump {i} failed")); + } + } + + return true; + } + + + /// + /// [TODO:description] + /// + /// [TODO:parameter] + /// [TODO:parameter] + /// [TODO:return] + public async ValueTask> CheckBitstreamCRC(int bitstreamNum, UInt32 checkSum) + { + { + var ret = await UDPClientPool.WriteAddr(this.ep, RemoteUpdateClientAddr.ReadCtrl2, 0x00_00_00_00, this.timeout); + if (!ret.IsSuccessful) return new(ret.Error); + if (!ret.Value) return new(new Exception("Write read control 2 failed")); + } { var ret = await UDPClientPool.WriteAddr( - this.remoteEP, Global.RemoteUpdaterAddr.ClearCtrl, - (UInt32)(0b1), timeout); + this.ep, RemoteUpdateClientAddr.ReadCtrl1, + Convert.ToUInt32((1024 << 16) | (1 << 15) | Convert.ToInt32(FlashAddr.User[bitstreamNum] / 4096)), this.timeout); if (!ret.IsSuccessful) return new(ret.Error); - if (!ret.Value) return new(new Exception("Run clear failed")); + if (!ret.Value) return new(new Exception("Write read control 1 failed")); } + { var ret = await UDPClientPool.ReadAddrWithWait( - this.remoteEP, Global.RemoteUpdaterAddr.ClearSign, 0x00_00_00_01, 0x00_00_00_01, 60 * 1000); + this.ep, RemoteUpdateClientAddr.ReadSign, + 0x00_00_01_00, 0x00_00_01_00, this.timeoutForWait); if (!ret.IsSuccessful) return new(ret.Error); - if (!ret.Value) return new(new Exception("Clear failed even over time")); + if (!ret.Value) return new(new Exception( + $"Read bitstream failed after {this.timeoutForWait} milliseconds")); } - logger.Trace($"Device {this.address} remote update clear finished"); { - var ret = await UDPClientPool.WriteAddr( - this.remoteEP, Global.RemoteUpdaterAddr.WriteSwitchCtrl, - (UInt32)((bitstreamNum << 1) | 0b1), timeout); + var ret = await UDPClientPool.ReadAddr(this.ep, RemoteUpdateClientAddr.ReadCRC, this.timeout); if (!ret.IsSuccessful) return new(ret.Error); - if (!ret.Value) return new(new Exception("Run write switch code failed")); - } - { - var ret = await UDPClientPool.ReadAddrWithWait( - this.remoteEP, Global.RemoteUpdaterAddr.WriteSwitchSign, - 0x00_00_00_01, 0x00_00_00_01, 60 * 1000); - if (!ret.IsSuccessful) return new(ret.Error); - if (!ret.Value) return new(new Exception("Write switch code failed even over time")); - } - logger.Trace($"Device {this.address} remote update write switch open finished"); - { - var ret = await UDPClientPool.WriteAddr( - this.remoteEP, Global.RemoteUpdaterAddr.HotResetCtrl, (UInt32)(0b1), timeout); - if (!ret.IsSuccessful) return new(ret.Error); - return ret.Value; + var bytes = ret.Value.Options.Data; + if (bytes is null) + return new(new Exception("CRC is null")); + + var remoteCRC = Common.Number.BytesToUInt32(bytes); + if (!remoteCRC.IsSuccessful) return new(remoteCRC.Error); + + logger.Debug($"Expected CRC: \t 0x{Convert.ToString(checkSum, 16)}"); + logger.Debug($"Received CRC: \t 0x{Convert.ToString(remoteCRC.Value, 16)}"); + + return remoteCRC.Value == checkSum; } } /// - /// Updates the bitstream on the FPGA device. + /// [TODO:description] /// - /// The bitstream number (0-3). - /// The bitstream data to update. - /// A result indicating success or failure. - public async ValueTask> UpdateBitstream(int bitstreamNum, byte[] bitstream) + /// [TODO:parameter] + /// [TODO:return] + public async ValueTask> HotRest(int bitstreamNum) { + // Assert + if (bitstreamNum <= 0 || bitstreamNum > 3) + return new(new ArgumentException( + $"Bitsteam num should be 1 ~ 3, but given {bitstreamNum}", nameof(bitstreamNum))); + + var ret = await UDPClientPool.WriteAddr( + this.ep, RemoteUpdateClientAddr.HotResetCtrl, + ((FlashAddr.User[bitstreamNum] << 8) | 1), this.timeout); + if (!ret.IsSuccessful) return new(ret.Error); + return ret.Value; + } + + /// + /// [TODO:description] + /// + /// [TODO:parameter] + /// [TODO:parameter] + /// [TODO:return] + public async ValueTask> UpdateBitstream(int bitstreamNum, byte[] bytesData) + { + // Assert + if (bitstreamNum <= 0 || bitstreamNum > 3) + return new(new ArgumentException( + $"Bitsteam num should be 1 ~ 3, but given {bitstreamNum}", nameof(bitstreamNum))); + { - var ret = await WriteBitstream(bitstreamNum, bitstream); + var ret = await InitRemoteUpdate(bitstreamNum); + if (!ret.IsSuccessful) return new(ret.Error); + if (!ret.Value) return new(new Exception("Init remote update failed")); + } + + { + var ret = await WriteFlash(FlashAddr.User[bitstreamNum], 1024, bytesData); if (!ret.IsSuccessful) return new(ret.Error); if (!ret.Value) return new(new Exception("Write bitstream failed")); } - { - var crc = Honoo.IO.Hashing.Crc.Create(Honoo.IO.Hashing.CrcName.CRC32_MPEG_2); - var checkSum = crc.ComputeFinal(bitstream); - var ret = await CheckBitstreamCRC(bitstreamNum, checkSum.ToUInt32()); - if (!ret.IsSuccessful) return new(ret.Error); - // if (!ret.Value) return new(new Exception("Check bitstream crc32/mpeg-2 failed")); - } { - var ret = await HotReset(bitstreamNum); + var ret = await HotRest(bitstreamNum); if (!ret.IsSuccessful) return new(ret.Error); - if (!ret.Value) return new(new Exception("Hot reset failed")); return ret.Value; } } - } From 55e363d505352b132a5c31563b8b5f926039e083 Mon Sep 17 00:00:00 2001 From: SikongJueluo Date: Sun, 4 May 2025 21:56:19 +0800 Subject: [PATCH 6/8] fix: remote update failed --- server.test/CommonTest.cs | 13 +++ server.test/UDPServerTest.cs | 6 +- server/src/RemoteUpdate.cs | 187 +++++++++++++++++++++++++---------- 3 files changed, 153 insertions(+), 53 deletions(-) diff --git a/server.test/CommonTest.cs b/server.test/CommonTest.cs index 782a428..5d6061f 100644 --- a/server.test/CommonTest.cs +++ b/server.test/CommonTest.cs @@ -1,3 +1,4 @@ +using System.Buffers.Binary; using Common; namespace server.test; @@ -45,4 +46,16 @@ public class CommonTest Assert.Equal(Number.ToBit(0xAA, 3).Value, true); Assert.Equal(Number.ToBit(0xAA, 2).Value, false); } + + [Fact] + public void ReverseBits() + { + Assert.Equal(BinaryPrimitives.ReverseEndianness((byte)0xA0), (byte)0x50); + + var bytesSrc = new byte[] { 0xAB, 0x00, 0x00, 0x01 }; + var bytes = new byte[4]; + for (int i = 0; i < 4; i++) + bytes[i] = BinaryPrimitives.ReverseEndianness(bytesSrc[i]); + Assert.Equal(bytesSrc, new byte[] { 0xD5, 0x00, 0x00, 0x80 }); + } } diff --git a/server.test/UDPServerTest.cs b/server.test/UDPServerTest.cs index 5cde6f3..5ec27ce 100644 --- a/server.test/UDPServerTest.cs +++ b/server.test/UDPServerTest.cs @@ -92,7 +92,7 @@ public class UDPServerTest Assert.True(ret.HasValue); var data = ret.Value; Assert.Equal(address, data.Address); - Assert.Equal(number, Number.BytesToNumber(data.Data)); + Assert.Equal(number, Number.BytesToUInt32(data.Data).Value); } } @@ -112,7 +112,7 @@ public class UDPServerTest Assert.True(ret.IsSuccessful); var data = ret.Value; Assert.True(data.IsSuccessful); - Assert.Equal(number, Number.BytesToNumber(data.ToBytes())); + Assert.Equal(number, Number.BytesToUInt32(data.ToBytes()).Value); } } @@ -132,7 +132,7 @@ public class UDPServerTest Assert.True(ret.IsSuccessful); var data = ret.Value; Assert.True(data.IsSuccessful); - Assert.Equal(number, Number.BytesToNumber(data.ToBytes())); + Assert.Equal(number, Number.BytesToUInt32(data.ToBytes()).Value); } } } diff --git a/server/src/RemoteUpdate.cs b/server/src/RemoteUpdate.cs index 727f72b..72ba3c0 100644 --- a/server/src/RemoteUpdate.cs +++ b/server/src/RemoteUpdate.cs @@ -1,22 +1,24 @@ +using System.Buffers.Binary; using System.Net; using DotNext; namespace RemoteUpdate; static class RemoteUpdateClientAddr { + public const UInt32 Base = 0x20_00_00_00; /// /// ADDR: 0X00: 写Flash-读写地址——控制位
/// [31:16]: wr_sector_num
/// [15: 0]: {flash_wr_en,-,-,-, start_wr_sector}
///
- public const UInt32 WriteCtrl = 0x00; + public const UInt32 WriteCtrl = Base + 0x00; /// /// ADDR: 0X01: 写Flash-只写地址——FIFO入口
/// [31:0]: 写比特流数据入口
///
- public const UInt32 WriteFIFO = 0x01; + public const UInt32 WriteFIFO = Base + 0x01; /// /// ADDR: 0X02: 写Flash-只读地址——标志位
@@ -25,14 +27,14 @@ static class RemoteUpdateClientAddr /// [15: 8]: {-, -, -, -, -, -, -, flash_wr_done}
/// [ 7: 0]: {-, -, -, -, -, -, -, flash_clear_done}
///
- public const UInt32 WriteSign = 0x02; + public const UInt32 WriteSign = Base + 0x02; /// /// ADDR: 0X03: 读Flash-读写地址——控制位1
/// [31:16]: rd_sector_num
/// [15: 0]: {flash_rd_en,-,-,-, start_rd_sub_sector}
///
- public const UInt32 ReadCtrl1 = 0x03; + public const UInt32 ReadCtrl1 = Base + 0x03; /// /// ADDR: 0X04: 读Flash-读写地址——控制位2
@@ -41,19 +43,19 @@ static class RemoteUpdateClientAddr /// [15: 8]: {-, -, -, -, -, -, -, crc_check_en}
/// [ 7: 0]: {-, -, -, -, -, -, -, bitstream_up2cpu_en}
///
- public const UInt32 ReadCtrl2 = 0x04; + public const UInt32 ReadCtrl2 = Base + 0x04; /// /// ADDR: 0X05: 读Flash-只读地址——FIFO出口
/// [31:0]: 读比特流数据出口
///
- public const UInt32 ReadFIFO = 0x05; + public const UInt32 ReadFIFO = Base + 0x05; /// /// ADDR: 0X06: 读Flash-只读地址——CRC校验值
/// [31:0]: CRC校验值 bs_readback_crc
///
- public const UInt32 ReadCRC = 0x06; + public const UInt32 ReadCRC = Base + 0x06; /// /// ADDR: 0X07: 读Flash-只读地址——标志位
@@ -62,29 +64,27 @@ static class RemoteUpdateClientAddr /// [15: 8]: {-, -, -, -, -, -, -, flash_rd_done}
/// [ 7: 0]: {-, -, -, -, -, -, -, bs_readback_crc_valid}
///
- public const UInt32 ReadSign = 0x07; + public const UInt32 ReadSign = Base + 0x07; /// /// ADDR: 0X08: 热启动开关-读写地址——控制位
/// [31: 8]: hotreset_addr
/// [ 7: 0]: {-, -, -, -, -, -, -, hotreset_en}
///
- public const UInt32 HotResetCtrl = 0x08; + public const UInt32 HotResetCtrl = Base + 0x08; /// /// ADDR: 0X09: 只读地址 版本号
/// [31: 0]: FPGA_VERSION[31:0]
///
- public const UInt32 Version = 0x09; + public const UInt32 Version = Base + 0x09; } static class FlashAddr { - public static readonly UInt32[] Switch = { 0x0000, 0x2000, 0x4000 }; - public static readonly UInt32[] Jump = { 0x1000, 0x3000, 0x5000 }; - public static readonly UInt32[] User = { 0x406000, 0x806000, 0xC06000 }; - - public const UInt32 Golden = 0x6000; + public static readonly UInt32[] Switch = { 0xFFFF, 0x0000, 0x2000, 0x4000 }; + public static readonly UInt32[] Jump = { 0xFFFF, 0x1000, 0x3000, 0x5000 }; + public static readonly UInt32[] Bitstream = { 0x006000, 0x406000, 0x806000, 0xC06000 }; } @@ -131,7 +131,7 @@ public class RemoteUpdateClient /// [TODO:parameter] /// [TODO:parameter] /// [TODO:return] - public async ValueTask> WriteFlash(UInt32 flashAddr, int writeSectorNum, byte[] bytesData) + private async ValueTask> WriteFlash(UInt32 flashAddr, int writeSectorNum, byte[] bytesData) { // Assert if (writeSectorNum <= 0 || writeSectorNum >= FLASH_SECTOR_LENGTH) @@ -178,19 +178,19 @@ public class RemoteUpdateClient /// /// [TODO:parameter] /// [TODO:return] - public async ValueTask> EnableBitstream(int bitstreamNum) + private async ValueTask> EnableBitstream(int bitstreamNum) { // Assert if (bitstreamNum <= 0 || bitstreamNum > 3) return new(new ArgumentException( - $"Bitsteam num should be 1 ~ 3, but given {bitstreamNum}", nameof(bitstreamNum))); + $"Bitsteam num should be 1 ~ 3 for EnableBitstream, but given {bitstreamNum}", nameof(bitstreamNum))); var bytesData = new byte[FLASH_SECTOR_LENGTH]; Array.Fill(bytesData, 0xFF); - bytesData[FLASH_SECTOR_LENGTH - 1] = 0x01; - bytesData[FLASH_SECTOR_LENGTH - 2] = 0x33; - bytesData[FLASH_SECTOR_LENGTH - 3] = 0x2D; - bytesData[FLASH_SECTOR_LENGTH - 4] = 0x94; + bytesData[FLASH_SECTOR_LENGTH - 4] = 0x80; // 0b10000000 + bytesData[FLASH_SECTOR_LENGTH - 3] = 0xCC; // 0b11001100 + bytesData[FLASH_SECTOR_LENGTH - 2] = 0xB4; // 0b10110100 + bytesData[FLASH_SECTOR_LENGTH - 1] = 0x29; // 0b00101001 var ret = await WriteFlash(FlashAddr.Switch[bitstreamNum], 1, bytesData); if (!ret.IsSuccessful) return new(ret.Error); @@ -202,12 +202,12 @@ public class RemoteUpdateClient /// /// [TODO:parameter] /// [TODO:return] - public async ValueTask> DisableBitstream(int bitstreamNum) + private async ValueTask> DisableBitstream(int bitstreamNum) { // Assert if (bitstreamNum <= 0 || bitstreamNum > 3) return new(new ArgumentException( - $"Bitsteam num should be 1 ~ 3, but given {bitstreamNum}", nameof(bitstreamNum))); + $"Bitsteam num should be 1 ~ 3 for DisableBitstream, but given {bitstreamNum}", nameof(bitstreamNum))); var bytesData = new byte[FLASH_SECTOR_LENGTH]; Array.Fill(bytesData, 0xFF); @@ -223,28 +223,68 @@ public class RemoteUpdateClient /// /// [TODO:parameter] /// [TODO:return] - public async ValueTask> WriteJumpCmd(int bitstreamNum) + private async ValueTask> WriteJumpCmd(int bitstreamNum) { // Assert if (bitstreamNum <= 0 || bitstreamNum > 3) return new(new ArgumentException( - $"Bitsteam num should be 1 ~ 3, but given {bitstreamNum}", nameof(bitstreamNum))); + $"Bitsteam num should be 1 ~ 3 for WriteJumpCmd, but given {bitstreamNum}", nameof(bitstreamNum))); // Init data var bytesData = new byte[FLASH_SECTOR_LENGTH]; for (int i = 0; i < FLASH_SECTOR_LENGTH; i += 4) - bytesData[i] = 0xA0; + bytesData[i] = BinaryPrimitives.ReverseEndianness((byte)0xA0); - Buffer.BlockCopy(new byte[] { 0xAB, 0x00, 0x00, 0x01 }, 0, bytesData, 0x04, 4); - Buffer.BlockCopy(new byte[] { 0x00, 0x00, 0x00, 0x0B }, 0, bytesData, 0x08, 4); - Buffer.BlockCopy(new byte[] { 0xAB, 0xC0, 0x00, 0x01 }, 0, bytesData, 0x34, 4); - Buffer.BlockCopy(new byte[] { 0x00, 0x00, 0x00, 0x00 }, 0, bytesData, 0x38, 4); - Buffer.BlockCopy(new byte[] { 0xAC, 0x00, 0x00, 0x01 }, 0, bytesData, 0x3C, 4); - Buffer.BlockCopy(Common.Number.NumberToBytes(FlashAddr.User[bitstreamNum], 4).Value, 0, bytesData, 0x40, 4); - Buffer.BlockCopy(new byte[] { 0xA8, 0x80, 0x00, 0x01 }, 0, bytesData, 0x44, 4); - Buffer.BlockCopy(new byte[] { 0x00, 0x00, 0x00, 0x0F }, 0, bytesData, 0x48, 4); + { + var bytesSrc = new byte[] { 0xAB, 0x00, 0x00, 0x01 }; + for (int i = 0; i < 4; i++) + bytesSrc[i] = BinaryPrimitives.ReverseEndianness(bytesSrc[i]); + Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x04, 4); + } + { + var bytesSrc = new byte[] { 0x00, 0x00, 0x00, 0x0B }; + for (int i = 0; i < 4; i++) + bytesSrc[i] = BinaryPrimitives.ReverseEndianness(bytesSrc[i]); + Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x08, 4); + } + { + var bytesSrc = new byte[] { 0xAB, 0xC0, 0x00, 0x01 }; + for (int i = 0; i < 4; i++) + bytesSrc[i] = BinaryPrimitives.ReverseEndianness(bytesSrc[i]); + Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x34, 4); + } + { + var bytesSrc = new byte[] { 0x00, 0x00, 0x00, 0x00 }; + for (int i = 0; i < 4; i++) + bytesSrc[i] = BinaryPrimitives.ReverseEndianness(bytesSrc[i]); + Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x38, 4); + } + { + var bytesSrc = new byte[] { 0xAC, 0x00, 0x00, 0x01 }; + for (int i = 0; i < 4; i++) + bytesSrc[i] = BinaryPrimitives.ReverseEndianness(bytesSrc[i]); + Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x3C, 4); + } + { + var bytesSrc = Common.Number.NumberToBytes(FlashAddr.Bitstream[bitstreamNum], 4).Value; + for (int i = 0; i < 4; i++) + bytesSrc[i] = BinaryPrimitives.ReverseEndianness(bytesSrc[i]); + Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x40, 4); + } + { + var bytesSrc = new byte[] { 0xA8, 0x80, 0x00, 0x01 }; + for (int i = 0; i < 4; i++) + bytesSrc[i] = BinaryPrimitives.ReverseEndianness(bytesSrc[i]); + Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x44, 4); + } + { + var bytesSrc = new byte[] { 0x00, 0x00, 0x00, 0x0F }; + for (int i = 0; i < 4; i++) + bytesSrc[i] = BinaryPrimitives.ReverseEndianness(bytesSrc[i]); + Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x48, 4); + } - var ret = await WriteFlash(FlashAddr.Switch[bitstreamNum], 1, bytesData); + var ret = await WriteFlash(FlashAddr.Jump[bitstreamNum], 1, bytesData); if (!ret.IsSuccessful) return new(ret.Error); return ret.Value; } @@ -254,14 +294,14 @@ public class RemoteUpdateClient /// /// [TODO:parameter] /// [TODO:return] - public async ValueTask> InitRemoteUpdate(int bitstreamNum) + private async ValueTask> InitRemoteUpdate(int bitstreamNum) { // Assert - if (bitstreamNum <= 0 || bitstreamNum > 3) + if (bitstreamNum < 0 || bitstreamNum > 3) return new(new ArgumentException( - $"Bitsteam num should be 1 ~ 3, but given {bitstreamNum}", nameof(bitstreamNum))); + $"Bitsteam num should be 0 ~ 3 for InitRemoteUpdate, but given {bitstreamNum}", nameof(bitstreamNum))); - for (int i = 0; i < 3; i++) + for (int i = 1; i <= 3; i++) { { var ret = (i == bitstreamNum) ? await EnableBitstream(i) : await DisableBitstream(i); @@ -284,9 +324,10 @@ public class RemoteUpdateClient /// [TODO:description] /// /// [TODO:parameter] + /// [TODO:parameter] /// [TODO:parameter] /// [TODO:return] - public async ValueTask> CheckBitstreamCRC(int bitstreamNum, UInt32 checkSum) + private async ValueTask> CheckBitstreamCRC(int bitstreamNum, int bitstreamLen, UInt32 checkSum) { { var ret = await UDPClientPool.WriteAddr(this.ep, RemoteUpdateClientAddr.ReadCtrl2, 0x00_00_00_00, this.timeout); @@ -297,7 +338,8 @@ public class RemoteUpdateClient { var ret = await UDPClientPool.WriteAddr( this.ep, RemoteUpdateClientAddr.ReadCtrl1, - Convert.ToUInt32((1024 << 16) | (1 << 15) | Convert.ToInt32(FlashAddr.User[bitstreamNum] / 4096)), this.timeout); + Convert.ToUInt32((bitstreamLen << 16) | (1 << 15) | Convert.ToInt32(FlashAddr.Bitstream[bitstreamNum] / 4096)), + this.timeout); if (!ret.IsSuccessful) return new(ret.Error); if (!ret.Value) return new(new Exception("Write read control 1 failed")); } @@ -334,16 +376,16 @@ public class RemoteUpdateClient /// /// [TODO:parameter] /// [TODO:return] - public async ValueTask> HotRest(int bitstreamNum) + private async ValueTask> HotRest(int bitstreamNum) { // Assert - if (bitstreamNum <= 0 || bitstreamNum > 3) + if (bitstreamNum < 0 || bitstreamNum > 3) return new(new ArgumentException( - $"Bitsteam num should be 1 ~ 3, but given {bitstreamNum}", nameof(bitstreamNum))); + $"Bitsteam num should be 0 ~ 3 for HotRest, but given {bitstreamNum}", nameof(bitstreamNum))); var ret = await UDPClientPool.WriteAddr( this.ep, RemoteUpdateClientAddr.HotResetCtrl, - ((FlashAddr.User[bitstreamNum] << 8) | 1), this.timeout); + ((FlashAddr.Bitstream[bitstreamNum] << 8) | 1), this.timeout); if (!ret.IsSuccessful) return new(ret.Error); return ret.Value; } @@ -356,10 +398,13 @@ public class RemoteUpdateClient /// [TODO:return] public async ValueTask> UpdateBitstream(int bitstreamNum, byte[] bytesData) { - // Assert - if (bitstreamNum <= 0 || bitstreamNum > 3) + if (bytesData.Length % (4 * 1024) != 0) return new(new ArgumentException( - $"Bitsteam num should be 1 ~ 3, but given {bitstreamNum}", nameof(bitstreamNum))); + $"The length of data should be divided by 4096, bug given {bytesData.Length}", nameof(bytesData))); + var bitstreamBlockNum = bytesData.Length / (4 * 1024); + + await MsgBus.UDPServer.ClearUDPData(this.address); + logger.Trace("Clear udp data finished"); { var ret = await InitRemoteUpdate(bitstreamNum); @@ -368,15 +413,57 @@ public class RemoteUpdateClient } { - var ret = await WriteFlash(FlashAddr.User[bitstreamNum], 1024, bytesData); + var ret = await WriteFlash(FlashAddr.Bitstream[bitstreamNum], bitstreamBlockNum, bytesData); if (!ret.IsSuccessful) return new(ret.Error); if (!ret.Value) return new(new Exception("Write bitstream failed")); } + { + var crc = Honoo.IO.Hashing.Crc.Create(Honoo.IO.Hashing.CrcName.CRC32_MPEG_2); + var checkSum = crc.ComputeFinal(bytesData); + var ret = await CheckBitstreamCRC(bitstreamNum, bitstreamBlockNum, checkSum.ToUInt32()); + if (!ret.IsSuccessful) return new(ret.Error); + if (!ret.Value) logger.Warn("CRC32 not correct!"); + else logger.Info("CRC32 calibration passed"); + } + { var ret = await HotRest(bitstreamNum); if (!ret.IsSuccessful) return new(ret.Error); return ret.Value; } } + + /// + /// [TODO:description] + /// + /// [TODO:parameter] + /// [TODO:return] + public async ValueTask> HotResetBitstream(int bitstreamNum) + { + await MsgBus.UDPServer.ClearUDPData(this.address); + logger.Trace("Clear udp data finished"); + + { + var ret = await InitRemoteUpdate(bitstreamNum); + if (!ret.IsSuccessful) return new(ret.Error); + if (!ret.Value) return new(new Exception("Init remote update failed")); + } + + { + var ret = await HotRest(bitstreamNum); + if (!ret.IsSuccessful) return new(ret.Error); + return ret.Value; + } + } + + public async ValueTask> UploadBitstreams( + int enableBitstreamNum, + byte[]? goldenBitream, + byte[]? bitstream1, + byte[]? bitstream2, + byte[]? bitstream3) + { + return true; + } } From f75b245abca3f2422d2f921321b23dfcc529c288 Mon Sep 17 00:00:00 2001 From: SikongJueluo Date: Mon, 5 May 2025 14:24:22 +0800 Subject: [PATCH 7/8] fix: reboot very slow after remote update\ --- server.test/CommonTest.cs | 14 +++--- server.test/UDPServerTest.cs | 2 +- server/src/Common.cs | 60 +++++++++++++++++++++- server/src/Controllers.cs | 16 +++--- server/src/RemoteUpdate.cs | 96 +++++++++++++++++++++++++----------- 5 files changed, 142 insertions(+), 46 deletions(-) diff --git a/server.test/CommonTest.cs b/server.test/CommonTest.cs index 5d6061f..1f36b90 100644 --- a/server.test/CommonTest.cs +++ b/server.test/CommonTest.cs @@ -41,21 +41,21 @@ public class CommonTest [Fact] public void ToBitTest() { - Assert.Equal(Number.ToBit(0xFF, 3).Value, true); - Assert.Equal(Number.ToBit(0x00, 3).Value, false); - Assert.Equal(Number.ToBit(0xAA, 3).Value, true); - Assert.Equal(Number.ToBit(0xAA, 2).Value, false); + Assert.Equal(true, Number.ToBit(0xFF, 3).Value); + Assert.Equal(false, Number.ToBit(0x00, 3).Value); + Assert.Equal(true, Number.ToBit(0xAA, 3).Value); + Assert.Equal(false, Number.ToBit(0xAA, 2).Value); } [Fact] public void ReverseBits() { - Assert.Equal(BinaryPrimitives.ReverseEndianness((byte)0xA0), (byte)0x50); + Assert.Equal((byte)0x05, Common.Number.ReverseBits((byte)0xA0)); var bytesSrc = new byte[] { 0xAB, 0x00, 0x00, 0x01 }; var bytes = new byte[4]; for (int i = 0; i < 4; i++) - bytes[i] = BinaryPrimitives.ReverseEndianness(bytesSrc[i]); - Assert.Equal(bytesSrc, new byte[] { 0xD5, 0x00, 0x00, 0x80 }); + bytes[i] = Common.Number.ReverseBits(bytesSrc[i]); + Assert.Equal(new byte[] { 0xD5, 0x00, 0x00, 0x80 }, bytes); } } diff --git a/server.test/UDPServerTest.cs b/server.test/UDPServerTest.cs index 5ec27ce..3274507 100644 --- a/server.test/UDPServerTest.cs +++ b/server.test/UDPServerTest.cs @@ -132,7 +132,7 @@ public class UDPServerTest Assert.True(ret.IsSuccessful); var data = ret.Value; Assert.True(data.IsSuccessful); - Assert.Equal(number, Number.BytesToUInt32(data.ToBytes()).Value); + Assert.Equal((UInt64)number, Number.BytesToUInt64(data.ToBytes()).Value); } } } diff --git a/server/src/Common.cs b/server/src/Common.cs index 46c0fcc..5639ef7 100644 --- a/server/src/Common.cs +++ b/server/src/Common.cs @@ -7,6 +7,40 @@ namespace Common /// public class Number { + private static readonly byte[] BitReverseTable = new byte[] { + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, + 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, + 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, + 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, + 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, + 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, + 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, + 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff + }; /// /// 整数转成二进制字节数组 /// @@ -256,7 +290,7 @@ namespace Common "Distance is larger than bytesArray", nameof(distance))); if (srcBytesLen % distance != 0) return new(new ArgumentException( - "The length of bytes can't be divided by 2 without reminder", nameof(distance))); + "The length of bytes can't be divided by distance without reminder", nameof(distance))); var dstBytes = new byte[srcBytesLen]; var buffer = new byte[distance]; @@ -272,7 +306,31 @@ namespace Common return dstBytes; } + /// + /// 反转字节内比特顺序(使用查找表的方法) + /// + /// 字节 + /// 反转后的字节 + public static byte ReverseBits(byte srcByte) + { + return BitReverseTable[srcByte]; + } + /// + /// 反转字节数组的字节内比特顺序(使用查找表的方法) + /// + /// 字节数组 + /// 反转后的字节字节数组 + public static byte[] ReverseBits(byte[] srcBytes) + { + var bytesLen = srcBytes.Length; + var dstBytes = new byte[bytesLen]; + for (int i = 0; i < bytesLen; i++) + { + dstBytes[i] = BitReverseTable[srcBytes[i]]; + } + return dstBytes; + } } /// diff --git a/server/src/Controllers.cs b/server/src/Controllers.cs index 6124b2c..80365ed 100644 --- a/server/src/Controllers.cs +++ b/server/src/Controllers.cs @@ -306,10 +306,10 @@ public class JtagController : ControllerBase if (!retBuffer.IsSuccessful) return TypedResults.InternalServerError(retBuffer.Error); revBuffer = retBuffer.Value; - for (int i = 0; i < buffer.Length; i++) - { - revBuffer[i] = BinaryPrimitives.ReverseEndianness(revBuffer[i]); - } + // for (int i = 0; i < buffer.Length; i++) + // { + // revBuffer[i] = Common.Number.ReverseBits(revBuffer[i]); + // } await memoryStream.WriteAsync(revBuffer, 0, bytesRead); totalBytesRead += bytesRead; @@ -435,10 +435,10 @@ public class RemoteUpdater : ControllerBase if (!retBuffer.IsSuccessful) return TypedResults.InternalServerError(retBuffer.Error); revBuffer = retBuffer.Value; - for (int i = 0; i < buffer.Length; i++) - { - revBuffer[i] = BinaryPrimitives.ReverseEndianness(revBuffer[i]); - } + // for (int i = 0; i < buffer.Length; i++) + // { + // revBuffer[i] = Common.Number.ReverseBits(revBuffer[i]); + // } await memoryStream.WriteAsync(revBuffer, 0, bytesRead); totalBytesRead += bytesRead; diff --git a/server/src/RemoteUpdate.cs b/server/src/RemoteUpdate.cs index 72ba3c0..330f33c 100644 --- a/server/src/RemoteUpdate.cs +++ b/server/src/RemoteUpdate.cs @@ -187,10 +187,15 @@ public class RemoteUpdateClient var bytesData = new byte[FLASH_SECTOR_LENGTH]; Array.Fill(bytesData, 0xFF); - bytesData[FLASH_SECTOR_LENGTH - 4] = 0x80; // 0b10000000 - bytesData[FLASH_SECTOR_LENGTH - 3] = 0xCC; // 0b11001100 - bytesData[FLASH_SECTOR_LENGTH - 2] = 0xB4; // 0b10110100 - bytesData[FLASH_SECTOR_LENGTH - 1] = 0x29; // 0b00101001 + // bytesData[FLASH_SECTOR_LENGTH - 4] = 0x80; // 0b10000000 + // bytesData[FLASH_SECTOR_LENGTH - 3] = 0xCC; // 0b11001100 + // bytesData[FLASH_SECTOR_LENGTH - 2] = 0xB4; // 0b10110100 + // bytesData[FLASH_SECTOR_LENGTH - 1] = 0x29; // 0b00101001 + bytesData[FLASH_SECTOR_LENGTH - 1] = 0x01; + bytesData[FLASH_SECTOR_LENGTH - 2] = 0x33; + bytesData[FLASH_SECTOR_LENGTH - 3] = 0x2D; + bytesData[FLASH_SECTOR_LENGTH - 4] = 0x94; + var ret = await WriteFlash(FlashAddr.Switch[bitstreamNum], 1, bytesData); if (!ret.IsSuccessful) return new(ret.Error); @@ -232,57 +237,90 @@ public class RemoteUpdateClient // Init data var bytesData = new byte[FLASH_SECTOR_LENGTH]; - for (int i = 0; i < FLASH_SECTOR_LENGTH; i += 4) - bytesData[i] = BinaryPrimitives.ReverseEndianness((byte)0xA0); + for (int i = 3; i < FLASH_SECTOR_LENGTH; i += 4) + // bytesData[i] = Common.Number.ReverseBits((byte)0xA0); + bytesData[i] = (byte)0xA0; { - var bytesSrc = new byte[] { 0xAB, 0x00, 0x00, 0x01 }; - for (int i = 0; i < 4; i++) - bytesSrc[i] = BinaryPrimitives.ReverseEndianness(bytesSrc[i]); + var bytesSrc = new byte[] { 0x01, 0x00, 0x00, 0xAB }; Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x04, 4); } { - var bytesSrc = new byte[] { 0x00, 0x00, 0x00, 0x0B }; - for (int i = 0; i < 4; i++) - bytesSrc[i] = BinaryPrimitives.ReverseEndianness(bytesSrc[i]); + var bytesSrc = new byte[] { 0x0B, 0x00, 0x00, 0x00 }; Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x08, 4); } { - var bytesSrc = new byte[] { 0xAB, 0xC0, 0x00, 0x01 }; - for (int i = 0; i < 4; i++) - bytesSrc[i] = BinaryPrimitives.ReverseEndianness(bytesSrc[i]); + var bytesSrc = new byte[] { 0x01, 0x00, 0xC0, 0xAB }; Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x34, 4); } { var bytesSrc = new byte[] { 0x00, 0x00, 0x00, 0x00 }; - for (int i = 0; i < 4; i++) - bytesSrc[i] = BinaryPrimitives.ReverseEndianness(bytesSrc[i]); Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x38, 4); } { - var bytesSrc = new byte[] { 0xAC, 0x00, 0x00, 0x01 }; - for (int i = 0; i < 4; i++) - bytesSrc[i] = BinaryPrimitives.ReverseEndianness(bytesSrc[i]); + var bytesSrc = new byte[] { 0x01, 0x00, 0x00, 0xAC }; Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x3C, 4); } { var bytesSrc = Common.Number.NumberToBytes(FlashAddr.Bitstream[bitstreamNum], 4).Value; - for (int i = 0; i < 4; i++) - bytesSrc[i] = BinaryPrimitives.ReverseEndianness(bytesSrc[i]); - Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x40, 4); + Buffer.BlockCopy(Common.Number.ReverseBytes(bytesSrc, 4).Value, 0, bytesData, 0x40, 4); } { - var bytesSrc = new byte[] { 0xA8, 0x80, 0x00, 0x01 }; - for (int i = 0; i < 4; i++) - bytesSrc[i] = BinaryPrimitives.ReverseEndianness(bytesSrc[i]); + var bytesSrc = new byte[] { 0x01, 0x00, 0x80, 0xA8 }; Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x44, 4); } { - var bytesSrc = new byte[] { 0x00, 0x00, 0x00, 0x0F }; - for (int i = 0; i < 4; i++) - bytesSrc[i] = BinaryPrimitives.ReverseEndianness(bytesSrc[i]); + var bytesSrc = new byte[] { 0x0F, 0x00, 0x00, 0x00 }; Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x48, 4); } + // { + // var bytesSrc = new byte[] { 0xAB, 0x00, 0x00, 0x01 }; + // for (int i = 0; i < 4; i++) + // bytesSrc[i] = Common.Number.ReverseBits(bytesSrc[i]); + // Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x04, 4); + // } + // { + // var bytesSrc = new byte[] { 0x00, 0x00, 0x00, 0x0B }; + // for (int i = 0; i < 4; i++) + // bytesSrc[i] = Common.Number.ReverseBits(bytesSrc[i]); + // Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x08, 4); + // } + // { + // var bytesSrc = new byte[] { 0xAB, 0xC0, 0x00, 0x01 }; + // for (int i = 0; i < 4; i++) + // bytesSrc[i] = Common.Number.ReverseBits(bytesSrc[i]); + // Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x34, 4); + // } + // { + // var bytesSrc = new byte[] { 0x00, 0x00, 0x00, 0x00 }; + // for (int i = 0; i < 4; i++) + // bytesSrc[i] = Common.Number.ReverseBits(bytesSrc[i]); + // Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x38, 4); + // } + // { + // var bytesSrc = new byte[] { 0xAC, 0x00, 0x00, 0x01 }; + // for (int i = 0; i < 4; i++) + // bytesSrc[i] = Common.Number.ReverseBits(bytesSrc[i]); + // Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x3C, 4); + // } + // { + // var bytesSrc = Common.Number.NumberToBytes(FlashAddr.Bitstream[bitstreamNum], 4).Value; + // for (int i = 0; i < 4; i++) + // bytesSrc[i] = Common.Number.ReverseBits(bytesSrc[i]); + // Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x40, 4); + // } + // { + // var bytesSrc = new byte[] { 0xA8, 0x80, 0x00, 0x01 }; + // for (int i = 0; i < 4; i++) + // bytesSrc[i] = Common.Number.ReverseBits(bytesSrc[i]); + // Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x44, 4); + // } + // { + // var bytesSrc = new byte[] { 0x00, 0x00, 0x00, 0x0F }; + // for (int i = 0; i < 4; i++) + // bytesSrc[i] = Common.Number.ReverseBits(bytesSrc[i]); + // Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x48, 4); + // } var ret = await WriteFlash(FlashAddr.Jump[bitstreamNum], 1, bytesData); if (!ret.IsSuccessful) return new(ret.Error); From 51fd1145d876ed6a7f179d6bdd8945ccd9ce02c9 Mon Sep 17 00:00:00 2001 From: SikongJueluo Date: Mon, 5 May 2025 17:24:28 +0800 Subject: [PATCH 8/8] feature: add more web api for remote update --- server/src/Controllers.cs | 265 +++++++++++++++++++++++++++---------- server/src/RemoteUpdate.cs | 186 +++++++++++++++----------- 2 files changed, 299 insertions(+), 152 deletions(-) diff --git a/server/src/Controllers.cs b/server/src/Controllers.cs index 80365ed..968ab0a 100644 --- a/server/src/Controllers.cs +++ b/server/src/Controllers.cs @@ -1,6 +1,6 @@ -using System.Buffers.Binary; using System.Net; using Common; +using DotNext; using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; @@ -143,6 +143,8 @@ public class JtagController : ControllerBase { private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); + private const string BITSTREAM_PATH = "bitstream/Jtag"; + /// /// 页面 /// @@ -244,7 +246,7 @@ public class JtagController : ControllerBase // 生成安全的文件名(避免路径遍历攻击) var fileName = Path.GetRandomFileName(); - var uploadsFolder = Path.Combine(Environment.CurrentDirectory, $"bitstream/{address}"); + var uploadsFolder = Path.Combine(Environment.CurrentDirectory, $"{BITSTREAM_PATH}/{address}"); // 如果存在文件,则删除原文件再上传 if (Directory.Exists(uploadsFolder)) @@ -276,7 +278,7 @@ public class JtagController : ControllerBase public async ValueTask DownloadBitstream(string address, int port) { // 检查文件 - var fileDir = Path.Combine(Environment.CurrentDirectory, $"bitstream/{address}"); + var fileDir = Path.Combine(Environment.CurrentDirectory, $"{BITSTREAM_PATH}/{address}"); if (!Directory.Exists(fileDir)) return TypedResults.BadRequest("Empty bitstream, Please upload it first"); @@ -306,10 +308,6 @@ public class JtagController : ControllerBase if (!retBuffer.IsSuccessful) return TypedResults.InternalServerError(retBuffer.Error); revBuffer = retBuffer.Value; - // for (int i = 0; i < buffer.Length; i++) - // { - // revBuffer[i] = Common.Number.ReverseBits(revBuffer[i]); - // } await memoryStream.WriteAsync(revBuffer, 0, bytesRead); totalBytesRead += bytesRead; @@ -357,22 +355,36 @@ public class RemoteUpdater : ControllerBase { private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); + private const string BITSTREAM_PATH = "bitstream/RemoteUpdate"; + /// /// 上传远程更新比特流文件 /// /// 设备地址 - /// 比特流文件 + /// 黄金比特流文件 + /// 比特流文件1 + /// 比特流文件2 + /// 比特流文件3 + /// 上传结果 [HttpPost("UploadBitstream")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] - public async ValueTask UploadBitstream(string address, IFormFile file) + public async ValueTask UploadBitstreams( + string address, + IFormFile? goldenBitream, + IFormFile? bitstream1, + IFormFile? bitstream2, + IFormFile? bitstream3) { - if (file == null || file.Length == 0) + if ((goldenBitream is null || goldenBitream.Length == 0) && + (bitstream1 is null || bitstream1.Length == 0) && + (bitstream2 is null || bitstream2.Length == 0) && + (bitstream3 is null || bitstream3.Length == 0)) return TypedResults.BadRequest("未选择文件"); // 生成安全的文件名(避免路径遍历攻击) var fileName = Path.GetRandomFileName(); - var uploadsFolder = Path.Combine(Environment.CurrentDirectory, $"bitstream/RemoteUpdate/{address}"); + var uploadsFolder = Path.Combine(Environment.CurrentDirectory, $"{BITSTREAM_PATH}/{address}"); // 如果存在文件,则删除原文件再上传 if (Directory.Exists(uploadsFolder)) @@ -381,19 +393,79 @@ public class RemoteUpdater : ControllerBase } Directory.CreateDirectory(uploadsFolder); - var filePath = Path.Combine(uploadsFolder, fileName); - - using (var stream = new FileStream(filePath, FileMode.Create)) + for (int bitstreamNum = 0; bitstreamNum < 4; bitstreamNum++) { - await file.CopyToAsync(stream); + IFormFile file; + if (bitstreamNum == 0 && goldenBitream is not null) + file = goldenBitream; + else if (bitstreamNum == 1 && bitstream1 is not null) + file = bitstream1; + else if (bitstreamNum == 2 && bitstream2 is not null) + file = bitstream2; + else if (bitstreamNum == 3 && bitstream3 is not null) + file = bitstream3; + else continue; + + var fileFolder = Path.Combine(uploadsFolder, bitstreamNum.ToString()); + Directory.CreateDirectory(fileFolder); + + var filePath = Path.Combine(fileFolder, fileName); + + using (var stream = new FileStream(filePath, FileMode.Create)) + { + await file.CopyToAsync(stream); + } } logger.Info($"Device {address} Upload Bitstream Successfully"); return TypedResults.Ok("Bitstream Upload Successfully"); } + private async ValueTask> ProcessBitstream(string filePath) + { + using (var fileStream = System.IO.File.Open(filePath, System.IO.FileMode.Open)) + { + if (fileStream is null || fileStream.Length <= 0) + return new(new ArgumentException("Wrong bitstream path")); + + // 定义缓冲区大小: 32KB + byte[] buffer = new byte[32 * 1024]; + byte[] revBuffer = new byte[32 * 1024]; + long totalBytesRead = 0; + + // 使用异步流读取文件 + using (var memoryStream = new MemoryStream()) + { + int bytesRead; + while ((bytesRead = await fileStream.ReadAsync(buffer, 0, buffer.Length)) > 0) + { + // 反转 32bits + var retBuffer = Common.Number.ReverseBytes(buffer, 4); + if (!retBuffer.IsSuccessful) + return new(retBuffer.Error); + revBuffer = retBuffer.Value; + + await memoryStream.WriteAsync(revBuffer, 0, bytesRead); + totalBytesRead += bytesRead; + } + + // 将所有数据转换为字节数组(注意:如果文件非常大,可能不适合完全加载到内存) + var restStreamLen = memoryStream.Length % (4 * 1024); + if (restStreamLen != 0) + { + var appendLen = ((int)(4 * 1024 - restStreamLen)); + var bytesAppend = new byte[appendLen]; + Array.Fill(bytesAppend, 0xFF); + await memoryStream.WriteAsync(bytesAppend, 0, appendLen); + } + + return new(memoryStream.ToArray()); + } + } + } + /// - /// 远程更新比特流文件 + /// 远程更新单个比特流文件 /// /// 设备地址 /// 设备端口 @@ -405,7 +477,7 @@ public class RemoteUpdater : ControllerBase public async ValueTask UpdateBitstream(string address, int port, int bitstreamNum) { // 检查文件 - var fileDir = Path.Combine(Environment.CurrentDirectory, $"bitstream/RemoteUpdate/{address}"); + var fileDir = Path.Combine(Environment.CurrentDirectory, $"{BITSTREAM_PATH}/{address}/{bitstreamNum}"); if (!Directory.Exists(fileDir)) return TypedResults.BadRequest("Empty bitstream, Please upload it first"); @@ -414,63 +486,22 @@ public class RemoteUpdater : ControllerBase // 读取文件 var filePath = Directory.GetFiles(fileDir)[0]; - using (var fileStream = System.IO.File.Open(filePath, System.IO.FileMode.Open)) + var fileBytes = await ProcessBitstream(filePath); + if (!fileBytes.IsSuccessful) return TypedResults.InternalServerError(fileBytes.Error); + + // 下载比特流 + var remoteUpdater = new RemoteUpdate.RemoteUpdateClient(address, port); + var ret = await remoteUpdater.UpdateBitstream(bitstreamNum, fileBytes.Value); + + if (ret.IsSuccessful) { - if (fileStream is null || fileStream.Length <= 0) - return TypedResults.BadRequest("Wrong bitstream, Please upload it again"); - - // 定义缓冲区大小: 32KB - byte[] buffer = new byte[32 * 1024]; - byte[] revBuffer = new byte[32 * 1024]; - long totalBytesRead = 0; - - // 使用异步流读取文件 - using (var memoryStream = new MemoryStream()) - { - int bytesRead; - while ((bytesRead = await fileStream.ReadAsync(buffer, 0, buffer.Length)) > 0) - { - // 反转 32bits - var retBuffer = Common.Number.ReverseBytes(buffer, 4); - if (!retBuffer.IsSuccessful) - return TypedResults.InternalServerError(retBuffer.Error); - revBuffer = retBuffer.Value; - // for (int i = 0; i < buffer.Length; i++) - // { - // revBuffer[i] = Common.Number.ReverseBits(revBuffer[i]); - // } - - await memoryStream.WriteAsync(revBuffer, 0, bytesRead); - totalBytesRead += bytesRead; - } - - // 将所有数据转换为字节数组(注意:如果文件非常大,可能不适合完全加载到内存) - var restStreamLen = memoryStream.Length % (4 * 1024); - if (restStreamLen != 0) - { - var appendLen = ((int)(4 * 1024 - restStreamLen)); - var bytesAppend = new byte[appendLen]; - Array.Fill(bytesAppend, 0xFF); - await memoryStream.WriteAsync(bytesAppend, 0, appendLen); - } - var fileBytes = memoryStream.ToArray(); - - // 下载比特流 - var remoteUpdater = new RemoteUpdate.RemoteUpdateClient(address, port); - var ret = await remoteUpdater.UpdateBitstream(bitstreamNum, fileBytes); - - if (ret.IsSuccessful) - { - logger.Info($"Device {address} Update bitstream successfully"); - return TypedResults.Ok(ret.Value); - } - else - { - logger.Error(ret.Error); - return TypedResults.InternalServerError(ret.Error); - } - } - + logger.Info($"Device {address} Update bitstream successfully"); + return TypedResults.Ok(ret.Value); + } + else + { + logger.Error(ret.Error); + return TypedResults.InternalServerError(ret.Error); } } @@ -479,6 +510,94 @@ public class RemoteUpdater : ControllerBase return TypedResults.InternalServerError(error); } } + + + /// + /// 下载多个比特流文件 + /// + /// 设备地址 + /// 设备端口 + /// 比特流编号 + /// 总共上传比特流的数量 + [HttpPost("DownloadMultiBitstreams")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status500InternalServerError)] + public async ValueTask DownloadMultiBitstreams(string address, int port, int? bitstreamNum) + { + // 检查文件 + var bitstreamsFolder = Path.Combine(Environment.CurrentDirectory, $"{BITSTREAM_PATH}/{address}"); + if (!Directory.Exists(bitstreamsFolder)) + return TypedResults.BadRequest("Empty bitstream, Please upload it first"); + + try + { + var bitstreams = new List() { null, null, null, null }; + int cnt = 0; // 上传比特流数量 + for (int i = 0; i < 4; i++) + { + var bitstreamDir = Path.Combine(bitstreamsFolder, i.ToString()); + if (!Directory.Exists(bitstreamDir)) + continue; + cnt++; + + // 读取文件 + var filePath = Directory.GetFiles(bitstreamDir)[0]; + var fileBytes = await ProcessBitstream(filePath); + if (!fileBytes.IsSuccessful) return TypedResults.InternalServerError(fileBytes.Error); + bitstreams[i] = fileBytes.Value; + } + + // 下载比特流 + var remoteUpdater = new RemoteUpdate.RemoteUpdateClient(address, port); + { + var ret = await remoteUpdater.UploadBitstreams(bitstreams[0], bitstreams[1], bitstreams[2], bitstreams[3]); + if (!ret.IsSuccessful) return TypedResults.InternalServerError(ret.Error); + if (!ret.Value) return TypedResults.InternalServerError("Upload MultiBitstreams failed"); + } + + if (bitstreamNum is not null) + { + var ret = await remoteUpdater.HotResetBitstream(bitstreamNum ?? 0); + if (!ret.IsSuccessful) return TypedResults.InternalServerError(ret.Error); + if (!ret.Value) return TypedResults.InternalServerError("Hot reset failed"); + } + return TypedResults.Ok(cnt); + } + catch (Exception error) + { + return TypedResults.InternalServerError(error); + } + } + + + /// + /// 热复位比特流文件 + /// + /// 设备地址 + /// 设备端口 + /// 比特流编号 + /// 操作结果 + [HttpPost("HotResetBitstream")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status500InternalServerError)] + public async ValueTask HotResetBitstream(string address, int port, int bitstreamNum) + { + var remoteUpdater = new RemoteUpdate.RemoteUpdateClient(address, port); + var ret = await remoteUpdater.HotResetBitstream(bitstreamNum); + + if (ret.IsSuccessful) + { + logger.Info($"Device {address}即可 Update bitstream successfully"); + return TypedResults.Ok(ret.Value); + } + else + { + logger.Error(ret.Error); + return TypedResults.InternalServerError(ret.Error); + } + } } diff --git a/server/src/RemoteUpdate.cs b/server/src/RemoteUpdate.cs index 330f33c..b6db774 100644 --- a/server/src/RemoteUpdate.cs +++ b/server/src/RemoteUpdate.cs @@ -1,4 +1,3 @@ -using System.Buffers.Binary; using System.Net; using DotNext; namespace RemoteUpdate; @@ -187,10 +186,6 @@ public class RemoteUpdateClient var bytesData = new byte[FLASH_SECTOR_LENGTH]; Array.Fill(bytesData, 0xFF); - // bytesData[FLASH_SECTOR_LENGTH - 4] = 0x80; // 0b10000000 - // bytesData[FLASH_SECTOR_LENGTH - 3] = 0xCC; // 0b11001100 - // bytesData[FLASH_SECTOR_LENGTH - 2] = 0xB4; // 0b10110100 - // bytesData[FLASH_SECTOR_LENGTH - 1] = 0x29; // 0b00101001 bytesData[FLASH_SECTOR_LENGTH - 1] = 0x01; bytesData[FLASH_SECTOR_LENGTH - 2] = 0x33; bytesData[FLASH_SECTOR_LENGTH - 3] = 0x2D; @@ -238,7 +233,6 @@ public class RemoteUpdateClient // Init data var bytesData = new byte[FLASH_SECTOR_LENGTH]; for (int i = 3; i < FLASH_SECTOR_LENGTH; i += 4) - // bytesData[i] = Common.Number.ReverseBits((byte)0xA0); bytesData[i] = (byte)0xA0; { @@ -273,54 +267,6 @@ public class RemoteUpdateClient var bytesSrc = new byte[] { 0x0F, 0x00, 0x00, 0x00 }; Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x48, 4); } - // { - // var bytesSrc = new byte[] { 0xAB, 0x00, 0x00, 0x01 }; - // for (int i = 0; i < 4; i++) - // bytesSrc[i] = Common.Number.ReverseBits(bytesSrc[i]); - // Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x04, 4); - // } - // { - // var bytesSrc = new byte[] { 0x00, 0x00, 0x00, 0x0B }; - // for (int i = 0; i < 4; i++) - // bytesSrc[i] = Common.Number.ReverseBits(bytesSrc[i]); - // Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x08, 4); - // } - // { - // var bytesSrc = new byte[] { 0xAB, 0xC0, 0x00, 0x01 }; - // for (int i = 0; i < 4; i++) - // bytesSrc[i] = Common.Number.ReverseBits(bytesSrc[i]); - // Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x34, 4); - // } - // { - // var bytesSrc = new byte[] { 0x00, 0x00, 0x00, 0x00 }; - // for (int i = 0; i < 4; i++) - // bytesSrc[i] = Common.Number.ReverseBits(bytesSrc[i]); - // Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x38, 4); - // } - // { - // var bytesSrc = new byte[] { 0xAC, 0x00, 0x00, 0x01 }; - // for (int i = 0; i < 4; i++) - // bytesSrc[i] = Common.Number.ReverseBits(bytesSrc[i]); - // Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x3C, 4); - // } - // { - // var bytesSrc = Common.Number.NumberToBytes(FlashAddr.Bitstream[bitstreamNum], 4).Value; - // for (int i = 0; i < 4; i++) - // bytesSrc[i] = Common.Number.ReverseBits(bytesSrc[i]); - // Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x40, 4); - // } - // { - // var bytesSrc = new byte[] { 0xA8, 0x80, 0x00, 0x01 }; - // for (int i = 0; i < 4; i++) - // bytesSrc[i] = Common.Number.ReverseBits(bytesSrc[i]); - // Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x44, 4); - // } - // { - // var bytesSrc = new byte[] { 0x00, 0x00, 0x00, 0x0F }; - // for (int i = 0; i < 4; i++) - // bytesSrc[i] = Common.Number.ReverseBits(bytesSrc[i]); - // Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x48, 4); - // } var ret = await WriteFlash(FlashAddr.Jump[bitstreamNum], 1, bytesData); if (!ret.IsSuccessful) return new(ret.Error); @@ -402,8 +348,8 @@ public class RemoteUpdateClient var remoteCRC = Common.Number.BytesToUInt32(bytes); if (!remoteCRC.IsSuccessful) return new(remoteCRC.Error); - logger.Debug($"Expected CRC: \t 0x{Convert.ToString(checkSum, 16)}"); - logger.Debug($"Received CRC: \t 0x{Convert.ToString(remoteCRC.Value, 16)}"); + logger.Debug($"Bitstream {bitstreamNum} Expected CRC: \t 0x{Convert.ToString(checkSum, 16)}"); + logger.Debug($"Bitstream {bitstreamNum} Received CRC: \t 0x{Convert.ToString(remoteCRC.Value, 16)}"); return remoteCRC.Value == checkSum; } @@ -414,7 +360,7 @@ public class RemoteUpdateClient /// /// [TODO:parameter] /// [TODO:return] - private async ValueTask> HotRest(int bitstreamNum) + private async ValueTask> HotReset(int bitstreamNum) { // Assert if (bitstreamNum < 0 || bitstreamNum > 3) @@ -428,6 +374,81 @@ public class RemoteUpdateClient return ret.Value; } + /// + /// [TODO:description] + /// + /// [TODO:parameter] + /// [TODO:return] + public async ValueTask> HotResetBitstream(int bitstreamNum) + { + await MsgBus.UDPServer.ClearUDPData(this.address); + logger.Trace("Clear udp data finished"); + + { + var ret = await InitRemoteUpdate(bitstreamNum); + if (!ret.IsSuccessful) return new(ret.Error); + if (!ret.Value) return new(new Exception("Init remote update failed")); + } + + { + var ret = await HotReset(bitstreamNum); + if (!ret.IsSuccessful) return new(ret.Error); + return ret.Value; + } + } + + /// + /// [TODO:description] + /// + /// [TODO:parameter] + /// [TODO:parameter] + /// [TODO:parameter] + /// [TODO:parameter] + /// [TODO:return] + public async ValueTask> UploadBitstreams( + byte[]? goldenBitream, + byte[]? bitstream1, + byte[]? bitstream2, + byte[]? bitstream3) + { + await MsgBus.UDPServer.ClearUDPData(this.address); + logger.Trace("Clear udp data finished"); + + for (int bitstreamNum = 0; bitstreamNum < 4; bitstreamNum++) + { + byte[] bytesData; + if (bitstreamNum == 0 && goldenBitream is not null) + bytesData = goldenBitream; + else if (bitstreamNum == 1 && bitstream1 is not null) + bytesData = bitstream1; + else if (bitstreamNum == 2 && bitstream2 is not null) + bytesData = bitstream2; + else if (bitstreamNum == 3 && bitstream3 is not null) + bytesData = bitstream3; + else continue; + + var bitstreamBlockNum = bytesData.Length / (4 * 1024); + + { + var ret = await WriteFlash(FlashAddr.Bitstream[bitstreamNum], bitstreamBlockNum, bytesData); + if (!ret.IsSuccessful) return new(ret.Error); + if (!ret.Value) return new(new Exception("Write bitstream failed")); + } + + { + var crc = Honoo.IO.Hashing.Crc.Create(Honoo.IO.Hashing.CrcName.CRC32_MPEG_2); + var checkSum = crc.ComputeFinal(bytesData); + var ret = await CheckBitstreamCRC(bitstreamNum, bitstreamBlockNum, checkSum.ToUInt32()); + if (!ret.IsSuccessful) return new(ret.Error); + if (!ret.Value) logger.Warn($"Bitstream {bitstreamNum} CRC32 not correct!"); + else logger.Info($"Bitstream {bitstreamNum} CRC32 calibration passed"); + } + + } + + return true; + } + /// /// [TODO:description] /// @@ -466,7 +487,7 @@ public class RemoteUpdateClient } { - var ret = await HotRest(bitstreamNum); + var ret = await HotReset(bitstreamNum); if (!ret.IsSuccessful) return new(ret.Error); return ret.Value; } @@ -475,33 +496,40 @@ public class RemoteUpdateClient /// /// [TODO:description] /// - /// [TODO:parameter] + /// [TODO:parameter] + /// [TODO:parameter] + /// [TODO:parameter] + /// [TODO:parameter] + /// [TODO:parameter] /// [TODO:return] - public async ValueTask> HotResetBitstream(int bitstreamNum) - { - await MsgBus.UDPServer.ClearUDPData(this.address); - logger.Trace("Clear udp data finished"); - - { - var ret = await InitRemoteUpdate(bitstreamNum); - if (!ret.IsSuccessful) return new(ret.Error); - if (!ret.Value) return new(new Exception("Init remote update failed")); - } - - { - var ret = await HotRest(bitstreamNum); - if (!ret.IsSuccessful) return new(ret.Error); - return ret.Value; - } - } - - public async ValueTask> UploadBitstreams( + public async ValueTask> UpdateBitstreams( int enableBitstreamNum, byte[]? goldenBitream, byte[]? bitstream1, byte[]? bitstream2, byte[]? bitstream3) { - return true; + // Assert + if (goldenBitream is null && bitstream1 is null && bitstream2 is null && bitstream3 is null) + return new(new ArgumentException( + $"At least one bitstream should not be empty")); + if ((enableBitstreamNum == 0 && goldenBitream is null) || + (enableBitstreamNum == 1 && bitstream1 is null) || + (enableBitstreamNum == 2 && bitstream2 is null) || + (enableBitstreamNum == 3 && bitstream3 is null)) + return new(new ArgumentException($"Bitstream {enableBitstreamNum} shouldn't be empty")); + + { + var ret = await UploadBitstreams(goldenBitream, bitstream1, bitstream2, bitstream3); + if (!ret.IsSuccessful) return new(ret.Error); + if (!ret.Value) return false; + } + + { + var ret = await HotResetBitstream(enableBitstreamNum); + if (!ret.IsSuccessful) return new(ret.Error); + return ret.Value; + } } + }