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));
}
}