add nlog for server
This commit is contained in:
		
							
								
								
									
										12
									
								
								.justfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								.justfile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
@_show-dir:
 | 
			
		||||
  echo "Current Working Directory:"
 | 
			
		||||
  pwd
 | 
			
		||||
  echo
 | 
			
		||||
 | 
			
		||||
[working-directory: "server"]
 | 
			
		||||
publish: _show-dir
 | 
			
		||||
  dotnet publish --self-contained false -t:PublishAllRids
 | 
			
		||||
 | 
			
		||||
[working-directory: "server"]
 | 
			
		||||
run-server: _show-dir
 | 
			
		||||
  dotnet run
 | 
			
		||||
@@ -7,7 +7,10 @@
 | 
			
		||||
    let
 | 
			
		||||
      supportedSystems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ];
 | 
			
		||||
      forEachSupportedSystem = f: nixpkgs.lib.genAttrs supportedSystems (system: f {
 | 
			
		||||
        pkgs = import nixpkgs { inherit system; };
 | 
			
		||||
        pkgs = import nixpkgs { 
 | 
			
		||||
          inherit system;
 | 
			
		||||
          config.permittedInsecurePackages = ["dotnet-sdk-6.0.428"];
 | 
			
		||||
        };
 | 
			
		||||
      });
 | 
			
		||||
    in
 | 
			
		||||
    {
 | 
			
		||||
@@ -26,6 +29,7 @@
 | 
			
		||||
              dotnetCorePackages.sdk_8_0
 | 
			
		||||
            ])
 | 
			
		||||
            nuget
 | 
			
		||||
            # msbuild
 | 
			
		||||
            omnisharp-roslyn
 | 
			
		||||
            csharpier
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,51 +1,97 @@
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
using Microsoft.OpenApi.Models;
 | 
			
		||||
using NLog;
 | 
			
		||||
using NLog.Web;
 | 
			
		||||
 | 
			
		||||
var builder = WebApplication.CreateBuilder(args);
 | 
			
		||||
builder.Services.AddEndpointsApiExplorer();
 | 
			
		||||
builder.Services.AddSwaggerGen(options =>
 | 
			
		||||
// Early init of NLog to allow startup and exception logging, before host is built
 | 
			
		||||
var logger = NLog.LogManager.Setup()
 | 
			
		||||
                       .LoadConfigurationFromAppSettings()
 | 
			
		||||
                       .GetCurrentClassLogger();
 | 
			
		||||
logger.Debug("Init Main...");
 | 
			
		||||
 | 
			
		||||
try
 | 
			
		||||
{
 | 
			
		||||
    options.SwaggerDoc("v1", new OpenApiInfo
 | 
			
		||||
    var builder = WebApplication.CreateBuilder(args);
 | 
			
		||||
 | 
			
		||||
    // Add services to the container.
 | 
			
		||||
    builder.Services.AddControllersWithViews();
 | 
			
		||||
 | 
			
		||||
    // NLog: Setup NLog for Dependency injection
 | 
			
		||||
    builder.Logging.ClearProviders();
 | 
			
		||||
    builder.Host.UseNLog();
 | 
			
		||||
    builder.Services.AddEndpointsApiExplorer();
 | 
			
		||||
 | 
			
		||||
    // Add Swagger
 | 
			
		||||
    builder.Services.AddSwaggerGen(options =>
 | 
			
		||||
    {
 | 
			
		||||
        Title = "FPGA Web Lab API",
 | 
			
		||||
        Description = "Use FPGA in the cloud",
 | 
			
		||||
        Version = "v1"
 | 
			
		||||
        options.SwaggerDoc("v1", new OpenApiInfo
 | 
			
		||||
        {
 | 
			
		||||
            Title = "FPGA Web Lab API",
 | 
			
		||||
            Description = "Use FPGA in the cloud",
 | 
			
		||||
            Version = "v1"
 | 
			
		||||
        });
 | 
			
		||||
        // Generate Doc and Exam
 | 
			
		||||
        var executingAssembly = Assembly.GetExecutingAssembly();
 | 
			
		||||
        var xmlFilename = $"{executingAssembly.GetName().Name}.xml";
 | 
			
		||||
        options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename));
 | 
			
		||||
        var referencedProjectsXmlDocPaths =
 | 
			
		||||
            executingAssembly.GetReferencedAssemblies()
 | 
			
		||||
            .Where(assembly => assembly.Name != null && assembly.Name.StartsWith("server", StringComparison.InvariantCultureIgnoreCase))
 | 
			
		||||
            .Select(assembly => Path.Combine(AppContext.BaseDirectory, $"{assembly.Name}.xml"))
 | 
			
		||||
            .Where(path => File.Exists(path));
 | 
			
		||||
        foreach (var xmlDocPath in referencedProjectsXmlDocPaths) options.IncludeXmlComments(xmlDocPath);
 | 
			
		||||
    });
 | 
			
		||||
    // Generate Doc and Exam
 | 
			
		||||
    var executingAssembly = Assembly.GetExecutingAssembly();
 | 
			
		||||
    var xmlFilename = $"{executingAssembly.GetName().Name}.xml";
 | 
			
		||||
    options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename));
 | 
			
		||||
    var referencedProjectsXmlDocPaths =
 | 
			
		||||
        executingAssembly.GetReferencedAssemblies()
 | 
			
		||||
        .Where(assembly => assembly.Name != null && assembly.Name.StartsWith("server", StringComparison.InvariantCultureIgnoreCase))
 | 
			
		||||
        .Select(assembly => Path.Combine(AppContext.BaseDirectory, $"{assembly.Name}.xml"))
 | 
			
		||||
        .Where(path => File.Exists(path));
 | 
			
		||||
    foreach (var xmlDocPath in referencedProjectsXmlDocPaths) options.IncludeXmlComments(xmlDocPath);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
