206 lines
5.4 KiB
C#
206 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(
|
|
key: this.COMPort,
|
|
addValue: sp,
|
|
updateValueFactory: (_1, _2) => sp);
|
|
}
|
|
|
|
public event Action Connected;
|
|
public event Action Disconnected;
|
|
public event Action<string> Log;
|
|
|
|
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(3000);
|
|
this.closeAwaiter.Reset();
|
|
|
|
sp.DataReceived -= this.SP_DataReceived;
|
|
sp.Disposed -= this.SP_Disposed;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
this.Log?.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.Log?.Invoke(e.ToString());
|
|
}
|
|
}
|
|
}
|
|
|
|
public IEnumerable<byte[]> ReadBytes()
|
|
{
|
|
var sp = this.GetOpenSP();
|
|
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.Log?.Invoke(e.ToString());
|
|
}
|
|
|
|
this.readAwaiter.Reset();
|
|
|
|
yield return buffer;
|
|
}
|
|
}
|
|
}
|
|
|
|
public IEnumerable<string> ReadLines()
|
|
{
|
|
var sp = this.GetOpenSP();
|
|
var text = default(string);
|
|
|
|
using (sp)
|
|
{
|
|
while (sp.IsOpen)
|
|
{
|
|
this.readAwaiter.Wait();
|
|
|
|
try
|
|
{
|
|
text = sp.ReadLine();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
this.Log?.Invoke(e.ToString());
|
|
}
|
|
|
|
this.readAwaiter.Reset();
|
|
|
|
yield return text;
|
|
}
|
|
}
|
|
}
|
|
public void Remove()
|
|
{
|
|
this.Close();
|
|
|
|
serialPorts.TryRemove(this.COMPort, out var _);
|
|
}
|
|
|
|
public void Write(byte[] bytes)
|
|
{
|
|
var sp = this.GetOpenSP();
|
|
|
|
try
|
|
{
|
|
sp.Write(bytes, 0, bytes.Length);
|
|
|
|
this.Log?.Invoke(BitConverter.ToString(bytes));
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
this.Log?.Invoke(e.ToString());
|
|
}
|
|
}
|
|
|
|
public void Write(string text)
|
|
{
|
|
var sp = this.GetOpenSP();
|
|
|
|
try
|
|
{
|
|
sp.Write(text);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
this.Log?.Invoke(e.ToString());
|
|
}
|
|
}
|
|
|
|
private SysSerialPort GetOpenSP()
|
|
{
|
|
if (!serialPorts.TryGetValue(this.COMPort, out var sp))
|
|
{
|
|
throw new InvalidOperationException($"{nameof(SerialPort)} on {this.COMPort} dose not exists!");
|
|
}
|
|
|
|
if (!sp.IsOpen)
|
|
{
|
|
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();
|
|
}
|
|
}
|