Server: finish jtag controller; Web: finish sibebar animation
This commit is contained in:
		@@ -33,9 +33,8 @@ if (app.Environment.IsDevelopment())
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Setup UDP Server
 | 
			
		||||
var udpServer = new UDPServer(33000);
 | 
			
		||||
udpServer.Start();
 | 
			
		||||
// Setup Program
 | 
			
		||||
MsgBus.Init();
 | 
			
		||||
 | 
			
		||||
// Router
 | 
			
		||||
app.MapGet("/", () => "Hello World!");
 | 
			
		||||
@@ -46,6 +45,5 @@ app.MapPut("/api/SendDataPackage", Router.API.SendDataPackage);
 | 
			
		||||
app.Run("http://localhost:5000");
 | 
			
		||||
 | 
			
		||||
// Close UDP Server
 | 
			
		||||
Console.WriteLine("UDP Server is Closing now...");
 | 
			
		||||
udpServer.Stop();
 | 
			
		||||
 | 
			
		||||
Console.WriteLine("Program is Closing now...");
 | 
			
		||||
MsgBus.Exit();
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,7 @@
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <PackageReference Include="DotNext" Version="5.19.1" />
 | 
			
		||||
    <PackageReference Include="DotNext.Threading" Version="5.19.1" />
 | 
			
		||||
    <PackageReference Include="Microsoft.OpenApi" Version="1.6.23" />
 | 
			
		||||
    <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
 | 
			
		||||
    <PackageReference Include="Swashbuckle.AspNetCore" Version="8.1.0" />
 | 
			
		||||
 
 | 
			
		||||
