using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using leak_test_project.Models; using leak_test_project.Utils; namespace leak_test_project.Infrastructure { /// /// 실제 ADLINK 하드웨어와 통신하는 DIO 보드 구현체. /// Dask.cs 래퍼를 사용하여 PCIS-DASK API를 호출합니다. /// public class RealDioBoard : IDioBoard { private short _cardNumber = -1; private readonly Dictionary _inputs = new Dictionary(); private readonly Dictionary _outputs = new Dictionary(); private bool _disposed = false; private CancellationTokenSource _pollingCts; private Task _pollingTask; public event EventHandler InputChanged; public bool Initialize() { var config = DioConfigParser.LoadDefault(); if (config != null) { foreach (var p in config.InputPoints) _inputs[p.Name] = p; foreach (var p in config.OutputPoints) _outputs[p.Name] = p; ushort cardType = GetCardTypeFromConfig(config.BoardType); ushort boardNumber = (ushort)config.BoardNumber; try { short ret = DASK.Register_Card(cardType, boardNumber); if (ret < 0) { Console.WriteLine($"[RealDioBoard] Error registering ADLINK Card {config.BoardType}. Error code: {ret}"); return false; } _cardNumber = ret; Console.WriteLine($"[RealDioBoard] Registered ADLINK Card {config.BoardType} (Handle: {_cardNumber})"); } catch (Exception ex) { Console.WriteLine($"[RealDioBoard] Critical error during HW Registration: {ex.Message}"); // 드라이버가 없거나 하드웨어 접근 오류 시 앱이 죽지 않도록 false 반환 return false; } } else { Console.WriteLine("[RealDioBoard] No INI config found."); return false; } // Start background polling task for inputs _pollingCts = new CancellationTokenSource(); _pollingTask = Task.Run(() => InputPollingLoop(_pollingCts.Token)); return true; } private ushort GetCardTypeFromConfig(string boardType) { switch (boardType.ToUpper()) { case "PCI_7230": return DASK.PCI_7230; case "PCI_7432": return DASK.PCI_7432; case "PCI_7433": return DASK.PCI_7433; case "PCI_7434": return DASK.PCI_7434; case "PCI_7250": return DASK.PCI_7250; // Add more if needed. Default to 7432 default: Console.WriteLine($"[RealDioBoard] Unknown BoardType {boardType}. Defaulting to PCI_7432."); return DASK.PCI_7432; } } public bool ReadInput(string pointName) { if (_cardNumber < 0) return false; if (_inputs.TryGetValue(pointName, out var point)) { // Find port and line mathematically (Wait, actually we should use DIO port mapping) // Assuming simple 1-to-1 mapping where index == line in Port 0. int index = new List(_inputs.Values).IndexOf(point); if (index >= 0) { ushort port = 0; // Usually port 0 for first 32 lines. uint readValue; short ret = DASK.DI_ReadPort((ushort)_cardNumber, port, out readValue); if (ret >= 0) { bool isOn = (readValue & (1U << index)) != 0; point.Value = isOn; return isOn; } } } return false; } public void WriteOutput(string pointName, bool value) { if (_cardNumber < 0) return; if (_outputs.TryGetValue(pointName, out var point)) { int index = new List(_outputs.Values).IndexOf(point); if (index >= 0) { point.Value = value; ushort port = 0; // Actually, to safely write a single bit without affecting others: uint outValue; DASK.DO_ReadPort((ushort)_cardNumber, port, out outValue); if (value) { outValue |= (1U << index); } else { outValue &= ~(1U << index); } DASK.DO_WritePort((ushort)_cardNumber, port, outValue); Console.WriteLine($"[RealDioBoard] Set {pointName} (Line {index}) to {(value ? "ON" : "OFF")}"); } } } private async Task InputPollingLoop(CancellationToken token) { try { while (!token.IsCancellationRequested) { if (_cardNumber >= 0) { ushort port = 0; uint readValue; short ret = DASK.DI_ReadPort((ushort)_cardNumber, port, out readValue); if (ret >= 0) { var inputPoints = new List(_inputs.Values); for (int i = 0; i < inputPoints.Count; i++) { var point = inputPoints[i]; bool isCurrentlyOn = (readValue & (1U << i)) != 0; // If changed from OFF to ON if (isCurrentlyOn && !point.Value) { point.Value = true; Console.WriteLine($"[RealDioBoard] Input {point.Name} triggered (OFF→ON)"); InputChanged?.Invoke(this, new DioEventArgs(point.Name, true)); } else if (!isCurrentlyOn && point.Value) { point.Value = false; } } } } // 10ms polling rate (approx) await Task.Delay(10, token); } } catch (TaskCanceledException) { // Expected when disposing } catch (Exception ex) { Console.WriteLine($"[RealDioBoard] Polling error: {ex.Message}"); } } public List GetInputPoints() { return new List(_inputs.Values); } public List GetOutputPoints() { return new List(_outputs.Values); } public void Dispose() { if (!_disposed) { _disposed = true; if (_pollingCts != null) { _pollingCts.Cancel(); _pollingCts.Dispose(); } if (_cardNumber >= 0) { DASK.Release_Card((ushort)_cardNumber); Console.WriteLine("[RealDioBoard] Released ADLINK Card."); _cardNumber = -1; } } } } }