add remote update
This commit is contained in:
		@@ -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)
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user