From c6b819f24f7d47ed1a16e6b10215833150775b90 Mon Sep 17 00:00:00 2001 From: SikongJueluo Date: Sun, 4 May 2025 16:38:40 +0800 Subject: [PATCH] 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; } } - }