var app = builder.Build();
 | 
			
		||||
if (app.Environment.IsDevelopment())
 | 
			
		||||
{
 | 
			
		||||
    var app = builder.Build();
 | 
			
		||||
    // Configure the HTTP request pipeline.
 | 
			
		||||
    app.UseExceptionHandler("/Home/Error");
 | 
			
		||||
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
 | 
			
		||||
    app.UseHsts();
 | 
			
		||||
    app.UseHttpsRedirection();
 | 
			
		||||
    app.UseStaticFiles();
 | 
			
		||||
    app.UseRouting();
 | 
			
		||||
 | 
			
		||||
    app.UseAuthorization();
 | 
			
		||||
 | 
			
		||||
    app.MapControllerRoute(
 | 
			
		||||
        name: "default",
 | 
			
		||||
        pattern: "{controller=Home}/{action=Index}/{id?}");
 | 
			
		||||
 | 
			
		||||
    // if (app.Environment.IsDevelopment())
 | 
			
		||||
    // {
 | 
			
		||||
    app.UseSwagger();
 | 
			
		||||
    app.UseSwaggerUI(c =>
 | 
			
		||||
    {
 | 
			
		||||
        c.SwaggerEndpoint("/swagger/v1/swagger.json", "FPAG WebLab API V1");
 | 
			
		||||
    });
 | 
			
		||||
    // }
 | 
			
		||||
 | 
			
		||||
    // Setup Program
 | 
			
		||||
    MsgBus.Init();
 | 
			
		||||
 | 
			
		||||
    // Router
 | 
			
		||||
    app.MapGet("/", () => Results.Redirect("/swagger"));
 | 
			
		||||
    app.MapPut("/api/SendString", Router.API.SendString);
 | 
			
		||||
    app.MapPut("/api/SendAddrPackage", Router.API.SendAddrPackage);
 | 
			
		||||
    app.MapPut("/api/SendDataPackage", Router.API.SendDataPackage);
 | 
			
		||||
    app.MapPut("/api/jtag/RunCommand", Router.API.Jtag.RunCommand);
 | 
			
		||||
    app.MapPut("/api/jtag/GetIDCode", Router.API.Jtag.GetDeviceIDCode);
 | 
			
		||||
 | 
			
		||||
    app.Run("http://localhost:5000");
 | 
			
		||||
}
 | 
			
		||||
catch (Exception exception)
 | 
			
		||||
{
 | 
			
		||||
    // NLog: catch setup errors
 | 
			
		||||
    logger.Error(exception, "Stopped program because of exception");
 | 
			
		||||
    throw;
 | 
			
		||||
}
 | 
			
		||||