@@ -64,6 +64,21 @@ namespace Common
 | 
			
		||||
            return num;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static Result<byte[]> MultiBitsToBytes(ulong bits1, uint bits1Len, ulong bits2, uint bits2Len)
 | 
			
		||||
        {
 | 
			
		||||
            return NumberToBytes(MultiBitsToNumber(bits1, bits1Len, bits2, bits2Len).Value,
 | 
			
		||||
                        (bits1Len + bits2Len) % 8 != 0 ? (bits1Len + bits2Len) / 8 + 1 : (bits1Len + bits2Len) / 8);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static Result<ulong> MultiBitsToNumber(ulong bits1, uint bits1Len, ulong bits2, uint bits2Len)
 | 
			
		||||
        {
 | 
			
		||||
            if (bits1Len + bits2Len > 64) throw new ArgumentException("Two Bits is more than 64 bits");
 | 
			
		||||
 | 
			
		||||
            ulong num = (bits1 << (int)bits2Len) | bits2;
 | 
			
		||||
            return num;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        public static Result<byte[]> StringToBytes(string str, int numBase = 16)
 | 
			
		||||
        {
 | 
			
		||||
            var len = str.Length;
 | 
			
		||||
 
 | 
			
		||||
@@ -28,6 +28,93 @@ public static class JtagAddr
 | 
			
		||||
    public const UInt32 WRITE_CMD = 0x10_00_00_03;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// The Command bits of Jtag
 | 
			
		||||
/// </summary>
 | 
			
		||||
public static class JtagCmd
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 旁路指令
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public const UInt32 JTAG_DR_BYPASS = 0b1111111111;
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 采样指令
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public const UInt32 JTAG_DR_SAMPLE = 0b1010000000;
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 预装指令
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public const UInt32 JTAG_DR_PRELOAD = 0b1010000000;
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 外测试指令
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public const UInt32 JTAG_DR_EXTEST = 0b1010000001;
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 内测试指令
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public const UInt32 JTAG_DR_INTEST = 0b1010000010;
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 标识指令
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public const UInt32 JTAG_DR_IDCODE = 0b1010000011;
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 高阻指令
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public const UInt32 JTAG_DR_HIGHZ = 0b1010000101;
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 复位指令
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public const UInt32 JTAG_DR_JRST = 0b1010001010;
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 配置指令
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public const UInt32 JTAG_DR_CFGI = 0b1010001011;
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 回读指令
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public const UInt32 JTAG_DR_CFGO = 0b1010001100;
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 唤醒指令
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public const UInt32 JTAG_DR_JWAKEUP = 0b1010001101;
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 读UID指令
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public const UInt32 JTAG_DR_READ_UID = 0b0101001100;
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 读状态寄存器指令
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public const UInt32 JTAG_DR_RDSR = 0b0101011001;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 设定JTAG默认状态为TEST_LOGIC_RESET态 (JTAG复位)
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public const UInt32 CMD_JTAG_CLOSE_TEST = 0b0000;
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 设定JTAG默认状态为RUN_TEST_IDLE态    (JTAG空闲)
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public const UInt32 CMD_JTAG_RUN_TEST = 0b0001;
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// JTAG进入SHIFTIR循环cycle_num次后回到设定的默认状态
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public const UInt32 CMD_JTAG_LOAD_IR = 0b0010;
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// JTAG进入SHIFTDR循环cycle_num次后回到设定的默认状态,同时输入shift_in
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public const UInt32 CMD_JTAG_LOAD_DR_CAREI = 0b0011;
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// JTAG进入SHIFTDR循环cycle_num次后回到设定的默认状态,同时输出shift_out
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public const UInt32 CMD_JTAG_LOAD_DR_CAREO = 0b0100;
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// JTAG进入RUN_TEST_IDLE态循环cycle_num次
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public const UInt32 CMD_JTAG_IDLE_DELAY = 0b0101;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class Jtag
 | 
			
		||||
{
 | 
			
		||||
    readonly int timeout;
 | 
			
		||||
@@ -46,32 +133,78 @@ class Jtag
 | 
			
		||||
        this.timeout = outTime;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async ValueTask<Result<bool>> ClearRegisters()
 | 
			
		||||
    public async ValueTask<Result<bool>> RunCommand(uint devAddr, uint cmd, uint exRet)
 | 
			
		||||
    {
 | 
			
		||||
        var ret = true;
 | 
			
		||||
        var ret = false;
 | 
			
		||||
        var opts = new SendAddrPackOptions();
 | 
			
		||||
 | 
			
		||||
        opts.burstType = BurstType.FixedBurst;
 | 
			
		||||
        opts.burstLength = 4;
 | 
			
		||||
        opts.commandID = 0;
 | 
			
		||||
        opts.address = JtagAddr.STATE;
 | 
			
		||||
        opts.address = devAddr;
 | 
			
		||||
 | 
			
		||||
        // Write Jtag State Register
 | 
			
		||||
        opts.isWrite = true;
 | 
			
		||||
        ret = await UDPClientPool.SendAddrPackAsync(ep, new SendAddrPackage(opts));
 | 
			
		||||
        if (!ret) throw new Exception("Send 1st Address Package Failed!");
 | 
			
		||||
        ret = await UDPClientPool.SendDataPackAsync(ep,
 | 
			
		||||
                new SendDataPackage(NumberProcessor.NumberToBytes(0xFF_FF_FF_FF, 4).Value));
 | 
			
		||||
                new SendDataPackage(NumberProcessor.NumberToBytes(cmd, 4).Value));
 | 
			
		||||
        if (!ret) throw new Exception("Send Data Package Failed!");
 | 
			
		||||
 | 
			
		||||
        // Read Jtag State Register
 | 
			
		||||
        opts.address = JtagAddr.STATE;
 | 
			
		||||
        ret = await UDPClientPool.SendAddrPackAsync(ep, new SendAddrPackage(opts));
 | 
			
		||||
        if (!ret) throw new Exception("Send 2rd Address Package Failed!");
 | 
			
		||||
 | 
			
		||||
        // Wait for Ack
 | 
			
		||||
        var data = await UDPServer.
 | 
			
		||||
        if (!MsgBus.IsRunning)
 | 
			
		||||
            throw new Exception("Message Bus not Working!");
 | 
			
		||||
 | 
			
		||||
        var data = await MsgBus.UDPServer.FindDataAsync(address);
 | 
			
		||||
        if (!data.HasValue)
 | 
			
		||||
            throw new Exception("Get None after Time out!");
 | 
			
		||||
 | 
			
		||||
        var recvData = data.Value;
 | 
			
		||||
        if (recvData.addr != address || recvData.port != port)
 | 
			
		||||
            throw new Exception("Receive Data From Wrong Board!");
 | 
			
		||||
 | 
			
		||||
        var retPack = RecvDataPackage.FromBytes(recvData.data);
 | 
			
		||||
        if (!retPack.IsSuccessful)
 | 
			
		||||
            throw new Exception("Not Current RecvDataPackage!", retPack.Error);
 | 
			
		||||
 | 
			
		||||
        var retPackLen = retPack.Value.Options.data.Length;
 | 
			
		||||
        if (retPackLen != 3)
 | 
			
		||||
            throw new Exception($"RecvDataPackage BodyData Length not Equal to 3: Total {retPackLen} bytes");
 | 
			
		||||
 | 
			
		||||
        if (NumberProcessor.BytesToNumber(retPack.Value.Options.data).Value == exRet)
 | 
			
		||||
            ret = true;
 | 
			
		||||
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async ValueTask<Result<bool>> ClearAllRegisters()
 | 
			
		||||
    {
 | 
			
		||||
        return await RunCommand(JtagAddr.STATE, 0xFF_FF_FF_FF, 0x00_00_00_00);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async ValueTask<Result<bool>> ClearWriteDataReg()
 | 
			
		||||
    {
 | 
			
		||||
        return await RunCommand(JtagAddr.STATE, 0x00_00_11_00, 0x00_00_00_00);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async ValueTask<Result<bool>> RunTest()
 | 
			
		||||
    {
 | 
			
		||||
        return await RunCommand(JtagAddr.WRITE_CMD, 0x10_00_00_00, 0x01_00_00_00);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async ValueTask<Result<bool>> WriteIDCode()
 | 
			
		||||
    {
 | 
			
		||||
        return await RunCommand(JtagAddr.WRITE_DATA, 0b1010000011, 0x01_00_00_00);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async ValueTask<Result<bool>> LoadIR()
 | 
			
		||||
    {
 | 
			
		||||
        return await RunCommand(JtagAddr.WRITE_CMD, 0x20_00_00_0A, 0x01_00_00_00);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										22
									
								
								server/src/MsgBus.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								server/src/MsgBus.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
public static class MsgBus
 | 
			
		||||
{
 | 
			
		||||
    private static readonly UDPServer udpServer = new UDPServer(33000);
 | 
			
		||||
    public static UDPServer UDPServer { get { return udpServer; } }
 | 
			
		||||
 | 
			
		||||
    private static bool isRunning = false;
 | 
			
		||||
    public static bool IsRunning { get { return isRunning; } }
 | 
			
		||||
 | 
			
		||||
    public static void Init()
 | 
			
		||||
    {
 | 
			
		||||
        udpServer.Start();
 | 
			
		||||
        isRunning = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static void Exit()
 | 
			
		||||
    {
 | 
			
		||||
        udpServer.Stop();
 | 
			
		||||
        isRunning = false;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -2,6 +2,7 @@ using System.Net;
 | 
			
		||||
using System.Net.Sockets;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using DotNext;
 | 
			
		||||
using DotNext.Threading;
 | 
			
		||||
 | 
			
		||||
public struct UDPData
 | 
			
		||||
{
 | 
			
		||||
@@ -20,7 +21,7 @@ public class UDPServer
 | 
			
		||||
    private UdpClient listener;
 | 
			
		||||
    private IPEndPoint groupEP;
 | 
			
		||||
    private Dictionary<string, List<UDPData>> udpData = new Dictionary<string, List<UDPData>>();
 | 
			
		||||
    private Mutex mutUdpData = new Mutex();
 | 
			
		||||
    private AsyncReaderWriterLock udpDataLock = new AsyncReaderWriterLock(1);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Construct a udp server with fixed port
 | 
			
		||||
@@ -50,32 +51,21 @@ public class UDPServer
 | 
			
		||||
    /// Find UDP Receive Data According to ip address
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="ipAddr"> IP Address</param>
 | 
			
		||||
    /// <param name="rwTimeout"> Read and Write Wait for Milliseconds </param>
 | 
			
		||||
    /// <returns>UDP Data</returns>
 | 
			
		||||
    public Optional<UDPData> FindData(string ipAddr)
 | 
			
		||||
    public Optional<UDPData> FindData(string ipAddr, int rwTimeout = 1000)
 | 
			
		||||
    {
 | 
			
		||||
        UDPData? data = null;
 | 
			
		||||
        try
 | 
			
		||||
        using (udpDataLock.AcquireWriteLock(TimeSpan.FromMilliseconds(rwTimeout)))
 | 
			
		||||
        {
 | 
			
		||||
            var isOverTime = !mutUdpData.WaitOne(1000);
 | 
			
		||||
            if (isOverTime) return Optional.None<UDPData>();
 | 
			
		||||
            // Get
 | 
			
		||||
            var listData = udpData[ipAddr];
 | 
			
		||||
            data = listData[0];
 | 
			
		||||
 | 
			
		||||
            // Delete
 | 
			
		||||
            listData.RemoveAt(0);
 | 
			
		||||
        }
 | 
			
		||||
        catch
 | 
			
		||||
        {
 | 
			
		||||
            data = null;
 | 
			
		||||
        }
 | 
			
		||||
        finally
 | 
			
		||||
        {
 | 
			
		||||
            mutUdpData.ReleaseMutex();
 | 
			
		||||
            if (udpData.ContainsKey(ipAddr) && udpData[ipAddr].Count > 0)
 | 
			
		||||
            {
 | 
			
		||||
                data = udpData[ipAddr][0];
 | 
			
		||||
                udpData[ipAddr].RemoveAt(0);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Return
 | 
			
		||||
        if (data is null)
 | 
			
		||||
        if (data == null)
 | 
			
		||||
        {
 | 
			
		||||
            return Optional.None<UDPData>();
 | 
			
		||||
        }
 | 
			
		||||
@@ -93,35 +83,24 @@ public class UDPServer
 | 
			
		||||
    /// <returns>[TODO:return]</returns>
 | 
			
		||||
    public async ValueTask<Optional<UDPData>> FindDataAsync(string ipAddr, int timeout = 1000)
 | 
			
		||||
    {
 | 
			
		||||
        var time = 0;
 | 
			
		||||
        UDPData? data = null;
 | 
			
		||||
        while (time < timeout)
 | 
			
		||||
        using (await udpDataLock.AcquireWriteLockAsync(TimeSpan.FromMilliseconds(1000)))
 | 
			
		||||
        {
 | 
			
		||||
            await Task.Delay(1);
 | 
			
		||||
            try
 | 
			
		||||
            if (udpData.ContainsKey(ipAddr) && udpData[ipAddr].Count > 0)
 | 
			
		||||
            {
 | 
			
		||||
                var isOverTime = !mutUdpData.WaitOne(timeout - time);
 | 
			
		||||
                if (isOverTime) break;
 | 
			
		||||
                // Get
 | 
			
		||||
                var listData = udpData[ipAddr];
 | 
			
		||||
                data = listData[0];
 | 
			
		||||
 | 
			
		||||
                // Delete
 | 
			
		||||
                listData.RemoveAt(0);
 | 
			
		||||
                data = udpData[ipAddr][0];
 | 
			
		||||
                udpData[ipAddr].RemoveAt(0);
 | 
			
		||||
            }
 | 
			
		||||
            catch
 | 
			
		||||
            {
 | 
			
		||||
                data = null;
 | 
			
		||||
            }
 | 
			
		||||
            finally
 | 
			
		||||
            {
 | 
			
		||||
                mutUdpData.ReleaseMutex();
 | 
			
		||||
            }
 | 
			
		||||
            if (data is null) continue;
 | 
			
		||||
            else break;
 | 
			
		||||
        }
 | 
			
		||||
        if ((time >= timeout) || (data is null)) { return Optional.None<UDPData>(); }
 | 
			
		||||
        else { return Optional.Some((UDPData)data); }
 | 
			
		||||
 | 
			
		||||
        if (data == null)
 | 
			
		||||
        {
 | 
			
		||||
            return Optional.None<UDPData>();
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            return Optional.Some((UDPData)data);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void ReceiveHandler(IAsyncResult res)
 | 
			
		||||
@@ -131,7 +110,7 @@ public class UDPServer
 | 
			
		||||
        var nowtime = DateTime.Now;
 | 
			
		||||
 | 
			
		||||
        // Handle RemoteEP
 | 
			
		||||
        string remoteStr;
 | 
			
		||||
        string remoteStr = "Unknown";
 | 
			
		||||
        if (remoteEP is not null)
 | 
			
		||||
        {
 | 
			
		||||
            var remoteAddress = remoteEP.Address.ToString();
 | 
			
		||||
@@ -160,14 +139,10 @@ public class UDPServer
 | 
			
		||||
 | 
			
		||||
            remoteStr = $"{remoteAddress}:{remotePort}";
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            remoteStr = "Unknown";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Handle Package
 | 
			
		||||
        var sign = bytes[0];
 | 
			
		||||
        string recvData;
 | 
			
		||||
        string recvData = "";
 | 
			
		||||
        if (sign == (byte)WebProtocol.PackSign.SendAddr)
 | 
			
		||||
        {
 | 
			
		||||
            var resData = WebProtocol.SendAddrPackage.FromBytes(bytes);
 | 
			
		||||
@@ -176,18 +151,9 @@ public class UDPServer
 | 
			
		||||
            else
 | 
			
		||||
                recvData = resData.Error.ToString();
 | 
			
		||||
        }
 | 
			
		||||
        else if (sign == (byte)WebProtocol.PackSign.SendData)
 | 
			
		||||
        {
 | 
			
		||||
            recvData = "";
 | 
			
		||||
        }
 | 
			
		||||
        else if (sign == (byte)WebProtocol.PackSign.RecvData)
 | 
			
		||||
        {
 | 
			
		||||
            recvData = "";
 | 
			
		||||
        }
 | 
			
		||||
        else if (sign == (byte)WebProtocol.PackSign.RecvResp)
 | 
			
		||||
        {
 | 
			
		||||
            recvData = "";
 | 
			
		||||
        }
 | 
			
		||||
        else if (sign == (byte)WebProtocol.PackSign.SendData) { }
 | 
			
		||||
        else if (sign == (byte)WebProtocol.PackSign.RecvData) { }
 | 
			
		||||
        else if (sign == (byte)WebProtocol.PackSign.RecvResp) { }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            recvData = Encoding.ASCII.GetString(bytes, 0, bytes.Length);
 | 
			
		||||
 
 | 
			
		||||
@@ -59,6 +59,7 @@ namespace WebProtocol
 | 
			
		||||
    {
 | 
			
		||||
        public byte commandID;
 | 
			
		||||
        public bool isSuccess;
 | 
			
		||||
        public byte[] data;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public struct SendAddrPackage
 | 
			
		||||
@@ -184,13 +185,27 @@ namespace WebProtocol
 | 
			
		||||
            this.bodyData = bodyData;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public RecvPackOptions Options()
 | 
			
		||||
        public RecvPackOptions Options
 | 
			
		||||
        {
 | 
			
		||||
            RecvPackOptions opts;
 | 
			
		||||
            opts.commandID = commandID;
 | 
			
		||||
            opts.isSuccess = Convert.ToBoolean((resp >> 1) == 0b01 ? true : false);
 | 
			
		||||
            get
 | 
			
		||||
            {
 | 
			
		||||
                RecvPackOptions opts;
 | 
			
		||||
                opts.commandID = commandID;
 | 
			
		||||
                opts.isSuccess = Convert.ToBoolean((resp >> 1) == 0b01 ? true : false);
 | 
			
		||||
                opts.data = bodyData;
 | 
			
		||||
 | 
			
		||||
            return opts;
 | 
			
		||||
                return opts;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static Result<RecvDataPackage> FromBytes(byte[] bytes)
 | 
			
		||||
        {
 | 
			
		||||
            if (bytes[0] != (byte)PackSign.RecvData)
 | 
			
		||||
                throw new ArgumentException(
 | 
			
		||||
                    "The sign of bytes is not RecvData Package!",
 | 
			
		||||
                    nameof(bytes)
 | 
			
		||||
                );
 | 
			
		||||
            return new RecvDataPackage(bytes[1], bytes[2], bytes[4..]);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								src/App.vue
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								src/App.vue
									
									
									
									
									
								
							@@ -1,4 +1,5 @@
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import Sidebar from "./components/Sidebar.vue";
 | 
			
		||||
import { useThemeStore } from "./stores/theme";
 | 
			
		||||
 | 
			
		||||
const theme = useThemeStore();
 | 
			
		||||
@@ -6,12 +7,11 @@ const theme = useThemeStore();
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <div :data-theme="theme.currentTheme">
 | 
			
		||||
    <header>
 | 
			
		||||
      <RouterLink to="/user"> Go to User</RouterLink>
 | 
			
		||||
      <RouterLink to="/login"> Go to Login</RouterLink>
 | 
			
		||||
      <router-link to="/test"> Go to Test</router-link>
 | 
			
		||||
    <header class="relative">
 | 
			
		||||
      <div class="fixed left-0 top-0 z-50">
 | 
			
		||||
        <Sidebar />
 | 
			
		||||
      </div>
 | 
			
		||||
    </header>
 | 
			
		||||
    <div></div>
 | 
			
		||||
 | 
			
		||||
    <main>
 | 
			
		||||
      <RouterView />
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										11
									
								
								src/components/PopButton.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/components/PopButton.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <button class="btn transition-transform duration-150 ease-in-out hover:scale-120">
 | 
			
		||||
    Button A
 | 
			
		||||
  </button>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts" setup></script>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="postcss">
 | 
			
		||||
@import "@/assets/main.css";
 | 
			
		||||
</style>
 | 
			
		||||
@@ -1,123 +1,139 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div :class="[
 | 
			
		||||
    'card-dash',
 | 
			
		||||
    'sidebar-base',
 | 
			
		||||
    'transition-all',
 | 
			
		||||
    'duration-500',
 | 
			
		||||
    'ease-in-out',
 | 
			
		||||
    isClose ? 'sidebar-close' : 'sidebar-open',
 | 
			
		||||
  ]">
 | 
			
		||||
    <div class="card-body flex transition-all duration-500 ease-in-out">
 | 
			
		||||
  <div class="card card-dash sidebar-base" :class="[isClose ? 'w-31' : 'w-80']">
 | 
			
		||||
    <div class="card-body flex relative transition-all duration-500 ease-in-out">
 | 
			
		||||
      <!-- Avatar and Name -->
 | 
			
		||||
      <div :class="['flex', 'items-center', isClose ? 'flex-col' : '']">
 | 
			
		||||
      <div class="relative" :class="isClose ? 'h-50' : 'h-20'">
 | 
			
		||||
        <!-- Img -->
 | 
			
		||||
        <div class="avatar h-10">
 | 
			
		||||
        <div class="avatar h-10 fixed top-10" :class="isClose ? 'left-10' : 'left-7'">
 | 
			
		||||
          <div class="rounded-full">
 | 
			
		||||
            <img src="../assets/user.svg" alt="User" />
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <!-- Text -->
 | 
			
		||||
        <div v-if="!isClose" class="mx-5 grow">
 | 
			
		||||
          <label class="text-2xl">用户名</label>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <!-- Toggle Button -->
 | 
			
		||||
        <button class="btn btn-square rounded-lg p-2 m-3" @click="toggleSidebar">
 | 
			
		||||
          <img src="../assets/left.svg" alt="Menu Button" class="opacity-50">
 | 
			
		||||
        </button>
 | 
			
		||||
        <Transition>
 | 
			
		||||
          <div v-if="!isClose" class="mx-5 grow fixed left-20 top-11">
 | 
			
		||||
            <label class="text-2xl">用户名</label>
 | 
			
		||||
          </div>
 | 
			
		||||
        </Transition>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
      <!-- Toggle Button -->
 | 
			
		||||
      <button class="btn btn-square rounded-lg p-2 m-3 fixed" :class="isClose ? 'left-7 top-23' : 'left-60 top-7'"
 | 
			
		||||
        @click="toggleSidebar">
 | 
			
		||||
        <svg t="1741694970690" :class="isClose ? 'rotate-0' : 'rotate-540'" class="icon" viewBox="0 0 1024 1024"
 | 
			
		||||
          version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4546" xmlns:xlink="http://www.w3.org/1999/xlink"
 | 
			
		||||
          width="200" height="200">
 | 
			
		||||
          <path
 | 
			
		||||
            d="M803.758 514.017c-0.001-0.311-0.013-0.622-0.018-0.933-0.162-23.974-9.386-47.811-27.743-65.903-0.084-0.082-0.172-0.157-0.256-0.239-0.154-0.154-0.296-0.315-0.451-0.468L417.861 94.096c-37.685-37.153-99.034-37.476-136.331-0.718-37.297 36.758-36.979 97.231 0.707 134.384l290.361 286.257-290.362 286.257c-37.685 37.153-38.004 97.625-0.707 134.383 37.297 36.758 98.646 36.435 136.331-0.718l357.43-352.378c0.155-0.153 0.297-0.314 0.451-0.468 0.084-0.082 0.172-0.157 0.256-0.239 18.354-18.089 27.578-41.922 27.743-65.892 0.004-0.315 0.017-0.631 0.018-0.947z"
 | 
			
		||||
            :fill="theme.isLightTheme() ? '#828282' : '#C0C3C8'" p-id="4547"></path>
 | 
			
		||||
        </svg>
 | 
			
		||||
      </button>
 | 
			
		||||
 | 
			
		||||
      <div class="divider"></div>
 | 
			
		||||
 | 
			
		||||
      <ul class="menu h-full w-full">
 | 
			
		||||
        <li v-for="item in items" class="text-lg my-1">
 | 
			
		||||
        <li v-for="item in items" class="text-xl my-1">
 | 
			
		||||
          <a>
 | 
			
		||||
            <img class="h-[1.5em] opacity-50 mx-1" :src="item.icon" alt="An icon" />
 | 
			
		||||
            <p v-if="!isClose">{{ item.msg }}</p>
 | 
			
		||||
            <svg t="1741694797806" class="icon h-[1.5em] w-[1.5em] opacity-50 mx-1" viewBox="0 0 1024 1024"
 | 
			
		||||
              version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2622" xmlns:xlink="http://www.w3.org/1999/xlink"
 | 
			
		||||
              width="200" height="200">
 | 
			
		||||
              <path d="M192 192m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0Z" p-id="2623"></path>
 | 
			
		||||
              <path d="M192 512m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0Z" p-id="2624"></path>
 | 
			
		||||
              <path d="M192 832m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0Z" p-id="2625"></path>
 | 
			
		||||
              <path
 | 
			
		||||
                d="M864 160H352c-17.7 0-32 14.3-32 32s14.3 32 32 32h512c17.7 0 32-14.3 32-32s-14.3-32-32-32zM864 480H352c-17.7 0-32 14.3-32 32s14.3 32 32 32h512c17.7 0 32-14.3 32-32s-14.3-32-32-32zM864 800H352c-17.7 0-32 14.3-32 32s14.3 32 32 32h512c17.7 0 32-14.3 32-32s-14.3-32-32-32z"
 | 
			
		||||
                p-id="2626"></path>
 | 
			
		||||
            </svg>
 | 
			
		||||
            <Transition>
 | 
			
		||||
              <p v-if="!isClose">{{ item.msg }}</p>
 | 
			
		||||
            </Transition>
 | 
			
		||||
          </a>
 | 
			
		||||
        </li>
 | 
			
		||||
 | 
			
		||||
      </ul>
 | 
			
		||||
 | 
			
		||||
      <div class="divider"></div>
 | 
			
		||||
 | 
			
		||||
      <ul class="menu w-full">
 | 
			
		||||
        <li class="mb-5">
 | 
			
		||||
        <li>
 | 
			
		||||
          <a @click="theme.toggleTheme" class="text-xl">
 | 
			
		||||
            <ThemeControlButton />
 | 
			
		||||
            <p v-if="!isClose">改变主题</p>
 | 
			
		||||
            <ThemeControlToggle v-if="!isClose" />
 | 
			
		||||
            <Transition>
 | 
			
		||||
              <p v-if="!isClose" class="break-keep">改变主题</p>
 | 
			
		||||
            </Transition>
 | 
			
		||||
            <Transition>
 | 
			
		||||
              <ThemeControlToggle v-if="!isClose" />
 | 
			
		||||
            </Transition>
 | 
			
		||||
          </a>
 | 
			
		||||
        </li>
 | 
			
		||||
      </ul>
 | 
			
		||||
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import iconMenu from "../assets/menu.svg"
 | 
			
		||||
import iconMenu from "../assets/menu.svg";
 | 
			
		||||
import { useThemeStore } from "@/stores/theme";
 | 
			
		||||
import { computed, ref } from "vue";
 | 
			
		||||
import ThemeControlButton from "./ThemeControlButton.vue";
 | 
			
		||||
import ThemeControlToggle from "./ThemeControlToggle.vue";
 | 
			
		||||
 | 
			
		||||
const theme = useThemeStore()
 | 
			
		||||
const isClose = ref(false)
 | 
			
		||||
const theme = useThemeStore();
 | 
			
		||||
const isClose = ref(false);
 | 
			
		||||
 | 
			
		||||
const items = [
 | 
			
		||||
  { id: 1, icon: iconMenu, msg: "btn1" },
 | 
			
		||||
  { id: 2, icon: iconMenu, msg: "btn2" },
 | 
			
		||||
  { id: 3, icon: iconMenu, msg: "btn3" },
 | 
			
		||||
  { id: 4, icon: iconMenu, msg: "btn4" },
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
const themeSidebar = computed(() => {
 | 
			
		||||
  return [
 | 
			
		||||
    "card-dash",
 | 
			
		||||
    "sidebar-base",
 | 
			
		||||
    "transition",
 | 
			
		||||
    "duration-300",
 | 
			
		||||
    "ease-in-out",
 | 
			
		||||
    isClose.value ? "sidebar-close" : "sidebar-open",
 | 
			
		||||
  ]
 | 
			
		||||
})
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
function closeSidebar() {
 | 
			
		||||
  isClose.value = true;
 | 
			
		||||
  console.info("Close sidebar")
 | 
			
		||||
  console.info("Close sidebar");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function openSidebar() {
 | 
			
		||||
  isClose.value = false;
 | 
			
		||||
  console.info("Open sidebar")
 | 
			
		||||
  console.info("Open sidebar");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function toggleSidebar() {
 | 
			
		||||
  if (isClose.value) {
 | 
			
		||||
    openSidebar()
 | 
			
		||||
    openSidebar();
 | 
			
		||||
    // themeSidebar.value = "card-dash sidebar-base sidebar-open"
 | 
			
		||||
  }
 | 
			
		||||
  else {
 | 
			
		||||
    closeSidebar()
 | 
			
		||||
  } else {
 | 
			
		||||
    closeSidebar();
 | 
			
		||||
    // themeSidebar.value = "card-dash sidebar-base sidebar-close"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="postcss">
 | 
			
		||||
@reference "../assets/main.css";
 | 
			
		||||
 | 
			
		||||
* {
 | 
			
		||||
  @apply transition-all duration-500 ease-in-out;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.sidebar-base {
 | 
			
		||||
  @apply card shadow-xl h-screen;
 | 
			
		||||
  @apply shadow-xl h-screen;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.sidebar-open {
 | 
			
		||||
  @apply w-80
 | 
			
		||||
  @apply w-80;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.sidebar-close {
 | 
			
		||||
  @apply w-31
 | 
			
		||||
  @apply w-31;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.v-enter-active,
 | 
			
		||||
.v-leave-active {
 | 
			
		||||
  transition: opacity 0.3s ease;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.v-enter-from,
 | 
			
		||||
.v-leave-to {
 | 
			
		||||
  opacity: 0;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,29 +1,31 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="card card-dash shadow-xl w-90 h-60">
 | 
			
		||||
    <div class="card-body flex">
 | 
			
		||||
 | 
			
		||||
      <!-- Title -->
 | 
			
		||||
      <h1 class="card-title place-self-center font-bold text-2xl">上传比特流文件</h1>
 | 
			
		||||
      <h1 class="card-title place-self-center font-bold text-2xl">
 | 
			
		||||
        上传比特流文件
 | 
			
		||||
      </h1>
 | 
			
		||||
 | 
			
		||||
      <!-- Input File -->
 | 
			
		||||
      <fieldset class="fieldset w-full">
 | 
			
		||||
        <legend class="fieldset-legend text-sm">选择或拖拽上传文件</legend>
 | 
			
		||||
        <input type="file" class="file-input" @change="handleFileChange" />
 | 
			
		||||
        <label class="fieldset-label">Max size 2MB</label>
 | 
			
		||||
        <label class="fieldset-label">文件最大容量: 2MB</label>
 | 
			
		||||
      </fieldset>
 | 
			
		||||
 | 
			
		||||
      <!-- Upload Button -->
 | 
			
		||||
      <div class="card-actions">
 | 
			
		||||
        <button @click="uploadBitStream" class="btn btn-primary grow">上传</button>
 | 
			
		||||
        <button @click="uploadBitStream" class="btn btn-primary grow">
 | 
			
		||||
          上传
 | 
			
		||||
        </button>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts" setup>
 | 
			
		||||
import { client } from '@/client';
 | 
			
		||||
import { TRPCClientError } from '@trpc/client';
 | 
			
		||||
import { client } from "@/client";
 | 
			
		||||
import { TRPCClientError } from "@trpc/client";
 | 
			
		||||
 | 
			
		||||
var bitstream = null;
 | 
			
		||||
 | 
			
		||||
@@ -32,7 +34,7 @@ function handleFileChange(event: Event): void {
 | 
			
		||||
  const file = target.files?.[0]; // 获取选中的第一个文件
 | 
			
		||||
 | 
			
		||||
  if (!file) {
 | 
			
		||||
    console.error('未选择文件');
 | 
			
		||||
    console.error("未选择文件");
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -45,22 +47,18 @@ async function uploadBitStream() {
 | 
			
		||||
  try {
 | 
			
		||||
    const serverStatus = await client.api.status.query();
 | 
			
		||||
    if (serverStatus != "OK") {
 | 
			
		||||
      throw new Error("Server Busy...")
 | 
			
		||||
      throw new Error("Server Busy...");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    if (error instanceof TRPCClientError) {
 | 
			
		||||
      console.error("Can't connect to Server!")
 | 
			
		||||
      console.error("Can't connect to Server!");
 | 
			
		||||
    } else {
 | 
			
		||||
      console.error(error)
 | 
			
		||||
      console.error(error);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function checkFileType(file: File) {
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
function checkFileType(file: File) { }
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="postcss">
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										0
									
								
								src/stores/sidebar.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								src/stores/sidebar.ts
									
									
									
									
									
										Normal file
									
								
							@@ -2,16 +2,16 @@
 | 
			
		||||
  <div class="w-screen h-screen">
 | 
			
		||||
    <!-- <Switch width="720" height="720" /> -->
 | 
			
		||||
    <MechanicalButton width="720" height="720" />
 | 
			
		||||
    <PopButton></PopButton>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import MechanicalButton from '@/components/equipments/MechanicalButton.vue';
 | 
			
		||||
import Switch from '@/components/equipments/Switch.vue';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import PopButton from "@/components/PopButton.vue";
 | 
			
		||||
// import MechanicalButton from "@/components/equipments/MechanicalButton.vue";
 | 
			
		||||
// import Switch from "@/components/equipments/Switch.vue";
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="postcss">
 | 
			
		||||
@import "../assets/main.css"
 | 
			
		||||
@import "../assets/main.css";
 | 
			
		||||
</style>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,6 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <header>
 | 
			
		||||
  </header>
 | 
			
		||||
  <header></header>
 | 
			
		||||
  <main class="relative">
 | 
			
		||||
    <div class="fixed left-0 top-0 z-50">
 | 
			
		||||
      <Sidebar />
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="w-screen h-screen flex items-center justify-center">
 | 
			
		||||
      <UploadCard />
 | 
			
		||||
    </div>
 | 
			
		||||
@@ -12,10 +8,10 @@
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import UploadCard from '@/components/UploadCard.vue';
 | 
			
		||||
import Sidebar from '../components/Sidebar.vue'
 | 
			
		||||
import UploadCard from "@/components/UploadCard.vue";
 | 
			
		||||
import Sidebar from "../components/Sidebar.vue";
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped>
 | 
			
		||||
@import "../assets/main.css"
 | 
			
		||||
@import "../assets/main.css";
 | 
			
		||||
</style>
 | 
			
		||||
 
 | 
			
		||||
@@ -6,9 +6,6 @@
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "path": "./tsconfig.app.json"
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "path": "./tsconfig.bun.json"
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user