diff --git a/server.test/ProgressTrackerTest.cs b/server.test/ProgressTrackerTest.cs
index 95b4bed..6ca5a92 100644
--- a/server.test/ProgressTrackerTest.cs
+++ b/server.test/ProgressTrackerTest.cs
@@ -6,7 +6,7 @@ using server.Services;
public class ProgressTrackerTest
{
[Fact]
- public async Task Test_ProgressReporter_Basic()
+ public void Test_ProgressReporter_Basic()
{
int reportedValue = -1;
var reporter = new ProgressReporter(async v => { reportedValue = v; await Task.CompletedTask; }, 0, 100, 10);
diff --git a/server/server.csproj b/server/server.csproj
index b17c9bc..6c501a1 100644
--- a/server/server.csproj
+++ b/server/server.csproj
@@ -31,7 +31,7 @@
-
+
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/server/src/Controllers/NetConfigController.cs b/server/src/Controllers/NetConfigController.cs
index 5f3679f..c7a485d 100644
--- a/server/src/Controllers/NetConfigController.cs
+++ b/server/src/Controllers/NetConfigController.cs
@@ -21,8 +21,8 @@ public class NetConfigController : ControllerBase
private const int BOARD_PORT = 1234;
// 本机网络信息
- private readonly IPAddress _localIP;
- private readonly byte[] _localMAC;
+ private readonly IPAddress _localIP = IPAddress.Any;
+ private readonly byte[] _localMAC = new byte[6];
private readonly string _localIPString;
private readonly string _localMACString;
private readonly string _localInterface;
diff --git a/server/src/Hubs/DigitalTubesHub.cs b/server/src/Hubs/DigitalTubesHub.cs
new file mode 100644
index 0000000..da0c961
--- /dev/null
+++ b/server/src/Hubs/DigitalTubesHub.cs
@@ -0,0 +1,41 @@
+using Microsoft.AspNetCore.Authorization;
+using System.Security.Claims;
+using Microsoft.AspNetCore.SignalR;
+using Microsoft.AspNetCore.Cors;
+using TypedSignalR.Client;
+using Tapper;
+using server.Services;
+
+namespace server.Hubs;
+
+[Hub]
+public interface IDigitalTubesHub
+{
+ Task Join(string taskId);
+}
+
+[Receiver]
+public interface IDigitalTubesReceiver
+{
+ Task OnReceive();
+}
+
+
+[Authorize]
+[EnableCors("SignalR")]
+public class DigitalTubesHub : Hub, IDigitalTubesHub
+{
+ private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
+
+ private readonly IHubContext _hubContext;
+
+ public DigitalTubesHub(IHubContext hubContext)
+ {
+ _hubContext = hubContext;
+ }
+
+ public async Task Join(string taskId)
+ {
+ return true;
+ }
+}
diff --git a/server/src/Hubs/JtagHub.cs b/server/src/Hubs/JtagHub.cs
index 51cf78a..9acd195 100644
--- a/server/src/Hubs/JtagHub.cs
+++ b/server/src/Hubs/JtagHub.cs
@@ -69,23 +69,26 @@ public class JtagHub : Hub, IJtagHub
public async Task SetBoundaryScanFreq(int freq)
{
- try
+ return await Task.Run(() =>
{
- var userName = Context.User?.FindFirstValue(ClaimTypes.Name);
- if (userName is null)
+ try
{
- logger.Error("Can't get user info");
+ var userName = Context.User?.FindFirstValue(ClaimTypes.Name);
+ if (userName is null)
+ {
+ logger.Error("Can't get user info");
+ return false;
+ }
+
+ FreqTable.AddOrUpdate(userName, freq, (key, value) => freq);
+ return true;
+ }
+ catch (Exception error)
+ {
+ logger.Error(error);
return false;
}
-
- FreqTable.AddOrUpdate(userName, freq, (key, value) => freq);
- return true;
- }
- catch (Exception error)
- {
- logger.Error(error);
- return false;
- }
+ });
}
public async Task StartBoundaryScan(int freq = 100)
@@ -99,7 +102,7 @@ public class JtagHub : Hub, IJtagHub
return false;
}
- SetBoundaryScanFreq(freq);
+ await SetBoundaryScanFreq(freq);
var cts = new CancellationTokenSource();
CancellationTokenSourceTable.AddOrUpdate(userName, cts, (key, value) => cts);
@@ -145,23 +148,27 @@ public class JtagHub : Hub, IJtagHub
public async Task StopBoundaryScan()
{
- var userName = Context.User?.FindFirstValue(ClaimTypes.Name);
- if (userName is null)
+ return await Task.Run(() =>
{
- logger.Error("No Such User");
- return false;
- }
+ var userName = Context.User?.FindFirstValue(ClaimTypes.Name);
+ if (userName is null)
+ {
+ logger.Error("No Such User");
+ return false;
+ }
- if (!CancellationTokenSourceTable.TryGetValue(userName, out var cts))
- {
- return false;
- }
+ if (!CancellationTokenSourceTable.TryGetValue(userName, out var cts))
+ {
+ return false;
+ }
- cts.Cancel();
- cts.Token.WaitHandle.WaitOne();
+ cts.Cancel();
+ cts.Token.WaitHandle.WaitOne();
+
+ logger.Info($"Boundary scan stopped for user {userName}");
+ return true;
+ });
- logger.Info($"Boundary scan stopped for user {userName}");
- return true;
}
private async Task BoundaryScanLogicPorts(string connectionID, string userName, CancellationToken cancellationToken)
diff --git a/server/src/Hubs/ProgressHub.cs b/server/src/Hubs/ProgressHub.cs
index 4bfeaf4..068b919 100644
--- a/server/src/Hubs/ProgressHub.cs
+++ b/server/src/Hubs/ProgressHub.cs
@@ -33,10 +33,10 @@ public enum ProgressStatus
[TranspilationSource]
public class ProgressInfo
{
- public string TaskId { get; }
- public ProgressStatus Status { get; }
- public int ProgressPercent { get; }
- public string ErrorMessage { get; }
+ public virtual string TaskId { get; } = string.Empty;
+ public virtual ProgressStatus Status { get; }
+ public virtual int ProgressPercent { get; } = 0;
+ public virtual string ErrorMessage { get; } = string.Empty;
};
[Authorize]
@@ -56,6 +56,6 @@ public class ProgressHub : Hub, IProgressHub
public async Task Join(string taskId)
{
- return _tracker.BindTask(taskId, Context.ConnectionId);
+ return await Task.Run(() => _tracker.BindTask(taskId, Context.ConnectionId));
}
}
diff --git a/server/src/MsgBus.cs b/server/src/MsgBus.cs
index 6b8af28..5a93abc 100644
--- a/server/src/MsgBus.cs
+++ b/server/src/MsgBus.cs
@@ -21,7 +21,7 @@ public static class MsgBus
/// 通信总线初始化
///
/// 无
- public async static void Init()
+ public static void Init()
{
if (!ArpClient.IsAdministrator())
{
diff --git a/server/src/Peripherals/HdmiInClient.cs b/server/src/Peripherals/HdmiInClient.cs
index 493da7e..409a181 100644
--- a/server/src/Peripherals/HdmiInClient.cs
+++ b/server/src/Peripherals/HdmiInClient.cs
@@ -1,6 +1,5 @@
using System.Net;
using DotNext;
-using Peripherals.PowerClient;
using WebProtocol;
namespace Peripherals.HdmiInClient;
diff --git a/server/src/Peripherals/JtagClient.cs b/server/src/Peripherals/JtagClient.cs
index 04b5dd4..11f43fd 100644
--- a/server/src/Peripherals/JtagClient.cs
+++ b/server/src/Peripherals/JtagClient.cs
@@ -709,8 +709,10 @@ public class Jtag
/// 下载比特流到 JTAG 设备
///
/// 比特流数据
+ /// 进度报告器
/// 指示下载是否成功的异步结果
- public async ValueTask> DownloadBitstream(byte[] bitstream, ProgressReporter? progress = null)
+ public async ValueTask> DownloadBitstream(
+ byte[] bitstream, ProgressReporter? progress = null)
{
// Clear Data
MsgBus.UDPServer.ClearUDPData(this.address, 0);
diff --git a/server/src/Peripherals/SevenDigitalTubesClient.cs b/server/src/Peripherals/SevenDigitalTubesClient.cs
new file mode 100644
index 0000000..bc182ea
--- /dev/null
+++ b/server/src/Peripherals/SevenDigitalTubesClient.cs
@@ -0,0 +1,79 @@
+using System.Net;
+using DotNext;
+using Common;
+
+namespace Peripherals.SevenDigitalTubesClient;
+
+static class SevenDigitalTubesAddr
+{
+ public const UInt32 BASE = 0x0000_0000;
+}
+
+public class SevenDigitalTubesCtrl
+{
+ private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
+
+ readonly int timeout = 500;
+ readonly int taskID;
+ readonly int port;
+ readonly string address;
+ private IPEndPoint ep;
+
+ ///
+ /// 初始化七段数码管控制器
+ ///
+ /// 七段数码管控制器IP地址
+ /// 七段数码管控制器端口
+ /// 任务ID
+ /// 超时时间(毫秒)
+ public SevenDigitalTubesCtrl(string address, int port, int taskID, int timeout = 500)
+ {
+ if (timeout < 0)
+ throw new ArgumentException("Timeout couldn't be negative", nameof(timeout));
+ this.address = address;
+ this.port = port;
+ this.ep = new IPEndPoint(IPAddress.Parse(address), port);
+ this.taskID = taskID;
+ this.timeout = timeout;
+ }
+
+ public async ValueTask> ReadTube(int num)
+ {
+ if (num < 0 || num > 31)
+ throw new ArgumentOutOfRangeException(nameof(num), "Tube number must be between 0 and 31");
+
+ var ret = await UDPClientPool.ReadAddr(
+ this.ep, this.taskID, SevenDigitalTubesAddr.BASE + (UInt32)num, this.timeout);
+ if (!ret.IsSuccessful)
+ {
+ logger.Error($"Read tubes failed: {ret.Error}");
+ return new(ret.Error);
+ }
+ if (ret.Value.Options.Data == null || ret.Value.Options.Data.Length < 4)
+ return new(new Exception("Data length is too short"));
+
+ var data = Number.BytesToUInt32(ret.Value.Options.Data, 0, 4, true).Value;
+
+ if ((data >> 8) != num)
+ {
+ logger.Error($"Read wrong tube number: {num} != {data >> 8}");
+ return new(new Exception($"Read wrong tube number: {num} != {data >> 8}"));
+ }
+
+ return (byte)(data & 0xFF);
+ }
+
+ public async ValueTask> ScanTubes()
+ {
+ var tubes = new byte[32];
+ for (int i = 0; i < 32; i++)
+ {
+ var ret = await ReadTube(i);
+ if (!ret.IsSuccessful)
+ return new(ret.Error);
+ tubes[i] = ret.Value;
+ }
+ return tubes;
+ }
+
+}
diff --git a/server/src/Services/HttpHdmiVideoStreamService.cs b/server/src/Services/HttpHdmiVideoStreamService.cs
index 883137b..e5c3442 100644
--- a/server/src/Services/HttpHdmiVideoStreamService.cs
+++ b/server/src/Services/HttpHdmiVideoStreamService.cs
@@ -192,11 +192,6 @@ public class HttpHdmiVideoStreamService : BackgroundService
}
var hdmiInToken = _clientDict[boardId].CTS.Token;
- if (hdmiInToken == null)
- {
- await SendErrorAsync(context.Response, "HDMI input is not available");
- return;
- }
if (path == "/snapshot")
{
diff --git a/server/src/Services/ProgressTrackerService.cs b/server/src/Services/ProgressTrackerService.cs
index 4fecfca..420dfc8 100644
--- a/server/src/Services/ProgressTrackerService.cs
+++ b/server/src/Services/ProgressTrackerService.cs
@@ -39,12 +39,12 @@ public class ProgressReporter : ProgressInfo, IProgress
public ProgressReporter? Child { get; set; }
private ProgressStatus _status = ProgressStatus.Pending;
- private string _errorMessage;
+ private string _errorMessage = string.Empty;
- public string TaskId { get; set; } = Guid.NewGuid().ToString();
- public int ProgressPercent => _progress * 100 / MaxProgress;
- public ProgressStatus Status => _status;
- public string ErrorMessage => _errorMessage;
+ public override string TaskId { get; } = Guid.NewGuid().ToString();
+ public override int ProgressPercent => _progress * 100 / MaxProgress;
+ public override ProgressStatus Status => _status;
+ public override string ErrorMessage => _errorMessage;
public ProgressReporter(Func? reporter = null, int initProgress = 0, int maxProgress = 100, int step = 1)
{
@@ -86,7 +86,7 @@ public class ProgressReporter : ProgressInfo, IProgress
}
}
- public async void Report(int value)
+ public void Report(int value)
{
if (this._status == ProgressStatus.Pending)
this._status = ProgressStatus.InProgress;
@@ -153,7 +153,7 @@ public class ProgressTrackerService : BackgroundService
private class TaskProgressInfo
{
- public ProgressReporter Reporter { get; set; }
+ public ProgressReporter? Reporter { get; set; }
public string? ConnectionId { get; set; }
public required CancellationToken CancellationToken { get; set; }
public required CancellationTokenSource CancellationTokenSource { get; set; }
@@ -176,10 +176,15 @@ public class ProgressTrackerService : BackgroundService
{
var info = kvp.Value;
// 超过 1 分钟且任务已完成/失败/取消
- if ((now - info.UpdatedAt).TotalMinutes > 1 &&
- (info.Reporter.Status == ProgressStatus.Completed ||
- info.Reporter.Status == ProgressStatus.Failed ||
- info.Reporter.Status == ProgressStatus.Canceled))
+ if (
+ (now - info.UpdatedAt).TotalMinutes > 1 &&
+ info.Reporter != null &&
+ (
+ info.Reporter.Status == ProgressStatus.Completed ||
+ info.Reporter.Status == ProgressStatus.Failed ||
+ info.Reporter.Status == ProgressStatus.Canceled
+ )
+ )
{
_taskMap.TryRemove(kvp.Key, out _);
logger.Info($"Cleaned up task {kvp.Key}");
@@ -219,7 +224,7 @@ public class ProgressTrackerService : BackgroundService
cancellationTokenSource.Token.ThrowIfCancellationRequested();
// 通过 SignalR 推送进度
- if (progressInfo.ConnectionId != null)
+ if (progressInfo.ConnectionId != null && progressInfo.Reporter != null)
await _hubContext.Clients.Client(progressInfo.ConnectionId).OnReceiveProgress(progressInfo.Reporter);
});
@@ -243,7 +248,8 @@ public class ProgressTrackerService : BackgroundService
{
if (_taskMap.TryGetValue(taskId, out var info))
{
- return info.Reporter.Status;
+ if (info.Reporter != null)
+ return info.Reporter.Status;
}
return Optional.None;
}
@@ -265,7 +271,7 @@ public class ProgressTrackerService : BackgroundService
{
try
{
- if (_taskMap.TryGetValue(taskId, out var info) && info != null)
+ if (_taskMap.TryGetValue(taskId, out var info) && info != null && info.Reporter != null)
{
lock (info)
{
diff --git a/server/src/UdpClientPool.cs b/server/src/UdpClientPool.cs
index 665109a..16cf988 100644
--- a/server/src/UdpClientPool.cs
+++ b/server/src/UdpClientPool.cs
@@ -607,6 +607,7 @@ public class UDPClientPool
/// 设备地址
/// 要写入的32位数据
/// 超时时间(毫秒)
+ /// 进度报告器
/// 写入结果,true表示写入成功
public static async ValueTask> WriteAddr(
IPEndPoint endPoint, int taskID, UInt32 devAddr,
@@ -654,6 +655,7 @@ public class UDPClientPool
/// 设备地址
/// 要写入的字节数组
/// 超时时间(毫秒)
+ /// 进度报告器
/// 写入结果,true表示写入成功
public static async ValueTask> WriteAddr(
IPEndPoint endPoint, int taskID, UInt32 devAddr,