finally
 | 
			
		||||
{
 | 
			
		||||
    // Close UDP Server
 | 
			
		||||
    logger.Info("Program is Closing now...");
 | 
			
		||||
    MsgBus.Exit();
 | 
			
		||||
 | 
			
		||||
    // Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)
 | 
			
		||||
    NLog.LogManager.Shutdown();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Setup Program
 | 
			
		||||
MsgBus.Init();
 | 
			
		||||
 | 
			
		||||
// Router
 | 
			
		||||
app.MapGet("/", () => "Hello World!");
 | 
			
		||||
app.MapPut("/api/SendString", Router.API.SendString);
 | 
			
		||||
app.MapPut("/api/SendAddrPackage", Router.API.SendAddrPackage);
 | 
			
		||||
app.MapPut("/api/SendDataPackage", Router.API.SendDataPackage);
 | 
			
		||||
app.MapPut("/api/jtag/RunCommand", Router.API.Jtag.RunCommand);
 | 
			
		||||
app.MapPut("/api/jtag/GetIDCode", Router.API.Jtag.GetDeviceIDCode);
 | 
			
		||||
 | 
			
		||||
app.Run("http://localhost:5000");
 | 
			
		||||
 | 
			
		||||
// Close UDP Server
 | 
			
		||||
Console.WriteLine("Program is Closing now...");
 | 
			
		||||
MsgBus.Exit();
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										28
									
								
								server/PublishAllRids.targets
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								server/PublishAllRids.targets
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
			
		||||
<Project DefaultTargets="Build">
 | 
			
		||||
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
 | 
			
		||||
 | 
			
		||||
    <!-- Enable roll-forward to latest patch.  This allows one restore operation
 | 
			
		||||
         to apply to all of the self-contained publish operations. -->
 | 
			
		||||
    <TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
 | 
			
		||||
  <Target Name="PublishAllRids">
 | 
			
		||||
    <ItemGroup>
 | 
			
		||||
      <!-- Transform RuntimeIdentifiers property to item -->
 | 
			
		||||
      <RuntimeIdentifierForPublish Include="$(RuntimeIdentifiers)" />
 | 
			
		||||
 | 
			
		||||
      <!-- Transform RuntimeIdentifierForPublish items to project items to pass to MSBuild task -->
 | 
			
		||||
      <ProjectToPublish Include="@(RuntimeIdentifierForPublish->'$(MSBuildProjectFullPath)')">
 | 
			
		||||
        <AdditionalProperties>RuntimeIdentifier=%(RuntimeIdentifierForPublish.Identity)</AdditionalProperties>
 | 
			
		||||
      </ProjectToPublish>
 | 
			
		||||
    </ItemGroup>
 | 
			
		||||
 | 
			
		||||
    <MSBuild Projects="@(ProjectToPublish)"
 | 
			
		||||
             Targets="Publish"
 | 
			
		||||
             BuildInParallel="true"
 | 
			
		||||
             />
 | 
			
		||||
  </Target>
 | 
			
		||||
 | 
			
		||||
</Project>
 | 
			
		||||
@@ -2,8 +2,60 @@
 | 
			
		||||
  "Logging": {
 | 
			
		||||
    "LogLevel": {
 | 
			
		||||
      "Default": "Information",
 | 
			
		||||
      "Microsoft.AspNetCore": "Warning"
 | 
			
		||||
      "Microsoft": "Warning",
 | 
			
		||||
      "Microsoft.AspNetCore": "Warning",
 | 
			
		||||
      "Microsoft.Hosting.Lifetime": "Information"
 | 
			
		||||
    },
 | 
			
		||||
    "NLog": {
 | 
			
		||||
      "RemoveLoggerFactoryFilter": true
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  "AllowedHosts": "*"
 | 
			
		||||
  "AllowedHosts": "*",
 | 
			
		||||
  "NLog": {
 | 
			
		||||
    "extensions": [
 | 
			
		||||
      {
 | 
			
		||||
        "assembly": "NLog.Web.AspNetCore"
 | 
			
		||||
      }
 | 
			
		||||
    ],
 | 
			
		||||
    "throwConfigExceptions": true,
 | 
			
		||||
    "targets": {
 | 
			
		||||
      "async": true,
 | 
			
		||||
      "AllFile": {
 | 
			
		||||
        "type": "File",
 | 
			
		||||
        "fileName": "./log/all-${shortdate}.log"
 | 
			
		||||
      },
 | 
			
		||||
      "WebAllFile": {
 | 
			
		||||
        "type": "File",
 | 
			
		||||
        "fileName": "./log/web-all-${shortdate}.log"
 | 
			
		||||
      },
 | 
			
		||||
      "Console": {
 | 
			
		||||
        "type": "ColoredConsole"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "rules": [
 | 
			
		||||
      {
 | 
			
		||||
        "logger": "*",
 | 
			
		||||
        "finalMinLevel": "Trace",
 | 
			
		||||
        "writeTo": "AllFile"
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        "logger": "*",
 | 
			
		||||
        "finalMinLevel": "Trace",
 | 
			
		||||
        "writeTo": "WebAllFile"
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        "logger": "System.*",
 | 
			
		||||
        "finalMinLevel": "Warn"
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        "logger": "Microsoft.*",
 | 
			
		||||
        "finalMinLevel": "Warn"
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        "logger": "Microsoft.Hosting.Lifetime*",
 | 
			
		||||
        "finalMinLevel": "Info",
 | 
			
		||||
        "writeTo": "Console"
 | 
			
		||||
      }
 | 
			
		||||
    ]
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,13 @@
 | 
			
		||||
<Project Sdk="Microsoft.NET.Sdk.Web">
 | 
			
		||||
  <Import Project="PublishAllRids.targets" />
 | 
			
		||||
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <TargetFramework>net9.0</TargetFramework>
 | 
			
		||||
    <Nullable>enable</Nullable>
 | 
			
		||||
    <ImplicitUsings>enable</ImplicitUsings>
 | 
			
		||||
    <GenerateDocumentationFile>true</GenerateDocumentationFile>
 | 
			
		||||
    <RuntimeIdentifiers>win-x64;linux-x64;</RuntimeIdentifiers>
 | 
			
		||||
    <PublishSingleFile>true</PublishSingleFile>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
@@ -13,6 +16,7 @@
 | 
			
		||||
    <PackageReference Include="Microsoft.OpenApi" Version="1.6.23" />
 | 
			
		||||
    <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
 | 
			
		||||
    <PackageReference Include="NLog" Version="5.4.0" />
 | 
			
		||||
    <PackageReference Include="NLog.Web.AspNetCore" Version="5.4.0" />
 | 
			
		||||
    <PackageReference Include="Swashbuckle.AspNetCore" Version="8.1.0" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -236,11 +236,12 @@ class Jtag
 | 
			
		||||
        var opts = new SendAddrPackOptions();
 | 
			
		||||
 | 
			
		||||
        opts.burstType = BurstType.FixedBurst;
 | 
			
		||||
        opts.burstLength = 4;
 | 
			
		||||
        opts.burstLength = 0;
 | 
			
		||||
        opts.commandID = 0;
 | 
			
		||||
        opts.address = devAddr;
 | 
			
		||||
 | 
			
		||||
        // Read Jtag State Register
 | 
			
		||||
        opts.isWrite = false;
 | 
			
		||||
        ret = await UDPClientPool.SendAddrPackAsync(ep, new SendAddrPackage(opts));
 | 
			
		||||
        if (!ret) throw new Exception("Send Address Package Failed!");
 | 
			
		||||
 | 
			
		||||
@@ -276,7 +277,7 @@ class Jtag
 | 
			
		||||
        var opts = new SendAddrPackOptions();
 | 
			
		||||
 | 
			
		||||
        opts.burstType = BurstType.FixedBurst;
 | 
			
		||||
        opts.burstLength = 4;
 | 
			
		||||
        opts.burstLength = 0;
 | 
			
		||||
        opts.commandID = 0;
 | 
			
		||||
        opts.address = devAddr;
 | 
			
		||||
 | 
			
		||||
@@ -289,6 +290,7 @@ class Jtag
 | 
			
		||||
        if (!ret) throw new Exception("Send Data Package Failed!");
 | 
			
		||||
 | 
			
		||||
        // Read Jtag State Register
 | 
			
		||||
        opts.isWrite = false;
 | 
			
		||||
        opts.address = JtagAddr.STATE;
 | 
			
		||||
        ret = await UDPClientPool.SendAddrPackAsync(ep, new SendAddrPackage(opts));
 | 
			
		||||
        if (!ret) throw new Exception("Send 2rd Address Package Failed!");
 | 
			
		||||
 
 | 
			
		||||
@@ -1,19 +1,36 @@
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// 多线程通信总线
 | 
			
		||||
/// </summary>
 | 
			
		||||
public static class MsgBus
 | 
			
		||||
{
 | 
			
		||||
    private static readonly UDPServer udpServer = new UDPServer(33000);
 | 
			
		||||
    private static readonly UDPServer udpServer = new UDPServer(1234);
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 获取UDP服务器
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public static UDPServer UDPServer { get { return udpServer; } }
 | 
			
		||||
 | 
			
		||||
    private static bool isRunning = false;
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 获取通信总线运行状态
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public static bool IsRunning { get { return isRunning; } }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 通信总线初始化
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <returns>无</returns>
 | 
			
		||||
    public static void Init()
 | 
			
		||||
    {
 | 
			
		||||
        udpServer.Start();
 | 
			
		||||
        isRunning = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 关闭通信总线
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <returns>无</returns>
 | 
			
		||||
    public static void Exit()
 | 
			
		||||
    {
 | 
			
		||||
        udpServer.Stop();
 | 
			
		||||
 
 | 
			
		||||
@@ -16,10 +16,10 @@ namespace Router
 | 
			
		||||
    class API
 | 
			
		||||
    {
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Send some String
 | 
			
		||||
        /// 发送字符串
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="address">IP V4/V6 address</param>
 | 
			
		||||
        /// <param name="port">Device UDP port</param>
 | 
			
		||||
        /// <param name="address">IPV4 或者 IPV6 地址</param>
 | 
			
		||||
        /// <param name="port">设备端口号</param>
 | 
			
		||||
        /// <param name="text">Text for send</param>
 | 
			
		||||
        /// <returns>Json: true or false</returns>
 | 
			
		||||
        public static async ValueTask<IResult> SendString(string address, int port, string text)
 | 
			
		||||
 
 | 
			
		||||
@@ -4,11 +4,24 @@ using System.Text;
 | 
			
		||||
using DotNext;
 | 
			
		||||
using DotNext.Threading;
 | 
			
		||||
 | 
			
		||||
/// <summary> UDP接受数据包格式 </summary>
 | 
			
		||||
public struct UDPData
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 接受到的时间
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public DateTime datetime;
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 发送来源的IP地址
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public string addr;
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 发送来源的端口号
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public int port;
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 接受到的数据
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public byte[] data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -51,18 +64,29 @@ 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>
 | 
			
		||||
    /// <param name="timeout"> Read and Write Wait for Milliseconds </param>
 | 
			
		||||
    /// <returns>UDP Data</returns>
 | 
			
		||||
    public Optional<UDPData> FindData(string ipAddr, int rwTimeout = 1000)
 | 
			
		||||
    public Optional<UDPData> FindData(string ipAddr, int timeout = 1000)
 | 
			
		||||
    {
 | 
			
		||||
        UDPData? data = null;
 | 
			
		||||
        using (udpDataLock.AcquireWriteLock(TimeSpan.FromMilliseconds(rwTimeout)))
 | 
			
		||||
 | 
			
		||||
        var startTime = DateTime.Now;
 | 
			
		||||
        var isTimeout = false;
 | 
			
		||||
        var timeleft = TimeSpan.FromMilliseconds(timeout);
 | 
			
		||||
        while (!isTimeout)
 | 
			
		||||
        {
 | 
			
		||||
            if (udpData.ContainsKey(ipAddr) && udpData[ipAddr].Count > 0)
 | 
			
		||||
 | 
			
		||||
            using (udpDataLock.AcquireWriteLock(timeleft))
 | 
			
		||||
            {
 | 
			
		||||
                data = udpData[ipAddr][0];
 | 
			
		||||
                udpData[ipAddr].RemoveAt(0);
 | 
			
		||||
                if (udpData.ContainsKey(ipAddr) && udpData[ipAddr].Count > 0)
 | 
			
		||||
                {
 | 
			
		||||
                    data = udpData[ipAddr][0];
 | 
			
		||||
                    udpData[ipAddr].RemoveAt(0);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            timeleft = DateTime.Now.Subtract(startTime);
 | 
			
		||||
            isTimeout = timeleft >= TimeSpan.FromMilliseconds(timeout);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (data == null)
 | 
			
		||||
@@ -76,21 +100,36 @@ public class UDPServer
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Find UDP Receive Data Async
 | 
			
		||||
    /// 异步寻找目标发送的内容
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="ipAddr">[TODO:parameter]</param>
 | 
			
		||||
    /// <param name="timeout">[TODO:parameter]</param>
 | 
			
		||||
    /// <returns>[TODO:return]</returns>
 | 
			
		||||
    /// <param name="ipAddr"> 目标IP地址 </param>
 | 
			
		||||
    /// <param name="timeout">超时时间</param>
 | 
			
		||||
    /// <returns>
 | 
			
		||||
    /// 异步Optional 数据包:
 | 
			
		||||
    /// Optional 为空时,表明找不到数据;
 | 
			
		||||
    /// Optional 存在时,为最先收到的数据
 | 
			
		||||
    /// </returns>
 | 
			
		||||
    public async ValueTask<Optional<UDPData>> FindDataAsync(string ipAddr, int timeout = 1000)
 | 
			
		||||
    {
 | 
			
		||||
        UDPData? data = null;
 | 
			
		||||
        using (await udpDataLock.AcquireWriteLockAsync(TimeSpan.FromMilliseconds(1000)))
 | 
			
		||||
 | 
			
		||||
        var startTime = DateTime.Now;
 | 
			
		||||
        var isTimeout = false;
 | 
			
		||||
        var timeleft = TimeSpan.FromMilliseconds(timeout);
 | 
			
		||||
        while (!isTimeout)
 | 
			
		||||
        {
 | 
			
		||||
            if (udpData.ContainsKey(ipAddr) && udpData[ipAddr].Count > 0)
 | 
			
		||||
 | 
			
		||||
            using (await udpDataLock.AcquireWriteLockAsync(timeleft))
 | 
			
		||||
            {
 | 
			
		||||
                data = udpData[ipAddr][0];
 | 
			
		||||
                udpData[ipAddr].RemoveAt(0);
 | 
			
		||||
                if (udpData.ContainsKey(ipAddr) && udpData[ipAddr].Count > 0)
 | 
			
		||||
                {
 | 
			
		||||
                    data = udpData[ipAddr][0];
 | 
			
		||||
                    udpData[ipAddr].RemoveAt(0);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            timeleft = DateTime.Now.Subtract(startTime);
 | 
			
		||||
            isTimeout = timeleft >= TimeSpan.FromMilliseconds(timeout);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (data == null)
 | 
			
		||||
@@ -152,8 +191,22 @@ public class UDPServer
 | 
			
		||||
                recvData = resData.Error.ToString();
 | 
			
		||||
        }
 | 
			
		||||
        else if (sign == (byte)WebProtocol.PackSign.SendData) { }
 | 
			
		||||
        else if (sign == (byte)WebProtocol.PackSign.RecvData) { }
 | 
			
		||||
        else if (sign == (byte)WebProtocol.PackSign.RecvResp) { }
 | 
			
		||||
        else if (sign == (byte)WebProtocol.PackSign.RecvData)
 | 
			
		||||
        {
 | 
			
		||||
            var resData = WebProtocol.RecvDataPackage.FromBytes(bytes);
 | 
			
		||||
            if (resData.IsSuccessful)
 | 
			
		||||
                recvData = resData.Value.Options.ToString();
 | 
			
		||||
            else
 | 
			
		||||
                recvData = resData.Error.ToString();
 | 
			
		||||
        }
 | 
			
		||||
        else if (sign == (byte)WebProtocol.PackSign.RecvResp)
 | 
			
		||||
        {
 | 
			
		||||
            var resData = WebProtocol.RecvRespPackage.FromBytes(bytes);
 | 
			
		||||
            if (resData.IsSuccessful)
 | 
			
		||||
                recvData = resData.Value.Options.ToString();
 | 
			
		||||
            else
 | 
			
		||||
                recvData = resData.Error.ToString();
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            recvData = Encoding.ASCII.GetString(bytes, 0, bytes.Length);
 | 
			
		||||
 
 | 
			
		||||
@@ -42,8 +42,10 @@ namespace WebProtocol
 | 
			
		||||
        public BurstType burstType;
 | 
			
		||||
        /// <example>1</example>
 | 
			
		||||
        public byte commandID;
 | 
			
		||||
        /// <summary> 标识写入还是读取 </summary>
 | 
			
		||||
        /// <example> true </example>
 | 
			
		||||
        public bool isWrite;
 | 
			
		||||
        /// <summary> 突发长度:0是32bits,255是32bits x 256 </summary>
 | 
			
		||||
        /// <example> 255 </example>
 | 
			
		||||
        public byte burstLength;
 | 
			
		||||
        /// <example> 0x10_00_00_00 </example>
 | 
			
		||||
@@ -62,6 +64,19 @@ namespace WebProtocol
 | 
			
		||||
    /// <summary> Package Options which to receive from boards </summary>
 | 
			
		||||
    public struct RecvPackOptions
 | 
			
		||||
    {
 | 
			
		||||
        /// <summary> 数据包类型 </summary>
 | 
			
		||||
        public enum PackType
 | 
			
		||||
        {
 | 
			
		||||
            /// <summary> 读响应包 </summary>
 | 
			
		||||
            ReadResp,
 | 
			
		||||
            /// <summary> 写响应包 </summary>
 | 
			
		||||
            WriteResp
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// 数据包类型
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public PackType type;
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Task ID
 | 
			
		||||
        /// </summary>
 | 
			
		||||
@@ -85,7 +100,7 @@ namespace WebProtocol
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary> Package which send address to write </summary>
 | 
			
		||||
    /// <summary> Server->FPGA 地址包 </summary>
 | 
			
		||||
    public struct SendAddrPackage
 | 
			
		||||
    {
 | 
			
		||||
        readonly byte sign = (byte)PackSign.SendAddr;
 | 
			
		||||
@@ -94,22 +109,36 @@ namespace WebProtocol
 | 
			
		||||
        readonly byte _reserved = 0;
 | 
			
		||||
        readonly UInt32 address;
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// 使用地址包选项构造地址包
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="opts"> 地址包选项 </param>
 | 
			
		||||
        public SendAddrPackage(SendAddrPackOptions opts)
 | 
			
		||||
        {
 | 
			
		||||
            byte byteBurstType = Convert.ToByte((byte)opts.burstType << 5);
 | 
			
		||||
            byte byteCommandID = Convert.ToByte((opts.commandID & 0x03) << 3);
 | 
			
		||||
            byte byteBurstType = Convert.ToByte((byte)opts.burstType << 6);
 | 
			
		||||
            byte byteCommandID = Convert.ToByte((opts.commandID & 0x03) << 4);
 | 
			
		||||
            byte byteIsWrite = (opts.isWrite ? (byte)0x01 : (byte)0x00);
 | 
			
		||||
            this.commandType = Convert.ToByte(byteBurstType | byteCommandID | byteIsWrite);
 | 
			
		||||
            this.burstLength = opts.burstLength;
 | 
			
		||||
            this.address = opts.address;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public SendAddrPackage(BurstType burstType, byte commandID, bool isWrite)
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// 使用完整参数构造地址包
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="burstType"> 突发类型 </param>
 | 
			
		||||
        /// <param name="commandID"> 任务ID </param>
 | 
			
		||||
        /// <param name="isWrite"> 是否是写数据 </param>
 | 
			
		||||
        /// <param name="burstLength"> 突发长度 </param>
 | 
			
		||||
        /// <param name="address"> 设备地址 </param>
 | 
			
		||||
        public SendAddrPackage(BurstType burstType, byte commandID, bool isWrite, byte burstLength, UInt32 address)
 | 
			
		||||
        {
 | 
			
		||||
            byte byteBurstType = Convert.ToByte((byte)burstType << 5);
 | 
			
		||||
            byte byteCommandID = Convert.ToByte((commandID & 0x03) << 3);
 | 
			
		||||
            byte byteBurstType = Convert.ToByte((byte)burstType << 6);
 | 
			
		||||
            byte byteCommandID = Convert.ToByte((commandID & 0x03) << 4);
 | 
			
		||||
            byte byteIsWrite = (isWrite ? (byte)0x01 : (byte)0x00);
 | 
			
		||||
            this.commandType = Convert.ToByte(byteBurstType | byteCommandID | byteIsWrite);
 | 
			
		||||
            this.burstLength = burstLength;
 | 
			
		||||
            this.address = address;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public SendAddrPackage(byte commandType, byte burstLength, UInt32 address)
 | 
			
		||||
@@ -119,6 +148,10 @@ namespace WebProtocol
 | 
			
		||||
            this.address = address;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// 将地址包转化为字节数组
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <returns> 字节数组 </returns>
 | 
			
		||||
        public byte[] ToBytes()
 | 
			
		||||
        {
 | 
			
		||||
            var arr = new byte[8];
 | 
			
		||||
@@ -133,11 +166,15 @@ namespace WebProtocol
 | 
			
		||||
            return arr;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// 讲地址包转化为Json格式的地址包选项
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <returns> 字符串 </returns>
 | 
			
		||||
        public override string ToString()
 | 
			
		||||
        {
 | 
			
		||||
            SendAddrPackOptions opts;
 | 
			
		||||
            opts.burstType = (BurstType)(commandType >> 5);
 | 
			
		||||
            opts.commandID = Convert.ToByte((commandType >> 3) & 0b0011);
 | 
			
		||||
            opts.burstType = (BurstType)(commandType >> 6);
 | 
			
		||||
            opts.commandID = Convert.ToByte((commandType >> 4) & 0b0011);
 | 
			
		||||
            opts.isWrite = Convert.ToBoolean(commandType & 0x01);
 | 
			
		||||
            opts.burstLength = burstLength;
 | 
			
		||||
            opts.address = address;
 | 
			
		||||
@@ -194,6 +231,7 @@ namespace WebProtocol
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary> FPGA->Server 读数据包 </summary>
 | 
			
		||||
    public struct RecvDataPackage
 | 
			
		||||
    {
 | 
			
		||||
        readonly byte sign = (byte)PackSign.RecvData;
 | 
			
		||||
@@ -202,6 +240,13 @@ namespace WebProtocol
 | 
			
		||||
        readonly byte _reserved = 0;
 | 
			
		||||
        readonly byte[] bodyData;
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        ///  FPGA->Server 读数据包 
 | 
			
		||||
        ///  构造函数
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="commandID"> 任务ID号 </param>
 | 
			
		||||
        /// <param name="resp"> 读数据包响应 </param>
 | 
			
		||||
        /// <param name="bodyData"> 数据 </param>
 | 
			
		||||
        public RecvDataPackage(byte commandID, byte resp, byte[] bodyData)
 | 
			
		||||
        {
 | 
			
		||||
            this.commandID = commandID;
 | 
			
		||||
@@ -209,13 +254,17 @@ namespace WebProtocol
 | 
			
		||||
            this.bodyData = bodyData;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// 获取读数据包选项
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public RecvPackOptions Options
 | 
			
		||||
        {
 | 
			
		||||
            get
 | 
			
		||||
            {
 | 
			
		||||
                RecvPackOptions opts;
 | 
			
		||||
                opts.type = RecvPackOptions.PackType.ReadResp;
 | 
			
		||||
                opts.commandID = commandID;
 | 
			
		||||
                opts.isSuccess = Convert.ToBoolean((resp >> 1) == 0b01 ? true : false);
 | 
			
		||||
                opts.isSuccess = Convert.ToBoolean((resp >> 1) == 0b01 ? false : true);
 | 
			
		||||
                opts.data = bodyData;
 | 
			
		||||
 | 
			
		||||
                return opts;
 | 
			
		||||
@@ -246,14 +295,28 @@ namespace WebProtocol
 | 
			
		||||
            this.resp = resp;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public RecvPackOptions Options()
 | 
			
		||||
        public RecvPackOptions Options
 | 
			
		||||
        {
 | 
			
		||||
            RecvPackOptions opts;
 | 
			
		||||
            opts.commandID = commandID;
 | 
			
		||||
            opts.isSuccess = Convert.ToBoolean((resp >> 1) == 0b01 ? true : false);
 | 
			
		||||
            opts.data = null;
 | 
			
		||||
            get
 | 
			
		||||
            {
 | 
			
		||||
                RecvPackOptions opts;
 | 
			
		||||
                opts.type = RecvPackOptions.PackType.WriteResp;
 | 
			
		||||
                opts.commandID = commandID;
 | 
			
		||||
                opts.isSuccess = Convert.ToBoolean((resp >> 1) == 0b01 ? false : true);
 | 
			
		||||
                opts.data = null;
 | 
			
		||||
 | 
			
		||||
            return opts;
 | 
			
		||||
                return opts;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static Result<RecvRespPackage> FromBytes(byte[] bytes)
 | 
			
		||||
        {
 | 
			
		||||
            if (bytes[0] != (byte)PackSign.RecvResp)
 | 
			
		||||
                throw new ArgumentException(
 | 
			
		||||
                    "The sign of bytes is not RecvData Package!",
 | 
			
		||||
                    nameof(bytes)
 | 
			
		||||
                );
 | 
			
		||||
            return new RecvRespPackage(bytes[1], bytes[2]);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user