using Microsoft.AspNetCore.Authorization; using System.Security.Claims; using Microsoft.AspNetCore.SignalR; using Microsoft.AspNetCore.Cors; using TypedSignalR.Client; using DotNext; using Tapper; using System.Collections.Concurrent; using Peripherals.OscilloscopeClient; #pragma warning disable 1998 namespace server.Hubs; [Hub] public interface IOscilloscopeHub { Task Initialize(OscilloscopeFullConfig config); Task StartCapture(); Task StopCapture(); Task GetData(); Task SetTrigger(byte level); Task SetRisingEdge(bool risingEdge); Task SetSampling(ushort decimationRate); Task SetFrequency(int frequency); } [Receiver] public interface IOscilloscopeReceiver { Task OnDataReceived(OscilloscopeDataResponse data); } [TranspilationSource] public class OscilloscopeDataResponse { public uint AdFrequency { get; set; } public byte AdVpp { get; set; } public byte AdMax { get; set; } public byte AdMin { get; set; } public string WaveformData { get; set; } = ""; } [TranspilationSource] public class OscilloscopeFullConfig { public bool CaptureEnabled { get; set; } public byte TriggerLevel { get; set; } public bool TriggerRisingEdge { get; set; } public ushort HorizontalShift { get; set; } public ushort DecimationRate { get; set; } public int CaptureFrequency { get; set; } // public bool AutoRefreshRAM { get; set; } public OscilloscopeConfig ToOscilloscopeConfig() { return new OscilloscopeConfig { CaptureEnabled = CaptureEnabled, TriggerLevel = TriggerLevel, TriggerRisingEdge = TriggerRisingEdge, HorizontalShift = HorizontalShift, DecimationRate = DecimationRate, }; } } class OscilloscopeScanTaskInfo { public Task? ScanTask { get; set; } public OscilloscopeCtrl Client { get; set; } public CancellationTokenSource CTS { get; set; } = new CancellationTokenSource(); public int Frequency { get; set; } = 100; public OscilloscopeScanTaskInfo(OscilloscopeCtrl client) { Client = client; } } [Authorize] [EnableCors("SignalR")] public class OscilloscopeHub : Hub, IOscilloscopeHub { private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); private readonly IHubContext _hubContext; private readonly Database.UserManager _userManager = new(); private static ConcurrentDictionary _scanTasks = new(); public OscilloscopeHub(IHubContext hubContext) { _hubContext = hubContext; } private Optional TryGetBoard() { var userName = Context.User?.FindFirstValue(ClaimTypes.Name); if (string.IsNullOrEmpty(userName)) { logger.Error("User name is null or empty"); return null; } var boardRet = _userManager.GetBoardByUserName(userName); if (!boardRet.IsSuccessful || !boardRet.Value.HasValue) { logger.Error($"Board not found"); return null; } return boardRet.Value.Value; } private Optional GetOscilloscope() { try { var board = TryGetBoard().OrThrow(() => new Exception("Board not found")); var client = new OscilloscopeCtrl(board.IpAddr, board.Port); return client; } catch (Exception ex) { logger.Error(ex, "Failed to get oscilloscope"); return null; } } public async Task Initialize(OscilloscopeFullConfig config) { try { var client = GetOscilloscope().OrThrow(() => new Exception("Oscilloscope not found")); var result = await client.Init(config.ToOscilloscopeConfig()); if (!result.IsSuccessful) { logger.Error(result.Error, "Initialize failed"); return false; } return result.Value; } catch (Exception ex) { logger.Error(ex, "Failed to initialize oscilloscope"); return false; } } private Task ScanTask(OscilloscopeScanTaskInfo taskInfo, string clientId) { var token = taskInfo.CTS.Token; return Task.Run(async () => { while (!token.IsCancellationRequested) { var data = await GetCaptureData(taskInfo.Client); if (data == null) { logger.Error("GetData failed"); continue; } await _hubContext.Clients.Client(clientId).OnDataReceived(data); await Task.Delay(1000 / taskInfo.Frequency, token); } }, token).ContinueWith(t => { if (t.IsFaulted) logger.Error(t.Exception, "ScanTask failed"); }); } public async Task StartCapture() { try { var board = TryGetBoard().OrThrow(() => new Exception("Board not found")); var key = board.ID.ToString(); var client = GetOscilloscope().OrThrow(() => new Exception("Oscilloscope not found")); if (_scanTasks.TryGetValue(key, out var existing)) return true; var result = await client.SetCaptureEnable(true); if (!result.IsSuccessful) { logger.Error(result.Error, "StartCapture failed"); return false; } var scanTaskInfo = new OscilloscopeScanTaskInfo(client); scanTaskInfo.ScanTask = ScanTask(scanTaskInfo, Context.ConnectionId); return _scanTasks.TryAdd(key, scanTaskInfo); } catch (Exception ex) { logger.Error(ex, "Failed to start capture"); return false; } } public async Task StopCapture() { try { var board = TryGetBoard().OrThrow(() => new Exception("Board not found")); var client = GetOscilloscope().OrThrow(() => new Exception("Oscilloscope not found")); var key = board.ID.ToString(); if (_scanTasks.TryRemove(key, out var taskInfo)) { taskInfo.CTS.Cancel(); if (taskInfo.ScanTask != null) taskInfo.ScanTask.Wait(); var result = await client.SetCaptureEnable(false); if (!result.IsSuccessful) { logger.Error(result.Error, "StopCapture failed"); return false; } return result.Value; } throw new Exception("Task not found"); } catch (Exception ex) { logger.Error(ex, "Failed to stop capture"); return false; } } private async Task GetCaptureData(OscilloscopeCtrl oscilloscope) { try { var freqResult = await oscilloscope.GetADFrequency(); var vppResult = await oscilloscope.GetADVpp(); var maxResult = await oscilloscope.GetADMax(); var minResult = await oscilloscope.GetADMin(); var waveformResult = await oscilloscope.GetWaveformData(); if (!freqResult.IsSuccessful) { logger.Error($"获取AD采样频率失败: {freqResult.Error}"); throw new Exception($"获取AD采样频率失败: {freqResult.Error}"); } if (!vppResult.IsSuccessful) { logger.Error($"获取AD采样幅度失败: {vppResult.Error}"); throw new Exception($"获取AD采样幅度失败: {vppResult.Error}"); } if (!maxResult.IsSuccessful) { logger.Error($"获取AD采样最大值失败: {maxResult.Error}"); throw new Exception($"获取AD采样最大值失败: {maxResult.Error}"); } if (!minResult.IsSuccessful) { logger.Error($"获取AD采样最小值失败: {minResult.Error}"); throw new Exception($"获取AD采样最小值失败: {minResult.Error}"); } if (!waveformResult.IsSuccessful) { logger.Error($"获取波形数据失败: {waveformResult.Error}"); throw new Exception($"获取波形数据失败: {waveformResult.Error}"); } var response = new OscilloscopeDataResponse { AdFrequency = freqResult.Value, AdVpp = vppResult.Value, AdMax = maxResult.Value, AdMin = minResult.Value, WaveformData = Convert.ToBase64String(waveformResult.Value) }; return new OscilloscopeDataResponse { AdFrequency = freqResult.Value, AdVpp = vppResult.Value, AdMax = maxResult.Value, AdMin = minResult.Value, WaveformData = Convert.ToBase64String(waveformResult.Value) }; } catch (Exception ex) { logger.Error(ex, "获取示波器数据时发生异常"); return null; } } public async Task GetData() { try { var oscilloscope = GetOscilloscope().OrThrow(() => new Exception("Oscilloscope not found")); var response = await GetCaptureData(oscilloscope); return response; } catch (Exception ex) { logger.Error(ex, "获取示波器数据时发生异常"); return null; } } public async Task SetTrigger(byte level) { try { var client = GetOscilloscope().OrThrow(() => new Exception("Oscilloscope not found")); var ret = await client.SetTriggerLevel(level); if (!ret.IsSuccessful) { logger.Error(ret.Error, "UpdateTrigger failed"); return false; } return ret.Value; } catch (Exception ex) { logger.Error(ex, "Failed to update trigger"); return false; } } public async Task SetRisingEdge(bool risingEdge) { try { var client = GetOscilloscope().OrThrow(() => new Exception("Oscilloscope not found")); var ret = await client.SetTriggerEdge(risingEdge); if (!ret.IsSuccessful) { logger.Error(ret.Error, "Update Rising Edge failed"); return false; } return ret.Value; } catch (Exception ex) { logger.Error(ex, "SetRisingEdge failed"); return false; } } public async Task SetSampling(ushort decimationRate) { try { var client = GetOscilloscope().OrThrow(() => new Exception("Oscilloscope not found")); var result = await client.SetDecimationRate(decimationRate); if (!result.IsSuccessful) { logger.Error(result.Error, "UpdateSampling failed"); return false; } return result.Value; } catch (Exception ex) { logger.Error(ex, "Failed to update sampling"); return false; } } public async Task SetFrequency(int frequency) { try { if (frequency < 1 || frequency > 1000) return false; var board = TryGetBoard().OrThrow(() => new Exception("Board not found")); var key = board.ID.ToString(); if (_scanTasks.TryGetValue(key, out var scanInfo)) { scanInfo.Frequency = frequency; return true; } else { logger.Warn($"SetFrequency called but no running scan for board {board.ID} and client {Context.ConnectionId}"); return false; } } catch (Exception ex) { logger.Error(ex, "Failed to set frequency"); return false; } } }