laatzen/Common/Hardware/Common.Hardware.Ports/SerialPort.cs
2025-01-28 14:39:42 +01:00

208 lines
5.4 KiB
C#

namespace Common.Hardware.Ports
{
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO.Ports;
using System.Threading;
using SysSerialPort = System.IO.Ports.SerialPort;
public sealed class SerialPort
{
private static readonly ConcurrentDictionary<string, SysSerialPort> serialPorts
= new ConcurrentDictionary<string, SysSerialPort>();
private readonly ManualResetEventSlim readAwaiter;
private readonly ManualResetEventSlim closeAwaiter;
public SerialPort(string name, int baudRate, Parity parity, int dataBits, StopBits stopBits)
{
this.COMPort = name;
this.readAwaiter = new ManualResetEventSlim();
this.closeAwaiter = new ManualResetEventSlim();
var sp = new SysSerialPort(this.COMPort, baudRate, parity, dataBits, stopBits);
serialPorts.AddOrUpdate(this.COMPort, sp, (key, value) =>
{
value?.Close();
return sp;
});
}
public event Action Connected;
public event Action Disconnected;
public event Action<string> Logging;
public string COMPort { get; }
public bool IsOpen => serialPorts.TryGetValue(this.COMPort, out var sp) && sp.IsOpen;
public void Close()
{
if (serialPorts.TryGetValue(this.COMPort, out var sp))
{
try
{
sp.Close();
this.closeAwaiter.Wait(5000);
this.closeAwaiter.Reset();
sp.DataReceived -= this.SP_DataReceived;
sp.Disposed -= this.SP_Disposed;
}
catch (Exception e)
{
this.Logging?.Invoke(e.ToString());
}
}
}
public void Open()
{
if (serialPorts.TryGetValue(this.COMPort, out var sp) && !sp.IsOpen)
{
try
{
sp.DataReceived += this.SP_DataReceived;
sp.Disposed += this.SP_Disposed;
sp.Open();
this.Connected?.Invoke();
}
catch (Exception e)
{
this.Logging?.Invoke(e.ToString());
}
}
}
public IEnumerable<byte[]> ReadBytes()
{
var sp = this.GetOpenedSP();
var size = sp.ReadBufferSize;
var buffer = new byte[size];
var length = 0;
using (sp)
{
while (sp.IsOpen)
{
this.readAwaiter.Wait();
try
{
buffer = new byte[size];
length = sp.Read(buffer, 0, size);
Array.Resize(ref buffer, length);
}
catch (Exception e)
{
this.Logging?.Invoke(e.ToString());
}
this.readAwaiter.Reset();
yield return buffer;
}
sp.Close();
}
}
public IEnumerable<string> ReadLines()
{
var sp = this.GetOpenedSP();
var text = default(string);
using (sp)
{
while (sp.IsOpen)
{
this.readAwaiter.Wait();
try
{
text = sp.ReadLine();
}
catch (Exception e)
{
this.Logging?.Invoke(e.ToString());
}
this.readAwaiter.Reset();
yield return text;
}
}
}
public void Remove()
{
if (serialPorts.TryRemove(this.COMPort, out var sp))
{
sp.Close();
}
}
public void Write(byte[] bytes)
{
var sp = this.GetOpenedSP();
try
{
sp.Write(bytes, 0, bytes.Length);
}
catch (Exception e)
{
this.Logging?.Invoke(e.ToString());
}
}
public void Write(string text)
{
var sp = this.GetOpenedSP();
try
{
sp.Write(text);
}
catch (Exception e)
{
this.Logging?.Invoke(e.ToString());
}
}
private SysSerialPort GetOpenedSP()
{
if (!serialPorts.TryGetValue(this.COMPort, out var sp))
{
throw new InvalidOperationException($"{nameof(SerialPort)} on {this.COMPort} dose not exists!");
}
if (!sp.IsOpen)
{
this.Close();
this.Open();
}
return sp;
}
private void SP_DataReceived(object _, SerialDataReceivedEventArgs args)
=> this.readAwaiter.Set();
private void SP_Disposed(object _, EventArgs _1)
{
this.closeAwaiter.Set();
this.Disconnected?.Invoke();
}
public static string[] GetPortNames()
=> SysSerialPort.GetPortNames();
}
}