add remote update

This commit is contained in:
SikongJueluo 2025-04-27 21:53:02 +08:00
parent f35a295af2
commit 3f77a1a426
No known key found for this signature in database
6 changed files with 480 additions and 64 deletions

View File

@ -44,12 +44,12 @@ namespace Common
}
/// <summary>
/// 二进制字节数组转成整数
/// 二进制字节数组转成64bits整数
/// </summary>
/// <param name="bytes">二进制字节数组</param>
/// <param name="isRightHigh">是否高位在右边</param>
/// <returns>整数</returns>
public static Result<ulong> BytesToNumber(byte[] bytes, bool isRightHigh = false)
public static Result<UInt64> 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);
}
}
/// <summary>
/// 二进制字节数组转成32bits整数
/// </summary>
/// <param name="bytes">二进制字节数组</param>
/// <param name="isRightHigh">是否高位在右边</param>
/// <returns>整数</returns>
public static Result<UInt32> 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);
}
}
/// <summary>
@ -152,6 +203,12 @@ namespace Common
return (srcBits & mask) == dstBits;
}
/// <summary>
/// 获取整型对应位置的比特
/// </summary>
/// <param name="srcBits">整型数字</param>
/// <param name="location">位置</param>
/// <returns>比特</returns>
public static Result<bool> ToBit(UInt32 srcBits, int location)
{
if (location < 0)

View File

@ -347,6 +347,137 @@ public class JtagController : ControllerBase
}
}
/// <summary>
/// 远程更新
/// </summary>
[ApiController]
[Route("api/[controller]")]
public class RemoteUpdater : ControllerBase
{
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
/// <summary>
/// 上传远程更新比特流文件
/// </summary>
/// <param name="address"> 设备地址 </param>
/// <param name="file">比特流文件</param>
[HttpPost("UploadBitstream")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async ValueTask<IResult> UploadBitstream(string address, IFormFile file)
{
if (file == null || file.Length == 0)
return TypedResults.BadRequest("未选择文件");
// 生成安全的文件名(避免路径遍历攻击)
var fileName = Path.GetRandomFileName();
var uploadsFolder = Path.Combine(Environment.CurrentDirectory, $"bitstream/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");
}
/// <summary>
/// 远程更新比特流文件
/// </summary>
/// <param name="address"> 设备地址 </param>
/// <param name="port"> 设备端口 </param>
/// <param name="bitstreamNum"> 比特流位号 </param>
[HttpPost("DownloadBitstream")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async ValueTask<IResult> 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);
}
}
}
/// <summary>
/// 日志控制器
/// </summary>

View File

@ -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);
}
/// <summary>
@ -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;

View File

