208 lines
5.4 KiB
C#
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();
|
|
}
|
|
}
|