using System.IO.Ports; using Microsoft.Extensions.Options; using YD_TrainingCompetition_Api.Options; namespace YD_TrainingCompetition_Api.Serial; public sealed class SerialGateway : ISerialGateway { private readonly SerialPort _serialPort; public SerialGateway(IOptions options) { var cfg = options.Value; _serialPort = new SerialPort { PortName = cfg.PortName, BaudRate = cfg.BaudRate, DataBits = cfg.DataBits, StopBits = StopBits.One, Parity = Parity.None, ReadBufferSize = cfg.ReadBufferSize, WriteBufferSize = cfg.WriteBufferSize }; _serialPort.DataReceived += (_, _) => { try { var len = _serialPort.BytesToRead; if (len <= 0) { return; } var buf = new byte[len]; _serialPort.Read(buf, 0, len); DataReceived?.Invoke(this, buf); } catch { } }; } public event EventHandler? DataReceived; public bool IsOpen => _serialPort.IsOpen; public string? CurrentPort => _serialPort.IsOpen ? _serialPort.PortName : null; public string[] GetAvailablePorts() => SerialPort.GetPortNames().OrderBy(x => x, StringComparer.OrdinalIgnoreCase).ToArray(); public Task OpenAsync(string portName, CancellationToken cancellationToken = default) { if (_serialPort.IsOpen) { _serialPort.Close(); } _serialPort.PortName = portName; _serialPort.Open(); return Task.CompletedTask; } public Task CloseAsync(CancellationToken cancellationToken = default) { if (_serialPort.IsOpen) { _serialPort.Close(); } return Task.CompletedTask; } public Task SendAsync(byte[] data, CancellationToken cancellationToken = default) { if (!_serialPort.IsOpen) { throw new InvalidOperationException("Serial port is not open"); } _serialPort.Write(data, 0, data.Length); return Task.CompletedTask; } }