@ -12,54 +12,54 @@ static class Global
/// <summary>
/// 基地址
/// </summary>
public const UInt32 BaseAddr = 0x3000_0000;
public const UInt32 BaseAddr = 0x2000_0000;
/// <summary>
/// 写比特流-读写地址——控制位
/// [31:24]: 保留
/// [23:17]: 保留
/// [16: 8]: 保留
/// [ 7: 0]: {-, -, -, -, -,{bitstream_wr_num}, flash_wr_en}
/// 写比特流-读写地址——控制位 <br/>
/// [31:24]: 保留 <br/>
/// [23:17]: 保留 <br/>
/// [16: 8]: 保留 <br/>
/// [ 7: 0]: {-, -, -, -, -,{bitstream_wr_num}, flash_wr_en} <br/>
/// </summary>
public const UInt32 WriteCtrl = 0x3000_0000;
public const UInt32 WriteCtrl = 0x2000_0000;
/// <summary>
/// 写比特流-只写地址——FIFO入口
/// [31:0]: 写比特流数据入口
/// </summary>
public const UInt32 WriteFIFO = 0x3000_0001;
public const UInt32 WriteFIFO = 0x2000_0001;
/// <summary>
/// 写比特流-只读地址——标志位
/// [31:24]: {-, -, -, -, -, -, -, wr_fifo_full}
/// [23:17]: {-, -, -, -, -, -, -, wr_fifo_empty}
/// [16: 8]: {-, -, -, -, -, -, -, bitstream_wr_done}
/// [ 7: 0]: {-, -, -, -, -, -, -, clear_bs_done}
/// 写比特流-只读地址——标志位 <br/>
/// [31:24]: {-, -, -, -, -, -, -, wr_fifo_full} <br/>
/// [23:17]: {-, -, -, -, -, -, -, wr_fifo_empty} <br/>
/// [16: 8]: {-, -, -, -, -, -, -, bitstream_wr_done} <br/>
/// [ 7: 0]: {-, -, -, -, -, -, -, clear_bs_done} <br/>
/// </summary>
public const UInt32 WriteSign = 0x3000_0002;
public const UInt32 WriteSign = 0x2000_0002;
/// <summary>
/// 读比特流-读写地址——控制位
/// [31:24]: {-, -, -, -, -, -,{ bs_crc32_ok }}
/// [23:17]: {-, -, -, -, -, -, -, crc_check_en}
/// [16: 8]: {-, -, -, -, -, -, -, bitstream_up2cpu_en}
/// [ 7: 0]: {-, -, -, -, -,{bitstream_rd_num},flash_rd_en}
/// 读比特流-读写地址——控制位 <br/>
/// [31:24]: {-, -, -, -, -, -,{ bs_crc32_ok }} <br/>
/// [23:17]: {-, -, -, -, -, -, -, crc_check_en} <br/>
/// [16: 8]: {-, -, -, -, -, -, -, bitstream_up2cpu_en} <br/>
/// [ 7: 0]: {-, -, -, -, -,{bitstream_rd_num},flash_rd_en} <br/>
/// </summary>
public const UInt32 ReadCtrl = 0x3000_0003;
public const UInt32 ReadCtrl = 0x2000_0003;
/// <summary>
/// 读比特流-只读地址——FIFO出口
/// [31:0]: 读比特流数据出口
/// </summary>
public const UInt32 ReadFIFO = 0x3000_0004;
public const UInt32 ReadFIFO = 0x2000_0004;
/// <summary>
/// 读比特流-只读地址——CRC校验值
/// [31:0]: CRC校验值 bs_readback_crc
/// </summary>
public const UInt32 ReadCRC = 0x3000_0005;
public const UInt32 ReadCRC = 0x2000_0005;
/// <summary>
/// 读比特流-只读地址——标志位
/// [31:24]: {-, -, -, -, -, -, -, rd_fifo_afull}
/// [23:17]: {-, -, -, -, -, -, -, rd_fifo_empty}
/// [16: 8]: {-, -, -, -, -, -, -, bitstream_rd_done}
/// [ 7: 0]: {-, -, -, -, -, -, -, bs_readback_crc_valid}
/// 读比特流-只读地址——标志位 <br/>
/// [31:24]: {-, -, -, -, -, -, -, rd_fifo_afull} <br/>
/// [23:17]: {-, -, -, -, -, -, -, rd_fifo_empty} <br/>
/// [16: 8]: {-, -, -, -, -, -, -, bitstream_rd_done} <br/>
/// [ 7: 0]: {-, -, -, -, -, -, -, bs_readback_crc_valid} <br/>
/// </summary>
public const UInt32 ReadSign = 0x3000_0006;
public const UInt32 ReadSign = 0x2000_0006;
/// <summary>
/// 单独擦除开关-读写地址——控制位
/// [31:24]: {-, -, -, -, -, -, -, - }
@ -67,15 +67,15 @@ static class Global
/// [16: 8]: {-, -, -, -, -, -, -, - }
/// [ 7: 0]: {-, -, -, -, -, -, -, clear_sw_en}
/// </summary>
public const UInt32 ClearCtrl = 0x3000_0007;
public const UInt32 ClearCtrl = 0x2000_0007;
/// <summary>
/// 单独擦除开关-只读地址——标志位
/// [31:24]: {-, -, -, -, -, -, -, time_out_reg}
/// [23:17]: { flash_flag_status[15:8]}
/// [16: 8]: { flash_flag_status[7:0]}
/// [ 7: 0]: {-, -, -, -, -, -, -, clear_sw_done}
/// 单独擦除开关-只读地址——标志位 <br/>
/// [31:24]: {-, -, -, -, -, -, -, time_out_reg} <br/>
/// [23:17]: { flash_flag_status[15:8]} <br/>
/// [16: 8]: { flash_flag_status[7:0]} <br/>
/// [ 7: 0]: {-, -, -, -, -, -, -, clear_sw_done} <br/>
/// </summary>
public const UInt32 ClearSign = 0x3000_0008;
public const UInt32 ClearSign = 0x2000_0008;
/// <summary>
/// 写开关-读写地址——标志位
/// [31:24]: {-, -, -, -, -, -, -, - }
@ -83,7 +83,7 @@ static class Global
/// [16: 8]: {-, -, -, -, -, -, { open_sw_num}}
/// [ 7: 0]: {-, -, -, -, -, -, -, write_sw_code_en}
/// </summary>
public const UInt32 WriteSwitchSign = 0x3000_0009;
public const UInt32 WriteSwitchSign = 0x2000_0009;
/// <summary>
/// 写开关-只读地址——控制位
/// [31:24]: {-, -, -, -, -, -, -, - }
@ -91,7 +91,7 @@ static class Global
/// [16: 8]: {-, -, -, -, -, -, -, ipal_busy}
/// [ 7: 0]: {-, -, -, -, -, -, -, open_sw_code_done}
/// </summary>
public const UInt32 WriteSwitchCtrl = 0x3000_0010;
public const UInt32 WriteSwitchCtrl = 0x2000_0010;
/// <summary>
/// 热启动开关-读写地址——控制位
/// [31:24]: {-, -, -, -, -, -, -, - }
@ -99,7 +99,7 @@ static class Global
/// [16: 8]: {-, -, -, -, -, -, }
/// [ 7: 0]: {-, -, -, -, -, -, -, hotreset_en}
/// </summary>
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<Result<bool>> UpdateBitstream(int bitstreamNum, byte[] bitstream)
/// <summary>
/// [TODO:description]
/// </summary>
/// <param name="bitstreamNum">[TODO:parameter]</param>
/// <param name="bitstream">[TODO:parameter]</param>
/// <returns>[TODO:return]</returns>
public async ValueTask<Result<bool>> 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;
}
/// <summary>
/// [TODO:description]
/// </summary>
/// <param name="bitstreamNum">[TODO:parameter]</param>
/// <param name="checkSum">[TODO:parameter]</param>
/// <returns>[TODO:return]</returns>
public async ValueTask<Result<bool>> 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;
}
}
/// <summary>
/// [TODO:description]
/// </summary>
/// <param name="bitstreamNum">[TODO:parameter]</param>
/// <param name="bitstream">[TODO:parameter]</param>
/// <returns>[TODO:return]</returns>
public async ValueTask<Result<bool>> 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;
}
}
}

