Compare commits
No commits in common. "master" and "dpp" have entirely different histories.
|
@ -22,7 +22,6 @@
|
|||
sqlite
|
||||
sqls
|
||||
sql-studio
|
||||
zlib
|
||||
# Backend
|
||||
(dotnetCorePackages.combinePackages [
|
||||
dotnetCorePackages.sdk_9_0
|
||||
|
@ -38,8 +37,7 @@
|
|||
typescript-language-server
|
||||
];
|
||||
shellHook = ''
|
||||
export PATH=$PATH:
|
||||
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${pkgs.zlib}/lib
|
||||
export PATH=$PATH:$HOME/.bun/bin
|
||||
'';
|
||||
|
||||
};
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
using System.Buffers.Binary;
|
||||
using Common;
|
||||
|
||||
namespace server.test;
|
||||
|
@ -41,21 +40,9 @@ public class CommonTest
|
|||
[Fact]
|
||||
public void ToBitTest()
|
||||
{
|
||||
Assert.Equal(true, Number.ToBit(0xFF, 3).Value);
|
||||
Assert.Equal(false, Number.ToBit(0x00, 3).Value);
|
||||
Assert.Equal(true, Number.ToBit(0xAA, 3).Value);
|
||||
Assert.Equal(false, Number.ToBit(0xAA, 2).Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReverseBits()
|
||||
{
|
||||
Assert.Equal((byte)0x05, Common.Number.ReverseBits((byte)0xA0));
|
||||
|
||||
var bytesSrc = new byte[] { 0xAB, 0x00, 0x00, 0x01 };
|
||||
var bytes = new byte[4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
bytes[i] = Common.Number.ReverseBits(bytesSrc[i]);
|
||||
Assert.Equal(new byte[] { 0xD5, 0x00, 0x00, 0x80 }, bytes);
|
||||
Assert.Equal(Number.ToBit(0xFF, 3).Value, true);
|
||||
Assert.Equal(Number.ToBit(0x00, 3).Value, false);
|
||||
Assert.Equal(Number.ToBit(0xAA, 3).Value, true);
|
||||
Assert.Equal(Number.ToBit(0xAA, 2).Value, false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,7 +92,7 @@ public class UDPServerTest
|
|||
Assert.True(ret.HasValue);
|
||||
var data = ret.Value;
|
||||
Assert.Equal(address, data.Address);
|
||||
Assert.Equal(number, Number.BytesToUInt32(data.Data).Value);
|
||||
Assert.Equal(number, Number.BytesToNumber(data.Data));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -112,7 +112,7 @@ public class UDPServerTest
|
|||
Assert.True(ret.IsSuccessful);
|
||||
var data = ret.Value;
|
||||
Assert.True(data.IsSuccessful);
|
||||
Assert.Equal(number, Number.BytesToUInt32(data.ToBytes()).Value);
|
||||
Assert.Equal(number, Number.BytesToNumber(data.ToBytes()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,7 +132,7 @@ public class UDPServerTest
|
|||
Assert.True(ret.IsSuccessful);
|
||||
var data = ret.Value;
|
||||
Assert.True(data.IsSuccessful);
|
||||
Assert.Equal((UInt64)number, Number.BytesToUInt64(data.ToBytes()).Value);
|
||||
Assert.Equal(number, Number.BytesToNumber(data.ToBytes()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,17 +37,16 @@ try
|
|||
});
|
||||
|
||||
// Add CORS policy
|
||||
if (builder.Environment.IsDevelopment())
|
||||
builder.Services.AddCors(options =>
|
||||
{
|
||||
builder.Services.AddCors(options =>
|
||||
options.AddPolicy("Development", policy =>
|
||||
{
|
||||
options.AddPolicy("Development", policy => policy
|
||||
policy
|
||||
.AllowAnyOrigin()
|
||||
.AllowAnyMethod()
|
||||
.AllowAnyHeader()
|
||||
);
|
||||
.AllowAnyHeader();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Add Swagger
|
||||
builder.Services.AddControllers();
|
||||
|
|
|
@ -13,15 +13,12 @@
|
|||
<ItemGroup>
|
||||
<PackageReference Include="DotNext" Version="5.19.1" />
|
||||
<PackageReference Include="DotNext.Threading" Version="5.19.1" />
|
||||
<PackageReference Include="Honoo.IO.Hashing.Crc" Version="1.3.3" />
|
||||
<PackageReference Include="linq2db.AspNet" Version="5.4.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="9.0.4" />
|
||||
<PackageReference Include="Microsoft.OpenApi" Version="1.6.23" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="NLog" Version="5.4.0" />
|
||||
<PackageReference Include="NLog.Web.AspNetCore" Version="5.4.0" />
|
||||
<PackageReference Include="NSwag.AspNetCore" Version="14.3.0" />
|
||||
<PackageReference Include="System.Data.SQLite.Core" Version="1.0.119" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -7,48 +7,14 @@ namespace Common
|
|||
/// </summary>
|
||||
public class Number
|
||||
{
|
||||
private static readonly byte[] BitReverseTable = new byte[] {
|
||||
0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
|
||||
0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
|
||||
0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
|
||||
0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
|
||||
0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
|
||||
0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
|
||||
0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
|
||||
0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
|
||||
0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
|
||||
0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
|
||||
0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
|
||||
0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
|
||||
0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
|
||||
0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
|
||||
0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
|
||||
0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
|
||||
0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
|
||||
0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
|
||||
0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
|
||||
0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
|
||||
0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
|
||||
0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
|
||||
0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
|
||||
0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
|
||||
0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
|
||||
0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
|
||||
0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
|
||||
0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
|
||||
0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
|
||||
0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
|
||||
0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
|
||||
0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
|
||||
};
|
||||
/// <summary>
|
||||
/// 整数转成二进制字节数组
|
||||
/// </summary>
|
||||
/// <param name="num">整数</param>
|
||||
/// <param name="length">整数长度</param>
|
||||
/// <param name="isLowNumHigh">是否高位在数组索引低</param>
|
||||
/// <param name="isRightHigh">是否高位在右边</param>
|
||||
/// <returns>二进制字节数组</returns>
|
||||
public static Result<byte[]> NumberToBytes(ulong num, uint length, bool isLowNumHigh = false)
|
||||
public static Result<byte[]> NumberToBytes(ulong num, uint length, bool isRightHigh = false)
|
||||
{
|
||||
if (length > 8)
|
||||
{
|
||||
|
@ -60,7 +26,7 @@ namespace Common
|
|||
|
||||
var arr = new byte[length];
|
||||
|
||||
if (isLowNumHigh)
|
||||
if (isRightHigh)
|
||||
{
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
|
@ -78,12 +44,12 @@ namespace Common
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// 二进制字节数组转成64bits整数
|
||||
/// 二进制字节数组转成整数
|
||||
/// </summary>
|
||||
/// <param name="bytes">二进制字节数组</param>
|
||||
/// <param name="isLowNumHigh">是否高位在数组索引低</param>
|
||||
/// <param name="isRightHigh">是否高位在右边</param>
|
||||
/// <returns>整数</returns>
|
||||
public static Result<UInt64> BytesToUInt64(byte[] bytes, bool isLowNumHigh = false)
|
||||
public static Result<ulong> BytesToNumber(byte[] bytes, bool isRightHigh = false)
|
||||
{
|
||||
if (bytes.Length > 8)
|
||||
{
|
||||
|
@ -93,78 +59,27 @@ namespace Common
|
|||
));
|
||||
}
|
||||
|
||||
UInt64 num = 0;
|
||||
ulong num = 0;
|
||||
int len = bytes.Length;
|
||||
|
||||
try
|
||||
if (isRightHigh)
|
||||
{
|
||||
if (isLowNumHigh)
|
||||
for (var i = 0; i < len; i++)
|
||||
{
|
||||
for (var i = 0; i < len; i++)
|
||||
{
|
||||
num += Convert.ToUInt64((UInt64)bytes[len - 1 - i] << (i << 3));
|
||||
}
|
||||
num += Convert.ToUInt64((UInt64)bytes[len - 1 - i] << (i << 3));
|
||||
}
|
||||
else
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var i = 0; i < len; i++)
|
||||
{
|
||||
for (var i = 0; i < len; i++)
|
||||
{
|
||||
num += Convert.ToUInt64((UInt64)bytes[i] << ((int)(len - 1 - i) << 3));
|
||||
}
|
||||
num += Convert.ToUInt64((UInt64)bytes[i] << ((int)(len - 1 - i) << 3));
|
||||
}
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
catch (Exception error)
|
||||
{
|
||||
return new(error);
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 二进制字节数组转成32bits整数
|
||||
/// </summary>
|
||||
/// <param name="bytes">二进制字节数组</param>
|
||||
/// <param name="isLowNumHigh">是否高位在数组索引低</param>
|
||||
/// <returns>整数</returns>
|
||||
public static Result<UInt32> BytesToUInt32(byte[] bytes, bool isLowNumHigh = 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 (isLowNumHigh)
|
||||
{
|
||||
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>
|
||||
|
@ -237,12 +152,6 @@ 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)
|
||||
|
@ -290,7 +199,7 @@ namespace Common
|
|||
"Distance is larger than bytesArray", nameof(distance)));
|
||||
if (srcBytesLen % distance != 0)
|
||||
return new(new ArgumentException(
|
||||
"The length of bytes can't be divided by distance without reminder", nameof(distance)));
|
||||
"The length of bytes can't be divided by 2 without reminder", nameof(distance)));
|
||||
|
||||
var dstBytes = new byte[srcBytesLen];
|
||||
var buffer = new byte[distance];
|
||||
|
@ -306,31 +215,7 @@ namespace Common
|
|||
return dstBytes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 反转字节内比特顺序(使用查找表的方法)
|
||||
/// </summary>
|
||||
/// <param name="srcByte">字节</param>
|
||||
/// <returns>反转后的字节</returns>
|
||||
public static byte ReverseBits(byte srcByte)
|
||||
{
|
||||
return BitReverseTable[srcByte];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 反转字节数组的字节内比特顺序(使用查找表的方法)
|
||||
/// </summary>
|
||||
/// <param name="srcBytes">字节数组</param>
|
||||
/// <returns>反转后的字节字节数组</returns>
|
||||
public static byte[] ReverseBits(byte[] srcBytes)
|
||||
{
|
||||
var bytesLen = srcBytes.Length;
|
||||
var dstBytes = new byte[bytesLen];
|
||||
for (int i = 0; i < bytesLen; i++)
|
||||
{
|
||||
dstBytes[i] = BitReverseTable[srcBytes[i]];
|
||||
}
|
||||
return dstBytes;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using System.Buffers.Binary;
|
||||
using System.Net;
|
||||
using Common;
|
||||
using DotNext;
|
||||
using Microsoft.AspNetCore.Cors;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Newtonsoft.Json;
|
||||
using WebProtocol;
|
||||
|
@ -143,8 +142,6 @@ public class JtagController : ControllerBase
|
|||
{
|
||||
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
|
||||
|
||||
private const string BITSTREAM_PATH = "bitstream/Jtag";
|
||||
|
||||
/// <summary>
|
||||
/// 页面
|
||||
/// </summary>
|
||||
|
@ -246,7 +243,7 @@ public class JtagController : ControllerBase
|
|||
|
||||
// 生成安全的文件名(避免路径遍历攻击)
|
||||
var fileName = Path.GetRandomFileName();
|
||||
var uploadsFolder = Path.Combine(Environment.CurrentDirectory, $"{BITSTREAM_PATH}/{address}");
|
||||
var uploadsFolder = Path.Combine(Environment.CurrentDirectory, $"bitstream/{address}");
|
||||
|
||||
// 如果存在文件,则删除原文件再上传
|
||||
if (Directory.Exists(uploadsFolder))
|
||||
|
@ -278,7 +275,7 @@ public class JtagController : ControllerBase
|
|||
public async ValueTask<IResult> DownloadBitstream(string address, int port)
|
||||
{
|
||||
// 检查文件
|
||||
var fileDir = Path.Combine(Environment.CurrentDirectory, $"{BITSTREAM_PATH}/{address}");
|
||||
var fileDir = Path.Combine(Environment.CurrentDirectory, $"bitstream/{address}");
|
||||
if (!Directory.Exists(fileDir))
|
||||
return TypedResults.BadRequest("Empty bitstream, Please upload it first");
|
||||
|
||||
|
@ -308,6 +305,10 @@ public class JtagController : ControllerBase
|
|||
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;
|
||||
|
@ -346,325 +347,6 @@ public class JtagController : ControllerBase
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 远程更新
|
||||
/// </summary>
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class RemoteUpdater : ControllerBase
|
||||
{
|
||||
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
|
||||
|
||||
private const string BITSTREAM_PATH = "bitstream/RemoteUpdate";
|
||||
|
||||
/// <summary>
|
||||
/// 上传远程更新比特流文件
|
||||
/// </summary>
|
||||
/// <param name="address"> 设备地址 </param>
|
||||
/// <param name="goldenBitream">黄金比特流文件</param>
|
||||
/// <param name="bitstream1">比特流文件1</param>
|
||||
/// <param name="bitstream2">比特流文件2</param>
|
||||
/// <param name="bitstream3">比特流文件3</param>
|
||||
/// <returns>上传结果</returns>
|
||||
[HttpPost("UploadBitstream")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
public async ValueTask<IResult> UploadBitstreams(
|
||||
string address,
|
||||
IFormFile? goldenBitream,
|
||||
IFormFile? bitstream1,
|
||||
IFormFile? bitstream2,
|
||||
IFormFile? bitstream3)
|
||||
{
|
||||
if ((goldenBitream is null || goldenBitream.Length == 0) &&
|
||||
(bitstream1 is null || bitstream1.Length == 0) &&
|
||||
(bitstream2 is null || bitstream2.Length == 0) &&
|
||||
(bitstream3 is null || bitstream3.Length == 0))
|
||||
return TypedResults.BadRequest("未选择文件");
|
||||
|
||||
// 生成安全的文件名(避免路径遍历攻击)
|
||||
var fileName = Path.GetRandomFileName();
|
||||
var uploadsFolder = Path.Combine(Environment.CurrentDirectory, $"{BITSTREAM_PATH}/{address}");
|
||||
|
||||
// 如果存在文件,则删除原文件再上传
|
||||
if (Directory.Exists(uploadsFolder))
|
||||
{
|
||||
Directory.Delete(uploadsFolder, true);
|
||||
}
|
||||
Directory.CreateDirectory(uploadsFolder);
|
||||
|
||||
for (int bitstreamNum = 0; bitstreamNum < 4; bitstreamNum++)
|
||||
{
|
||||
IFormFile file;
|
||||
if (bitstreamNum == 0 && goldenBitream is not null)
|
||||
file = goldenBitream;
|
||||
else if (bitstreamNum == 1 && bitstream1 is not null)
|
||||
file = bitstream1;
|
||||
else if (bitstreamNum == 2 && bitstream2 is not null)
|
||||
file = bitstream2;
|
||||
else if (bitstreamNum == 3 && bitstream3 is not null)
|
||||
file = bitstream3;
|
||||
else continue;
|
||||
|
||||
var fileFolder = Path.Combine(uploadsFolder, bitstreamNum.ToString());
|
||||
Directory.CreateDirectory(fileFolder);
|
||||
|
||||
var filePath = Path.Combine(fileFolder, 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");
|
||||
}
|
||||
|
||||
private async ValueTask<Result<byte[]>> ProcessBitstream(string filePath)
|
||||
{
|
||||
using (var fileStream = System.IO.File.Open(filePath, System.IO.FileMode.Open))
|
||||
{
|
||||
if (fileStream is null || fileStream.Length <= 0)
|
||||
return new(new ArgumentException("Wrong bitstream path"));
|
||||
|
||||
// 定义缓冲区大小: 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 new(retBuffer.Error);
|
||||
revBuffer = retBuffer.Value;
|
||||
|
||||
await memoryStream.WriteAsync(revBuffer, 0, bytesRead);
|
||||
totalBytesRead += bytesRead;
|
||||
}
|
||||
|
||||
// 将所有数据转换为字节数组(注意:如果文件非常大,可能不适合完全加载到内存)
|
||||
var restStreamLen = memoryStream.Length % (4 * 1024);
|
||||
if (restStreamLen != 0)
|
||||
{
|
||||
var appendLen = ((int)(4 * 1024 - restStreamLen));
|
||||
var bytesAppend = new byte[appendLen];
|
||||
Array.Fill<byte>(bytesAppend, 0xFF);
|
||||
await memoryStream.WriteAsync(bytesAppend, 0, appendLen);
|
||||
}
|
||||
|
||||
return new(memoryStream.ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <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_PATH}/{address}/{bitstreamNum}");
|
||||
if (!Directory.Exists(fileDir))
|
||||
return TypedResults.BadRequest("Empty bitstream, Please upload it first");
|
||||
|
||||
try
|
||||
{
|
||||
// 读取文件
|
||||
var filePath = Directory.GetFiles(fileDir)[0];
|
||||
|
||||
var fileBytes = await ProcessBitstream(filePath);
|
||||
if (!fileBytes.IsSuccessful) return TypedResults.InternalServerError(fileBytes.Error);
|
||||
|
||||
// 下载比特流
|
||||
var remoteUpdater = new RemoteUpdate.RemoteUpdateClient(address, port);
|
||||
var ret = await remoteUpdater.UpdateBitstream(bitstreamNum, fileBytes.Value);
|
||||
|
||||
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>
|
||||
/// <param name="address">设备地址</param>
|
||||
/// <param name="port">设备端口</param>
|
||||
/// <param name="bitstreamNum">比特流编号</param>
|
||||
/// <returns>总共上传比特流的数量</returns>
|
||||
[HttpPost("DownloadMultiBitstreams")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
|
||||
public async ValueTask<IResult> DownloadMultiBitstreams(string address, int port, int? bitstreamNum)
|
||||
{
|
||||
// 检查文件
|
||||
var bitstreamsFolder = Path.Combine(Environment.CurrentDirectory, $"{BITSTREAM_PATH}/{address}");
|
||||
if (!Directory.Exists(bitstreamsFolder))
|
||||
return TypedResults.BadRequest("Empty bitstream, Please upload it first");
|
||||
|
||||
try
|
||||
{
|
||||
var bitstreams = new List<byte[]?>() { null, null, null, null };
|
||||
int cnt = 0; // 上传比特流数量
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
var bitstreamDir = Path.Combine(bitstreamsFolder, i.ToString());
|
||||
if (!Directory.Exists(bitstreamDir))
|
||||
continue;
|
||||
cnt++;
|
||||
|
||||
// 读取文件
|
||||
var filePath = Directory.GetFiles(bitstreamDir)[0];
|
||||
var fileBytes = await ProcessBitstream(filePath);
|
||||
if (!fileBytes.IsSuccessful) return TypedResults.InternalServerError(fileBytes.Error);
|
||||
bitstreams[i] = fileBytes.Value;
|
||||
}
|
||||
|
||||
// 下载比特流
|
||||
var remoteUpdater = new RemoteUpdate.RemoteUpdateClient(address, port);
|
||||
{
|
||||
var ret = await remoteUpdater.UploadBitstreams(bitstreams[0], bitstreams[1], bitstreams[2], bitstreams[3]);
|
||||
if (!ret.IsSuccessful) return TypedResults.InternalServerError(ret.Error);
|
||||
if (!ret.Value) return TypedResults.InternalServerError("Upload MultiBitstreams failed");
|
||||
}
|
||||
|
||||
if (bitstreamNum is not null)
|
||||
{
|
||||
var ret = await remoteUpdater.HotResetBitstream(bitstreamNum ?? 0);
|
||||
if (!ret.IsSuccessful) return TypedResults.InternalServerError(ret.Error);
|
||||
if (!ret.Value) return TypedResults.InternalServerError("Hot reset failed");
|
||||
}
|
||||
return TypedResults.Ok(cnt);
|
||||
}
|
||||
catch (Exception error)
|
||||
{
|
||||
return TypedResults.InternalServerError(error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 热复位比特流文件
|
||||
/// </summary>
|
||||
/// <param name="address">设备地址</param>
|
||||
/// <param name="port">设备端口</param>
|
||||
/// <param name="bitstreamNum">比特流编号</param>
|
||||
/// <returns>操作结果</returns>
|
||||
[HttpPost("HotResetBitstream")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
|
||||
public async ValueTask<IResult> HotResetBitstream(string address, int port, int bitstreamNum)
|
||||
{
|
||||
var remoteUpdater = new RemoteUpdate.RemoteUpdateClient(address, port);
|
||||
var ret = await remoteUpdater.HotResetBitstream(bitstreamNum);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 数据控制器
|
||||
/// </summary>
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class Data : ControllerBase
|
||||
{
|
||||
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
|
||||
|
||||
/// <summary>
|
||||
/// 创建数据库表
|
||||
/// </summary>
|
||||
/// <returns>插入的记录数</returns>
|
||||
[EnableCors("Development")]
|
||||
[HttpPost("CreateTable")]
|
||||
public IResult CreateTables()
|
||||
{
|
||||
using var db = new Database.AppDataConnection();
|
||||
db.CreateAllTables();
|
||||
return TypedResults.Ok();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除数据库表
|
||||
/// </summary>
|
||||
/// <returns>插入的记录数</returns>
|
||||
[EnableCors("Development")]
|
||||
[HttpDelete("DropTables")]
|
||||
public IResult DropTables()
|
||||
{
|
||||
using var db = new Database.AppDataConnection();
|
||||
db.DropAllTables();
|
||||
return TypedResults.Ok();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有用户
|
||||
/// </summary>
|
||||
/// <returns>用户列表</returns>
|
||||
[HttpGet("AllUsers")]
|
||||
public IResult AllUsers()
|
||||
{
|
||||
using var db = new Database.AppDataConnection();
|
||||
var ret = db.User.ToList();
|
||||
return TypedResults.Ok(ret);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册新用户
|
||||
/// </summary>
|
||||
/// <param name="name">用户名</param>
|
||||
/// <returns>操作结果</returns>
|
||||
[HttpPost("SignUpUser")]
|
||||
public IResult SignUpUser(string name)
|
||||
{
|
||||
if (name.Length > 255)
|
||||
return TypedResults.BadRequest("Name Couln't over 255 characters");
|
||||
|
||||
using var db = new Database.AppDataConnection();
|
||||
var ret = db.AddUser(name);
|
||||
return TypedResults.Ok(ret);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 日志控制器
|
||||
/// </summary>
|
||||
|
|
|
@ -1,113 +0,0 @@
|
|||
using LinqToDB;
|
||||
using LinqToDB.Data;
|
||||
using LinqToDB.Mapping;
|
||||
|
||||
namespace Database;
|
||||
|
||||
/// <summary>
|
||||
/// 用户类,表示用户信息
|
||||
/// </summary>
|
||||
public class User
|
||||
{
|
||||
/// <summary>
|
||||
/// 用户的唯一标识符
|
||||
/// </summary>
|
||||
[PrimaryKey]
|
||||
public Guid ID { get; set; } = Guid.NewGuid();
|
||||
|
||||
/// <summary>
|
||||
/// 用户的名称
|
||||
/// </summary>
|
||||
[NotNull]
|
||||
public required string Name { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// FPGA 板子类,表示板子信息
|
||||
/// </summary>
|
||||
public class Board
|
||||
{
|
||||
/// <summary>
|
||||
/// FPGA 板子的唯一标识符
|
||||
/// </summary>
|
||||
[PrimaryKey]
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
|
||||
/// <summary>
|
||||
/// FPGA 板子的名称
|
||||
/// </summary>
|
||||
[NotNull]
|
||||
public required string BoardName { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 应用程序数据连接类,用于与数据库交互
|
||||
/// </summary>
|
||||
public class AppDataConnection : DataConnection
|
||||
{
|
||||
static readonly LinqToDB.DataOptions options =
|
||||
new LinqToDB.DataOptions()
|
||||
.UseSQLite($"Data Source={Environment.CurrentDirectory}/Database.sqlite");
|
||||
|
||||
/// <summary>
|
||||
/// 初始化应用程序数据连接
|
||||
/// </summary>
|
||||
public AppDataConnection() : base(options) { }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 创建所有数据库表
|
||||
/// </summary>
|
||||
public void CreateAllTables()
|
||||
{
|
||||
this.CreateTable<User>();
|
||||
this.CreateTable<Board>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除所有数据库表
|
||||
/// </summary>
|
||||
public void DropAllTables()
|
||||
{
|
||||
this.DropTable<User>();
|
||||
this.DropTable<Board>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加一个新的用户到数据库
|
||||
/// </summary>
|
||||
/// <param name="name">用户的名称</param>
|
||||
/// <returns>插入的记录数</returns>
|
||||
public int AddUser(string name)
|
||||
{
|
||||
var user = new User()
|
||||
{
|
||||
Name = name
|
||||
};
|
||||
return this.Insert(user);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加一块新的 FPGA 板子到数据库
|
||||
/// </summary>
|
||||
/// <param name="name">FPGA 板子的名称</param>
|
||||
/// <returns>插入的记录数</returns>
|
||||
public int AddBoard(string name)
|
||||
{
|
||||
var board = new Board()
|
||||
{
|
||||
BoardName = name
|
||||
};
|
||||
return this.Insert(board);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用户表
|
||||
/// </summary>
|
||||
public ITable<User> User => this.GetTable<User>();
|
||||
|
||||
/// <summary>
|
||||
/// FPGA 板子表
|
||||
/// </summary>
|
||||
public ITable<Board> Board => this.GetTable<Board>();
|
||||
}
|
|
@ -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.BytesToUInt64(retPackOpts.Data).Value);
|
||||
return Convert.ToUInt32(Common.Number.BytesToNumber(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.BytesToUInt64(retPack.Value.Options.Data).Value, result, resultMask))
|
||||
Common.Number.BytesToNumber(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.BytesToUInt64(retPack.Value.Options.Data).Value, result, resultMask))
|
||||
Common.Number.BytesToNumber(retPack.Value.Options.Data).Value, result, resultMask))
|
||||
ret = true;
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -1,535 +0,0 @@
|
|||
using System.Net;
|
||||
using DotNext;
|
||||
namespace RemoteUpdate;
|
||||
|
||||
static class RemoteUpdateClientAddr
|
||||
{
|
||||
public const UInt32 Base = 0x20_00_00_00;
|
||||
|
||||
/// <summary>
|
||||
/// ADDR: 0X00: 写Flash-读写地址——控制位 <br/>
|
||||
/// [31:16]: wr_sector_num <br/>
|
||||
/// [15: 0]: {flash_wr_en,-,-,-, start_wr_sector} <br/>
|
||||
/// </summary>
|
||||
public const UInt32 WriteCtrl = Base + 0x00;
|
||||
|
||||
/// <summary>
|
||||
/// ADDR: 0X01: 写Flash-只写地址——FIFO入口 <br/>
|
||||
/// [31:0]: 写比特流数据入口 <br/>
|
||||
/// </summary>
|
||||
public const UInt32 WriteFIFO = Base + 0x01;
|
||||
|
||||
/// <summary>
|
||||
/// ADDR: 0X02: 写Flash-只读地址——标志位 <br/>
|
||||
/// [31:24]: {-, -, -, -, -, -, -, wr_fifo_full} <br/>
|
||||
/// [23:16]: {-, -, -, -, -, -, -, wr_fifo_empty} <br/>
|
||||
/// [15: 8]: {-, -, -, -, -, -, -, flash_wr_done} <br/>
|
||||
/// [ 7: 0]: {-, -, -, -, -, -, -, flash_clear_done} <br/>
|
||||
/// </summary>
|
||||
public const UInt32 WriteSign = Base + 0x02;
|
||||
|
||||
/// <summary>
|
||||
/// ADDR: 0X03: 读Flash-读写地址——控制位1 <br/>
|
||||
/// [31:16]: rd_sector_num <br/>
|
||||
/// [15: 0]: {flash_rd_en,-,-,-, start_rd_sub_sector} <br/>
|
||||
/// </summary>
|
||||
public const UInt32 ReadCtrl1 = Base + 0x03;
|
||||
|
||||
/// <summary>
|
||||
/// ADDR: 0X04: 读Flash-读写地址——控制位2 <br/>
|
||||
/// [31:24]: { } <br/>
|
||||
/// [23:16]: {-, -, -, -, -, -,{ bs_crc32_ok }} <br/>
|
||||
/// [15: 8]: {-, -, -, -, -, -, -, crc_check_en} <br/>
|
||||
/// [ 7: 0]: {-, -, -, -, -, -, -, bitstream_up2cpu_en} <br/>
|
||||
/// </summary>
|
||||
public const UInt32 ReadCtrl2 = Base + 0x04;
|
||||
|
||||
/// <summary>
|
||||
/// ADDR: 0X05: 读Flash-只读地址——FIFO出口 <br/>
|
||||
/// [31:0]: 读比特流数据出口 <br/>
|
||||
/// </summary>
|
||||
public const UInt32 ReadFIFO = Base + 0x05;
|
||||
|
||||
/// <summary>
|
||||
/// ADDR: 0X06: 读Flash-只读地址——CRC校验值 <br/>
|
||||
/// [31:0]: CRC校验值 bs_readback_crc <br/>
|
||||
/// </summary>
|
||||
public const UInt32 ReadCRC = Base + 0x06;
|
||||
|
||||
/// <summary>
|
||||
/// ADDR: 0X07: 读Flash-只读地址——标志位 <br/>
|
||||
/// [31:24]: {-, -, -, -, -, -, -, rd_fifo_afull} <br/>
|
||||
/// [23:16]: {-, -, -, -, -, -, -, rd_fifo_empty} <br/>
|
||||
/// [15: 8]: {-, -, -, -, -, -, -, flash_rd_done} <br/>
|
||||
/// [ 7: 0]: {-, -, -, -, -, -, -, bs_readback_crc_valid} <br/>
|
||||
/// </summary>
|
||||
public const UInt32 ReadSign = Base + 0x07;
|
||||
|
||||
/// <summary>
|
||||
/// ADDR: 0X08: 热启动开关-读写地址——控制位 <br/>
|
||||
/// [31: 8]: hotreset_addr <br/>
|
||||
/// [ 7: 0]: {-, -, -, -, -, -, -, hotreset_en} <br/>
|
||||
/// </summary>
|
||||
public const UInt32 HotResetCtrl = Base + 0x08;
|
||||
|
||||
/// <summary>
|
||||
/// ADDR: 0X09: 只读地址 版本号 <br/>
|
||||
/// [31: 0]: FPGA_VERSION[31:0] <br/>
|
||||
/// </summary>
|
||||
public const UInt32 Version = Base + 0x09;
|
||||
}
|
||||
|
||||
static class FlashAddr
|
||||
{
|
||||
public static readonly UInt32[] Switch = { 0xFFFF, 0x0000, 0x2000, 0x4000 };
|
||||
public static readonly UInt32[] Jump = { 0xFFFF, 0x1000, 0x3000, 0x5000 };
|
||||
public static readonly UInt32[] Bitstream = { 0x006000, 0x406000, 0x806000, 0xC06000 };
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// [TODO:description]
|
||||
/// </summary>
|
||||
public class RemoteUpdateClient
|
||||
{
|
||||
private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
|
||||
|
||||
const int FLASH_SECTOR_LENGTH = 4 * 1024;
|
||||
|
||||
readonly int timeout = 2000;
|
||||
readonly int timeoutForWait = 60 * 1000;
|
||||
|
||||
readonly int port;
|
||||
readonly string address;
|
||||
private IPEndPoint ep;
|
||||
|
||||
/// <summary>
|
||||
/// [TODO:description]
|
||||
/// </summary>
|
||||
/// <param name="address">[TODO:parameter]</param>
|
||||
/// <param name="port">[TODO:parameter]</param>
|
||||
/// <param name="timeout">[TODO:parameter]</param>
|
||||
/// <param name="timeoutForWait">[TODO:parameter]</param>
|
||||
/// <returns>[TODO:return]</returns>
|
||||
public RemoteUpdateClient(string address, int port, int timeout = 2000, int timeoutForWait = 60 * 1000)
|
||||
{
|
||||
if (timeout < 0)
|
||||
throw new ArgumentException("Timeout couldn't be negative", nameof(timeout));
|
||||
this.address = address;
|
||||
this.port = port;
|
||||
this.ep = new IPEndPoint(IPAddress.Parse(address), port);
|
||||
this.timeout = timeout;
|
||||
this.timeoutForWait = timeoutForWait;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// [TODO:description]
|
||||
/// </summary>
|
||||
/// <param name="flashAddr">[TODO:parameter]</param>
|
||||
/// <param name="writeSectorNum">[TODO:parameter]</param>
|
||||
/// <param name="bytesData">[TODO:parameter]</param>
|
||||
/// <returns>[TODO:return]</returns>
|
||||
private async ValueTask<Result<bool>> WriteFlash(UInt32 flashAddr, int writeSectorNum, byte[] bytesData)
|
||||
{
|
||||
// Assert
|
||||
if (writeSectorNum <= 0 || writeSectorNum >= FLASH_SECTOR_LENGTH)
|
||||
return new(new ArgumentException(
|
||||
$"Write sector num should be 1 ~ 4096, but given {writeSectorNum}", nameof(writeSectorNum)));
|
||||
if (bytesData.Length % (4 * 1024) != 0)
|
||||
return new(new ArgumentException(
|
||||
$"The length of data should be divided by 4096, bug given {bytesData.Length}", nameof(bytesData)));
|
||||
|
||||
{
|
||||
var ret = await UDPClientPool.WriteAddr(
|
||||
this.ep, RemoteUpdateClientAddr.WriteCtrl,
|
||||
Convert.ToUInt32((writeSectorNum << 16) | (1 << 15) | Convert.ToInt32(flashAddr / 4096)), this.timeout);
|
||||
if (!ret.IsSuccessful) return new(ret.Error);
|
||||
if (!ret.Value) return new(new Exception("Enable write flash failed"));
|
||||
}
|
||||
|
||||
{
|
||||
var ret = await UDPClientPool.ReadAddrWithWait(
|
||||
this.ep, RemoteUpdateClientAddr.WriteSign,
|
||||
0x00_00_00_01, 0x00_00_00_01, this.timeoutForWait);
|
||||
if (!ret.IsSuccessful) return new(ret.Error);
|
||||
if (!ret.Value) return new(new Exception(
|
||||
$"Flash clear failed after {this.timeoutForWait} milliseconds"));
|
||||
}
|
||||
|
||||
{
|
||||
var ret = await UDPClientPool.WriteAddr(this.ep, RemoteUpdateClientAddr.WriteFIFO, bytesData, this.timeout);
|
||||
if (!ret.IsSuccessful) return new(ret.Error);
|
||||
if (!ret.Value) return new(new Exception("Send data to flash failed"));
|
||||
}
|
||||
|
||||
{
|
||||
var ret = await UDPClientPool.ReadAddrWithWait(
|
||||
this.ep, RemoteUpdateClientAddr.WriteSign,
|
||||
0x00_00_01_00, 0x00_00_01_00, this.timeoutForWait);
|
||||
if (!ret.IsSuccessful) return new(ret.Error);
|
||||
return ret.Value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// [TODO:description]
|
||||
/// </summary>
|
||||
/// <param name="bitstreamNum">[TODO:parameter]</param>
|
||||
/// <returns>[TODO:return]</returns>
|
||||
private async ValueTask<Result<bool>> EnableBitstream(int bitstreamNum)
|
||||
{
|
||||
// Assert
|
||||
if (bitstreamNum <= 0 || bitstreamNum > 3)
|
||||
return new(new ArgumentException(
|
||||
$"Bitsteam num should be 1 ~ 3 for EnableBitstream, but given {bitstreamNum}", nameof(bitstreamNum)));
|
||||
|
||||
var bytesData = new byte[FLASH_SECTOR_LENGTH];
|
||||
Array.Fill<byte>(bytesData, 0xFF);
|
||||
bytesData[FLASH_SECTOR_LENGTH - 1] = 0x01;
|
||||
bytesData[FLASH_SECTOR_LENGTH - 2] = 0x33;
|
||||
bytesData[FLASH_SECTOR_LENGTH - 3] = 0x2D;
|
||||
bytesData[FLASH_SECTOR_LENGTH - 4] = 0x94;
|
||||
|
||||
|
||||
var ret = await WriteFlash(FlashAddr.Switch[bitstreamNum], 1, bytesData);
|
||||
if (!ret.IsSuccessful) return new(ret.Error);
|
||||
return ret.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// [TODO:description]
|
||||
/// </summary>
|
||||
/// <param name="bitstreamNum">[TODO:parameter]</param>
|
||||
/// <returns>[TODO:return]</returns>
|
||||
private async ValueTask<Result<bool>> DisableBitstream(int bitstreamNum)
|
||||
{
|
||||
// Assert
|
||||
if (bitstreamNum <= 0 || bitstreamNum > 3)
|
||||
return new(new ArgumentException(
|
||||
$"Bitsteam num should be 1 ~ 3 for DisableBitstream, but given {bitstreamNum}", nameof(bitstreamNum)));
|
||||
|
||||
var bytesData = new byte[FLASH_SECTOR_LENGTH];
|
||||
Array.Fill<byte>(bytesData, 0xFF);
|
||||
|
||||
var ret = await WriteFlash(FlashAddr.Switch[bitstreamNum], 1, bytesData);
|
||||
if (!ret.IsSuccessful) return new(ret.Error);
|
||||
return ret.Value;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// [TODO:description]
|
||||
/// </summary>
|
||||
/// <param name="bitstreamNum">[TODO:parameter]</param>
|
||||
/// <returns>[TODO:return]</returns>
|
||||
private async ValueTask<Result<bool>> WriteJumpCmd(int bitstreamNum)
|
||||
{
|
||||
// Assert
|
||||
if (bitstreamNum <= 0 || bitstreamNum > 3)
|
||||
return new(new ArgumentException(
|
||||
$"Bitsteam num should be 1 ~ 3 for WriteJumpCmd, but given {bitstreamNum}", nameof(bitstreamNum)));
|
||||
|
||||
// Init data
|
||||
var bytesData = new byte[FLASH_SECTOR_LENGTH];
|
||||
for (int i = 3; i < FLASH_SECTOR_LENGTH; i += 4)
|
||||
bytesData[i] = (byte)0xA0;
|
||||
|
||||
{
|
||||
var bytesSrc = new byte[] { 0x01, 0x00, 0x00, 0xAB };
|
||||
Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x04, 4);
|
||||
}
|
||||
{
|
||||
var bytesSrc = new byte[] { 0x0B, 0x00, 0x00, 0x00 };
|
||||
Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x08, 4);
|
||||
}
|
||||
{
|
||||
var bytesSrc = new byte[] { 0x01, 0x00, 0xC0, 0xAB };
|
||||
Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x34, 4);
|
||||
}
|
||||
{
|
||||
var bytesSrc = new byte[] { 0x00, 0x00, 0x00, 0x00 };
|
||||
Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x38, 4);
|
||||
}
|
||||
{
|
||||
var bytesSrc = new byte[] { 0x01, 0x00, 0x00, 0xAC };
|
||||
Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x3C, 4);
|
||||
}
|
||||
{
|
||||
var bytesSrc = Common.Number.NumberToBytes(FlashAddr.Bitstream[bitstreamNum], 4).Value;
|
||||
Buffer.BlockCopy(Common.Number.ReverseBytes(bytesSrc, 4).Value, 0, bytesData, 0x40, 4);
|
||||
}
|
||||
{
|
||||
var bytesSrc = new byte[] { 0x01, 0x00, 0x80, 0xA8 };
|
||||
Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x44, 4);
|
||||
}
|
||||
{
|
||||
var bytesSrc = new byte[] { 0x0F, 0x00, 0x00, 0x00 };
|
||||
Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x48, 4);
|
||||
}
|
||||
|
||||
var ret = await WriteFlash(FlashAddr.Jump[bitstreamNum], 1, bytesData);
|
||||
if (!ret.IsSuccessful) return new(ret.Error);
|
||||
return ret.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// [TODO:description]
|
||||
/// </summary>
|
||||
/// <param name="bitstreamNum">[TODO:parameter]</param>
|
||||
/// <returns>[TODO:return]</returns>
|
||||
private async ValueTask<Result<bool>> InitRemoteUpdate(int bitstreamNum)
|
||||
{
|
||||
// Assert
|
||||
if (bitstreamNum < 0 || bitstreamNum > 3)
|
||||
return new(new ArgumentException(
|
||||
$"Bitsteam num should be 0 ~ 3 for InitRemoteUpdate, but given {bitstreamNum}", nameof(bitstreamNum)));
|
||||
|
||||
for (int i = 1; i <= 3; i++)
|
||||
{
|
||||
{
|
||||
var ret = (i == bitstreamNum) ? await EnableBitstream(i) : await DisableBitstream(i);
|
||||
if (!ret.IsSuccessful) return new(ret.Error);
|
||||
if (!ret.Value) return new(new Exception($"Write switch {i} failed"));
|
||||
}
|
||||
|
||||
{
|
||||
var ret = await WriteJumpCmd(i);
|
||||
if (!ret.IsSuccessful) return new(ret.Error);
|
||||
if (!ret.Value) return new(new Exception($"Write jump {i} failed"));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// [TODO:description]
|
||||
/// </summary>
|
||||
/// <param name="bitstreamNum">[TODO:parameter]</param>
|
||||
/// <param name="bitstreamLen">[TODO:parameter]</param>
|
||||
/// <param name="checkSum">[TODO:parameter]</param>
|
||||
/// <returns>[TODO:return]</returns>
|
||||
private async ValueTask<Result<bool>> CheckBitstreamCRC(int bitstreamNum, int bitstreamLen, UInt32 checkSum)
|
||||
{
|
||||
{
|
||||
var ret = await UDPClientPool.WriteAddr(this.ep, RemoteUpdateClientAddr.ReadCtrl2, 0x00_00_00_00, this.timeout);
|
||||
if (!ret.IsSuccessful) return new(ret.Error);
|
||||
if (!ret.Value) return new(new Exception("Write read control 2 failed"));
|
||||
}
|
||||
|
||||
{
|
||||
var ret = await UDPClientPool.WriteAddr(
|
||||
this.ep, RemoteUpdateClientAddr.ReadCtrl1,
|
||||
Convert.ToUInt32((bitstreamLen << 16) | (1 << 15) | Convert.ToInt32(FlashAddr.Bitstream[bitstreamNum] / 4096)),
|
||||
this.timeout);
|
||||
if (!ret.IsSuccessful) return new(ret.Error);
|
||||
if (!ret.Value) return new(new Exception("Write read control 1 failed"));
|
||||
}
|
||||
|
||||
{
|
||||
var ret = await UDPClientPool.ReadAddrWithWait(
|
||||
this.ep, RemoteUpdateClientAddr.ReadSign,
|
||||
0x00_00_01_00, 0x00_00_01_00, this.timeoutForWait);
|
||||
if (!ret.IsSuccessful) return new(ret.Error);
|
||||
if (!ret.Value) return new(new Exception(
|
||||
$"Read bitstream failed after {this.timeoutForWait} milliseconds"));
|
||||
}
|
||||
|
||||
{
|
||||
var ret = await UDPClientPool.ReadAddr(this.ep, RemoteUpdateClientAddr.ReadCRC, this.timeout);
|
||||
if (!ret.IsSuccessful) return new(ret.Error);
|
||||
|
||||
var bytes = ret.Value.Options.Data;
|
||||
if (bytes is null)
|
||||
return new(new Exception("CRC is null"));
|
||||
|
||||
var remoteCRC = Common.Number.BytesToUInt32(bytes);
|
||||
if (!remoteCRC.IsSuccessful) return new(remoteCRC.Error);
|
||||
|
||||
logger.Debug($"Bitstream {bitstreamNum} Expected CRC: \t 0x{Convert.ToString(checkSum, 16)}");
|
||||
logger.Debug($"Bitstream {bitstreamNum} Received CRC: \t 0x{Convert.ToString(remoteCRC.Value, 16)}");
|
||||
|
||||
return remoteCRC.Value == checkSum;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// [TODO:description]
|
||||
/// </summary>
|
||||
/// <param name="bitstreamNum">[TODO:parameter]</param>
|
||||
/// <returns>[TODO:return]</returns>
|
||||
private async ValueTask<Result<bool>> HotReset(int bitstreamNum)
|
||||
{
|
||||
// Assert
|
||||
if (bitstreamNum < 0 || bitstreamNum > 3)
|
||||
return new(new ArgumentException(
|
||||
$"Bitsteam num should be 0 ~ 3 for HotRest, but given {bitstreamNum}", nameof(bitstreamNum)));
|
||||
|
||||
var ret = await UDPClientPool.WriteAddr(
|
||||
this.ep, RemoteUpdateClientAddr.HotResetCtrl,
|
||||
((FlashAddr.Bitstream[bitstreamNum] << 8) | 1), this.timeout);
|
||||
if (!ret.IsSuccessful) return new(ret.Error);
|
||||
return ret.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// [TODO:description]
|
||||
/// </summary>
|
||||
/// <param name="bitstreamNum">[TODO:parameter]</param>
|
||||
/// <returns>[TODO:return]</returns>
|
||||
public async ValueTask<Result<bool>> HotResetBitstream(int bitstreamNum)
|
||||
{
|
||||
await MsgBus.UDPServer.ClearUDPData(this.address);
|
||||
logger.Trace("Clear udp data finished");
|
||||
|
||||
{
|
||||
var ret = await InitRemoteUpdate(bitstreamNum);
|
||||
if (!ret.IsSuccessful) return new(ret.Error);
|
||||
if (!ret.Value) return new(new Exception("Init remote update failed"));
|
||||
}
|
||||
|
||||
{
|
||||
var ret = await HotReset(bitstreamNum);
|
||||
if (!ret.IsSuccessful) return new(ret.Error);
|
||||
return ret.Value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// [TODO:description]
|
||||
/// </summary>
|
||||
/// <param name="goldenBitream">[TODO:parameter]</param>
|
||||
/// <param name="bitstream1">[TODO:parameter]</param>
|
||||
/// <param name="bitstream2">[TODO:parameter]</param>
|
||||
/// <param name="bitstream3">[TODO:parameter]</param>
|
||||
/// <returns>[TODO:return]</returns>
|
||||
public async ValueTask<Result<bool>> UploadBitstreams(
|
||||
byte[]? goldenBitream,
|
||||
byte[]? bitstream1,
|
||||
byte[]? bitstream2,
|
||||
byte[]? bitstream3)
|
||||
{
|
||||
await MsgBus.UDPServer.ClearUDPData(this.address);
|
||||
logger.Trace("Clear udp data finished");
|
||||
|
||||
for (int bitstreamNum = 0; bitstreamNum < 4; bitstreamNum++)
|
||||
{
|
||||
byte[] bytesData;
|
||||
if (bitstreamNum == 0 && goldenBitream is not null)
|
||||
bytesData = goldenBitream;
|
||||
else if (bitstreamNum == 1 && bitstream1 is not null)
|
||||
bytesData = bitstream1;
|
||||
else if (bitstreamNum == 2 && bitstream2 is not null)
|
||||
bytesData = bitstream2;
|
||||
else if (bitstreamNum == 3 && bitstream3 is not null)
|
||||
bytesData = bitstream3;
|
||||
else continue;
|
||||
|
||||
var bitstreamBlockNum = bytesData.Length / (4 * 1024);
|
||||
|
||||
{
|
||||
var ret = await WriteFlash(FlashAddr.Bitstream[bitstreamNum], bitstreamBlockNum, bytesData);
|
||||
if (!ret.IsSuccessful) return new(ret.Error);
|
||||
if (!ret.Value) return new(new Exception("Write bitstream failed"));
|
||||
}
|
||||
|
||||
{
|
||||
var crc = Honoo.IO.Hashing.Crc.Create(Honoo.IO.Hashing.CrcName.CRC32_MPEG_2);
|
||||
var checkSum = crc.ComputeFinal(bytesData);
|
||||
var ret = await CheckBitstreamCRC(bitstreamNum, bitstreamBlockNum, checkSum.ToUInt32());
|
||||
if (!ret.IsSuccessful) return new(ret.Error);
|
||||
if (!ret.Value) logger.Warn($"Bitstream {bitstreamNum} CRC32 not correct!");
|
||||
else logger.Info($"Bitstream {bitstreamNum} CRC32 calibration passed");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// [TODO:description]
|
||||
/// </summary>
|
||||
/// <param name="bitstreamNum">[TODO:parameter]</param>
|
||||
/// <param name="bytesData">[TODO:parameter]</param>
|
||||
/// <returns>[TODO:return]</returns>
|
||||
public async ValueTask<Result<bool>> UpdateBitstream(int bitstreamNum, byte[] bytesData)
|
||||
{
|
||||
if (bytesData.Length % (4 * 1024) != 0)
|
||||
return new(new ArgumentException(
|
||||
$"The length of data should be divided by 4096, bug given {bytesData.Length}", nameof(bytesData)));
|
||||
var bitstreamBlockNum = bytesData.Length / (4 * 1024);
|
||||
|
||||
await MsgBus.UDPServer.ClearUDPData(this.address);
|
||||
logger.Trace("Clear udp data finished");
|
||||
|
||||
{
|
||||
var ret = await InitRemoteUpdate(bitstreamNum);
|
||||
if (!ret.IsSuccessful) return new(ret.Error);
|
||||
if (!ret.Value) return new(new Exception("Init remote update failed"));
|
||||
}
|
||||
|
||||
{
|
||||
var ret = await WriteFlash(FlashAddr.Bitstream[bitstreamNum], bitstreamBlockNum, bytesData);
|
||||
if (!ret.IsSuccessful) return new(ret.Error);
|
||||
if (!ret.Value) return new(new Exception("Write bitstream failed"));
|
||||
}
|
||||
|
||||
{
|
||||
var crc = Honoo.IO.Hashing.Crc.Create(Honoo.IO.Hashing.CrcName.CRC32_MPEG_2);
|
||||
var checkSum = crc.ComputeFinal(bytesData);
|
||||
var ret = await CheckBitstreamCRC(bitstreamNum, bitstreamBlockNum, checkSum.ToUInt32());
|
||||
if (!ret.IsSuccessful) return new(ret.Error);
|
||||
if (!ret.Value) logger.Warn("CRC32 not correct!");
|
||||
else logger.Info("CRC32 calibration passed");
|
||||
}
|
||||
|
||||
{
|
||||
var ret = await HotReset(bitstreamNum);
|
||||
if (!ret.IsSuccessful) return new(ret.Error);
|
||||
return ret.Value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// [TODO:description]
|
||||
/// </summary>
|
||||
/// <param name="enableBitstreamNum">[TODO:parameter]</param>
|
||||
/// <param name="goldenBitream">[TODO:parameter]</param>
|
||||
/// <param name="bitstream1">[TODO:parameter]</param>
|
||||
/// <param name="bitstream2">[TODO:parameter]</param>
|
||||
/// <param name="bitstream3">[TODO:parameter]</param>
|
||||
/// <returns>[TODO:return]</returns>
|
||||
public async ValueTask<Result<bool>> UpdateBitstreams(
|
||||
int enableBitstreamNum,
|
||||
byte[]? goldenBitream,
|
||||
byte[]? bitstream1,
|
||||
byte[]? bitstream2,
|
||||
byte[]? bitstream3)
|
||||
{
|
||||
// Assert
|
||||
if (goldenBitream is null && bitstream1 is null && bitstream2 is null && bitstream3 is null)
|
||||
return new(new ArgumentException(
|
||||
$"At least one bitstream should not be empty"));
|
||||
if ((enableBitstreamNum == 0 && goldenBitream is null) ||
|
||||
(enableBitstreamNum == 1 && bitstream1 is null) ||
|
||||
(enableBitstreamNum == 2 && bitstream2 is null) ||
|
||||
(enableBitstreamNum == 3 && bitstream3 is null))
|
||||
return new(new ArgumentException($"Bitstream {enableBitstreamNum} shouldn't be empty"));
|
||||
|
||||
{
|
||||
var ret = await UploadBitstreams(goldenBitream, bitstream1, bitstream2, bitstream3);
|
||||
if (!ret.IsSuccessful) return new(ret.Error);
|
||||
if (!ret.Value) return false;
|
||||
}
|
||||
|
||||
{
|
||||
var ret = await HotResetBitstream(enableBitstreamNum);
|
||||
if (!ret.IsSuccessful) return new(ret.Error);
|
||||
return ret.Value;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,8 +1,6 @@
|
|||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using DotNext;
|
||||
using WebProtocol;
|
||||
|
||||
/// <summary>
|
||||
/// UDP客户端发送池
|
||||
|
@ -163,228 +161,4 @@ public class UDPClientPool
|
|||
|
||||
return isSuccessful;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// [TODO:description]
|
||||
/// </summary>
|
||||
/// <param name="endPoint">[TODO:parameter]</param>
|
||||
/// <param name="devAddr">[TODO:parameter]</param>
|
||||
/// <param name="timeout">[TODO:parameter]</param>
|
||||
/// <returns>[TODO:return]</returns>
|
||||
public static async ValueTask<Result<RecvDataPackage>> ReadAddr(
|
||||
IPEndPoint endPoint, uint devAddr, int timeout = 1000)
|
||||
{
|
||||
var ret = false;
|
||||
var opts = new SendAddrPackOptions();
|
||||
|
||||
opts.BurstType = BurstType.FixedBurst;
|
||||
opts.BurstLength = 0;
|
||||
opts.CommandID = 0;
|
||||
opts.Address = devAddr;
|
||||
|
||||
// Read Jtag State Register
|
||||
opts.IsWrite = false;
|
||||
ret = await UDPClientPool.SendAddrPackAsync(endPoint, new SendAddrPackage(opts));
|
||||
if (!ret) return new(new Exception("Send Address Package Failed!"));
|
||||
|
||||
// Wait for Read Ack
|
||||
if (!MsgBus.IsRunning)
|
||||
return new(new Exception("Message Bus not Working!"));
|
||||
|
||||
var retPack = await MsgBus.UDPServer.WaitForDataAsync(
|
||||
endPoint.Address.ToString(), endPoint.Port, timeout);
|
||||
if (!retPack.IsSuccessful) return new(retPack.Error);
|
||||
else if (!retPack.Value.IsSuccessful)
|
||||
return new(new Exception("Send address package failed"));
|
||||
|
||||
var retPackOpts = retPack.Value.Options;
|
||||
if (retPackOpts.Data is null)
|
||||
return new(new Exception($"Data is Null, package: {retPackOpts.ToString()}"));
|
||||
|
||||
return retPack;
|
||||
}
|
||||
|
||||
/// <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;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// [TODO:description]
|
||||
/// </summary>
|
||||
/// <param name="endPoint">[TODO:parameter]</param>
|
||||
/// <param name="devAddr">[TODO:parameter]</param>
|
||||
/// <param name="data">[TODO:parameter]</param>
|
||||
/// <param name="timeout">[TODO:parameter]</param>
|
||||
/// <returns>[TODO:return]</returns>
|
||||
public static async ValueTask<Result<bool>> WriteAddr(
|
||||
IPEndPoint endPoint, UInt32 devAddr, UInt32 data, int timeout = 1000)
|
||||
{
|
||||
var ret = false;
|
||||
var opts = new SendAddrPackOptions();
|
||||
|
||||
opts.BurstType = BurstType.FixedBurst;
|
||||
opts.BurstLength = 0;
|
||||
opts.CommandID = 0;
|
||||
opts.Address = devAddr;
|
||||
|
||||
// Write Jtag State Register
|
||||
opts.IsWrite = true;
|
||||
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(Common.Number.NumberToBytes(data, 4).Value));
|
||||
if (!ret) return new(new Exception("Send data package failed!"));
|
||||
|
||||
// Check Msg Bus
|
||||
if (!MsgBus.IsRunning)
|
||||
return new(new Exception("Message bus not working!"));
|
||||
|
||||
// Wait for Write Ack
|
||||
var udpWriteAck = await MsgBus.UDPServer.WaitForAckAsync(
|
||||
endPoint.Address.ToString(), endPoint.Port, timeout);
|
||||
if (!udpWriteAck.IsSuccessful) return new(udpWriteAck.Error);
|
||||
|
||||
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 hasRest = dataArray.Length % (256 * (32 / 8)) != 0;
|
||||
var writeTimes = hasRest ?
|
||||
dataArray.Length / (256 * (32 / 8)) + 1 :
|
||||
dataArray.Length / (256 * (32 / 8));
|
||||
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.BytesToUInt64(bytes[4..]).Value;
|
||||
var address = Common.Number.BytesToNumber(bytes[4..]).Value;
|
||||
return new SendAddrPackage(bytes[1], bytes[2], Convert.ToUInt32(address));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue