Merge branch 'master' of ssh://git.swordlost.top:222/SikongJueluo/FPGA_WebLab into dpp
This commit is contained in:
		
							
								
								
									
										17
									
								
								.justfile
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								.justfile
									
									
									
									
									
								
							@@ -3,20 +3,35 @@
 | 
				
			|||||||
  pwd
 | 
					  pwd
 | 
				
			||||||
  echo
 | 
					  echo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 清空构建文件
 | 
				
			||||||
clean: 
 | 
					clean: 
 | 
				
			||||||
  rm -rf "server/bin"
 | 
					  rm -rf "server/bin"
 | 
				
			||||||
  rm -rf "server/obj"
 | 
					  rm -rf "server/obj"
 | 
				
			||||||
  rm -rf "server.test/bin"
 | 
					  rm -rf "server.test/bin"
 | 
				
			||||||
  rm -rf "server.test/obj"
 | 
					  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"]
 | 
					[working-directory: "server"]
 | 
				
			||||||
publish: _show-dir
 | 
					build-server: _show-dir
 | 
				
			||||||
  dotnet publish --self-contained false -t:PublishAllRids
 | 
					  dotnet publish --self-contained false -t:PublishAllRids
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 运行服务器
 | 
				
			||||||
[working-directory: "server"]
 | 
					[working-directory: "server"]
 | 
				
			||||||
run-server: _show-dir
 | 
					run-server: _show-dir
 | 
				
			||||||
  dotnet run
 | 
					  dotnet run
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 运行网页客户端
 | 
				
			||||||
 | 
					run-web: 
 | 
				
			||||||
 | 
					  npm run dev
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
 | 
					# 运行测试用例测试服务器
 | 
				
			||||||
[working-directory: "server.test"]
 | 
					[working-directory: "server.test"]
 | 
				
			||||||
test-server: _show-dir
 | 
					test-server: _show-dir
 | 
				
			||||||
  dotnet test --logger "console;verbosity=detailed"
 | 
					  dotnet test --logger "console;verbosity=detailed"
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										39
									
								
								server.test/CommonTest.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								server.test/CommonTest.cs
									
									
									
									
									
										Normal file
									
								
							@@ -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);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -5,30 +5,6 @@ using Xunit.Abstractions;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace server.test;
 | 
					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<object[]> GetData(System.Reflection.MethodInfo testMethod)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        foreach (var iterationNumber in Enumerable.Range(start: 1, count: this.count))
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            yield return new object[] { iterationNumber };
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class UDPServerTest
 | 
					public class UDPServerTest
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -36,6 +36,18 @@ try
 | 
				
			|||||||
        options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
 | 
					        options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Add CORS policy
 | 
				
			||||||
 | 
					    builder.Services.AddCors(options =>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        options.AddPolicy("Development", policy =>
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            policy
 | 
				
			||||||
 | 
					                .AllowAnyOrigin()
 | 
				
			||||||
 | 
					                .AllowAnyMethod()
 | 
				
			||||||
 | 
					                .AllowAnyHeader();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Add Swagger
 | 
					    // Add Swagger
 | 
				
			||||||
    builder.Services.AddControllers();
 | 
					    builder.Services.AddControllers();
 | 
				
			||||||
    builder.Services.AddOpenApiDocument(options =>
 | 
					    builder.Services.AddOpenApiDocument(options =>
 | 
				
			||||||
@@ -75,6 +87,7 @@ try
 | 
				
			|||||||
    app.UseHttpsRedirection();
 | 
					    app.UseHttpsRedirection();
 | 
				
			||||||
    app.UseStaticFiles();
 | 
					    app.UseStaticFiles();
 | 
				
			||||||
    app.UseRouting();
 | 
					    app.UseRouting();
 | 
				
			||||||
 | 
					    app.UseCors();
 | 
				
			||||||
    app.UseAuthorization();
 | 
					    app.UseAuthorization();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // if (app.Environment.IsDevelopment())
 | 
					    // if (app.Environment.IsDevelopment())
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -85,11 +85,11 @@ namespace Common
 | 
				
			|||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// 比特合并成二进制字节
 | 
					        /// 比特合并成二进制字节
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        /// <param name="bits1">[TODO:parameter]</param>
 | 
					        /// <param name="bits1">第一个比特值</param>
 | 
				
			||||||
        /// <param name="bits1Len">[TODO:parameter]</param>
 | 
					        /// <param name="bits1Len">第一个比特值的长度(位数)</param>
 | 
				
			||||||
        /// <param name="bits2">[TODO:parameter]</param>
 | 
					        /// <param name="bits2">第二个比特值</param>
 | 
				
			||||||
        /// <param name="bits2Len">[TODO:parameter]</param>
 | 
					        /// <param name="bits2Len">第二个比特值的长度(位数)</param>
 | 
				
			||||||
        /// <returns>[TODO:return]</returns>
 | 
					        /// <returns>合并后的二进制字节数组</returns>
 | 
				
			||||||
        public static Result<byte[]> MultiBitsToBytes(ulong bits1, uint bits1Len, ulong bits2, uint bits2Len)
 | 
					        public static Result<byte[]> MultiBitsToBytes(ulong bits1, uint bits1Len, ulong bits2, uint bits2Len)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            return NumberToBytes(MultiBitsToNumber(bits1, bits1Len, bits2, bits2Len).Value,
 | 
					            return NumberToBytes(MultiBitsToNumber(bits1, bits1Len, bits2, bits2Len).Value,
 | 
				
			||||||
@@ -99,11 +99,11 @@ namespace Common
 | 
				
			|||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// 比特合并成整型
 | 
					        /// 比特合并成整型
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        /// <param name="bits1">[TODO:parameter]</param>
 | 
					        /// <param name="bits1">第一个比特值</param>
 | 
				
			||||||
        /// <param name="bits1Len">[TODO:parameter]</param>
 | 
					        /// <param name="bits1Len">第一个比特值的长度(位数)</param>
 | 
				
			||||||
        /// <param name="bits2">[TODO:parameter]</param>
 | 
					        /// <param name="bits2">第二个比特值</param>
 | 
				
			||||||
        /// <param name="bits2Len">[TODO:parameter]</param>
 | 
					        /// <param name="bits2Len">第二个比特值的长度(位数)</param>
 | 
				
			||||||
        /// <returns>[TODO:return]</returns>
 | 
					        /// <returns>合并后的整型值</returns>
 | 
				
			||||||
        public static Result<ulong> MultiBitsToNumber(ulong bits1, uint bits1Len, ulong bits2, uint bits2Len)
 | 
					        public static Result<ulong> MultiBitsToNumber(ulong bits1, uint bits1Len, ulong bits2, uint bits2Len)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (bits1Len + bits2Len > 64) return new(new ArgumentException("Two Bits is more than 64 bits"));
 | 
					            if (bits1Len + bits2Len > 64) return new(new ArgumentException("Two Bits is more than 64 bits"));
 | 
				
			||||||
@@ -115,11 +115,11 @@ namespace Common
 | 
				
			|||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// 比特合并成整型
 | 
					        /// 比特合并成整型
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        /// <param name="bits1">[TODO:parameter]</param>
 | 
					        /// <param name="bits1">第一个比特值</param>
 | 
				
			||||||
        /// <param name="bits1Len">[TODO:parameter]</param>
 | 
					        /// <param name="bits1Len">第一个比特值的长度(位数)</param>
 | 
				
			||||||
        /// <param name="bits2">[TODO:parameter]</param>
 | 
					        /// <param name="bits2">第二个比特值</param>
 | 
				
			||||||
        /// <param name="bits2Len">[TODO:parameter]</param>
 | 
					        /// <param name="bits2Len">第二个比特值的长度(位数)</param>
 | 
				
			||||||
        /// <returns>[TODO:return]</returns>
 | 
					        /// <returns>合并后的整型值</returns>
 | 
				
			||||||
        public static Result<uint> MultiBitsToNumber(uint bits1, uint bits1Len, uint bits2, uint bits2Len)
 | 
					        public static Result<uint> MultiBitsToNumber(uint bits1, uint bits1Len, uint bits2, uint bits2Len)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (bits1Len + bits2Len > 64) return new(new ArgumentException("Two Bits is more than 64 bits"));
 | 
					            if (bits1Len + bits2Len > 64) return new(new ArgumentException("Two Bits is more than 64 bits"));
 | 
				
			||||||
@@ -131,10 +131,10 @@ namespace Common
 | 
				
			|||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// 比特位检查
 | 
					        /// 比特位检查
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        /// <param name="srcBits">[TODO:parameter]</param>
 | 
					        /// <param name="srcBits">源比特值</param>
 | 
				
			||||||
        /// <param name="dstBits">[TODO:parameter]</param>
 | 
					        /// <param name="dstBits">目标比特值</param>
 | 
				
			||||||
        /// <param name="mask">[TODO:parameter]</param>
 | 
					        /// <param name="mask">掩码(默认为全1)</param>
 | 
				
			||||||
        /// <returns>[TODO:return]</returns>
 | 
					        /// <returns>检查结果(是否匹配)</returns>
 | 
				
			||||||
        public static bool BitsCheck(ulong srcBits, ulong dstBits, ulong mask = 0xFFFF_FFFF_FFFF_FFFF)
 | 
					        public static bool BitsCheck(ulong srcBits, ulong dstBits, ulong mask = 0xFFFF_FFFF_FFFF_FFFF)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            return (srcBits & mask) == dstBits;
 | 
					            return (srcBits & mask) == dstBits;
 | 
				
			||||||
@@ -143,22 +143,31 @@ namespace Common
 | 
				
			|||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// 比特位检查
 | 
					        /// 比特位检查
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        /// <param name="srcBits">[TODO:parameter]</param>
 | 
					        /// <param name="srcBits">源比特值</param>
 | 
				
			||||||
        /// <param name="dstBits">[TODO:parameter]</param>
 | 
					        /// <param name="dstBits">目标比特值</param>
 | 
				
			||||||
        /// <param name="mask">[TODO:parameter]</param>
 | 
					        /// <param name="mask">掩码(默认为全1)</param>
 | 
				
			||||||
        /// <returns>[TODO:return]</returns>
 | 
					        /// <returns>检查结果(是否匹配)</returns>
 | 
				
			||||||
        public static bool BitsCheck(uint srcBits, uint dstBits, uint mask = 0xFFFF_FFFF)
 | 
					        public static bool BitsCheck(uint srcBits, uint dstBits, uint mask = 0xFFFF_FFFF)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            return (srcBits & mask) == dstBits;
 | 
					            return (srcBits & mask) == dstBits;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public static Result<bool> ToBit(UInt32 srcBits, int location)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (location < 0)
 | 
				
			||||||
 | 
					                return new(new ArgumentException(
 | 
				
			||||||
 | 
					                    "Location can't be negetive", nameof(location)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return (srcBits & (1 << location)) == 1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// 字符串转二进制字节数组
 | 
					        /// 字符串转二进制字节数组
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        /// <param name="str">[TODO:parameter]</param>
 | 
					        /// <param name="str">输入的字符串</param>
 | 
				
			||||||
        /// <param name="numBase">[TODO:parameter]</param>
 | 
					        /// <param name="numBase">进制(默认为16进制)</param>
 | 
				
			||||||
        /// <returns>[TODO:return]</returns>
 | 
					        /// <returns>转换后的二进制字节数组</returns>
 | 
				
			||||||
        public static byte[] StringToBytes(string str, int numBase = 16)
 | 
					        public static byte[] StringToBytes(string str, int numBase = 16)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var len = str.Length;
 | 
					            var len = str.Length;
 | 
				
			||||||
@@ -173,6 +182,59 @@ namespace Common
 | 
				
			|||||||
            return bytes;
 | 
					            return bytes;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// 反转字节数组中的子数组
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        /// <param name="srcBytes">源字节数组</param>
 | 
				
			||||||
 | 
					        /// <param name="distance">子数组的长度(反转的步长)</param>
 | 
				
			||||||
 | 
					        /// <returns>反转后的字节数组</returns>
 | 
				
			||||||
 | 
					        public static Result<byte[]> 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;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 字符串处理工具
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public class String
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// 反转字符串
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        /// <param name="s">输入的字符串</param>
 | 
				
			||||||
 | 
					        /// <returns>反转后的字符串</returns>
 | 
				
			||||||
 | 
					        public static string Reverse(string s)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            char[] charArray = s.ToCharArray();
 | 
				
			||||||
 | 
					            Array.Reverse(charArray);
 | 
				
			||||||
 | 
					            return new string(charArray);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
 | 
					using System.Buffers.Binary;
 | 
				
			||||||
using System.Net;
 | 
					using System.Net;
 | 
				
			||||||
using Common;
 | 
					using Common;
 | 
				
			||||||
using DotNext;
 | 
					 | 
				
			||||||
using Microsoft.AspNetCore.Mvc;
 | 
					using Microsoft.AspNetCore.Mvc;
 | 
				
			||||||
using Newtonsoft.Json;
 | 
					using Newtonsoft.Json;
 | 
				
			||||||
using WebProtocol;
 | 
					using WebProtocol;
 | 
				
			||||||
@@ -196,6 +196,38 @@ public class JtagController : ControllerBase
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 获取状态寄存器
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="address"> 设备地址 </param>
 | 
				
			||||||
 | 
					    /// <param name="port"> 设备端口 </param>
 | 
				
			||||||
 | 
					    [HttpGet("ReadStatusReg")]
 | 
				
			||||||
 | 
					    [ProducesResponseType(StatusCodes.Status200OK)]
 | 
				
			||||||
 | 
					    [ProducesResponseType(StatusCodes.Status500InternalServerError)]
 | 
				
			||||||
 | 
					    public async ValueTask<IResult> 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);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 上传比特流文件
 | 
					    /// 上传比特流文件
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
@@ -251,46 +283,77 @@ public class JtagController : ControllerBase
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            // 读取文件
 | 
					            // 读取文件
 | 
				
			||||||
            var filePath = Directory.GetFiles(fileDir)[0];
 | 
					            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
 | 
					            using (var fileStream = System.IO.File.Open(filePath, System.IO.FileMode.Open))
 | 
				
			||||||
            byte[] buffer = new byte[32 * 1024];
 | 
					 | 
				
			||||||
            long totalBytesRead = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // 使用异步流读取文件
 | 
					 | 
				
			||||||
            using (var memoryStream = new MemoryStream())
 | 
					 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                int bytesRead;
 | 
					                if (fileStream is null || fileStream.Length <= 0)
 | 
				
			||||||
                while ((bytesRead = await fileStream.ReadAsync(buffer, 0, buffer.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);
 | 
					                    int bytesRead;
 | 
				
			||||||
                    totalBytesRead += 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)
 | 
					        catch (Exception error)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            return TypedResults.InternalServerError(error);
 | 
					            return TypedResults.InternalServerError(error);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        finally
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// 日志控制器
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					[ApiController]
 | 
				
			||||||
 | 
					[Route("api/[controller]")]
 | 
				
			||||||
 | 
					public class Log : ControllerBase
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 日志文件路径
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    private readonly string _logFilePath = Directory.GetFiles(Directory.GetCurrentDirectory())[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,6 @@
 | 
				
			|||||||
using System.Net;
 | 
					using System.Net;
 | 
				
			||||||
using DotNext;
 | 
					using DotNext;
 | 
				
			||||||
 | 
					using Newtonsoft.Json;
 | 
				
			||||||
using WebProtocol;
 | 
					using WebProtocol;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace JtagClient;
 | 
					namespace JtagClient;
 | 
				
			||||||
@@ -213,6 +214,160 @@ public static class JtagCmd
 | 
				
			|||||||
    public const UInt32 CMD_JTAG_IDLE_DELAY = 0b0101;
 | 
					    public const UInt32 CMD_JTAG_IDLE_DELAY = 0b0101;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// JTAG 状态寄存器
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public class JtagStatusReg
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// ID 错误标志
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public bool id_err;
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// CRC 错误标志
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public bool crc_err;
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 自动测试错误标志
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public bool aut_err;
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 回读 CRC 错误标志
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public bool rbcrc_err;
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 超时标志
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public bool timeout;
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 唤醒完成标志
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public bool wakeup_over;
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 休眠完成标志
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public bool wakedown_over;
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 模式位
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public byte m;
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 初始化完成标志
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public bool init_complete;
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 初始化状态(低电平有效)
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public bool init_n;
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 完成标志
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public bool done;
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 内部完成标志
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public bool done_i;
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 全局逻辑使能标志
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public bool glogen;
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 全局逻辑反馈标志
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public bool glogen_fb;
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 全局输出使能标志
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public bool gouten;
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 全局复位标志
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public bool grsn;
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 全局写使能标志
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public bool gwen;
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// PLL 锁定标志
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public bool pll_lock;
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 回退标志
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public bool fallback;
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// IPAL 模式位
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public byte ipal_m;
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 8 位标志
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public bool flg_x8;
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 16 位标志
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public bool flg_x16;
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 32 位标志
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public bool flg_x32;
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 过温标志
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public bool over_temp;
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 配置错误标志
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public bool prcfg_err;
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 配置完成标志
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public bool prcfg_over;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 构造函数,从 32 位代码解析 JTAG 状态寄存器
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="code">32 位状态寄存器值</param>
 | 
				
			||||||
 | 
					    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;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 转换为Json字符串
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <returns>Json字符串</returns>
 | 
				
			||||||
 | 
					    public override string ToString()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return JsonConvert.SerializeObject(this);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// <summary>
 | 
					/// <summary>
 | 
				
			||||||
/// Jtag控制器
 | 
					/// Jtag控制器
 | 
				
			||||||
/// </summary>
 | 
					/// </summary>
 | 
				
			||||||
@@ -220,6 +375,8 @@ public class Jtag
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
 | 
					    private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private const int CLOCK_FREQ = 50; // MHz
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    readonly int timeout;
 | 
					    readonly int timeout;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    readonly int port;
 | 
					    readonly int port;
 | 
				
			||||||
@@ -227,11 +384,11 @@ public class Jtag
 | 
				
			|||||||
    private IPEndPoint ep;
 | 
					    private IPEndPoint ep;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// Jtag构造函数
 | 
					    /// Jtag 构造函数
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    /// <param name="address">目标IP地址</param>
 | 
					    /// <param name="address">目标 IP 地址</param>
 | 
				
			||||||
    /// <param name="port">目标UDP端口</param>
 | 
					    /// <param name="port">目标 UDP 端口</param>
 | 
				
			||||||
    /// <param name="timeout">超时时间</param>
 | 
					    /// <param name="timeout">超时时间(毫秒)</param>
 | 
				
			||||||
    public Jtag(string address, int port, int timeout = 2000)
 | 
					    public Jtag(string address, int port, int timeout = 2000)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        this.address = address;
 | 
					        this.address = address;
 | 
				
			||||||
@@ -274,7 +431,14 @@ public class Jtag
 | 
				
			|||||||
        return Convert.ToUInt32(Common.Number.BytesToNumber(retPackOpts.Data).Value);
 | 
					        return Convert.ToUInt32(Common.Number.BytesToNumber(retPackOpts.Data).Value);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public async ValueTask<Result<RecvDataPackage>> WriteFIFO(UInt32 devAddr, UInt32 data)
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 向指定的 JTAG 设备地址写入数据到 FIFO
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="devAddr">目标设备地址</param>
 | 
				
			||||||
 | 
					    /// <param name="data">要写入的数据</param>
 | 
				
			||||||
 | 
					    /// <param name="delayMilliseconds">写入后的延迟时间(毫秒)</param>
 | 
				
			||||||
 | 
					    /// <returns>包含接收数据包的异步结果</returns>
 | 
				
			||||||
 | 
					    public async ValueTask<Result<RecvDataPackage>> WriteFIFO(UInt32 devAddr, UInt32 data, UInt32 delayMilliseconds = 0)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        var ret = false;
 | 
					        var ret = false;
 | 
				
			||||||
        var opts = new SendAddrPackOptions();
 | 
					        var opts = new SendAddrPackOptions();
 | 
				
			||||||
@@ -303,6 +467,9 @@ public class Jtag
 | 
				
			|||||||
        else if (!udpWriteAck.Value.IsSuccessful)
 | 
					        else if (!udpWriteAck.Value.IsSuccessful)
 | 
				
			||||||
            return new(new Exception("Send address package failed"));
 | 
					            return new(new Exception("Send address package failed"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Delay some time before read register
 | 
				
			||||||
 | 
					        await Task.Delay(TimeSpan.FromMilliseconds(delayMilliseconds));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Read Jtag State Register
 | 
					        // Read Jtag State Register
 | 
				
			||||||
        opts.IsWrite = false;
 | 
					        opts.IsWrite = false;
 | 
				
			||||||
        opts.Address = JtagAddr.STATE;
 | 
					        opts.Address = JtagAddr.STATE;
 | 
				
			||||||
@@ -317,7 +484,7 @@ public class Jtag
 | 
				
			|||||||
        return udpDataResp.Value;
 | 
					        return udpDataResp.Value;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async ValueTask<Result<RecvDataPackage>> WriteFIFO(UInt32 devAddr, byte[] dataArray)
 | 
					    async ValueTask<Result<RecvDataPackage>> WriteFIFO(UInt32 devAddr, byte[] dataArray, UInt32 delayMilliseconds = 0)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        var ret = false;
 | 
					        var ret = false;
 | 
				
			||||||
        var opts = new SendAddrPackOptions();
 | 
					        var opts = new SendAddrPackOptions();
 | 
				
			||||||
@@ -334,20 +501,21 @@ public class Jtag
 | 
				
			|||||||
        var writeTimes = dataArray.Length / (256 * (32 / 8)) + 1;
 | 
					        var writeTimes = dataArray.Length / (256 * (32 / 8)) + 1;
 | 
				
			||||||
        for (var i = 0; i < writeTimes; i++)
 | 
					        for (var i = 0; i < writeTimes; i++)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            // Sperate Data Array
 | 
				
			||||||
            var isLastData = i == writeTimes - 1;
 | 
					            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
 | 
					            // Write Jtag State Register
 | 
				
			||||||
            opts.IsWrite = true;
 | 
					            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));
 | 
					            ret = await UDPClientPool.SendAddrPackAsync(ep, new SendAddrPackage(opts));
 | 
				
			||||||
            if (!ret) return new(new Exception("Send 1st address package failed!"));
 | 
					            if (!ret) return new(new Exception("Send 1st address package failed!"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Send Data Package
 | 
					            // Send Data Package
 | 
				
			||||||
            ret = await UDPClientPool.SendDataPackAsync(ep,
 | 
					            ret = await UDPClientPool.SendDataPackAsync(ep, new SendDataPackage(sendDataArray));
 | 
				
			||||||
                    new SendDataPackage(
 | 
					 | 
				
			||||||
                        isLastData ?
 | 
					 | 
				
			||||||
                        dataArray[(i * (256 * (32 / 8)))..] :
 | 
					 | 
				
			||||||
                        dataArray[(i * (256 * (32 / 8)))..((i + 1) * (256 * (32 / 8)) - 1)]
 | 
					 | 
				
			||||||
                    )
 | 
					 | 
				
			||||||
                );
 | 
					 | 
				
			||||||
            if (!ret) return new(new Exception("Send data package failed!"));
 | 
					            if (!ret) return new(new Exception("Send data package failed!"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Wait for Write Ack
 | 
					            // Wait for Write Ack
 | 
				
			||||||
@@ -357,6 +525,9 @@ public class Jtag
 | 
				
			|||||||
                return new(new Exception("Send address package failed"));
 | 
					                return new(new Exception("Send address package failed"));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Delay some time before read register
 | 
				
			||||||
 | 
					        await Task.Delay(TimeSpan.FromMilliseconds(delayMilliseconds));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Read Jtag State Register
 | 
					        // Read Jtag State Register
 | 
				
			||||||
        opts.IsWrite = false;
 | 
					        opts.IsWrite = false;
 | 
				
			||||||
        opts.BurstLength = 0;
 | 
					        opts.BurstLength = 0;
 | 
				
			||||||
@@ -373,10 +544,10 @@ public class Jtag
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async ValueTask<Result<bool>> WriteFIFO
 | 
					    async ValueTask<Result<bool>> 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 ret = false;
 | 
				
			||||||
        var retPack = await WriteFIFO(devAddr, data);
 | 
					        var retPack = await WriteFIFO(devAddr, data, delayMilliseconds);
 | 
				
			||||||
        if (!retPack.IsSuccessful) return new(retPack.Error);
 | 
					        if (!retPack.IsSuccessful) return new(retPack.Error);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (retPack.Value.Options.Data is null)
 | 
					        if (retPack.Value.Options.Data is null)
 | 
				
			||||||
@@ -394,10 +565,10 @@ public class Jtag
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async ValueTask<Result<bool>> WriteFIFO
 | 
					    async ValueTask<Result<bool>> 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 ret = false;
 | 
				
			||||||
        var retPack = await WriteFIFO(devAddr, data);
 | 
					        var retPack = await WriteFIFO(devAddr, data, delayMilliseconds);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (retPack.Value.Options.Data is null)
 | 
					        if (retPack.Value.Options.Data is null)
 | 
				
			||||||
            return new(new Exception($"Data is Null, package: {retPack.Value.Options.ToString()}"));
 | 
					            return new(new Exception($"Data is Null, package: {retPack.Value.Options.ToString()}"));
 | 
				
			||||||
@@ -413,17 +584,68 @@ public class Jtag
 | 
				
			|||||||
        return ret;
 | 
					        return ret;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async ValueTask<Result<bool>> 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;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 清除所有 JTAG 寄存器
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <returns>指示清除是否成功的异步结果</returns>
 | 
				
			||||||
    async ValueTask<Result<bool>> ClearAllRegisters()
 | 
					    async ValueTask<Result<bool>> ClearAllRegisters()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return await WriteFIFO(JtagAddr.STATE, 0xFF_FF_FF_FF, 0x01_02_02_02, JtagState.ALL_REG);
 | 
					        return await WriteFIFO(JtagAddr.STATE, 0xFF_FF_FF_FF, 0x01_02_02_02, JtagState.ALL_REG);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 清除 JTAG 写数据寄存器
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <returns>指示清除是否成功的异步结果</returns>
 | 
				
			||||||
    async ValueTask<Result<bool>> ClearWriteDataReg()
 | 
					    async ValueTask<Result<bool>> ClearWriteDataReg()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return await WriteFIFO(JtagAddr.STATE, 0x00_00_11_00, 0x01_00_02_00, JtagState.WRITE_DATA_FIFO | JtagState.CMD_EXEC_FINISH);
 | 
					        return await WriteFIFO(JtagAddr.STATE, 0x00_00_11_00, 0x01_00_02_00, JtagState.WRITE_DATA_FIFO | JtagState.CMD_EXEC_FINISH);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 关闭 JTAG 测试模式
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <returns>指示操作是否成功的异步结果</returns>
 | 
				
			||||||
    async ValueTask<Result<bool>> CloseTest()
 | 
					    async ValueTask<Result<bool>> CloseTest()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return await WriteFIFO(
 | 
					        return await WriteFIFO(
 | 
				
			||||||
@@ -432,6 +654,10 @@ public class Jtag
 | 
				
			|||||||
                0x01_00_00_00, JtagState.CMD_EXEC_FINISH);
 | 
					                0x01_00_00_00, JtagState.CMD_EXEC_FINISH);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 启动 JTAG 测试模式
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <returns>指示操作是否成功的异步结果</returns>
 | 
				
			||||||
    async ValueTask<Result<bool>> RunTest()
 | 
					    async ValueTask<Result<bool>> RunTest()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return await WriteFIFO(
 | 
					        return await WriteFIFO(
 | 
				
			||||||
@@ -440,6 +666,11 @@ public class Jtag
 | 
				
			|||||||
                0x01_00_00_00, JtagState.CMD_EXEC_FINISH);
 | 
					                0x01_00_00_00, JtagState.CMD_EXEC_FINISH);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 设置 JTAG 空闲延迟时间
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="milliseconds">延迟时间(毫秒)</param>
 | 
				
			||||||
 | 
					    /// <returns>指示操作是否成功的异步结果</returns>
 | 
				
			||||||
    async ValueTask<Result<bool>> IdleDelay(UInt32 milliseconds)
 | 
					    async ValueTask<Result<bool>> IdleDelay(UInt32 milliseconds)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (milliseconds > Math.Pow(2, 28)) return new(new Exception("Timespan is over 2^28 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(
 | 
					        return await WriteFIFO(
 | 
				
			||||||
                JtagAddr.WRITE_CMD,
 | 
					                JtagAddr.WRITE_CMD,
 | 
				
			||||||
                Common.Number.MultiBitsToNumber(JtagCmd.CMD_JTAG_IDLE_DELAY, JtagCmd.LEN_CMD_JTAG, milliseconds, 28).Value,
 | 
					                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<Result<bool>> ExecRDCmd(uint command)
 | 
					    async ValueTask<Result<bool>> ExecRDCmd(uint command)
 | 
				
			||||||
@@ -472,7 +703,7 @@ public class Jtag
 | 
				
			|||||||
        return await ClearWriteDataReg();
 | 
					        return await ClearWriteDataReg();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async ValueTask<Result<bool>> LoadDRCareInput(byte[] bytesArray)
 | 
					    async ValueTask<Result<bool>> LoadDRCareInput(byte[] bytesArray, UInt32 timeout = 10_000, UInt32 cycle = 500)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        var bytesLen = ((uint)(bytesArray.Length * 8));
 | 
					        var bytesLen = ((uint)(bytesArray.Length * 8));
 | 
				
			||||||
        if (bytesLen > Math.Pow(2, 28)) return new(new Exception("Length is over 2^(28 - 3)"));
 | 
					        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(
 | 
					            var ret = await WriteFIFO(
 | 
				
			||||||
                    JtagAddr.WRITE_CMD,
 | 
					                    JtagAddr.WRITE_CMD,
 | 
				
			||||||
                    Common.Number.MultiBitsToNumber(JtagCmd.CMD_JTAG_LOAD_DR_CAREI, JtagCmd.LEN_CMD_JTAG, bytesLen, 28).Value,
 | 
					                    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);
 | 
					            if (!ret.IsSuccessful) return new(ret.Error);
 | 
				
			||||||
            else if (!ret.Value) return new(new Exception("Write CMD_JTAG_LOAD_DR_CAREI Failed"));
 | 
					            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);
 | 
					            if (!ret.IsSuccessful) return new(ret.Error);
 | 
				
			||||||
            else if (!ret.Value) return new(new Exception("Write Data Failed"));
 | 
					            else if (!ret.Value) return new(new Exception("Write Data Failed"));
 | 
				
			||||||
@@ -510,6 +745,10 @@ public class Jtag
 | 
				
			|||||||
            return new(new Exception("LoadDRCareo Failed!"));
 | 
					            return new(new Exception("LoadDRCareo Failed!"));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 读取 JTAG 设备的 ID 代码
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <returns>包含 ID 代码的异步结果</returns>
 | 
				
			||||||
    public async ValueTask<Result<uint>> ReadIDCode()
 | 
					    public async ValueTask<Result<uint>> ReadIDCode()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        // Clear Data
 | 
					        // Clear Data
 | 
				
			||||||
@@ -544,6 +783,49 @@ public class Jtag
 | 
				
			|||||||
        return retData.Value;
 | 
					        return retData.Value;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 读取 JTAG 设备的状态寄存器
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <returns>包含状态寄存器值的异步结果</returns>
 | 
				
			||||||
 | 
					    public async ValueTask<Result<uint>> ReadStatusReg()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // Clear Data
 | 
				
			||||||
 | 
					        await MsgBus.UDPServer.ClearUDPData(this.address);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        logger.Trace($"Clear up udp server {this.address} receive data");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Result<bool> 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;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 下载比特流到 JTAG 设备
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="bitstream">比特流数据</param>
 | 
				
			||||||
 | 
					    /// <returns>指示下载是否成功的异步结果</returns>
 | 
				
			||||||
    public async ValueTask<Result<bool>> DownloadBitstream(byte[] bitstream)
 | 
					    public async ValueTask<Result<bool>> DownloadBitstream(byte[] bitstream)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        // Clear Data
 | 
					        // Clear Data
 | 
				
			||||||
@@ -577,7 +859,7 @@ public class Jtag
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        logger.Trace("Jtag ready to write bitstream");
 | 
					        logger.Trace("Jtag ready to write bitstream");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ret = await IdleDelay(75000);
 | 
					        ret = await IdleDelay(100000);
 | 
				
			||||||
        if (!ret.IsSuccessful) return new(ret.Error);
 | 
					        if (!ret.IsSuccessful) return new(ret.Error);
 | 
				
			||||||
        else if (!ret.Value) return new(new Exception("Jtag IDLE Delay Failed"));
 | 
					        else if (!ret.Value) return new(new Exception("Jtag IDLE Delay Failed"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -601,7 +883,7 @@ public class Jtag
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        logger.Trace("Jtag reset device");
 | 
					        logger.Trace("Jtag reset device");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ret = await IdleDelay(1000);
 | 
					        ret = await IdleDelay(10000);
 | 
				
			||||||
        if (!ret.IsSuccessful) return new(ret.Error);
 | 
					        if (!ret.IsSuccessful) return new(ret.Error);
 | 
				
			||||||
        else if (!ret.Value) return new(new Exception("Jtag IDLE Delay Failed"));
 | 
					        else if (!ret.Value) return new(new Exception("Jtag IDLE Delay Failed"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -81,9 +81,13 @@ public class UDPServer
 | 
				
			|||||||
    /// <summary> UDP 服务器的错误代码 </summary>
 | 
					    /// <summary> UDP 服务器的错误代码 </summary>
 | 
				
			||||||
    public enum ErrorCode
 | 
					    public enum ErrorCode
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
					        /// <summary> [TODO:description] </summary>
 | 
				
			||||||
        Success = 0,
 | 
					        Success = 0,
 | 
				
			||||||
 | 
					        /// <summary> [TODO:description] </summary>
 | 
				
			||||||
        GetNoneAfterTimeout,
 | 
					        GetNoneAfterTimeout,
 | 
				
			||||||
 | 
					        /// <summary> [TODO:description] </summary>
 | 
				
			||||||
        ResponseWrong,
 | 
					        ResponseWrong,
 | 
				
			||||||
 | 
					        /// <summary> [TODO:description] </summary>
 | 
				
			||||||
        NotRecvDataPackage,
 | 
					        NotRecvDataPackage,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -116,6 +120,7 @@ public class UDPServer
 | 
				
			|||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    /// <param name="ipAddr"> 目标IP地址 </param>
 | 
					    /// <param name="ipAddr"> 目标IP地址 </param>
 | 
				
			||||||
    /// <param name="timeout">超时时间</param>
 | 
					    /// <param name="timeout">超时时间</param>
 | 
				
			||||||
 | 
					    /// <param name="cycle">延迟时间</param>
 | 
				
			||||||
    /// <param name="callerName">调用函数名称</param>
 | 
					    /// <param name="callerName">调用函数名称</param>
 | 
				
			||||||
    /// <param name="callerLineNum">调用函数位置</param>
 | 
					    /// <param name="callerLineNum">调用函数位置</param>
 | 
				
			||||||
    /// <returns>
 | 
					    /// <returns>
 | 
				
			||||||
@@ -124,7 +129,7 @@ public class UDPServer
 | 
				
			|||||||
    /// Optional 存在时,为最先收到的数据
 | 
					    /// Optional 存在时,为最先收到的数据
 | 
				
			||||||
    /// </returns>
 | 
					    /// </returns>
 | 
				
			||||||
    public async ValueTask<Optional<UDPData>> FindDataAsync(
 | 
					    public async ValueTask<Optional<UDPData>> FindDataAsync(
 | 
				
			||||||
         string ipAddr, int timeout = 1000,
 | 
					         string ipAddr, int timeout = 1000, int cycle = 0,
 | 
				
			||||||
         [CallerMemberName] string callerName = "",
 | 
					         [CallerMemberName] string callerName = "",
 | 
				
			||||||
         [CallerLineNumber] int callerLineNum = 0)
 | 
					         [CallerLineNumber] int callerLineNum = 0)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@@ -153,6 +158,8 @@ public class UDPServer
 | 
				
			|||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            await Task.Delay(cycle);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (data is null)
 | 
					        if (data is null)
 | 
				
			||||||
@@ -171,8 +178,9 @@ public class UDPServer
 | 
				
			|||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    /// <param name="ipAddr">IP地址</param>
 | 
					    /// <param name="ipAddr">IP地址</param>
 | 
				
			||||||
    /// <param name="timeout">超时时间</param>
 | 
					    /// <param name="timeout">超时时间</param>
 | 
				
			||||||
 | 
					    /// <param name="cycle">延迟时间</param>
 | 
				
			||||||
    /// <returns>数据列表</returns>
 | 
					    /// <returns>数据列表</returns>
 | 
				
			||||||
    public async ValueTask<Optional<List<UDPData>>> GetDataArrayAsync(string ipAddr, int timeout = 1000)
 | 
					    public async ValueTask<Optional<List<UDPData>>> GetDataArrayAsync(string ipAddr, int timeout = 1000, int cycle = 0)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        List<UDPData>? data = null;
 | 
					        List<UDPData>? data = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,10 +20,10 @@ namespace WebProtocol
 | 
				
			|||||||
    /// <summary> Package Burst Type </summary>
 | 
					    /// <summary> Package Burst Type </summary>
 | 
				
			||||||
    public enum BurstType
 | 
					    public enum BurstType
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        /// <summary> Extended Type </summary>
 | 
					 | 
				
			||||||
        ExtendBurst = 0b00,
 | 
					 | 
				
			||||||
        /// <summary> Fixed Type </summary>
 | 
					        /// <summary> Fixed Type </summary>
 | 
				
			||||||
        FixedBurst = 0b01,
 | 
					        FixedBurst = 0b00,
 | 
				
			||||||
 | 
					        /// <summary> Extended Type </summary>
 | 
				
			||||||
 | 
					        ExtendBurst = 0b01,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										10
									
								
								src/App.vue
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								src/App.vue
									
									
									
									
									
								
							@@ -1,6 +1,7 @@
 | 
				
			|||||||
<script setup lang="ts">
 | 
					<script setup lang="ts">
 | 
				
			||||||
import iconMenu from "./assets/menu.svg";
 | 
					import iconMenu from "./assets/menu.svg";
 | 
				
			||||||
import Sidebar from "./components/Sidebar.vue";
 | 
					import Sidebar from "./components/Sidebar.vue";
 | 
				
			||||||
 | 
					import Navbar from "./components/Navbar.vue";
 | 
				
			||||||
import { useThemeStore } from "./stores/theme";
 | 
					import { useThemeStore } from "./stores/theme";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const theme = useThemeStore();
 | 
					const theme = useThemeStore();
 | 
				
			||||||
@@ -15,14 +16,21 @@ const items = [
 | 
				
			|||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <div :data-theme="theme.currentTheme">
 | 
					  <div :data-theme="theme.currentTheme">
 | 
				
			||||||
    <header class="relative">
 | 
					    <header class="relative">
 | 
				
			||||||
      <div class="fixed left-0 top-0 z-50">
 | 
					      <div class="fixed left-0 top-0 z-50 hidden">
 | 
				
			||||||
        <Sidebar :items="items" />
 | 
					        <Sidebar :items="items" />
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
 | 
					      <Navbar></Navbar>
 | 
				
			||||||
    </header>
 | 
					    </header>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <main>
 | 
					    <main>
 | 
				
			||||||
      <RouterView />
 | 
					      <RouterView />
 | 
				
			||||||
    </main>
 | 
					    </main>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <footer class="footer footer-center p-4 bg-base-300 text-base-content">
 | 
				
			||||||
 | 
					      <div>
 | 
				
			||||||
 | 
					        <p>Copyright © 2023 - All right reserved by OurEDA</p>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </footer>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,7 +2,7 @@
 | 
				
			|||||||
  <div class="navbar bg-base-100 shadow-sm">
 | 
					  <div class="navbar bg-base-100 shadow-sm">
 | 
				
			||||||
    <div class="navbar-start">
 | 
					    <div class="navbar-start">
 | 
				
			||||||
      <div class="dropdown">
 | 
					      <div class="dropdown">
 | 
				
			||||||
        <div tabindex="0" role="button" class="btn btn-ghost lg:hidden">
 | 
					        <div tabindex="0" role="button" class="btn btn-ghost hidden">
 | 
				
			||||||
          <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
 | 
					          <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
 | 
				
			||||||
            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h8m-8 6h16" />
 | 
					            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h8m-8 6h16" />
 | 
				
			||||||
          </svg>
 | 
					          </svg>
 | 
				
			||||||
@@ -19,25 +19,13 @@
 | 
				
			|||||||
          <li><a>Item 3</a></li>
 | 
					          <li><a>Item 3</a></li>
 | 
				
			||||||
        </ul>
 | 
					        </ul>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
      <a class="btn btn-ghost text-xl">daisyUI</a>
 | 
					 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
    <div class="navbar-center hidden lg:flex">
 | 
					    <div class="navbar-center lg:flex">
 | 
				
			||||||
      <ul class="menu menu-horizontal px-1">
 | 
					      <a class="btn btn-ghost text-xl">FPGA Web Lab</a>
 | 
				
			||||||
        <li><a>Item 1</a></li>
 | 
					 | 
				
			||||||
        <li>
 | 
					 | 
				
			||||||
          <details>
 | 
					 | 
				
			||||||
            <summary>Parent</summary>
 | 
					 | 
				
			||||||
            <ul class="p-2">
 | 
					 | 
				
			||||||
              <li><a>Submenu 1</a></li>
 | 
					 | 
				
			||||||
              <li><a>Submenu 2</a></li>
 | 
					 | 
				
			||||||
            </ul>
 | 
					 | 
				
			||||||
          </details>
 | 
					 | 
				
			||||||
        </li>
 | 
					 | 
				
			||||||
        <li><a>Item 3</a></li>
 | 
					 | 
				
			||||||
      </ul>
 | 
					 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
    <div class="navbar-end">
 | 
					    <div class="navbar-end">
 | 
				
			||||||
      <a class="btn">Button</a>
 | 
					      <a class="btn btn-soft w-20 mx-10">注册</a>
 | 
				
			||||||
 | 
					      <a class="btn btn-primary w-25">登录</a>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,9 +4,10 @@ import UserView from "../views/UserView.vue";
 | 
				
			|||||||
import TestView from "../views/TestView.vue";
 | 
					import TestView from "../views/TestView.vue";
 | 
				
			||||||
import JtagTest from "../views/JtagTest.vue";
 | 
					import JtagTest from "../views/JtagTest.vue";
 | 
				
			||||||
import ProjectView from "../views/ProjectView.vue";
 | 
					import ProjectView from "../views/ProjectView.vue";
 | 
				
			||||||
 | 
					import HomeView from "@/views/HomeView.vue";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const routes = [
 | 
					const routes = [
 | 
				
			||||||
  { path: "/", redirect: "/user" },
 | 
					  { path: "/", name: "Home", component: HomeView },
 | 
				
			||||||
  { path: "/login", name: "Login", component: LoginView },
 | 
					  { path: "/login", name: "Login", component: LoginView },
 | 
				
			||||||
  { path: "/user", name: "User", component: UserView },
 | 
					  { path: "/user", name: "User", component: UserView },
 | 
				
			||||||
  { path: "/test", name: "Test", component: TestView },
 | 
					  { path: "/test", name: "Test", component: TestView },
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										29
									
								
								src/views/HomeView.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/views/HomeView.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <div class="bg-base-200 min-h-screen">
 | 
				
			||||||
 | 
					    <main class="hero min-h-screen bg-base-200">
 | 
				
			||||||
 | 
					      <div class="hero-content flex-col lg:flex-row-reverse">
 | 
				
			||||||
 | 
					        <img src="https://placehold.co/600x400" class="max-w-sm rounded-lg shadow-2xl" />
 | 
				
			||||||
 | 
					        <div>
 | 
				
			||||||
 | 
					          <h1 class="text-5xl font-bold">Welcome to FPGA Web Lab!</h1>
 | 
				
			||||||
 | 
					          <p class="py-6">
 | 
				
			||||||
 | 
					            Prototype and simulate electronic circuits in your browser.
 | 
				
			||||||
 | 
					          </p>
 | 
				
			||||||
 | 
					          <button class="btn btn-primary">Get Started</button>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </main>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div class="fixed bottom-10 right-10 btn btn-circle">
 | 
				
			||||||
 | 
					      <ThemeControlButton class=""></ThemeControlButton>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script lang="ts" setup>
 | 
				
			||||||
 | 
					import ThemeControlButton from "@/components/ThemeControlButton.vue";
 | 
				
			||||||
 | 
					import "@/router";
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style scoped lang="postcss">
 | 
				
			||||||
 | 
					@import "../assets/main.css";
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
@@ -3,13 +3,39 @@
 | 
				
			|||||||
    <div class="h-full w-32"></div>
 | 
					    <div class="h-full w-32"></div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <div class="h-full w-[70%] shadow-2xl flex">
 | 
					    <div class="h-full w-[70%] shadow-2xl flex">
 | 
				
			||||||
      
 | 
					 | 
				
			||||||
      <button class="btn btn-primary h-10 w-30">获取ID Code</button>
 | 
					      <button class="btn btn-primary h-10 w-30">获取ID Code</button>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script lang="ts" setup></script>
 | 
					<script lang="ts" setup>
 | 
				
			||||||
 | 
					import { ref, onMounted, onUnmounted } from "vue";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const eventSource = ref<EventSource>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const initSource = () => {
 | 
				
			||||||
 | 
					  eventSource.value = new EventSource("http://localhost:500/api/log/example");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  eventSource.value.onmessage = (event) => {
 | 
				
			||||||
 | 
					    console.log("收到消息内容是:", event.data);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  eventSource.value.onerror = (error) => {
 | 
				
			||||||
 | 
					    console.error("SSE 连接出错:", error);
 | 
				
			||||||
 | 
					    eventSource.value!.close();
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					onMounted(() => {
 | 
				
			||||||
 | 
					  initSource();
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					onUnmounted(() => {
 | 
				
			||||||
 | 
					  if (eventSource) {
 | 
				
			||||||
 | 
					    eventSource.value?.close();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<style scoped lang="postcss">
 | 
					<style scoped lang="postcss">
 | 
				
			||||||
@import "../assets/main.css";
 | 
					@import "../assets/main.css";
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user