222 lines
5.2 KiB
C#
222 lines
5.2 KiB
C#
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<IObserver<BatteryControllerPacket>> _packetObservers = new();
|
|
private readonly BlockingListener<string> _commandListener = new();
|
|
|
|
public BatteryController(ILogger logger, Action<SerialPort> 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<BatteryControllerPacket> 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<BatteryControllerPacket>.Subscribe(IObserver<BatteryControllerPacket> observer)
|
|
{
|
|
return AddSerialObserver(observer);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IObserver
|
|
|
|
void IObserver<string>.OnCompleted()
|
|
{
|
|
|
|
}
|
|
|
|
void IObserver<string>.OnError(Exception error)
|
|
{
|
|
|
|
}
|
|
|
|
void IObserver<string>.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
|
|
}
|