View File

@ -204,9 +204,90 @@ public class UDPClientPool
return retPack;
}
public static async ValueTask<Result<RecvDataPackage>> ReadAddrWithCheck(
IPEndPoint endPoint, uint devAddr, int timeout = 1000)
/// <summary>
/// [TODO:description]
/// </summary>
/// <param name="endPoint">[TODO:parameter]</param>
/// <param name="devAddr">[TODO:parameter]</param>
/// <param name="result">[TODO:parameter]</param>
/// <param name="resultMask">[TODO:parameter]</param>
/// <param name="timeout">[TODO:parameter]</param>
/// <returns>[TODO:return]</returns>
public static async ValueTask<Result<bool>> 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);
}
}
/// <summary>
/// [TODO:description]
/// </summary>
/// <param name="endPoint">[TODO:parameter]</param>
/// <param name="devAddr">[TODO:parameter]</param>
/// <param name="result">[TODO:parameter]</param>
/// <param name="resultMask">[TODO:parameter]</param>
/// <param name="timeout">[TODO:parameter]</param>
/// <returns>[TODO:return]</returns>
public static async ValueTask<Result<bool>> 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;
}
/// <summary>
/// [TODO:description]
/// </summary>
/// <param name="endPoint">[TODO:parameter]</param>
/// <param name="devAddr">[TODO:parameter]</param>
/// <param name="dataArray">[TODO:parameter]</param>
/// <param name="timeout">[TODO:parameter]</param>
/// <returns>[TODO:return]</returns>
public static async ValueTask<Result<bool>> 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;
}
}

View File

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