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 @@ + 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 BytesToNumber(byte[] bytes, bool isRightLeft = false) + public static Result 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 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 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 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; } +/// +/// Jtag 状态寄存器的掩码及其确认函数 +/// +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的写不改变其值 + */ + + /// + /// 移位数据读fifo清空,1为有效,清空后自动置0,实际一直为零 + /// + public const UInt32 READ_DATA_FIFO_CLEAR = 0b0001 << 0; + /// + /// 移位数据fifo读入口-空标识,只读,对JTAG_STATE_REG的写不改变其值 + /// + public const UInt32 READ_DATA_FIFO_EMPTY = 0b0010 << 0; + /// + /// 移位数据fifo读入口-满标识,只读,对JTAG_STATE_REG的写不改变其值 + /// + public const UInt32 READ_DATA_FIFO_AFULL = 0b0100 << 0; + /// + /// 移位数据读fifo + /// + public const UInt32 READ_DATA_FIFO = 0b0111 << 0; + + /// + /// 移位数据写fifo清空,1为有效,清空后自动置0 + /// + public const UInt32 WRITE_DATA_FIFO_CLEAR = 0b0001 << 8; + /// + /// 移位数据fifo写入口-空标识,只读,对JTAG_STATE_REG的写不改变其值 + /// + public const UInt32 WRITE_DATA_FIFO_EMPTY = 0b0010 << 8; + /// + /// 移位数据fifo写入口-满标识,只读,对JTAG_STATE_REG的写不改变其值 + /// + public const UInt32 WRITE_DATA_FIFO_AFULL = 0b0100 << 8; + /// + /// 移位数据写fifo + /// + public const UInt32 WRITE_DATA_FIFO = 0b0111 << 8; + + /// + /// 移位命令写fifo清空,1为有效,清空后自动置0 + /// + public const UInt32 WRITE_CMD_FIFO_CLEAR = 0b0001 << 16; + /// + /// 移位命令fifo写入口-空标识,只读,对JTAG_STATE_REG的写不改变其值 + /// + public const UInt32 WRITE_CMD_FIFO_EMPTY = 0b0010 << 16; + /// + /// 移位命令fifo写入口-满标识,只读,对JTAG_STATE_REG的写不改变其值 + /// + public const UInt32 WRITE_CMD_FIFO_AFULL = 0b0100 << 16; + /// + /// 移位命令写fifo + /// + public const UInt32 WRITE_CMD_FIFO = 0b0111 << 16; + + /// + /// CMD执行完毕标识,只读,对JTAG_STATE_REG的写不改变其值 + /// + public const UInt32 CMD_EXEC_FINISH = 0b0001 << 24; + /// + /// 全部FIFO + /// + public const UInt32 ALL_FIFO = READ_DATA_FIFO | WRITE_DATA_FIFO | WRITE_CMD_FIFO; + /// + /// 全部寄存器 + /// + public const UInt32 ALL_REG = READ_DATA_FIFO | WRITE_DATA_FIFO | WRITE_CMD_FIFO | CMD_EXEC_FINISH; + +} + /// /// The Command bits of Jtag /// public static class JtagCmd { + /// + /// The length of JTAG_DR_XXXX + /// + public const UInt32 LEN_JTAG_DR = 10; /// /// 旁路指令 /// @@ -89,6 +184,10 @@ public static class JtagCmd + /// + /// The length of CMD_JTAG_XXXX_XXXX + /// + public const UInt32 LEN_CMD_JTAG = 4; /// /// 设定JTAG默认状态为TEST_LOGIC_RESET态 (JTAG复位) /// @@ -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> RunCommand(uint devAddr, uint cmd, uint exRet) + public async ValueTask> 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> 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> 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> 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> 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> 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> WriteIDCode() + public async ValueTask> 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> 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> 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> 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; + } + /// /// Web API /// @@ -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 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 GetDeviceIDCode(string address, int port) + public class Jtag { + /// + /// 执行一个Jtag命令 + /// + /// 设备地址 + /// 设备端口 + /// 16进制设备目的地址(Jtag) + /// 16进制命令 + /// 16进制预期结果 + /// Response + public static async ValueTask 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 }); } + } + + + /// + /// 获取Jtag ID Code + /// + /// 设备地址 + /// 设备端口 + /// Response + public static async ValueTask 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 /// 0x10_00_00_00 public UInt32 address; + /// + /// Convert to Json String + /// + /// Json String public override string ToString() { return JsonConvert.SerializeObject(this); } } + /// Package Options which to receive from boards public struct RecvPackOptions { + /// + /// Task ID + /// public byte commandID; + /// + /// Whether is succeed to finish command + /// public bool isSuccess; - public byte[] data; + /// + /// Return Data + /// + public byte[]? data; + + /// + /// Convert to Json String + /// + /// Json String + public override string ToString() + { + return JsonConvert.SerializeObject(this); + } } + /// Package which send address to write 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; }