add remote update
This commit is contained in:
parent
f35a295af2
commit
3f77a1a426
|
@ -44,12 +44,12 @@ namespace Common
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 二进制字节数组转成整数
|
/// 二进制字节数组转成64bits整数
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="bytes">二进制字节数组</param>
|
/// <param name="bytes">二进制字节数组</param>
|
||||||
/// <param name="isRightHigh">是否高位在右边</param>
|
/// <param name="isRightHigh">是否高位在右边</param>
|
||||||
/// <returns>整数</returns>
|
/// <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)
|
if (bytes.Length > 8)
|
||||||
{
|
{
|
||||||
|
@ -59,27 +59,78 @@ namespace Common
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
ulong num = 0;
|
UInt64 num = 0;
|
||||||
int len = bytes.Length;
|
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
|
||||||
else
|
|
||||||
{
|
|
||||||
for (var i = 0; i < len; i++)
|
|
||||||
{
|
{
|
||||||
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>
|
/// <summary>
|
||||||
|
@ -152,6 +203,12 @@ namespace Common
|
||||||
return (srcBits & mask) == dstBits;
|
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)
|
public static Result<bool> ToBit(UInt32 srcBits, int location)
|
||||||
{
|
{
|
||||||
if (location < 0)
|
if (location < 0)
|
||||||
|
|
|
@ -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>
|
||||||
/// 日志控制器
|
/// 日志控制器
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -428,7 +428,7 @@ public class Jtag
|
||||||
if (retPackLen != 4)
|
if (retPackLen != 4)
|
||||||
return new(new Exception($"RecvDataPackage BodyData Length not Equal to 4: Total {retPackLen} bytes"));
|
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>
|
/// <summary>
|
||||||
|
@ -558,7 +558,7 @@ public class Jtag
|
||||||
return new(new Exception($"RecvDataPackage BodyData Length not Equal to 4: Total {retPackLen} bytes"));
|
return new(new Exception($"RecvDataPackage BodyData Length not Equal to 4: Total {retPackLen} bytes"));
|
||||||
|
|
||||||
if (Common.Number.BitsCheck(
|
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;
|
ret = true;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -578,7 +578,7 @@ public class Jtag
|
||||||
return new(new Exception($"RecvDataPackage BodyData Length not Equal to 4: Total {retPackLen} bytes"));
|
return new(new Exception($"RecvDataPackage BodyData Length not Equal to 4: Total {retPackLen} bytes"));
|
||||||
|
|
||||||
if (Common.Number.BitsCheck(
|
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;
|
ret = true;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -12,54 +12,54 @@ static class Global
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 基地址
|
/// 基地址
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const UInt32 BaseAddr = 0x3000_0000;
|
public const UInt32 BaseAddr = 0x2000_0000;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 写比特流-读写地址——控制位
|
/// 写比特流-读写地址——控制位 <br/>
|
||||||
/// [31:24]: 保留
|
/// [31:24]: 保留 <br/>
|
||||||
/// [23:17]: 保留
|
/// [23:17]: 保留 <br/>
|
||||||
/// [16: 8]: 保留
|
/// [16: 8]: 保留 <br/>
|
||||||
/// [ 7: 0]: {-, -, -, -, -,{bitstream_wr_num}, flash_wr_en}
|
/// [ 7: 0]: {-, -, -, -, -,{bitstream_wr_num}, flash_wr_en} <br/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const UInt32 WriteCtrl = 0x3000_0000;
|
public const UInt32 WriteCtrl = 0x2000_0000;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 写比特流-只写地址——FIFO入口
|
/// 写比特流-只写地址——FIFO入口
|
||||||
/// [31:0]: 写比特流数据入口
|
/// [31:0]: 写比特流数据入口
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const UInt32 WriteFIFO = 0x3000_0001;
|
public const UInt32 WriteFIFO = 0x2000_0001;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 写比特流-只读地址——标志位
|
/// 写比特流-只读地址——标志位 <br/>
|
||||||
/// [31:24]: {-, -, -, -, -, -, -, wr_fifo_full}
|
/// [31:24]: {-, -, -, -, -, -, -, wr_fifo_full} <br/>
|
||||||
/// [23:17]: {-, -, -, -, -, -, -, wr_fifo_empty}
|
/// [23:17]: {-, -, -, -, -, -, -, wr_fifo_empty} <br/>
|
||||||
/// [16: 8]: {-, -, -, -, -, -, -, bitstream_wr_done}
|
/// [16: 8]: {-, -, -, -, -, -, -, bitstream_wr_done} <br/>
|
||||||
/// [ 7: 0]: {-, -, -, -, -, -, -, clear_bs_done}
|
/// [ 7: 0]: {-, -, -, -, -, -, -, clear_bs_done} <br/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const UInt32 WriteSign = 0x3000_0002;
|
public const UInt32 WriteSign = 0x2000_0002;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 读比特流-读写地址——控制位
|
/// 读比特流-读写地址——控制位 <br/>
|
||||||
/// [31:24]: {-, -, -, -, -, -,{ bs_crc32_ok }}
|
/// [31:24]: {-, -, -, -, -, -,{ bs_crc32_ok }} <br/>
|
||||||
/// [23:17]: {-, -, -, -, -, -, -, crc_check_en}
|
/// [23:17]: {-, -, -, -, -, -, -, crc_check_en} <br/>
|
||||||
/// [16: 8]: {-, -, -, -, -, -, -, bitstream_up2cpu_en}
|
/// [16: 8]: {-, -, -, -, -, -, -, bitstream_up2cpu_en} <br/>
|
||||||
/// [ 7: 0]: {-, -, -, -, -,{bitstream_rd_num},flash_rd_en}
|
/// [ 7: 0]: {-, -, -, -, -,{bitstream_rd_num},flash_rd_en} <br/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const UInt32 ReadCtrl = 0x3000_0003;
|
public const UInt32 ReadCtrl = 0x2000_0003;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 读比特流-只读地址——FIFO出口
|
/// 读比特流-只读地址——FIFO出口
|
||||||
/// [31:0]: 读比特流数据出口
|
/// [31:0]: 读比特流数据出口
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const UInt32 ReadFIFO = 0x3000_0004;
|
public const UInt32 ReadFIFO = 0x2000_0004;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 读比特流-只读地址——CRC校验值
|
/// 读比特流-只读地址——CRC校验值
|
||||||
/// [31:0]: CRC校验值 bs_readback_crc
|
/// [31:0]: CRC校验值 bs_readback_crc
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const UInt32 ReadCRC = 0x3000_0005;
|
public const UInt32 ReadCRC = 0x2000_0005;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 读比特流-只读地址——标志位
|
/// 读比特流-只读地址——标志位 <br/>
|
||||||
/// [31:24]: {-, -, -, -, -, -, -, rd_fifo_afull}
|
/// [31:24]: {-, -, -, -, -, -, -, rd_fifo_afull} <br/>
|
||||||
/// [23:17]: {-, -, -, -, -, -, -, rd_fifo_empty}
|
/// [23:17]: {-, -, -, -, -, -, -, rd_fifo_empty} <br/>
|
||||||
/// [16: 8]: {-, -, -, -, -, -, -, bitstream_rd_done}
|
/// [16: 8]: {-, -, -, -, -, -, -, bitstream_rd_done} <br/>
|
||||||
/// [ 7: 0]: {-, -, -, -, -, -, -, bs_readback_crc_valid}
|
/// [ 7: 0]: {-, -, -, -, -, -, -, bs_readback_crc_valid} <br/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const UInt32 ReadSign = 0x3000_0006;
|
public const UInt32 ReadSign = 0x2000_0006;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 单独擦除开关-读写地址——控制位
|
/// 单独擦除开关-读写地址——控制位
|
||||||
/// [31:24]: {-, -, -, -, -, -, -, - }
|
/// [31:24]: {-, -, -, -, -, -, -, - }
|
||||||
|
@ -67,15 +67,15 @@ static class Global
|
||||||
/// [16: 8]: {-, -, -, -, -, -, -, - }
|
/// [16: 8]: {-, -, -, -, -, -, -, - }
|
||||||
/// [ 7: 0]: {-, -, -, -, -, -, -, clear_sw_en}
|
/// [ 7: 0]: {-, -, -, -, -, -, -, clear_sw_en}
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const UInt32 ClearCtrl = 0x3000_0007;
|
public const UInt32 ClearCtrl = 0x2000_0007;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 单独擦除开关-只读地址——标志位
|
/// 单独擦除开关-只读地址——标志位 <br/>
|
||||||
/// [31:24]: {-, -, -, -, -, -, -, time_out_reg}
|
/// [31:24]: {-, -, -, -, -, -, -, time_out_reg} <br/>
|
||||||
/// [23:17]: { flash_flag_status[15:8]}
|
/// [23:17]: { flash_flag_status[15:8]} <br/>
|
||||||
/// [16: 8]: { flash_flag_status[7:0]}
|
/// [16: 8]: { flash_flag_status[7:0]} <br/>
|
||||||
/// [ 7: 0]: {-, -, -, -, -, -, -, clear_sw_done}
|
/// [ 7: 0]: {-, -, -, -, -, -, -, clear_sw_done} <br/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const UInt32 ClearSign = 0x3000_0008;
|
public const UInt32 ClearSign = 0x2000_0008;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 写开关-读写地址——标志位
|
/// 写开关-读写地址——标志位
|
||||||
/// [31:24]: {-, -, -, -, -, -, -, - }
|
/// [31:24]: {-, -, -, -, -, -, -, - }
|
||||||
|
@ -83,7 +83,7 @@ static class Global
|
||||||
/// [16: 8]: {-, -, -, -, -, -, { open_sw_num}}
|
/// [16: 8]: {-, -, -, -, -, -, { open_sw_num}}
|
||||||
/// [ 7: 0]: {-, -, -, -, -, -, -, write_sw_code_en}
|
/// [ 7: 0]: {-, -, -, -, -, -, -, write_sw_code_en}
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const UInt32 WriteSwitchSign = 0x3000_0009;
|
public const UInt32 WriteSwitchSign = 0x2000_0009;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 写开关-只读地址——控制位
|
/// 写开关-只读地址——控制位
|
||||||
/// [31:24]: {-, -, -, -, -, -, -, - }
|
/// [31:24]: {-, -, -, -, -, -, -, - }
|
||||||
|
@ -91,7 +91,7 @@ static class Global
|
||||||
/// [16: 8]: {-, -, -, -, -, -, -, ipal_busy}
|
/// [16: 8]: {-, -, -, -, -, -, -, ipal_busy}
|
||||||
/// [ 7: 0]: {-, -, -, -, -, -, -, open_sw_code_done}
|
/// [ 7: 0]: {-, -, -, -, -, -, -, open_sw_code_done}
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const UInt32 WriteSwitchCtrl = 0x3000_0010;
|
public const UInt32 WriteSwitchCtrl = 0x2000_0010;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 热启动开关-读写地址——控制位
|
/// 热启动开关-读写地址——控制位
|
||||||
/// [31:24]: {-, -, -, -, -, -, -, - }
|
/// [31:24]: {-, -, -, -, -, -, -, - }
|
||||||
|
@ -99,7 +99,7 @@ static class Global
|
||||||
/// [16: 8]: {-, -, -, -, -, -, }
|
/// [16: 8]: {-, -, -, -, -, -, }
|
||||||
/// [ 7: 0]: {-, -, -, -, -, -, -, hotreset_en}
|
/// [ 7: 0]: {-, -, -, -, -, -, -, hotreset_en}
|
||||||
/// </summary>
|
/// </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();
|
private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
const int timeout = 1000;
|
readonly int timeout = 1000;
|
||||||
|
|
||||||
int port { get; }
|
int port { get; }
|
||||||
string address { get; }
|
string address { get; }
|
||||||
|
@ -129,7 +129,13 @@ public class RemoteUpdater
|
||||||
this.remoteEP = new IPEndPoint(IPAddress.Parse(address), port);
|
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)
|
if (bitstreamNum < 0 || bitstreamNum > 0b11)
|
||||||
return new(new ArgumentException(
|
return new(new ArgumentException(
|
||||||
|
@ -149,18 +155,105 @@ public class RemoteUpdater
|
||||||
var ret = await UDPClientPool.WriteAddr(
|
var ret = await UDPClientPool.WriteAddr(
|
||||||
this.remoteEP, Global.RemoteUpdaterAddr.WriteCtrl, (UInt32)((bitstreamNum << 1) | 0b1), timeout);
|
this.remoteEP, Global.RemoteUpdaterAddr.WriteCtrl, (UInt32)((bitstreamNum << 1) | 0b1), timeout);
|
||||||
if (!ret.IsSuccessful) return new(ret.Error);
|
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(
|
var ret = await UDPClientPool.WriteAddr(this.remoteEP, Global.RemoteUpdaterAddr.WriteFIFO, bitstream);
|
||||||
this.remoteEP, Global.RemoteUpdaterAddr.ClearSign, timeout);
|
|
||||||
if (!ret.IsSuccessful) return new(ret.Error);
|
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;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -204,9 +204,90 @@ public class UDPClientPool
|
||||||
return retPack;
|
return retPack;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async ValueTask<Result<RecvDataPackage>> ReadAddrWithCheck(
|
/// <summary>
|
||||||
IPEndPoint endPoint, uint devAddr, int timeout = 1000)
|
/// [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;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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));
|
return new SendAddrPackage(bytes[1], bytes[2], Convert.ToUInt32(address));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue