Merge branch 'master' of ssh://git.swordlost.top:222/SikongJueluo/FPGA_WebLab
This commit is contained in:
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -28,7 +28,6 @@ DebuggerCmd.md
 | 
			
		||||
*.suo
 | 
			
		||||
*.ntvs*
 | 
			
		||||
*.njsproj
 | 
			
		||||
*.sln
 | 
			
		||||
*.sw?
 | 
			
		||||
 | 
			
		||||
*.tsbuildinfo
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										48
									
								
								FPGAWebLabServer.sln
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								FPGAWebLabServer.sln
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,48 @@
 | 
			
		||||
 | 
			
		||||
Microsoft Visual Studio Solution File, Format Version 12.00
 | 
			
		||||
# Visual Studio Version 17
 | 
			
		||||
VisualStudioVersion = 17.0.31903.59
 | 
			
		||||
MinimumVisualStudioVersion = 10.0.40219.1
 | 
			
		||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "server", "server\server.csproj", "{F31D6A0D-0407-41CE-A67E-01B847488EFB}"
 | 
			
		||||
EndProject
 | 
			
		||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "server.test", "server.test\server.test.csproj", "{CC274582-AC3C-4FD1-977C-96F1BC2760BD}"
 | 
			
		||||
EndProject
 | 
			
		||||
