diff --git a/.justfile b/.justfile index 551a2f3..7651ade 100644 --- a/.justfile +++ b/.justfile @@ -3,20 +3,35 @@ pwd echo +# 清空构建文件 clean: rm -rf "server/bin" rm -rf "server/obj" rm -rf "server.test/bin" rm -rf "server.test/obj" + rm -rf "dist" +# 生成Restful API到网页客户端 +gen-api: + cd server && dotnet run & + npx nswag openapi2tsclient /input:http://localhost:5000/swagger/v1/swagger.json /output:src/APIClient.ts + pkill server + +# 构建服务器,包含win与linux平台 [working-directory: "server"] -publish: _show-dir +build-server: _show-dir dotnet publish --self-contained false -t:PublishAllRids +# 运行服务器 [working-directory: "server"] run-server: _show-dir dotnet run + +# 运行网页客户端 +run-web: + npm run dev +# 运行测试用例测试服务器 [working-directory: "server.test"] test-server: _show-dir dotnet test --logger "console;verbosity=detailed" diff --git a/server.test/CommonTest.cs b/server.test/CommonTest.cs new file mode 100644 index 0000000..a6cb5e5 --- /dev/null +++ b/server.test/CommonTest.cs @@ -0,0 +1,39 @@ +using Common; + +namespace server.test; + +public class CommonTest +{ + [Fact] + public void ReverseBytesTest() + { + var rnd = new Random(); + var bytesLen = 8; + var bytesArray = new byte[bytesLen]; + rnd.NextBytes(bytesArray); + + var rev2Bytes = new byte[] { + bytesArray[1], + bytesArray[0], + bytesArray[3], + bytesArray[2], + bytesArray[5], + bytesArray[4], + bytesArray[7], + bytesArray[6], + }; + Assert.Equal(Number.ReverseBytes(bytesArray, 2).Value, rev2Bytes); + + var rev4Bytes = new byte[] { + bytesArray[3], + bytesArray[2], + bytesArray[1], + bytesArray[0], + bytesArray[7], + bytesArray[6], + bytesArray[5], + bytesArray[4], + }; + Assert.Equal(Number.ReverseBytes(bytesArray, 4).Value, rev4Bytes); + } +} diff --git a/server.test/UDPServerTest.cs b/server.test/UDPServerTest.cs index 11c4aad..5cde6f3 100644 --- a/server.test/UDPServerTest.cs +++ b/server.test/UDPServerTest.cs @@ -5,30 +5,6 @@ using Xunit.Abstractions; namespace server.test; -public sealed class RepeatAttribute : Xunit.Sdk.DataAttribute -{ - private readonly int count; - - public RepeatAttribute(int count) - { - if (count < 1) - { - throw new System.ArgumentOutOfRangeException( - paramName: nameof(count), - message: "Repeat count must be greater than 0." - ); - } - this.count = count; - } - - public override System.Collections.Generic.IEnumerable GetData(System.Reflection.MethodInfo testMethod) - { - foreach (var iterationNumber in Enumerable.Range(start: 1, count: this.count)) - { - yield return new object[] { iterationNumber }; - } - } -} public class UDPServerTest { diff --git a/server/Program.cs b/server/Program.cs index 9e111eb..cfba4f5 100644 --- a/server/Program.cs +++ b/server/Program.cs @@ -36,6 +36,18 @@ try options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore; }); + // Add CORS policy + builder.Services.AddCors(options => + { + options.AddPolicy("Development", policy => + { + policy + .AllowAnyOrigin() + .AllowAnyMethod() + .AllowAnyHeader(); + }); + }); + // Add Swagger builder.Services.AddControllers(); builder.Services.AddOpenApiDocument(options => @@ -75,6 +87,7 @@ try app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); + app.UseCors(); app.UseAuthorization(); // if (app.Environment.IsDevelopment()) diff --git a/server/src/Common.cs b/server/src/Common.cs index bc126ef..60bccc7 100644 --- a/server/src/Common.cs +++ b/server/src/Common.cs @@ -85,11 +85,11 @@ namespace Common /// /// 比特合并成二进制字节 /// - /// [TODO:parameter] - /// [TODO:parameter] - /// [TODO:parameter] - /// [TODO:parameter] - /// [TODO:return] + /// 第一个比特值 + /// 第一个比特值的长度(位数) + /// 第二个比特值 + /// 第二个比特值的长度(位数) + /// 合并后的二进制字节数组 public static Result MultiBitsToBytes(ulong bits1, uint bits1Len, ulong bits2, uint bits2Len) { return NumberToBytes(MultiBitsToNumber(bits1, bits1Len, bits2, bits2Len).Value, @@ -99,11 +99,11 @@ namespace Common /// /// 比特合并成整型 /// - /// [TODO:parameter] - /// [TODO:parameter] - /// [TODO:parameter] - /// [TODO:parameter] - /// [TODO:return] + /// 第一个比特值 + /// 第一个比特值的长度(位数) + /// 第二个比特值 + /// 第二个比特值的长度(位数) + /// 合并后的整型值 public static Result MultiBitsToNumber(ulong bits1, uint bits1Len, ulong bits2, uint bits2Len) { if (bits1Len + bits2Len > 64) return new(new ArgumentException("Two Bits is more than 64 bits")); @@ -115,11 +115,11 @@ namespace Common /// /// 比特合并成整型 /// - /// [TODO:parameter] - /// [TODO:parameter] - /// [TODO:parameter] - /// [TODO:parameter] - /// [TODO:return] + /// 第一个比特值 + /// 第一个比特值的长度(位数) + /// 第二个比特值 + /// 第二个比特值的长度(位数) + /// 合并后的整型值 public static Result MultiBitsToNumber(uint bits1, uint bits1Len, uint bits2, uint bits2Len) { if (bits1Len + bits2Len > 64) return new(new ArgumentException("Two Bits is more than 64 bits")); @@ -131,10 +131,10 @@ namespace Common /// /// 比特位检查 /// - /// [TODO:parameter] - /// [TODO:parameter] - /// [TODO:parameter] - /// [TODO:return] + /// 源比特值 + /// 目标比特值 + /// 掩码(默认为全1) + /// 检查结果(是否匹配) public static bool BitsCheck(ulong srcBits, ulong dstBits, ulong mask = 0xFFFF_FFFF_FFFF_FFFF) { return (srcBits & mask) == dstBits; @@ -143,22 +143,31 @@ namespace Common /// /// 比特位检查 /// - /// [TODO:parameter] - /// [TODO:parameter] - /// [TODO:parameter] - /// [TODO:return] + /// 源比特值 + /// 目标比特值 + /// 掩码(默认为全1) + /// 检查结果(是否匹配) public static bool BitsCheck(uint srcBits, uint dstBits, uint mask = 0xFFFF_FFFF) { return (srcBits & mask) == dstBits; } + public static Result ToBit(UInt32 srcBits, int location) + { + if (location < 0) + return new(new ArgumentException( + "Location can't be negetive", nameof(location))); + + return (srcBits & (1 << location)) == 1; + } + /// /// 字符串转二进制字节数组 /// - /// [TODO:parameter] - /// [TODO:parameter] - /// [TODO:return] + /// 输入的字符串 + /// 进制(默认为16进制) + /// 转换后的二进制字节数组 public static byte[] StringToBytes(string str, int numBase = 16) { var len = str.Length; @@ -173,6 +182,59 @@ namespace Common return bytes; } + /// + /// 反转字节数组中的子数组 + /// + /// 源字节数组 + /// 子数组的长度(反转的步长) + /// 反转后的字节数组 + public static Result ReverseBytes(byte[] srcBytes, int distance) + { + if (distance <= 0) + return new(new ArgumentException("Distance can't be negetive", nameof(distance))); + + var srcBytesLen = srcBytes.Length; + if (distance > srcBytesLen) + return new(new ArgumentException( + "Distance is larger than bytesArray", nameof(distance))); + if (srcBytesLen % distance != 0) + return new(new ArgumentException( + "The length of bytes can't be divided by 2 without reminder", nameof(distance))); + + var dstBytes = new byte[srcBytesLen]; + var buffer = new byte[distance]; + + for (int i = 0; i < srcBytesLen; i += distance) + { + var end = i + distance; + buffer = srcBytes[i..end]; + Array.Reverse(buffer); + Array.Copy(buffer, 0, dstBytes, i, distance); + } + + return dstBytes; + } + + + } + + /// + /// 字符串处理工具 + /// + public class String + { + /// + /// 反转字符串 + /// + /// 输入的字符串 + /// 反转后的字符串 + public static string Reverse(string s) + { + char[] charArray = s.ToCharArray(); + Array.Reverse(charArray); + return new string(charArray); + } + } } diff --git a/server/src/Controllers.cs b/server/src/Controllers.cs index e76db1a..8c1c770 100644 --- a/server/src/Controllers.cs +++ b/server/src/Controllers.cs @@ -1,6 +1,6 @@ +using System.Buffers.Binary; using System.Net; using Common; -using DotNext; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; using WebProtocol; @@ -196,6 +196,38 @@ public class JtagController : ControllerBase } } + /// + /// 获取状态寄存器 + /// + /// 设备地址 + /// 设备端口 + [HttpGet("ReadStatusReg")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status500InternalServerError)] + public async ValueTask ReadStatusReg(string address, int port) + { + var jtagCtrl = new JtagClient.Jtag(address, port); + var ret = await jtagCtrl.ReadStatusReg(); + + if (ret.IsSuccessful) + { + var binaryValue = Common.String.Reverse(Convert.ToString(ret.Value, 2).PadLeft(32, '0')); + var decodeValue = new JtagClient.JtagStatusReg(ret.Value); + logger.Info($"Read device {address} Status Register: \n\t 0b{binaryValue} \n\t {decodeValue}"); + return TypedResults.Ok(new + { + original = ret.Value, + binary = binaryValue, + decode = decodeValue, + }); + } + else + { + logger.Error(ret.Error); + return TypedResults.InternalServerError(ret.Error); + } + } + /// /// 上传比特流文件 /// @@ -251,46 +283,77 @@ public class JtagController : ControllerBase { // 读取文件 var filePath = Directory.GetFiles(fileDir)[0]; - 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]; - long totalBytesRead = 0; - - // 使用异步流读取文件 - using (var memoryStream = new MemoryStream()) + using (var fileStream = System.IO.File.Open(filePath, System.IO.FileMode.Open)) { - int bytesRead; - while ((bytesRead = await fileStream.ReadAsync(buffer, 0, buffer.Length)) > 0) + if (fileStream is null || fileStream.Length <= 0) + return TypedResults.BadRequest("Wrong bitstream, Please upload it again"); + + // 定义缓冲区大小: 32KB + byte[] buffer = new byte[32 * 1024]; + long totalBytesRead = 0; + + // 使用异步流读取文件 + using (var memoryStream = new MemoryStream()) { - await memoryStream.WriteAsync(buffer, 0, bytesRead); - totalBytesRead += bytesRead; + int bytesRead; + while ((bytesRead = await fileStream.ReadAsync(buffer, 0, buffer.Length)) > 0) + { + var revBuffer = Common.Number.ReverseBytes(buffer, 4); + + if (!revBuffer.IsSuccessful) + return TypedResults.InternalServerError(revBuffer.Error); + + await memoryStream.WriteAsync(revBuffer.Value, 0, bytesRead); + totalBytesRead += bytesRead; + } + + // 将所有数据转换为字节数组(注意:如果文件非常大,可能不适合完全加载到内存) + var fileBytes = memoryStream.ToArray(); + + // 下载比特流 + var jtagCtrl = new JtagClient.Jtag(address, port); + var ret = await jtagCtrl.DownloadBitstream(fileBytes); + + if (ret.IsSuccessful) + { + logger.Info($"Device {address} dowload bitstream successfully"); + return TypedResults.Ok(ret.Value); + } + else + { + logger.Error(ret.Error); + return TypedResults.InternalServerError(ret.Error); + } } - // 将所有数据转换为字节数组(注意:如果文件非常大,可能不适合完全加载到内存) - var fileBytes = memoryStream.ToArray(); - - // 下载比特流 - var jtagCtrl = new JtagClient.Jtag(address, port); - var ret = await jtagCtrl.DownloadBitstream(fileBytes); - - if (ret.IsSuccessful) - { - logger.Info($"Device {address} dowload bitstream successfully"); - return TypedResults.Ok(ret.Value); - } - else - { - logger.Error(ret.Error); - return TypedResults.InternalServerError(ret.Error); - } } + } catch (Exception error) { return TypedResults.InternalServerError(error); } + finally + { + + } } } + +/// +/// 日志控制器 +/// +[ApiController] +[Route("api/[controller]")] +public class Log : ControllerBase +{ + private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); + + /// + /// 日志文件路径 + /// + private readonly string _logFilePath = Directory.GetFiles(Directory.GetCurrentDirectory())[0]; + +} + diff --git a/server/src/JtagClient.cs b/server/src/JtagClient.cs index 6c5791e..676bdf8 100644 --- a/server/src/JtagClient.cs +++ b/server/src/JtagClient.cs @@ -1,5 +1,6 @@ using System.Net; using DotNext; +using Newtonsoft.Json; using WebProtocol; namespace JtagClient; @@ -213,6 +214,160 @@ public static class JtagCmd public const UInt32 CMD_JTAG_IDLE_DELAY = 0b0101; } +/// +/// JTAG 状态寄存器 +/// +public class JtagStatusReg +{ + /// + /// ID 错误标志 + /// + public bool id_err; + /// + /// CRC 错误标志 + /// + public bool crc_err; + /// + /// 自动测试错误标志 + /// + public bool aut_err; + /// + /// 回读 CRC 错误标志 + /// + public bool rbcrc_err; + /// + /// 超时标志 + /// + public bool timeout; + /// + /// 唤醒完成标志 + /// + public bool wakeup_over; + /// + /// 休眠完成标志 + /// + public bool wakedown_over; + /// + /// 模式位 + /// + public byte m; + /// + /// 初始化完成标志 + /// + public bool init_complete; + /// + /// 初始化状态(低电平有效) + /// + public bool init_n; + /// + /// 完成标志 + /// + public bool done; + /// + /// 内部完成标志 + /// + public bool done_i; + /// + /// 全局逻辑使能标志 + /// + public bool glogen; + /// + /// 全局逻辑反馈标志 + /// + public bool glogen_fb; + /// + /// 全局输出使能标志 + /// + public bool gouten; + /// + /// 全局复位标志 + /// + public bool grsn; + /// + /// 全局写使能标志 + /// + public bool gwen; + /// + /// PLL 锁定标志 + /// + public bool pll_lock; + /// + /// 回退标志 + /// + public bool fallback; + /// + /// IPAL 模式位 + /// + public byte ipal_m; + /// + /// 8 位标志 + /// + public bool flg_x8; + /// + /// 16 位标志 + /// + public bool flg_x16; + /// + /// 32 位标志 + /// + public bool flg_x32; + /// + /// 过温标志 + /// + public bool over_temp; + /// + /// 配置错误标志 + /// + public bool prcfg_err; + /// + /// 配置完成标志 + /// + public bool prcfg_over; + + /// + /// 构造函数,从 32 位代码解析 JTAG 状态寄存器 + /// + /// 32 位状态寄存器值 + public JtagStatusReg(UInt32 code) + { + this.id_err = Common.Number.ToBit(code, 0).Value; + this.crc_err = Common.Number.ToBit(code, 1).Value; + this.aut_err = Common.Number.ToBit(code, 2).Value; + this.rbcrc_err = Common.Number.ToBit(code, 3).Value; + this.timeout = Common.Number.ToBit(code, 4).Value; + this.wakeup_over = Common.Number.ToBit(code, 5).Value; + this.wakedown_over = Common.Number.ToBit(code, 6).Value; + this.m = ((byte)(code & (0b111 << 7))); + this.init_complete = Common.Number.ToBit(code, 10).Value; + this.init_n = Common.Number.ToBit(code, 11).Value; + this.done = Common.Number.ToBit(code, 12).Value; + this.done_i = Common.Number.ToBit(code, 13).Value; + this.glogen = Common.Number.ToBit(code, 14).Value; + this.glogen_fb = Common.Number.ToBit(code, 15).Value; + this.gouten = Common.Number.ToBit(code, 16).Value; + this.grsn = Common.Number.ToBit(code, 17).Value; + this.gwen = Common.Number.ToBit(code, 18).Value; + this.pll_lock = Common.Number.ToBit(code, 19).Value; + this.fallback = Common.Number.ToBit(code, 21).Value; + this.ipal_m = ((byte)(code & (0b11 << 22))); + this.flg_x8 = Common.Number.ToBit(code, 24).Value; + this.flg_x16 = Common.Number.ToBit(code, 25).Value; + this.flg_x32 = Common.Number.ToBit(code, 26).Value; + this.over_temp = Common.Number.ToBit(code, 27).Value; + this.prcfg_err = Common.Number.ToBit(code, 28).Value; + this.prcfg_over = Common.Number.ToBit(code, 29).Value; + } + + /// + /// 转换为Json字符串 + /// + /// Json字符串 + public override string ToString() + { + return JsonConvert.SerializeObject(this); + } +} + /// /// Jtag控制器 /// @@ -220,6 +375,8 @@ public class Jtag { private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); + private const int CLOCK_FREQ = 50; // MHz + readonly int timeout; readonly int port; @@ -227,11 +384,11 @@ public class Jtag private IPEndPoint ep; /// - /// Jtag构造函数 + /// Jtag 构造函数 /// - /// 目标IP地址 - /// 目标UDP端口 - /// 超时时间 + /// 目标 IP 地址 + /// 目标 UDP 端口 + /// 超时时间(毫秒) public Jtag(string address, int port, int timeout = 2000) { this.address = address; @@ -274,7 +431,14 @@ public class Jtag return Convert.ToUInt32(Common.Number.BytesToNumber(retPackOpts.Data).Value); } - public async ValueTask> WriteFIFO(UInt32 devAddr, UInt32 data) + /// + /// 向指定的 JTAG 设备地址写入数据到 FIFO + /// + /// 目标设备地址 + /// 要写入的数据 + /// 写入后的延迟时间(毫秒) + /// 包含接收数据包的异步结果 + public async ValueTask> WriteFIFO(UInt32 devAddr, UInt32 data, UInt32 delayMilliseconds = 0) { var ret = false; var opts = new SendAddrPackOptions(); @@ -303,6 +467,9 @@ public class Jtag else if (!udpWriteAck.Value.IsSuccessful) return new(new Exception("Send address package failed")); + // Delay some time before read register + await Task.Delay(TimeSpan.FromMilliseconds(delayMilliseconds)); + // Read Jtag State Register opts.IsWrite = false; opts.Address = JtagAddr.STATE; @@ -317,7 +484,7 @@ public class Jtag return udpDataResp.Value; } - async ValueTask> WriteFIFO(UInt32 devAddr, byte[] dataArray) + async ValueTask> WriteFIFO(UInt32 devAddr, byte[] dataArray, UInt32 delayMilliseconds = 0) { var ret = false; var opts = new SendAddrPackOptions(); @@ -334,20 +501,21 @@ public class Jtag 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.IsWrite = true; - opts.BurstLength = isLastData ? (byte)(dataArray.Length - i * (256 * (32 / 8)) - 1) : (byte)255; + opts.BurstLength = ((byte)(sendDataArray.Length / 4 - 1)); ret = await UDPClientPool.SendAddrPackAsync(ep, new SendAddrPackage(opts)); if (!ret) return new(new Exception("Send 1st address package failed!")); + // Send Data Package - ret = await UDPClientPool.SendDataPackAsync(ep, - new SendDataPackage( - isLastData ? - dataArray[(i * (256 * (32 / 8)))..] : - dataArray[(i * (256 * (32 / 8)))..((i + 1) * (256 * (32 / 8)) - 1)] - ) - ); + ret = await UDPClientPool.SendDataPackAsync(ep, new SendDataPackage(sendDataArray)); if (!ret) return new(new Exception("Send data package failed!")); // Wait for Write Ack @@ -357,6 +525,9 @@ public class Jtag return new(new Exception("Send address package failed")); } + // Delay some time before read register + await Task.Delay(TimeSpan.FromMilliseconds(delayMilliseconds)); + // Read Jtag State Register opts.IsWrite = false; opts.BurstLength = 0; @@ -373,10 +544,10 @@ public class Jtag } async ValueTask> WriteFIFO - (UInt32 devAddr, UInt32 data, UInt32 result, UInt32 resultMask = 0xFF_FF_FF_FF) + (UInt32 devAddr, UInt32 data, UInt32 result, UInt32 resultMask = 0xFF_FF_FF_FF, UInt32 delayMilliseconds = 0) { var ret = false; - var retPack = await WriteFIFO(devAddr, data); + var retPack = await WriteFIFO(devAddr, data, delayMilliseconds); if (!retPack.IsSuccessful) return new(retPack.Error); if (retPack.Value.Options.Data is null) @@ -394,10 +565,10 @@ public class Jtag } async ValueTask> WriteFIFO - (UInt32 devAddr, byte[] data, UInt32 result, UInt32 resultMask = 0xFF_FF_FF_FF) + (UInt32 devAddr, byte[] data, UInt32 result, UInt32 resultMask = 0xFF_FF_FF_FF, UInt32 delayMilliseconds = 0) { var ret = false; - var retPack = await WriteFIFO(devAddr, data); + var retPack = await WriteFIFO(devAddr, data, delayMilliseconds); if (retPack.Value.Options.Data is null) return new(new Exception($"Data is Null, package: {retPack.Value.Options.ToString()}")); @@ -413,17 +584,68 @@ public class Jtag return ret; } + async ValueTask> WaitForWriteFIFO + (UInt32 devAddr, byte[] data, UInt32 result, + UInt32 resultMask = 0xFF_FF_FF_FF, UInt32 timeout = 10_000, UInt32 cycle = 500) + { + { + var wrRet = await WriteFIFO(devAddr, data, result, resultMask); + if (!wrRet.IsSuccessful) return new(wrRet.Error); + if (wrRet.Value) return true; + } + + // Wait some time + var ret = false; + var startTime = DateTime.Now; + var isTimeout = false; + var timeleft = TimeSpan.FromMilliseconds(timeout); + while (!isTimeout) + { + // Check whether timeout + var elapsed = DateTime.Now - startTime; + isTimeout = elapsed >= TimeSpan.FromMilliseconds(timeout); + if (isTimeout) break; + timeleft = TimeSpan.FromMilliseconds(timeout) - elapsed; + + // Check FIFO + var retPack = await ReadFIFO(JtagAddr.STATE); + if (Common.Number.BitsCheck(retPack.Value, result, resultMask)) + { + ret = true; + break; + } + + // Wait + await Task.Delay(TimeSpan.FromMilliseconds(cycle)); + } + + return ret; + } + + + /// + /// 清除所有 JTAG 寄存器 + /// + /// 指示清除是否成功的异步结果 async ValueTask> ClearAllRegisters() { return await WriteFIFO(JtagAddr.STATE, 0xFF_FF_FF_FF, 0x01_02_02_02, JtagState.ALL_REG); } + /// + /// 清除 JTAG 写数据寄存器 + /// + /// 指示清除是否成功的异步结果 async ValueTask> ClearWriteDataReg() { return await WriteFIFO(JtagAddr.STATE, 0x00_00_11_00, 0x01_00_02_00, JtagState.WRITE_DATA_FIFO | JtagState.CMD_EXEC_FINISH); } + /// + /// 关闭 JTAG 测试模式 + /// + /// 指示操作是否成功的异步结果 async ValueTask> CloseTest() { return await WriteFIFO( @@ -432,6 +654,10 @@ public class Jtag 0x01_00_00_00, JtagState.CMD_EXEC_FINISH); } + /// + /// 启动 JTAG 测试模式 + /// + /// 指示操作是否成功的异步结果 async ValueTask> RunTest() { return await WriteFIFO( @@ -440,6 +666,11 @@ public class Jtag 0x01_00_00_00, JtagState.CMD_EXEC_FINISH); } + /// + /// 设置 JTAG 空闲延迟时间 + /// + /// 延迟时间(毫秒) + /// 指示操作是否成功的异步结果 async ValueTask> IdleDelay(UInt32 milliseconds) { if (milliseconds > Math.Pow(2, 28)) return new(new Exception("Timespan is over 2^28 milliseconds")); @@ -447,7 +678,7 @@ public class Jtag return await WriteFIFO( JtagAddr.WRITE_CMD, Common.Number.MultiBitsToNumber(JtagCmd.CMD_JTAG_IDLE_DELAY, JtagCmd.LEN_CMD_JTAG, milliseconds, 28).Value, - 0x01_00_00_00, JtagState.CMD_EXEC_FINISH); + 0x01_00_00_00, JtagState.CMD_EXEC_FINISH, (milliseconds / CLOCK_FREQ) + 100); } async ValueTask> ExecRDCmd(uint command) @@ -472,7 +703,7 @@ public class Jtag return await ClearWriteDataReg(); } - async ValueTask> LoadDRCareInput(byte[] bytesArray) + async ValueTask> LoadDRCareInput(byte[] bytesArray, UInt32 timeout = 10_000, UInt32 cycle = 500) { var bytesLen = ((uint)(bytesArray.Length * 8)); if (bytesLen > Math.Pow(2, 28)) return new(new Exception("Length is over 2^(28 - 3)")); @@ -481,13 +712,17 @@ public class Jtag var ret = await WriteFIFO( JtagAddr.WRITE_CMD, Common.Number.MultiBitsToNumber(JtagCmd.CMD_JTAG_LOAD_DR_CAREI, JtagCmd.LEN_CMD_JTAG, bytesLen, 28).Value, - 0x01_00_00_00, JtagState.CMD_EXEC_FINISH); + 0, 0); if (!ret.IsSuccessful) return new(ret.Error); else if (!ret.Value) return new(new Exception("Write CMD_JTAG_LOAD_DR_CAREI Failed")); } { - var ret = await WriteFIFO(JtagAddr.WRITE_DATA, bytesArray, 0x01_00_00_00, JtagState.CMD_EXEC_FINISH); + var ret = await WaitForWriteFIFO( + JtagAddr.WRITE_DATA, + bytesArray, 0x01_00_00_00, + JtagState.CMD_EXEC_FINISH, + timeout, cycle); if (!ret.IsSuccessful) return new(ret.Error); else if (!ret.Value) return new(new Exception("Write Data Failed")); @@ -510,6 +745,10 @@ public class Jtag return new(new Exception("LoadDRCareo Failed!")); } + /// + /// 读取 JTAG 设备的 ID 代码 + /// + /// 包含 ID 代码的异步结果 public async ValueTask> ReadIDCode() { // Clear Data @@ -544,6 +783,49 @@ public class Jtag return retData.Value; } + /// + /// 读取 JTAG 设备的状态寄存器 + /// + /// 包含状态寄存器值的异步结果 + public async ValueTask> ReadStatusReg() + { + // Clear Data + await MsgBus.UDPServer.ClearUDPData(this.address); + + logger.Trace($"Clear up udp server {this.address} receive data"); + + Result ret; + + ret = await ClearAllRegisters(); + if (!ret.IsSuccessful) return new(ret.Error); + else if (!ret.Value) return new(new Exception("Jtag Clear All Registers Failed")); + + ret = await RunTest(); + if (!ret.IsSuccessful) return new(ret.Error); + else if (!ret.Value) return new(new Exception("Jtag Run Test Failed")); + + ret = await ExecRDCmd(JtagCmd.JTAG_DR_RDSR); + if (!ret.IsSuccessful) return new(ret.Error); + else if (!ret.Value) return new(new Exception("Jtag Execute Command JTAG_DR_RDSR Failed")); + + ret = await ClearWriteDataReg(); + if (!ret.IsSuccessful) return new(ret.Error); + else if (!ret.Value) return new(new Exception("Jtag Clear Write Registers Failed")); + + var retData = await LoadDRCareOutput(4); + if (!retData.IsSuccessful) + { + return new(new Exception("Read Status Reg Failed")); + } + + return retData.Value; + } + + /// + /// 下载比特流到 JTAG 设备 + /// + /// 比特流数据 + /// 指示下载是否成功的异步结果 public async ValueTask> DownloadBitstream(byte[] bitstream) { // Clear Data @@ -577,7 +859,7 @@ public class Jtag logger.Trace("Jtag ready to write bitstream"); - ret = await IdleDelay(75000); + ret = await IdleDelay(100000); if (!ret.IsSuccessful) return new(ret.Error); else if (!ret.Value) return new(new Exception("Jtag IDLE Delay Failed")); @@ -601,7 +883,7 @@ public class Jtag logger.Trace("Jtag reset device"); - ret = await IdleDelay(1000); + ret = await IdleDelay(10000); if (!ret.IsSuccessful) return new(ret.Error); else if (!ret.Value) return new(new Exception("Jtag IDLE Delay Failed")); diff --git a/server/src/UdpServer.cs b/server/src/UdpServer.cs index b17937b..b9e933c 100644 --- a/server/src/UdpServer.cs +++ b/server/src/UdpServer.cs @@ -81,9 +81,13 @@ public class UDPServer /// UDP 服务器的错误代码 public enum ErrorCode { + /// [TODO:description] Success = 0, + /// [TODO:description] GetNoneAfterTimeout, + /// [TODO:description] ResponseWrong, + /// [TODO:description] NotRecvDataPackage, } @@ -116,6 +120,7 @@ public class UDPServer /// /// 目标IP地址 /// 超时时间 + /// 延迟时间 /// 调用函数名称 /// 调用函数位置 /// @@ -124,7 +129,7 @@ public class UDPServer /// Optional 存在时,为最先收到的数据 /// public async ValueTask> FindDataAsync( - string ipAddr, int timeout = 1000, + string ipAddr, int timeout = 1000, int cycle = 0, [CallerMemberName] string callerName = "", [CallerLineNumber] int callerLineNum = 0) { @@ -153,6 +158,8 @@ public class UDPServer break; } } + + await Task.Delay(cycle); } if (data is null) @@ -171,8 +178,9 @@ public class UDPServer /// /// IP地址 /// 超时时间 + /// 延迟时间 /// 数据列表 - public async ValueTask>> GetDataArrayAsync(string ipAddr, int timeout = 1000) + public async ValueTask>> GetDataArrayAsync(string ipAddr, int timeout = 1000, int cycle = 0) { List? data = null; diff --git a/server/src/WebProtocol.cs b/server/src/WebProtocol.cs index 88a99df..707a7e1 100644 --- a/server/src/WebProtocol.cs +++ b/server/src/WebProtocol.cs @@ -20,10 +20,10 @@ namespace WebProtocol /// Package Burst Type public enum BurstType { - /// Extended Type - ExtendBurst = 0b00, /// Fixed Type - FixedBurst = 0b01, + FixedBurst = 0b00, + /// Extended Type + ExtendBurst = 0b01, } diff --git a/src/App.vue b/src/App.vue index 908e59e..54e03aa 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,6 +1,7 @@ + + diff --git a/src/views/JtagTest.vue b/src/views/JtagTest.vue index c20d582..7fb5887 100644 --- a/src/views/JtagTest.vue +++ b/src/views/JtagTest.vue @@ -3,13 +3,39 @@
-
- +