From 3f77a1a426ea8694cc32e8283fd3985d5aa9245a Mon Sep 17 00:00:00 2001 From: SikongJueluo Date: Sun, 27 Apr 2025 21:53:02 +0800 Subject: [PATCH] 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)); } }