Global
 | 
			
		||||
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 | 
			
		||||
		Debug|Any CPU = Debug|Any CPU
 | 
			
		||||
		Debug|x64 = Debug|x64
 | 
			
		||||
		Debug|x86 = Debug|x86
 | 
			
		||||
		Release|Any CPU = Release|Any CPU
 | 
			
		||||
		Release|x64 = Release|x64
 | 
			
		||||
		Release|x86 = Release|x86
 | 
			
		||||
	EndGlobalSection
 | 
			
		||||
	GlobalSection(ProjectConfigurationPlatforms) = postSolution
 | 
			
		||||
		{F31D6A0D-0407-41CE-A67E-01B847488EFB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{F31D6A0D-0407-41CE-A67E-01B847488EFB}.Debug|Any CPU.Build.0 = Debug|Any CPU
 | 
			
		||||
		{F31D6A0D-0407-41CE-A67E-01B847488EFB}.Debug|x64.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{F31D6A0D-0407-41CE-A67E-01B847488EFB}.Debug|x64.Build.0 = Debug|Any CPU
 | 
			
		||||
		{F31D6A0D-0407-41CE-A67E-01B847488EFB}.Debug|x86.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{F31D6A0D-0407-41CE-A67E-01B847488EFB}.Debug|x86.Build.0 = Debug|Any CPU
 | 
			
		||||
		{F31D6A0D-0407-41CE-A67E-01B847488EFB}.Release|Any CPU.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{F31D6A0D-0407-41CE-A67E-01B847488EFB}.Release|Any CPU.Build.0 = Release|Any CPU
 | 
			
		||||
		{F31D6A0D-0407-41CE-A67E-01B847488EFB}.Release|x64.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{F31D6A0D-0407-41CE-A67E-01B847488EFB}.Release|x64.Build.0 = Release|Any CPU
 | 
			
		||||
		{F31D6A0D-0407-41CE-A67E-01B847488EFB}.Release|x86.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{F31D6A0D-0407-41CE-A67E-01B847488EFB}.Release|x86.Build.0 = Release|Any CPU
 | 
			
		||||
		{CC274582-AC3C-4FD1-977C-96F1BC2760BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{CC274582-AC3C-4FD1-977C-96F1BC2760BD}.Debug|Any CPU.Build.0 = Debug|Any CPU
 | 
			
		||||
		{CC274582-AC3C-4FD1-977C-96F1BC2760BD}.Debug|x64.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{CC274582-AC3C-4FD1-977C-96F1BC2760BD}.Debug|x64.Build.0 = Debug|Any CPU
 | 
			
		||||
		{CC274582-AC3C-4FD1-977C-96F1BC2760BD}.Debug|x86.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{CC274582-AC3C-4FD1-977C-96F1BC2760BD}.Debug|x86.Build.0 = Debug|Any CPU
 | 
			
		||||
		{CC274582-AC3C-4FD1-977C-96F1BC2760BD}.Release|Any CPU.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{CC274582-AC3C-4FD1-977C-96F1BC2760BD}.Release|Any CPU.Build.0 = Release|Any CPU
 | 
			
		||||
		{CC274582-AC3C-4FD1-977C-96F1BC2760BD}.Release|x64.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{CC274582-AC3C-4FD1-977C-96F1BC2760BD}.Release|x64.Build.0 = Release|Any CPU
 | 
			
		||||
		{CC274582-AC3C-4FD1-977C-96F1BC2760BD}.Release|x86.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{CC274582-AC3C-4FD1-977C-96F1BC2760BD}.Release|x86.Build.0 = Release|Any CPU
 | 
			
		||||
	EndGlobalSection
 | 
			
		||||
	GlobalSection(SolutionProperties) = preSolution
 | 
			
		||||
		HideSolutionNode = FALSE
 | 
			
		||||
	EndGlobalSection
 | 
			
		||||
EndGlobal
 | 
			
		||||
@@ -1,61 +0,0 @@
 | 
			
		||||
using System.Buffers.Binary;
 | 
			
		||||
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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void ToBitTest()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.Equal(true, Number.ToBit(0xFF, 3).Value);
 | 
			
		||||
        Assert.Equal(false, Number.ToBit(0x00, 3).Value);
 | 
			
		||||
        Assert.Equal(true, Number.ToBit(0xAA, 3).Value);
 | 
			
		||||
        Assert.Equal(false, Number.ToBit(0xAA, 2).Value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void ReverseBits()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.Equal((byte)0x05, Common.Number.ReverseBits((byte)0xA0));
 | 
			
		||||
 | 
			
		||||
        var bytesSrc = new byte[] { 0xAB, 0x00, 0x00, 0x01 };
 | 
			
		||||
        var bytes = new byte[4];
 | 
			
		||||
        for (int i = 0; i < 4; i++)
 | 
			
		||||
            bytes[i] = Common.Number.ReverseBits(bytesSrc[i]);
 | 
			
		||||
        Assert.Equal(new byte[] { 0xD5, 0x00, 0x00, 0x80 }, bytes);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										286
									
								
								server.test/NumberTest.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										286
									
								
								server.test/NumberTest.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,286 @@
 | 
			
		||||
using System.Collections;
 | 
			
		||||
using Common;
 | 
			
		||||
 | 
			
		||||
namespace CommonTest;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// 针对 Common.Number 的单元测试,覆盖所有公开方法
 | 
			
		||||
/// </summary>
 | 
			
		||||
public class NumberTest
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 测试 NumberToBytes 的正常与异常情况
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Test_NumberToBytes()
 | 
			
		||||
    {
 | 
			
		||||
        // 测试大端(isLowNumHigh=false)
 | 
			
		||||
        var result1 = Number.NumberToBytes(0x12345678ABCDEF01, 8, false);
 | 
			
		||||
        Assert.True(result1.IsSuccessful);
 | 
			
		||||
        Assert.Equal(new byte[] { 0x12, 0x34, 0x56, 0x78, 0xAB, 0xCD, 0xEF, 0x01 }, result1.Value);
 | 
			
		||||
 | 
			
		||||
        // 测试小端(isLowNumHigh=true)
 | 
			
		||||
        var result2 = Number.NumberToBytes(0x12345678ABCDEF01, 8, true);
 | 
			
		||||
        Assert.True(result2.IsSuccessful);
 | 
			
		||||
        Assert.Equal(new byte[] { 0x01, 0xEF, 0xCD, 0xAB, 0x78, 0x56, 0x34, 0x12 }, result2.Value);
 | 
			
		||||
 | 
			
		||||
        // 测试长度不足(4字节)
 | 
			
		||||
        var result3 = Number.NumberToBytes(0x12345678, 4, false);
 | 
			
		||||
        Assert.True(result3.IsSuccessful);
 | 
			
		||||
        Assert.Equal(new byte[] { 0x12, 0x34, 0x56, 0x78 }, result3.Value);
 | 
			
		||||
 | 
			
		||||
        // 测试超长
 | 
			
		||||
        var result4 = Number.NumberToBytes(0x1, 9, false);
 | 
			
		||||
        Assert.False(result4.IsSuccessful);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 测试 BytesToUInt64 的正常与异常情况
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Test_BytesToUInt64()
 | 
			
		||||
    {
 | 
			
		||||
        // 正常大端
 | 
			
		||||
        var bytes = new byte[] { 0x12, 0x34, 0x56, 0x78, 0xAB, 0xCD, 0xEF, 0x01 };
 | 
			
		||||
        var result = Number.BytesToUInt64((byte[])bytes.Clone(), false);
 | 
			
		||||
        Assert.True(result.IsSuccessful);
 | 
			
		||||
        Assert.Equal(0x12345678ABCDEF01UL, result.Value);
 | 
			
		||||
 | 
			
		||||
        // 正常小端
 | 
			
		||||
        var bytes2 = new byte[] { 0x01, 0xEF, 0xCD, 0xAB, 0x78, 0x56, 0x34, 0x12 };
 | 
			
		||||
        var result2 = Number.BytesToUInt64((byte[])bytes2.Clone(), true);
 | 
			
		||||
        Assert.True(result2.IsSuccessful);
 | 
			
		||||
        Assert.Equal(0x12345678ABCDEF01UL, result2.Value);
 | 
			
		||||
 | 
			
		||||
        // 异常:长度超限
 | 
			
		||||
        var result3 = Number.BytesToUInt64(new byte[9], false);
 | 
			
		||||
        Assert.False(result3.IsSuccessful);
 | 
			
		||||
 | 
			
		||||
        // 异常:不足8字节
 | 
			
		||||
        var result4 = Number.BytesToUInt64(new byte[] { 0x01, 0x02 }, false);
 | 
			
		||||
        Assert.False(result4.IsSuccessful); // BitConverter.ToUInt64 需要8字节
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 测试 BytesToUInt32 的正常与异常情况
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Test_BytesToUInt32()
 | 
			
		||||
    {
 | 
			
		||||
        // 正常大端
 | 
			
		||||
        var bytes = new byte[] { 0x12, 0x34, 0x56, 0x78 };
 | 
			
		||||
        var result = Number.BytesToUInt32((byte[])bytes.Clone(), false);
 | 
			
		||||
        Assert.True(result.IsSuccessful);
 | 
			
		||||
        Assert.Equal(0x12345678U, result.Value);
 | 
			
		||||
 | 
			
		||||
        // 正常小端
 | 
			
		||||
        var bytes2 = new byte[] { 0x78, 0x56, 0x34, 0x12 };
 | 
			
		||||
        var result2 = Number.BytesToUInt32((byte[])bytes2.Clone(), true);
 | 
			
		||||
        Assert.True(result2.IsSuccessful);
 | 
			
		||||
        Assert.Equal(0x12345678U, result2.Value);
 | 
			
		||||
 | 
			
		||||
        // 异常:长度超限
 | 
			
		||||
        var result3 = Number.BytesToUInt32(new byte[5], false);
 | 
			
		||||
        Assert.False(result3.IsSuccessful);
 | 
			
		||||
 | 
			
		||||
        // 异常:不足4字节
 | 
			
		||||
        var result4 = Number.BytesToUInt32(new byte[] { 0x01, 0x02 }, false);
 | 
			
		||||
        Assert.False(result4.IsSuccessful); // BitConverter.ToUInt32 需要4字节
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 测试 UInt32ArrayToBytes 的正常与异常情况
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Test_UInt32ArrayToBytes()
 | 
			
		||||
    {
 | 
			
		||||
        // 正常情况
 | 
			
		||||
        var arr = new UInt32[] { 0x12345678, 0xABCDEF01 };
 | 
			
		||||
        var result = Number.UInt32ArrayToBytes(arr);
 | 
			
		||||
        Assert.True(result.IsSuccessful);
 | 
			
		||||
        // BlockCopy 按小端序
 | 
			
		||||
        Assert.Equal(new byte[] { 0x78, 0x56, 0x34, 0x12, 0x01, 0xEF, 0xCD, 0xAB }, result.Value);
 | 
			
		||||
 | 
			
		||||
        // 空数组
 | 
			
		||||
        var result2 = Number.UInt32ArrayToBytes(new UInt32[0]);
 | 
			
		||||
        Assert.True(result2.IsSuccessful);
 | 
			
		||||
        Assert.Empty(result2.Value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 测试 MultiBitsToBytes 和 MultiBitsToNumber (ulong)
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Test_MultiBitsToBytesAndNumber_Ulong()
 | 
			
		||||
    {
 | 
			
		||||
        // 合并两个比特段
 | 
			
		||||
        var result = Number.MultiBitsToNumber(0b101UL, 3, 0b11UL, 2);
 | 
			
		||||
        Assert.True(result.IsSuccessful);
 | 
			
		||||
        Assert.Equal((ulong)0b10111, result.Value);
 | 
			
		||||
 | 
			
		||||
        // 合并为字节数组
 | 
			
		||||
        var bytesResult = Number.MultiBitsToBytes(0b101UL, 3, 0b11UL, 2);
 | 
			
		||||
        Assert.True(bytesResult.IsSuccessful);
 | 
			
		||||
        Assert.Equal(new byte[] { 0b10111 }, bytesResult.Value);
 | 
			
		||||
 | 
			
		||||
        // 超过64位
 | 
			
		||||
        var failResult = Number.MultiBitsToNumber(0xFFFFFFFFFFFFFFFF, 64, 1, 1);
 | 
			
		||||
        Assert.False(failResult.IsSuccessful);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 测试 MultiBitsToNumber (uint)
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Test_MultiBitsToNumber_Uint()
 | 
			
		||||
    {
 | 
			
		||||
        var result = Number.MultiBitsToNumber(0b101U, 3, 0b11U, 2);
 | 
			
		||||
        Assert.True(result.IsSuccessful);
 | 
			
		||||
        Assert.Equal((uint)0b10111, result.Value);
 | 
			
		||||
 | 
			
		||||
        // 超过64位
 | 
			
		||||
        var failResult = Number.MultiBitsToNumber(uint.MaxValue, 64, 1, 1);
 | 
			
		||||
        Assert.False(failResult.IsSuccessful);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 测试 BitsCheck (ulong)
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Test_BitsCheck_Ulong()
 | 
			
		||||
    {
 | 
			
		||||
        // 完全匹配
 | 
			
		||||
        Assert.True(Number.BitsCheck(0b1101UL, 0b1101UL));
 | 
			
		||||
        // 不匹配
 | 
			
		||||
        Assert.False(Number.BitsCheck(0b1101UL, 0b1001UL));
 | 
			
		||||
        // 掩码
 | 
			
		||||
        Assert.True(Number.BitsCheck(0b1101UL, 0b1001UL, 0b1001UL));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 测试 BitsCheck (uint)
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Test_BitsCheck_Uint()
 | 
			
		||||
    {
 | 
			
		||||
        Assert.True(Number.BitsCheck(0b1011U, 0b1011U));
 | 
			
		||||
        Assert.False(Number.BitsCheck(0b1011U, 0b1001U));
 | 
			
		||||
        Assert.True(Number.BitsCheck(0b1011U, 0b1001U, 0b1001U));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 测试 ToBit
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Test_ToBit()
 | 
			
		||||
    {
 | 
			
		||||
        // 取第0位
 | 
			
		||||
        var result = Number.ToBit(0b1010U, 0);
 | 
			
		||||
        Assert.True(result.IsSuccessful);
 | 
			
		||||
        Assert.False(result.Value);
 | 
			
		||||
 | 
			
		||||
        // 取第1位
 | 
			
		||||
        var result2 = Number.ToBit(0b1010U, 1);
 | 
			
		||||
        Assert.True(result2.IsSuccessful);
 | 
			
		||||
        Assert.True(result2.Value);
 | 
			
		||||
 | 
			
		||||
        // 负数位置
 | 
			
		||||
        var result3 = Number.ToBit(0b1010U, -1);
 | 
			
		||||
        Assert.False(result3.IsSuccessful);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 测试 BitsToNumber
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Test_BitsToNumber()
 | 
			
		||||
    {
 | 
			
		||||
        // 5位BitArray
 | 
			
		||||
        var bits = new BitArray(new bool[] { true, true, false, true, false }); // 0b01011
 | 
			
		||||
        var result = Number.BitsToNumber(bits);
 | 
			
		||||
        Assert.True(result.IsSuccessful);
 | 
			
		||||
        Assert.Equal((uint)0b01011, result.Value);
 | 
			
		||||
 | 
			
		||||
        // 超过32位
 | 
			
		||||
        var bits2 = new BitArray(33);
 | 
			
		||||
        Assert.Throws<ArgumentException>(() => Number.BitsToNumber(bits2));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 测试 StringToBytes
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Test_StringToBytes()
 | 
			
		||||
    {
 | 
			
		||||
        // 16进制字符串
 | 
			
		||||
        var bytes = Number.StringToBytes("1234ABCD");
 | 
			
		||||
        Assert.Equal(new byte[] { 0x12, 0x34, 0xAB, 0xCD }, bytes);
 | 
			
		||||
 | 
			
		||||
        // 8位字符串
 | 
			
		||||
        var bytes2 = Number.StringToBytes("01020304");
 | 
			
		||||
        Assert.Equal(new byte[] { 0x01, 0x02, 0x03, 0x04 }, bytes2);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 测试 ReverseBytes
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Test_ReverseBytes()
 | 
			
		||||
    {
 | 
			
		||||
        // 步长为2
 | 
			
		||||
        var src = new byte[] { 0x01, 0x02, 0x03, 0x04 };
 | 
			
		||||
        var result = Number.ReverseBytes(src, 2);
 | 
			
		||||
        Assert.True(result.IsSuccessful);
 | 
			
		||||
        Assert.Equal(new byte[] { 0x02, 0x01, 0x04, 0x03 }, result.Value);
 | 
			
		||||
 | 
			
		||||
        // 步长为4
 | 
			
		||||
        var src2 = new byte[] { 0x01, 0x02, 0x03, 0x04 };
 | 
			
		||||
        var result2 = Number.ReverseBytes(src2, 4);
 | 
			
		||||
        Assert.True(result2.IsSuccessful);
 | 
			
		||||
        Assert.Equal(new byte[] { 0x04, 0x03, 0x02, 0x01 }, result2.Value);
 | 
			
		||||
 | 
			
		||||
        // 步长为1(无变化)
 | 
			
		||||
        var src3 = new byte[] { 0x01, 0x02, 0x03, 0x04 };
 | 
			
		||||
        var result3 = Number.ReverseBytes(src3, 1);
 | 
			
		||||
        Assert.True(result3.IsSuccessful);
 | 
			
		||||
        Assert.Equal(src3, result3.Value);
 | 
			
		||||
 | 
			
		||||
        // 步长为0(异常)
 | 
			
		||||
        var result4 = Number.ReverseBytes(src3, 0);
 | 
			
		||||
        Assert.False(result4.IsSuccessful);
 | 
			
		||||
 | 
			
		||||
        // 步长不能整除
 | 
			
		||||
        var result5 = Number.ReverseBytes(src3, 3);
 | 
			
		||||
        Assert.False(result5.IsSuccessful);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 测试 ReverseBits (byte)
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Test_ReverseBits_Byte()
 | 
			
		||||
    {
 | 
			
		||||
        // 0b00010010 -> 0b01001000
 | 
			
		||||
        byte src = 0b00010010;
 | 
			
		||||
        byte reversed = Number.ReverseBits(src);
 | 
			
		||||
        Assert.Equal(0b01001000, reversed);
 | 
			
		||||
 | 
			
		||||
        // 0b11110000 -> 0b00001111
 | 
			
		||||
        Assert.Equal(0b00001111, Number.ReverseBits(0b11110000));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 测试 ReverseBits (byte[])
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void Test_ReverseBits_ByteArray()
 | 
			
		||||
    {
 | 
			
		||||
        var src = new byte[] { 0b00010010, 0b11110000 };
 | 
			
		||||
        var reversed = Number.ReverseBits(src);
 | 
			
		||||
        Assert.Equal(new byte[] { 0b01001000, 0b00001111 }, reversed);
 | 
			
		||||
 | 
			
		||||
        // 空数组
 | 
			
		||||
        var reversed2 = Number.ReverseBits(new byte[0]);
 | 
			
		||||
        Assert.Empty(reversed2);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,138 +0,0 @@
 | 
			
		||||
using System.Net;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using Common;
 | 
			
		||||
using Xunit.Abstractions;
 | 
			
		||||
 | 
			
		||||
namespace server.test;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
public class UDPServerTest
 | 
			
		||||
{
 | 
			
		||||
    const string address = "127.0.0.1";
 | 
			
		||||
    const int port = 33000;
 | 
			
		||||
    private static readonly UDPServer udpServer = new UDPServer(port);
 | 
			
		||||
 | 
			
		||||
    private readonly ITestOutputHelper output;
 | 
			
		||||
 | 
			
		||||
    public UDPServerTest(ITestOutputHelper output)
 | 
			
		||||
    {
 | 
			
		||||
        this.output = output;
 | 
			
		||||
        udpServer.Start();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public void UDPDataDeepClone()
 | 
			
		||||
    {
 | 
			
		||||
        var udpData = new UDPData()
 | 
			
		||||
        {
 | 
			
		||||
            DateTime = DateTime.Now,
 | 
			
		||||
            Address = "127.0.0.1",
 | 
			
		||||
            Port = 1234,
 | 
			
		||||
            Data = new byte[] { 0xf0, 00, 00, 00 },
 | 
			
		||||
            HasRead = false
 | 
			
		||||
        };
 | 
			
		||||
        var cloneUdpData = udpData.DeepClone();
 | 
			
		||||
 | 
			
		||||
        Assert.Equal(udpData.DateTime, cloneUdpData.DateTime);
 | 
			
		||||
        Assert.Equal(udpData.Address, cloneUdpData.Address);
 | 
			
		||||
        Assert.Equal(udpData.Port, cloneUdpData.Port);
 | 
			
		||||
        Assert.Equal(udpData.Data, cloneUdpData.Data);
 | 
			
		||||
        Assert.Equal(udpData.HasRead, cloneUdpData.HasRead);
 | 
			
		||||
 | 
			
		||||
        udpData.DateTime = DateTime.Now;
 | 
			
		||||
        udpData.Address = "192.168.1.1";
 | 
			
		||||
        udpData.Port = 33000;
 | 
			
		||||
        udpData.Data = new byte[] { 0xFF, 00, 00, 00 };
 | 
			
		||||
        udpData.HasRead = true;
 | 
			
		||||
 | 
			
		||||
        Assert.NotNull(cloneUdpData.DateTime);
 | 
			
		||||
        Assert.NotNull(cloneUdpData.Address);
 | 
			
		||||
        Assert.NotNull(cloneUdpData.Port);
 | 
			
		||||
        Assert.NotNull(cloneUdpData.Data);
 | 
			
		||||
        Assert.NotNull(cloneUdpData.HasRead);
 | 
			
		||||
 | 
			
		||||
        Assert.NotEqual(udpData.DateTime, cloneUdpData.DateTime);
 | 
			
		||||
        Assert.NotEqual(udpData.Address, cloneUdpData.Address);
 | 
			
		||||
        Assert.NotEqual(udpData.Port, cloneUdpData.Port);
 | 
			
		||||
        Assert.NotEqual(udpData.Data, cloneUdpData.Data);
 | 
			
		||||
        Assert.NotEqual(udpData.HasRead, cloneUdpData.HasRead);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Theory]
 | 
			
		||||
    [InlineData(new object[] { new string[] { "Hello World!", "Hello Server!", "What is your problem?" } })]
 | 
			
		||||
    public async Task UDPServerFindString(string[] textArray)
 | 
			
		||||
    {
 | 
			
		||||
        Assert.True(udpServer.IsRunning);
 | 
			
		||||
 | 
			
		||||
        var serverEP = new IPEndPoint(IPAddress.Parse(address), port);
 | 
			
		||||
 | 
			
		||||
        foreach (var text in textArray)
 | 
			
		||||
        {
 | 
			
		||||
            Assert.True(await UDPClientPool.SendStringAsync(serverEP, [text]));
 | 
			
		||||
            var ret = await udpServer.FindDataAsync(address);
 | 
			
		||||
            Assert.True(ret.HasValue);
 | 
			
		||||
            var data = ret.Value;
 | 
			
		||||
            Assert.Equal(address, data.Address);
 | 
			
		||||
            Assert.Equal(text, Encoding.ASCII.GetString(data.Data));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Theory]
 | 
			
		||||
    [InlineData(new object[] { new UInt32[] { 0xF0_00_00_00, 0xFF_00_00_00, 0xFF_FF_FF_FF } })]
 | 
			
		||||
    public async Task UDPServerFindBytes(UInt32[] bytesArray)
 | 
			
		||||
    {
 | 
			
		||||
        Assert.True(udpServer.IsRunning);
 | 
			
		||||
 | 
			
		||||
        var serverEP = new IPEndPoint(IPAddress.Parse(address), port);
 | 
			
		||||
 | 
			
		||||
        foreach (var number in bytesArray)
 | 
			
		||||
        {
 | 
			
		||||
            Assert.True(await UDPClientPool.SendBytesAsync(serverEP, Number.NumberToBytes(number, 4).Value));
 | 
			
		||||
            var ret = await udpServer.FindDataAsync(address);
 | 
			
		||||
            Assert.True(ret.HasValue);
 | 
			
		||||
            var data = ret.Value;
 | 
			
		||||
            Assert.Equal(address, data.Address);
 | 
			
		||||
            Assert.Equal(number, Number.BytesToUInt32(data.Data).Value);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Theory]
 | 
			
		||||
    [InlineData(new object[] { new UInt32[] { 0xF0_00_00_00, 0xF0_01_00_00 } })]
 | 
			
		||||
    public async Task UDPServerWaitResp(UInt32[] bytesArray)
 | 
			
		||||
    {
 | 
			
		||||
        Assert.True(udpServer.IsRunning);
 | 
			
		||||
 | 
			
		||||
        var serverEP = new IPEndPoint(IPAddress.Parse(address), port);
 | 
			
		||||
 | 
			
		||||
        foreach (var number in bytesArray)
 | 
			
		||||
        {
 | 
			
		||||
            Assert.True(await UDPClientPool.SendBytesAsync(serverEP, Number.NumberToBytes(number, 4).Value));
 | 
			
		||||
 | 
			
		||||
            var ret = await udpServer.WaitForAckAsync(address);
 | 
			
		||||
            Assert.True(ret.IsSuccessful);
 | 
			
		||||
            var data = ret.Value;
 | 
			
		||||
            Assert.True(data.IsSuccessful);
 | 
			
		||||
            Assert.Equal(number, Number.BytesToUInt32(data.ToBytes()).Value);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Theory]
 | 
			
		||||
    [InlineData(new object[] { new UInt64[] { 0x0F_00_00_00_01_02_02_02, 0x0F_01_00_00_FF_FF_FF_FF } })]
 | 
			
		||||
    public async Task UDPServerWaitData(UInt64[] bytesArray)
 | 
			
		||||
    {
 | 
			
		||||
        Assert.True(udpServer.IsRunning);
 | 
			
		||||
 | 
			
		||||
        var serverEP = new IPEndPoint(IPAddress.Parse(address), port);
 | 
			
		||||
 | 
			
		||||
        foreach (var number in bytesArray)
 | 
			
		||||
        {
 | 
			
		||||
            Assert.True(await UDPClientPool.SendBytesAsync(serverEP, Number.NumberToBytes(number, 8).Value));
 | 
			
		||||
 | 
			
		||||
            var ret = await udpServer.WaitForDataAsync(address);
 | 
			
		||||
            Assert.True(ret.IsSuccessful);
 | 
			
		||||
            var data = ret.Value;
 | 
			
		||||
            Assert.True(data.IsSuccessful);
 | 
			
		||||
            Assert.Equal((UInt64)number, Number.BytesToUInt64(data.ToBytes()).Value);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -14,6 +14,7 @@
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <PackageReference Include="ArpLookup" Version="2.0.3" />
 | 
			
		||||
    <PackageReference Include="DotNext" Version="5.23.0" />
 | 
			
		||||
    <PackageReference Include="DotNext.Threading" Version="5.23.0" />
 | 
			
		||||
    <PackageReference Include="Honoo.IO.Hashing.Crc" Version="1.3.3" />
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,14 @@
 | 
			
		||||
using System.Diagnostics;
 | 
			
		||||
using System.Net.NetworkInformation;
 | 
			
		||||
using ArpLookup;
 | 
			
		||||
using System.Runtime.InteropServices;
 | 
			
		||||
using System.Net;
 | 
			
		||||
using System.Text.RegularExpressions;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// ARP 记录管理静态类(跨平台支持)
 | 
			
		||||
/// </summary>
 | 
			
		||||
public static class Arp
 | 
			
		||||
public static class ArpClient
 | 
			
		||||
{
 | 
			
		||||
    private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
 | 
			
		||||
 | 
			
		||||
@@ -44,20 +47,28 @@ public static class Arp
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 通过 Ping 动态更新指定 IP 的 ARP 记录
 | 
			
		||||
    /// 动态更新指定 IP 的 ARP 记录
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="ipAddress">要更新的 IP 地址</param>
 | 
			
		||||
    /// <returns>是否成功发送 Ping</returns>
 | 
			
		||||
    public static async Task<bool> UpdateArpEntryByPingAsync(string ipAddress)
 | 
			
		||||
    public static async Task<bool> UpdateArpEntryAsync(string ipAddress)
 | 
			
		||||
    {
 | 
			
		||||
        if (string.IsNullOrWhiteSpace(ipAddress))
 | 
			
		||||
            throw new ArgumentException("IP 地址不能为空", nameof(ipAddress));
 | 
			
		||||
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            using var ping = new System.Net.NetworkInformation.Ping();
 | 
			
		||||
            var reply = await ping.SendPingAsync(ipAddress, 100);
 | 
			
		||||
            return reply.Status == System.Net.NetworkInformation.IPStatus.Success;
 | 
			
		||||
            var ret = await ArpClient.DeleteArpEntryAsync(ipAddress);
 | 
			
		||||
            if (!ret)
 | 
			
		||||
            {
 | 
			
		||||
                logger.Error($"删除 ARP 记录失败: {ipAddress}");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            PhysicalAddress? mac = await Arp.LookupAsync(IPAddress.Parse(ipAddress));
 | 
			
		||||
            if (mac == null)
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        catch
 | 
			
		||||
        {
 | 
			
		||||
@@ -228,22 +239,22 @@ public static class Arp
 | 
			
		||||
                return null;
 | 
			
		||||
 | 
			
		||||
            var lines = result.Output.Split('\n', StringSplitOptions.RemoveEmptyEntries);
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            foreach (var line in lines)
 | 
			
		||||
            {
 | 
			
		||||
                // 匹配接口行格式: Interface: 172.6.1.5 --- 0xa
 | 
			
		||||
                var interfacePattern = @"Interface:\s+(\d+\.\d+\.\d+\.\d+)\s+---\s+(0x[a-fA-F0-9]+)";
 | 
			
		||||
                var match = Regex.Match(line, interfacePattern);
 | 
			
		||||
                
 | 
			
		||||
 | 
			
		||||
                if (match.Success && match.Groups[1].Value == interfaceIp)
 | 
			
		||||
                {
 | 
			
		||||
                    // 将十六进制索引转换为十进制
 | 
			
		||||
                    var hexIndex = match.Groups[2].Value;
 | 
			
		||||
                    // 去掉 "0x" 前缀
 | 
			
		||||
                    var hexValue = hexIndex.StartsWith("0x", StringComparison.OrdinalIgnoreCase) 
 | 
			
		||||
                        ? hexIndex.Substring(2) 
 | 
			
		||||
                    var hexValue = hexIndex.StartsWith("0x", StringComparison.OrdinalIgnoreCase)
 | 
			
		||||
                        ? hexIndex.Substring(2)
 | 
			
		||||
                        : hexIndex;
 | 
			
		||||
                    
 | 
			
		||||
 | 
			
		||||
                    if (int.TryParse(hexValue, System.Globalization.NumberStyles.HexNumber, null, out int decimalIndex))
 | 
			
		||||
                    {
 | 
			
		||||
                        logger.Debug($"找到接口 {interfaceIp} 的索引: {hexIndex} -> {decimalIndex}");
 | 
			
		||||
@@ -251,7 +262,7 @@ public static class Arp
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            logger.Warn($"未找到接口 {interfaceIp} 的索引");
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
@@ -417,9 +428,9 @@ public static class Arp
 | 
			
		||||
    private static ArpEntry? ParseWindowsArpEntry(string line)
 | 
			
		||||
    {
 | 
			
		||||
        // 跳过空行和标题行
 | 
			
		||||
        if (string.IsNullOrWhiteSpace(line) || 
 | 
			
		||||
            line.Contains("Interface:") || 
 | 
			
		||||
            line.Contains("Internet Address") || 
 | 
			
		||||
        if (string.IsNullOrWhiteSpace(line) ||
 | 
			
		||||
            line.Contains("Interface:") ||
 | 
			
		||||
            line.Contains("Internet Address") ||
 | 
			
		||||
            line.Contains("Physical Address") ||
 | 
			
		||||
            line.Contains("Type"))
 | 
			
		||||
        {
 | 
			
		||||
@@ -518,7 +529,7 @@ public static class Arp
 | 
			
		||||
 | 
			
		||||
        // 格式化 MAC 地址以适配不同操作系统
 | 
			
		||||
        string formattedMac = FormatMacAddress(macAddress);
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        var entry = await GetArpEntryAsync(ipAddress);
 | 
			
		||||
        if (entry != null && string.Equals(FormatMacAddress(entry.MacAddress), formattedMac, StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
        {
 | 
			
		||||
@@ -534,7 +545,7 @@ public static class Arp
 | 
			
		||||
 | 
			
		||||
        // 新增 ARP 记录
 | 
			
		||||
        var ret = await AddArpEntryAsync(ipAddress, formattedMac, interfaceName);
 | 
			
		||||
        if(!ret) logger.Error($"添加 ARP 记录失败: {ipAddress} -> {formattedMac} on {interfaceName}");
 | 
			
		||||
        if (!ret) logger.Error($"添加 ARP 记录失败: {ipAddress} -> {formattedMac} on {interfaceName}");
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -65,7 +65,7 @@ public class Number
 | 
			
		||||
        {
 | 
			
		||||
            for (var i = 0; i < length; i++)
 | 
			
		||||
            {
 | 
			
		||||
                arr[length - 1 - i] = Convert.ToByte((num >> (i << 3)) & (0xFF));
 | 
			
		||||
                arr[i] = Convert.ToByte((num >> (i << 3)) & (0xFF));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
@@ -99,20 +99,11 @@ public class Number
 | 
			
		||||
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            if (isLowNumHigh)
 | 
			
		||||
            if (!isLowNumHigh)
 | 
			
		||||
            {
 | 
			
		||||
                for (var i = 0; i < len; i++)
 | 
			
		||||
                {
 | 
			
		||||
                    num += Convert.ToUInt64((UInt64)bytes[len - 1 - i] << (i << 3));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                for (var i = 0; i < len; i++)
 | 
			
		||||
                {
 | 
			
		||||
                    num += Convert.ToUInt64((UInt64)bytes[i] << ((int)(len - 1 - i) << 3));
 | 
			
		||||
                }
 | 
			
		||||
                Array.Reverse(bytes);
 | 
			
		||||
            }
 | 
			
		||||
            num = BitConverter.ToUInt64(bytes, 0);
 | 
			
		||||
 | 
			
		||||
            return num;
 | 
			
		||||
        }
 | 
			
		||||
@@ -143,20 +134,11 @@ public class Number
 | 
			
		||||
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            if (isLowNumHigh)
 | 
			
		||||
            if (!isLowNumHigh)
 | 
			
		||||
            {
 | 
			
		||||
                for (var i = 0; i < len; i++)
 | 
			
		||||
                {
 | 
			
		||||
                    num += Convert.ToUInt32((UInt32)bytes[len - 1 - i] << (i << 3));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                for (var i = 0; i < len; i++)
 | 
			
		||||
                {
 | 
			
		||||
                    num += Convert.ToUInt32((UInt32)bytes[i] << ((int)(len - 1 - i) << 3));
 | 
			
		||||
                }
 | 
			
		||||
                Array.Reverse(bytes);
 | 
			
		||||
            }
 | 
			
		||||
            num = BitConverter.ToUInt32(bytes, 0);
 | 
			
		||||
 | 
			
		||||
            return num;
 | 
			
		||||
        }
 | 
			
		||||
@@ -333,10 +315,9 @@ public class Number
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < srcBytesLen; i += distance)
 | 
			
		||||
        {
 | 
			
		||||
            var end = i + distance;
 | 
			
		||||
            buffer = srcBytes[i..end];
 | 
			
		||||
            Buffer.BlockCopy(srcBytes, i, buffer, 0, distance);
 | 
			
		||||
            Array.Reverse(buffer);
 | 
			
		||||
            Array.Copy(buffer, 0, dstBytes, i, distance);
 | 
			
		||||
            Buffer.BlockCopy(buffer, 0, dstBytes, i, distance);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return dstBytes;
 | 
			
		||||
 
 | 
			
		||||
@@ -51,7 +51,7 @@ public class DataController : ControllerBase
 | 
			
		||||
        public DateTime? BoardExpireTime { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 获取本机IP地址(优先选择与实验板同网段的IP)
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <returns>本机IP地址</returns>
 | 
			
		||||
@@ -60,7 +60,7 @@ public class DataController : ControllerBase
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            var boardIpSegments = BOARD_IP.Split('.').Take(3).ToArray();
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            // 优先选择与实验板IP前三段相同的IP
 | 
			
		||||
            var sameSegmentIP = System.Net.NetworkInformation.NetworkInterface
 | 
			
		||||
                .GetAllNetworkInterfaces()
 | 
			
		||||
@@ -278,7 +278,7 @@ public class DataController : ControllerBase
 | 
			
		||||
                return NotFound("没有可用的实验板");
 | 
			
		||||
 | 
			
		||||
            var boardInfo = boardOpt.Value;
 | 
			
		||||
            if (!(await Arp.CheckOrAddAsync(boardInfo.IpAddr, boardInfo.MacAddr, GetLocalIPAddress().ToString())))
 | 
			
		||||
            if (!(await ArpClient.CheckOrAddAsync(boardInfo.IpAddr, boardInfo.MacAddr, GetLocalIPAddress().ToString())))
 | 
			
		||||
            {
 | 
			
		||||
                logger.Error($"无法配置ARP,实验板可能会无法连接");
 | 
			
		||||
            }
 | 
			
		||||
@@ -346,7 +346,7 @@ public class DataController : ControllerBase
 | 
			
		||||
                return NotFound("未找到对应的实验板");
 | 
			
		||||
 | 
			
		||||
            var boardInfo = ret.Value.Value;
 | 
			
		||||
            if (!(await Arp.CheckOrAddAsync(boardInfo.IpAddr, boardInfo.MacAddr, GetLocalIPAddress().ToString())))
 | 
			
		||||
            if (!(await ArpClient.CheckOrAddAsync(boardInfo.IpAddr, boardInfo.MacAddr, GetLocalIPAddress().ToString())))
 | 
			
		||||
            {
 | 
			
		||||
                logger.Error($"无法配置ARP,实验板可能会无法连接");
 | 
			
		||||
            }
 | 
			
		||||
@@ -490,4 +490,3 @@ public class DataController : ControllerBase
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -380,7 +380,7 @@ public class DebuggerController : ControllerBase
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var rawData = dataResult.Value;
 | 
			
		||||
            logger.Debug($"rawData: {BitConverter.ToString(rawData)}");
 | 
			
		||||
            // logger.Debug($"rawData: {BitConverter.ToString(rawData)}");
 | 
			
		||||
            int depth = (int)config.captureDepth;
 | 
			
		||||
            int portDataLen = 4 * depth;
 | 
			
		||||
            int portNum = (int)config.totalPortNum;
 | 
			
		||||
@@ -406,13 +406,15 @@ public class DebuggerController : ControllerBase
 | 
			
		||||
                        return StatusCode(StatusCodes.Status500InternalServerError, "数据越界");
 | 
			
		||||
                    }
 | 
			
		||||
                    var sampleBytes = rawData[sampleOffset..(sampleOffset + 4)];
 | 
			
		||||
                    UInt32 sample = BitConverter.ToUInt32(Common.Number.ReverseBytes(sampleBytes, 4).Value, 0);
 | 
			
		||||
                    UInt32 sample = Common.Number.BytesToUInt32(sampleBytes, true).Value;
 | 
			
		||||
                    // 提取wireWidth位
 | 
			
		||||
                    UInt32 mask = (wireWidth == 32) ? 0xFFFFFFFF : ((1u << wireWidth) - 1u);
 | 
			
		||||
                    channelUintArr[i] = (sample >> wireStart) & mask;
 | 
			
		||||
                }
 | 
			
		||||
                logger.Debug($"{channel.name} HexData: {BitConverter.ToString(channelUintArr.SelectMany(BitConverter.GetBytes).ToArray())}");
 | 
			
		||||
                var base64 = Convert.ToBase64String(channelUintArr.SelectMany(BitConverter.GetBytes).ToArray());
 | 
			
		||||
                var channelBytes = new byte[4 * depth];
 | 
			
		||||
                Buffer.BlockCopy(channelUintArr, 0, channelBytes, 0, channelBytes.Length);
 | 
			
		||||
                // logger.Debug($"{channel.name} HexData: {BitConverter.ToString(channelBytes)}");
 | 
			
		||||
                var base64 = Convert.ToBase64String(channelBytes);
 | 
			
		||||
                channelDataList.Add(new ChannelCaptureData { name = channel.name, data = base64 });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -19,8 +19,7 @@ public class NetConfigController : ControllerBase
 | 
			
		||||
    // 固定的实验板IP,端口,MAC地址
 | 
			
		||||
    private const string BOARD_IP = "169.254.109.0";
 | 
			
		||||
    private const int BOARD_PORT = 1234;
 | 
			
		||||
    private const string BOARD_MAC = "12:34:56:78:9a:bc";
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    // 本机网络信息
 | 
			
		||||
    private readonly IPAddress _localIP;
 | 
			
		||||
    private readonly byte[] _localMAC;
 | 
			
		||||
@@ -33,14 +32,14 @@ public class NetConfigController : ControllerBase
 | 
			
		||||
        // 初始化本机IP地址
 | 
			
		||||
        _localIP = GetLocalIPAddress();
 | 
			
		||||
        _localIPString = _localIP?.ToString() ?? "未知";
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        // 初始化本机MAC地址
 | 
			
		||||
        _localMAC = GetLocalMACAddress();
 | 
			
		||||
        _localMACString = _localMAC != null ? BitConverter.ToString(_localMAC).Replace("-", ":") : "未知";
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        // 获取本机网络接口名称
 | 
			
		||||
        _localInterface = GetLocalNetworkInterface();
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        logger.Info($"NetConfigController 初始化完成 - 本机IP: {_localIPString}, 本机MAC: {_localMACString}, 接口: {_localInterface}");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -53,7 +52,7 @@ public class NetConfigController : ControllerBase
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            var boardIpSegments = BOARD_IP.Split('.').Take(3).ToArray();
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            // 优先选择与实验板IP前三段相同的IP
 | 
			
		||||
            var sameSegmentIP = System.Net.NetworkInformation.NetworkInterface
 | 
			
		||||
                .GetAllNetworkInterfaces()
 | 
			
		||||
@@ -130,7 +129,7 @@ public class NetConfigController : ControllerBase
 | 
			
		||||
    {
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            return await Arp.CheckOrAddAsync(BOARD_IP, BOARD_MAC, _localInterface);
 | 
			
		||||
            return await ArpClient.UpdateArpEntryAsync(BOARD_IP);
 | 
			
		||||
        }
 | 
			
		||||
        catch (Exception ex)
 | 
			
		||||
        {
 | 
			
		||||
 
 | 
			
		||||
@@ -23,7 +23,7 @@ public static class MsgBus
 | 
			
		||||
    /// <returns>无</returns>
 | 
			
		||||
    public async static void Init()
 | 
			
		||||
    {
 | 
			
		||||
        if (!Arp.IsAdministrator())
 | 
			
		||||
        if (!ArpClient.IsAdministrator())
 | 
			
		||||
        {
 | 
			
		||||
            logger.Error($"非管理员运行,ARP无法更新,请用管理员权限运行");
 | 
			
		||||
            // throw new Exception($"非管理员运行,ARP无法更新,请用管理员权限运行");
 | 
			
		||||
 
 | 
			
		||||
@@ -479,10 +479,10 @@ async function startCapture() {
 | 
			
		||||
          const arr = [];
 | 
			
		||||
          for (let i = 0; i < bin.length; i += 4) {
 | 
			
		||||
            arr.push(
 | 
			
		||||
              (bin.charCodeAt(i) << 24) |
 | 
			
		||||
                (bin.charCodeAt(i + 1) << 16) |
 | 
			
		||||
                (bin.charCodeAt(i + 2) << 8) |
 | 
			
		||||
                bin.charCodeAt(i + 3),
 | 
			
		||||
              bin.charCodeAt(i) |
 | 
			
		||||
                (bin.charCodeAt(i + 1) << 8) |
 | 
			
		||||
                (bin.charCodeAt(i + 2) << 16) |
 | 
			
		||||
                (bin.charCodeAt(i + 3) << 24),
 | 
			
		||||
            );
 | 
			
		||||
          }
 | 
			
		||||
          // 截取采样深度
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user