using System.IO.Ports; using MoniteurBaie.DataModels; using MoniteurBaie.Utils; namespace MoniteurBaie.SerialCom; public sealed class BatteryController : IBatteryController { private readonly ILogger _logger; private readonly SerialPort _serialPort; private readonly bool _closePort; private readonly List> _packetObservers = new(); private readonly BlockingListener _commandListener = new(); public BatteryController(ILogger logger, Action configure) { _logger = logger; _serialPort = new SerialPort(); configure(_serialPort); _closePort = true; } public BatteryController(ILogger logger, SerialPort serialPort, bool closePort = false) { _logger = logger; _serialPort = serialPort; _closePort = closePort; } public Task Open(CancellationToken cancellationToken) { _serialPort.Open(); var readThread = new Thread(Test) { IsBackground = true }; readThread.Start(); // var writeThread = new Thread(DoWrite) // { // IsBackground = true // }; // writeThread.Start(); return Task.CompletedTask; } public IDisposable AddSerialObserver(IObserver observer) { _packetObservers.Add(observer); return new Disposer(() => _packetObservers.Remove(observer)); } public Task SendCommand(string command, CancellationToken cancellationToken) { _commandListener.Push(command); return Task.CompletedTask; } private void Test() { try { while (_serialPort.IsOpen) { var b = _serialPort.ReadByte(); Console.WriteLine(b); } } catch (ObjectDisposedException ex) { _logger.LogError(ex, "The serial connection has been disposed."); } catch (Exception ex) { _logger.LogError(ex, "An exception occurred in the serial read loop."); throw; } } private void DoRead() { try { while (_serialPort.IsOpen) { string line; try { line = _serialPort.ReadLine(); } catch (Exception ex) { _logger.LogError(ex, "Failed to read line from serial connection."); continue; } if (string.IsNullOrEmpty(line)) { continue; } var packet = new BatteryControllerPacket(line); foreach (var observer in _packetObservers) { try { observer.OnNext(packet); } catch (Exception ex) { _logger.LogError(ex, "An exception occurred in a packet handler."); } } } } catch (ObjectDisposedException ex) { _logger.LogError(ex, "The serial connection has been disposed."); } catch (Exception ex) { _logger.LogError(ex, "An exception occurred in the serial read loop."); throw; } } private void DoWrite() { try { while (_serialPort.IsOpen) { var line = _commandListener.Next(); if (string.IsNullOrEmpty(line)) { continue; } try { _serialPort.Write(line + "\n"); } catch (Exception ex) { _logger.LogError(ex, "Failed to send command."); } } } catch (ObjectDisposedException ex) { _logger.LogError(ex, "The serial connection has been disposed."); } catch (Exception ex) { _logger.LogError(ex, "An exception occurred in the serial write loop."); throw; } } #region IObservable IDisposable IObservable.Subscribe(IObserver observer) { return AddSerialObserver(observer); } #endregion #region IObserver void IObserver.OnCompleted() { } void IObserver.OnError(Exception error) { } void IObserver.OnNext(string value) { SendCommand(value, default); } #endregion #region IDisposable private bool disposedValue; private void Dispose(bool disposing) { if (!disposedValue) { if (disposing) { if (_closePort) { _serialPort.Close(); } } disposedValue = true; } } public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } #endregion }