From 93add0c3153d812fe54a1fde321a7558207eafe7 Mon Sep 17 00:00:00 2001 From: SikongJueluo <selfconfusion@gmail.com> Date: Mon, 7 Apr 2025 21:56:30 +0800 Subject: [PATCH] add jtag get id code api --- server/Program.cs | 2 + server/server.csproj | 1 + server/src/Common.cs | 30 ++++- server/src/JtagController.cs | 214 ++++++++++++++++++++++++++++++++--- server/src/Router.cs | 55 +++++++-- server/src/WebProtocol.cs | 27 ++++- 6 files changed, 300 insertions(+), 29 deletions(-) diff --git a/server/Program.cs b/server/Program.cs index de3c392..692e916 100644 --- a/server/Program.cs +++ b/server/Program.cs @@ -41,6 +41,8 @@ app.MapGet("/", () => "Hello World!"); app.MapPut("/api/SendString", Router.API.SendString); app.MapPut("/api/SendAddrPackage", Router.API.SendAddrPackage); app.MapPut("/api/SendDataPackage", Router.API.SendDataPackage); +app.MapPut("/api/jtag/RunCommand", Router.API.Jtag.RunCommand); +app.MapPut("/api/jtag/GetIDCode", Router.API.Jtag.GetDeviceIDCode); app.Run("http://localhost:5000"); diff --git a/server/server.csproj b/server/server.csproj index 72e9b6e..faf5a41 100644 --- a/server/server.csproj +++ b/server/server.csproj @@ -12,6 +12,7 @@ <PackageReference Include="DotNext.Threading" Version="5.19.1" /> <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="Swashbuckle.AspNetCore" Version="8.1.0" /> </ItemGroup> diff --git a/server/src/Common.cs b/server/src/Common.cs index 714b566..465b096 100644 --- a/server/src/Common.cs +++ b/server/src/Common.cs @@ -27,13 +27,13 @@ namespace Common { for (var i = 0; i < length; i++) { - arr[i] = Convert.ToByte((num >> (i << 3)) & (0xFF)); + arr[i] = Convert.ToByte((num >> ((int)(length - 1 - i) << 3)) & (0xFF)); } } return arr; } - public static Result<ulong> BytesToNumber(byte[] bytes, bool isRightLeft = false) + public static Result<ulong> BytesToNumber(byte[] bytes, bool isRightHigh = false) { if (bytes.Length > 8) { @@ -46,7 +46,7 @@ namespace Common ulong num = 0; int len = bytes.Length; - if (isRightLeft) + if (isRightHigh) { for (var i = 0; i < len; i++) { @@ -57,13 +57,15 @@ namespace Common { for (var i = 0; i < len; i++) { - num += Convert.ToUInt64(bytes[i] << (i << 3)); + num += Convert.ToUInt64(bytes[i] << ((int)(len - 1 - i) << 3)); } } return num; } + + public static Result<byte[]> MultiBitsToBytes(ulong bits1, uint bits1Len, ulong bits2, uint bits2Len) { return NumberToBytes(MultiBitsToNumber(bits1, bits1Len, bits2, bits2Len).Value, @@ -74,10 +76,28 @@ namespace Common { if (bits1Len + bits2Len > 64) throw new ArgumentException("Two Bits is more than 64 bits"); - ulong num = (bits1 << (int)bits2Len) | bits2; + ulong num = (bits1 << Convert.ToInt32(bits2Len)) | bits2; return num; } + public static Result<uint> MultiBitsToNumber(uint bits1, uint bits1Len, uint bits2, uint bits2Len) + { + if (bits1Len + bits2Len > 64) throw new ArgumentException("Two Bits is more than 64 bits"); + + uint num = (bits1 << Convert.ToInt32(bits2Len)) | bits2; + return num; + } + + public static bool BitsCheck(ulong srcBits, ulong dstBits, ulong mask = 0xFFFF_FFFF_FFFF_FFFF) + { + return (srcBits & mask) == dstBits; + } + + public static bool BitsCheck(uint srcBits, uint dstBits, uint mask = 0xFFFF_FFFF) + { + return (srcBits & mask) == dstBits; + } + public static Result<byte[]> StringToBytes(string str, int numBase = 16) { diff --git a/server/src/JtagController.cs b/server/src/JtagController.cs index 0c092be..ae26c01 100644 --- a/server/src/JtagController.cs +++ b/server/src/JtagController.cs @@ -28,12 +28,107 @@ public static class JtagAddr public const UInt32 WRITE_CMD = 0x10_00_00_03; } +/// <summary> +/// Jtag 状态寄存器的掩码及其确认函数 +/// </summary> +public static class JtagState +{ + + /* + [0] 移位数据读fifo清空,1为有效,清空后自动置0 + [1] 移位数据fifo读入口-空标识,只读,对JTAG_STATE_REG的写不改变其值 + [2] 移位数据fifo读入口-满标识,只读,对JTAG_STATE_REG的写不改变其值 + [7:3] 保留 + + [8] 移位数据写fifo清空,1为有效,清空后自动置0 + [9] 移位数据fifo写入口-空标识,只读,对JTAG_STATE_REG的写不改变其值 + [10] 移位数据fifo写入口-满标识,只读,对JTAG_STATE_REG的写不改变其值 + [15:11]保留 + + [16] 移位命令写fifo清空,1为有效,清空后自动置0 + [17] 移位命令fifo写入口-空标识,只读,对JTAG_STATE_REG的写不改变其值 + [18] 移位命令fifo写入口-满标识,只读,对JTAG_STATE_REG的写不改变其值 + [23:19]保留 + + [24] CMD执行完毕标识,只读,对JTAG_STATE_REG的写不改变其值 + */ + + /// <summary> + /// 移位数据读fifo清空,1为有效,清空后自动置0,实际一直为零 + /// </summary> + public const UInt32 READ_DATA_FIFO_CLEAR = 0b0001 << 0; + /// <summary> + /// 移位数据fifo读入口-空标识,只读,对JTAG_STATE_REG的写不改变其值 + /// </summary> + public const UInt32 READ_DATA_FIFO_EMPTY = 0b0010 << 0; + /// <summary> + /// 移位数据fifo读入口-满标识,只读,对JTAG_STATE_REG的写不改变其值 + /// </summary> + public const UInt32 READ_DATA_FIFO_AFULL = 0b0100 << 0; + /// <summary> + /// 移位数据读fifo + /// </summary> + public const UInt32 READ_DATA_FIFO = 0b0111 << 0; + + /// <summary> + /// 移位数据写fifo清空,1为有效,清空后自动置0 + /// </summary> + public const UInt32 WRITE_DATA_FIFO_CLEAR = 0b0001 << 8; + /// <summary> + /// 移位数据fifo写入口-空标识,只读,对JTAG_STATE_REG的写不改变其值 + /// </summary> + public const UInt32 WRITE_DATA_FIFO_EMPTY = 0b0010 << 8; + /// <summary> + /// 移位数据fifo写入口-满标识,只读,对JTAG_STATE_REG的写不改变其值 + /// </summary> + public const UInt32 WRITE_DATA_FIFO_AFULL = 0b0100 << 8; + /// <summary> + /// 移位数据写fifo + /// </summary> + public const UInt32 WRITE_DATA_FIFO = 0b0111 << 8; + + /// <summary> + /// 移位命令写fifo清空,1为有效,清空后自动置0 + /// </summary> + public const UInt32 WRITE_CMD_FIFO_CLEAR = 0b0001 << 16; + /// <summary> + /// 移位命令fifo写入口-空标识,只读,对JTAG_STATE_REG的写不改变其值 + /// </summary> + public const UInt32 WRITE_CMD_FIFO_EMPTY = 0b0010 << 16; + /// <summary> + /// 移位命令fifo写入口-满标识,只读,对JTAG_STATE_REG的写不改变其值 + /// </summary> + public const UInt32 WRITE_CMD_FIFO_AFULL = 0b0100 << 16; + /// <summary> + /// 移位命令写fifo + /// </summary> + public const UInt32 WRITE_CMD_FIFO = 0b0111 << 16; + + /// <summary> + /// CMD执行完毕标识,只读,对JTAG_STATE_REG的写不改变其值 + /// </summary> + public const UInt32 CMD_EXEC_FINISH = 0b0001 << 24; + /// <summary> + /// 全部FIFO + /// </summary> + public const UInt32 ALL_FIFO = READ_DATA_FIFO | WRITE_DATA_FIFO | WRITE_CMD_FIFO; + /// <summary> + /// 全部寄存器 + /// </summary> + public const UInt32 ALL_REG = READ_DATA_FIFO | WRITE_DATA_FIFO | WRITE_CMD_FIFO | CMD_EXEC_FINISH; + +} + /// <summary> /// The Command bits of Jtag /// </summary> public static class JtagCmd { + /// <summary> + /// The length of JTAG_DR_XXXX + /// </summary> + public const UInt32 LEN_JTAG_DR = 10; /// <summary> /// 旁路指令 /// </summary> @@ -89,6 +184,10 @@ public static class JtagCmd + /// <summary> + /// The length of CMD_JTAG_XXXX_XXXX + /// </summary> + public const UInt32 LEN_CMD_JTAG = 4; /// <summary> /// 设定JTAG默认状态为TEST_LOGIC_RESET态 (JTAG复位) /// </summary> @@ -122,18 +221,56 @@ class Jtag readonly int port; readonly string address; private IPEndPoint ep; - private UDPServer server; - public Jtag(string address, int port, UDPServer udpServer, int outTime = 2000) + public Jtag(string address, int port, int outTime = 2000) { this.address = address; this.port = port; this.ep = new IPEndPoint(IPAddress.Parse(address), port); - this.server = udpServer; this.timeout = outTime; } - public async ValueTask<Result<bool>> RunCommand(uint devAddr, uint cmd, uint exRet) + public async ValueTask<Result<uint>> ReadFIFO(uint devAddr) + { + var ret = false; + var opts = new SendAddrPackOptions(); + + opts.burstType = BurstType.FixedBurst; + opts.burstLength = 4; + opts.commandID = 0; + opts.address = devAddr; + + // Read Jtag State Register + ret = await UDPClientPool.SendAddrPackAsync(ep, new SendAddrPackage(opts)); + if (!ret) throw new Exception("Send Address Package Failed!"); + + // Wait for Ack + if (!MsgBus.IsRunning) + throw new Exception("Message Bus not Working!"); + + var data = await MsgBus.UDPServer.FindDataAsync(address); + if (!data.HasValue) + throw new Exception("Get None after Time out!"); + + var recvData = data.Value; + if (recvData.addr != address || recvData.port != port) + throw new Exception("Receive Data From Wrong Board!"); + + var retPack = RecvDataPackage.FromBytes(recvData.data); + if (!retPack.IsSuccessful) + throw new Exception("Not RecvDataPackage!", retPack.Error); + + if (retPack.Value.Options.data is null) + throw new Exception($"Data is Null, package: {retPack.Value.Options.ToString()}"); + + var retPackLen = retPack.Value.Options.data.Length; + if (retPackLen != 4) + throw new Exception($"RecvDataPackage BodyData Length not Equal to 4: Total {retPackLen} bytes"); + + return (uint)(NumberProcessor.BytesToNumber(retPack.Value.Options.data)); + } + + public async ValueTask<Result<RecvDataPackage>> RunCommand(uint devAddr, uint command) { var ret = false; var opts = new SendAddrPackOptions(); @@ -148,7 +285,7 @@ class Jtag ret = await UDPClientPool.SendAddrPackAsync(ep, new SendAddrPackage(opts)); if (!ret) throw new Exception("Send 1st Address Package Failed!"); ret = await UDPClientPool.SendDataPackAsync(ep, - new SendDataPackage(NumberProcessor.NumberToBytes(cmd, 4).Value)); + new SendDataPackage(NumberProcessor.NumberToBytes(command, 4).Value)); if (!ret) throw new Exception("Send Data Package Failed!"); // Read Jtag State Register @@ -170,41 +307,88 @@ class Jtag var retPack = RecvDataPackage.FromBytes(recvData.data); if (!retPack.IsSuccessful) - throw new Exception("Not Current RecvDataPackage!", retPack.Error); + throw new Exception("Not RecvDataPackage!", retPack.Error); + + + return retPack; + } + + public async ValueTask<Result<bool>> RunCommand(uint devAddr, uint command, uint result, uint resultMask = 0xFF_FF_FF_FF) + { + var ret = false; + var retPack = await RunCommand(devAddr, command); + + if (retPack.Value.Options.data is null) + throw new Exception($"Data is Null, package: {retPack.Value.Options.ToString()}"); var retPackLen = retPack.Value.Options.data.Length; - if (retPackLen != 3) - throw new Exception($"RecvDataPackage BodyData Length not Equal to 3: Total {retPackLen} bytes"); + if (retPackLen != 4) + throw new Exception($"RecvDataPackage BodyData Length not Equal to 4: Total {retPackLen} bytes"); - if (NumberProcessor.BytesToNumber(retPack.Value.Options.data).Value == exRet) + if (NumberProcessor.BitsCheck( + NumberProcessor.BytesToNumber(retPack.Value.Options.data).Value, result, resultMask)) ret = true; return ret; } + public async ValueTask<Result<bool>> ClearAllRegisters() { - return await RunCommand(JtagAddr.STATE, 0xFF_FF_FF_FF, 0x00_00_00_00); + return await RunCommand(JtagAddr.STATE, 0xFF_FF_FF_FF, 0x01_02_02_02, JtagState.ALL_REG); } public async ValueTask<Result<bool>> ClearWriteDataReg() { - return await RunCommand(JtagAddr.STATE, 0x00_00_11_00, 0x00_00_00_00); + return await RunCommand(JtagAddr.STATE, 0x00_00_11_00, 0x01_00_02_00, JtagState.WRITE_DATA_FIFO | JtagState.CMD_EXEC_FINISH); } public async ValueTask<Result<bool>> RunTest() { - return await RunCommand(JtagAddr.WRITE_CMD, 0x10_00_00_00, 0x01_00_00_00); + return await RunCommand( + JtagAddr.WRITE_CMD, + NumberProcessor.MultiBitsToNumber(JtagCmd.CMD_JTAG_RUN_TEST, JtagCmd.LEN_CMD_JTAG, 0, 28).Value, + 0x01_00_00_00, JtagState.CMD_EXEC_FINISH); } - public async ValueTask<Result<bool>> WriteIDCode() + public async ValueTask<Result<bool>> DRIDcode() { - return await RunCommand(JtagAddr.WRITE_DATA, 0b1010000011, 0x01_00_00_00); + return await RunCommand( + JtagAddr.WRITE_DATA, + NumberProcessor.MultiBitsToNumber(0, 22, JtagCmd.JTAG_DR_IDCODE, JtagCmd.LEN_JTAG_DR).Value, 0, 0); } public async ValueTask<Result<bool>> LoadIR() { - return await RunCommand(JtagAddr.WRITE_CMD, 0x20_00_00_0A, 0x01_00_00_00); + return await RunCommand( + JtagAddr.WRITE_CMD, + NumberProcessor.MultiBitsToNumber(JtagCmd.CMD_JTAG_LOAD_IR, JtagCmd.LEN_CMD_JTAG, 10, 28).Value, + 0x01_00_00_00); + } + + public async ValueTask<Result<uint>> LoadDRCareo() + { + var ret = await RunCommand( + JtagAddr.WRITE_CMD, + NumberProcessor.MultiBitsToNumber(JtagCmd.CMD_JTAG_LOAD_DR_CAREO, JtagCmd.LEN_CMD_JTAG, 32, 28).Value, + 0x01_00_00_00, JtagState.CMD_EXEC_FINISH); + + if (ret.Value) + return await ReadFIFO(JtagAddr.READ_DATA); + else + throw new Exception("LoadDRCareo Failed!"); + } + + public async ValueTask<Result<uint>> ReadIDCode() + { + var ret = false; + + ret = (await ClearAllRegisters()).Value; + ret = (await RunTest()).Value; + ret = (await DRIDcode()).Value; + ret = (await LoadIR()).Value; + ret = (await ClearWriteDataReg()).Value; + return (await LoadDRCareo()).Value; } } diff --git a/server/src/Router.cs b/server/src/Router.cs index d8532a9..2b7ea41 100644 --- a/server/src/Router.cs +++ b/server/src/Router.cs @@ -1,10 +1,15 @@ using System.Net; using Common; -using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; namespace Router { + struct Response + { + public bool IsSuccess; + public object? Data; + } + /// <summary> /// Web API /// </summary> @@ -21,8 +26,8 @@ namespace Router { var endPoint = new IPEndPoint(IPAddress.Parse(address), port); var ret = await UDPClientPool.SendStringAsync(endPoint, [text]); - if (ret) { return Results.Json(true); } - else { return Results.Json(false); } + if (ret) { return Results.Json(new Response() { IsSuccess = true }); } + else { return Results.Json(new Response() { IsSuccess = false }); } } @@ -46,8 +51,8 @@ namespace Router var endPoint = new IPEndPoint(IPAddress.Parse(address), port); var ret = await UDPClientPool.SendAddrPackAsync(endPoint, new WebProtocol.SendAddrPackage(opts)); - if (ret) { return Results.Json(true); } - else { return Results.Json(false); } + if (ret) { return Results.Json(new Response() { IsSuccess = true }); } + else { return Results.Json(new Response() { IsSuccess = false }); } } public static async ValueTask<IResult> SendDataPackage(string address, int port, string data) @@ -55,12 +60,46 @@ namespace Router var endPoint = new IPEndPoint(IPAddress.Parse(address), port); var ret = await UDPClientPool.SendDataPackAsync(endPoint, new WebProtocol.SendDataPackage(NumberProcessor.StringToBytes(data).Value)); - if (ret) { return Results.Json(true); } - else { return Results.Json(false); } + if (ret) { return Results.Json(new Response() { IsSuccess = true }); } + else { return Results.Json(new Response() { IsSuccess = false }); } } - public static async ValueTask<IResult> GetDeviceIDCode(string address, int port) + public class Jtag { + /// <summary> + /// 执行一个Jtag命令 + /// </summary> + /// <param name="address"> 设备地址 </param> + /// <param name="port"> 设备端口 </param> + /// <param name="hexDevAddr"> 16进制设备目的地址(Jtag) </param> + /// <param name="hexCmd"> 16进制命令 </param> + /// <param name="hexExRet"> 16进制预期结果 </param> + /// <returns> Response </returns> + public static async ValueTask<IResult> RunCommand(string address, int port, string hexDevAddr, string hexCmd, string hexExRet) + { + var jtagCtrl = new JtagController.Jtag(address, port); + var ret = await jtagCtrl.RunCommand(Convert.ToUInt32(hexDevAddr, 16), Convert.ToUInt32(hexCmd, 16), Convert.ToUInt32(hexExRet, 16)); + + + if (ret.IsSuccessful) { return Results.Json(new Response() { IsSuccess = true }); } + else { return Results.Json(new Response() { IsSuccess = false, Data = ret.Error }); } + } + + + /// <summary> + /// 获取Jtag ID Code + /// </summary> + /// <param name="address"> 设备地址 </param> + /// <param name="port"> 设备端口 </param> + /// <returns> Response </returns> + public static async ValueTask<IResult> GetDeviceIDCode(string address, int port) + { + var jtagCtrl = new JtagController.Jtag(address, port); + var ret = await jtagCtrl.ReadIDCode(); + + if (ret.IsSuccessful) { return Results.Json(new Response() { IsSuccess = true, Data = ret.Value }); } + else { return Results.Json(new Response() { IsSuccess = false, Data = ret.Error }); } + } } diff --git a/server/src/WebProtocol.cs b/server/src/WebProtocol.cs index a224724..4c48312 100644 --- a/server/src/WebProtocol.cs +++ b/server/src/WebProtocol.cs @@ -49,19 +49,43 @@ namespace WebProtocol /// <example> 0x10_00_00_00 </example> public UInt32 address; + /// <summary> + /// Convert to Json String + /// </summary> + /// <returns> Json String </returns> public override string ToString() { return JsonConvert.SerializeObject(this); } } + /// <summary> Package Options which to receive from boards </summary> public struct RecvPackOptions { + /// <summary> + /// Task ID + /// </summary> public byte commandID; + /// <summary> + /// Whether is succeed to finish command + /// </summary> public bool isSuccess; - public byte[] data; + /// <summary> + /// Return Data + /// </summary> + public byte[]? data; + + /// <summary> + /// Convert to Json String + /// </summary> + /// <returns> Json String </returns> + public override string ToString() + { + return JsonConvert.SerializeObject(this); + } } + /// <summary> Package which send address to write </summary> public struct SendAddrPackage { readonly byte sign = (byte)PackSign.SendAddr; @@ -227,6 +251,7 @@ namespace WebProtocol RecvPackOptions opts; opts.commandID = commandID; opts.isSuccess = Convert.ToBoolean((resp >> 1) == 0b01 ? true : false); + opts.data = null; return opts; }