diff --git a/Nefarius.Peripherals.SerialPort/NativeMethods.txt b/Nefarius.Peripherals.SerialPort/NativeMethods.txt
index e754077..aa60595 100644
--- a/Nefarius.Peripherals.SerialPort/NativeMethods.txt
+++ b/Nefarius.Peripherals.SerialPort/NativeMethods.txt
@@ -1,4 +1,5 @@
CreateFile
+FILE_ACCESS_RIGHTS
GetHandleInformation
SetCommState
SetCommTimeouts
diff --git a/Nefarius.Peripherals.SerialPort/Nefarius.Peripherals.SerialPort.csproj b/Nefarius.Peripherals.SerialPort/Nefarius.Peripherals.SerialPort.csproj
index db2f479..0a6e29e 100644
--- a/Nefarius.Peripherals.SerialPort/Nefarius.Peripherals.SerialPort.csproj
+++ b/Nefarius.Peripherals.SerialPort/Nefarius.Peripherals.SerialPort.csproj
@@ -34,5 +34,6 @@
all
+
\ No newline at end of file
diff --git a/Nefarius.Peripherals.SerialPort/SerialPort.cs b/Nefarius.Peripherals.SerialPort/SerialPort.cs
index 04f018f..fbe1613 100644
--- a/Nefarius.Peripherals.SerialPort/SerialPort.cs
+++ b/Nefarius.Peripherals.SerialPort/SerialPort.cs
@@ -1,12 +1,16 @@
using System;
+using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
+
using Windows.Win32;
using Windows.Win32.Devices.Communication;
using Windows.Win32.Foundation;
using Windows.Win32.Storage.FileSystem;
+
using Microsoft.Win32.SafeHandles;
+
using Nefarius.Peripherals.SerialPort.Win32PInvoke;
namespace Nefarius.Peripherals.SerialPort;
@@ -14,6 +18,7 @@ namespace Nefarius.Peripherals.SerialPort;
///
/// Wrapper class around a serial (COM, RS-232) port.
///
+[SuppressMessage("ReSharper", "UnusedMember.Global")]
public partial class SerialPort : IDisposable
{
private readonly ManualResetEvent _writeEvent = new(false);
@@ -64,18 +69,25 @@ public partial class SerialPort : IDisposable
/// false if the port could not be opened
public bool Open()
{
- var portDcb = new DCB();
- var commTimeouts = new COMMTIMEOUTS();
+ DCB portDcb = new();
+ COMMTIMEOUTS commTimeouts = new();
- if (_online) return false;
+ if (_online)
+ {
+ return false;
+ }
_hPort = PInvoke.CreateFile(PortName,
- FILE_ACCESS_FLAGS.FILE_GENERIC_READ | FILE_ACCESS_FLAGS.FILE_GENERIC_WRITE, 0,
+ (uint)(FILE_ACCESS_RIGHTS.FILE_GENERIC_READ | FILE_ACCESS_RIGHTS.FILE_GENERIC_WRITE), 0,
null, FILE_CREATION_DISPOSITION.OPEN_EXISTING, FILE_FLAGS_AND_ATTRIBUTES.FILE_FLAG_OVERLAPPED, null);
if (_hPort.IsInvalid)
{
- if (Marshal.GetLastWin32Error() == (int)WIN32_ERROR.ERROR_ACCESS_DENIED) return false;
+ if (Marshal.GetLastWin32Error() == (int)WIN32_ERROR.ERROR_ACCESS_DENIED)
+ {
+ return false;
+ }
+
throw new CommPortException("Port Open Failure");
}
@@ -92,20 +104,28 @@ public partial class SerialPort : IDisposable
portDcb.ByteSize = (byte)DataBits;
portDcb.Parity = (DCB_PARITY)Parity;
portDcb.StopBits = (DCB_STOP_BITS)StopBits;
- portDcb.XoffChar = (CHAR)(byte)XoffChar;
- portDcb.XonChar = (CHAR)(byte)XonChar;
+ portDcb.XoffChar = new CHAR((sbyte)XoffChar);
+ portDcb.XonChar = new CHAR((sbyte)XonChar);
portDcb.XoffLim = (ushort)RxHighWater;
portDcb.XonLim = (ushort)RxLowWater;
if (RxQueue != 0 || TxQueue != 0)
+ {
if (!PInvoke.SetupComm(_hPort, (uint)RxQueue, (uint)TxQueue))
+ {
ThrowException("Bad queue settings");
+ }
+ }
if (!PInvoke.SetCommState(_hPort, portDcb))
+ {
ThrowException("Bad com settings");
+ }
if (!PInvoke.SetCommTimeouts(_hPort, commTimeouts))
+ {
ThrowException("Bad timeout settings");
+ }
_stateBrk = 0;
switch (UseDtr)
@@ -135,12 +155,9 @@ public partial class SerialPort : IDisposable
_rxException = null;
_rxExceptionReported = false;
- // TODO: utilize Task Parallel Library here
_rxThread = new Thread(ReceiveThread)
{
- Name = "CommBaseRx",
- Priority = ThreadPriority.AboveNormal,
- IsBackground = true
+ Name = "CommBaseRx", Priority = ThreadPriority.AboveNormal, IsBackground = true
};
_rxThread.Start();
@@ -211,14 +228,22 @@ public partial class SerialPort : IDisposable
/// Description of fault
protected void ThrowException(string reason)
{
- if (Thread.CurrentThread == _rxThread) throw new CommPortException(reason);
+ if (Thread.CurrentThread == _rxThread)
+ {
+ throw new CommPortException(reason);
+ }
+
if (_online)
{
BeforeClose(true);
InternalClose();
}
- if (_rxException == null) throw new CommPortException(reason);
+ if (_rxException == null)
+ {
+ throw new CommPortException(reason);
+ }
+
throw new CommPortException(_rxException);
}
@@ -228,7 +253,6 @@ public partial class SerialPort : IDisposable
/// Array of bytes to be sent
public unsafe void Write(byte[] toSend)
{
- uint sent;
CheckOnline();
CheckResult();
_writeCount = toSend.GetLength(0);
@@ -236,6 +260,7 @@ public partial class SerialPort : IDisposable
fixed (byte* ptr = toSend)
fixed (NativeOverlapped* ptrOl = &_ptrUwo)
{
+ uint sent;
if (PInvoke.WriteFile(_hPort, ptr, (uint)_writeCount, &sent, ptrOl))
{
_writeCount -= (int)sent;
@@ -243,7 +268,9 @@ public partial class SerialPort : IDisposable
else
{
if (Marshal.GetLastWin32Error() != (int)WIN32_ERROR.ERROR_IO_PENDING)
+ {
ThrowException("Unexpected failure");
+ }
}
}
}
@@ -263,7 +290,7 @@ public partial class SerialPort : IDisposable
/// Byte to be sent
public void Write(byte toSend)
{
- var b = new byte[1];
+ byte[] b = new byte[1];
b[0] = toSend;
Write(b);
}
@@ -288,15 +315,25 @@ public partial class SerialPort : IDisposable
private void CheckResult()
{
- if (_writeCount <= 0) return;
- if (PInvoke.GetOverlappedResult(_hPort, _ptrUwo, out var sent, _checkSends))
+ if (_writeCount <= 0)
+ {
+ return;
+ }
+
+ if (PInvoke.GetOverlappedResult(_hPort, _ptrUwo, out uint sent, _checkSends))
{
_writeCount -= (int)sent;
- if (_writeCount != 0) ThrowException("Send Timeout");
+ if (_writeCount != 0)
+ {
+ ThrowException("Send Timeout");
+ }
}
else
{
- if (Marshal.GetLastWin32Error() != (int)WIN32_ERROR.ERROR_IO_PENDING) ThrowException("Unexpected failure");
+ if (Marshal.GetLastWin32Error() != (int)WIN32_ERROR.ERROR_IO_PENDING)
+ {
+ ThrowException("Unexpected failure");
+ }
}
}
@@ -308,7 +345,10 @@ public partial class SerialPort : IDisposable
public void SendImmediate(byte tosend)
{
CheckOnline();
- if (!Win32Com.TransmitCommChar(_hPort.DangerousGetHandle(), tosend)) ThrowException("Transmission failure");
+ if (!Win32Com.TransmitCommChar(_hPort.DangerousGetHandle(), tosend))
+ {
+ ThrowException("Transmission failure");
+ }
}
///
@@ -318,7 +358,11 @@ public partial class SerialPort : IDisposable
protected ModemStatus GetModemStatus()
{
CheckOnline();
- if (!Win32Com.GetCommModemStatus(_hPort.DangerousGetHandle(), out var f)) ThrowException("Unexpected failure");
+ if (!Win32Com.GetCommModemStatus(_hPort.DangerousGetHandle(), out uint f))
+ {
+ ThrowException("Unexpected failure");
+ }
+
return new ModemStatus((MODEM_STATUS_FLAGS)f);
}
@@ -329,15 +373,19 @@ public partial class SerialPort : IDisposable
protected unsafe QueueStatus GetQueueStatus()
{
COMSTAT cs;
- var cp = new COMMPROP();
+ COMMPROP cp = new();
CLEAR_COMM_ERROR_FLAGS er;
CheckOnline();
if (!PInvoke.ClearCommError(_hPort, &er, &cs))
+ {
ThrowException("Unexpected failure");
+ }
- if (!PInvoke.GetCommProperties(_hPort, ref cp))
+ if (!PInvoke.GetCommProperties(_hPort, &cp))
+ {
ThrowException("Unexpected failure");
+ }
return new QueueStatus(cs._bitfield, cs.cbInQue, cs.cbOutQue, cp.dwCurrentRxQueue, cp.dwCurrentTxQueue);
}
@@ -412,13 +460,10 @@ public partial class SerialPort : IDisposable
private unsafe void ReceiveThread()
{
- var buf = stackalloc byte[1];
+ byte* buf = stackalloc byte[1];
- var sg = new AutoResetEvent(false);
- var ov = new NativeOverlapped
- {
- EventHandle = sg.SafeWaitHandle.DangerousGetHandle()
- };
+ AutoResetEvent sg = new(false);
+ NativeOverlapped ov = new() { EventHandle = sg.SafeWaitHandle.DangerousGetHandle() };
COMM_EVENT_MASK eventMask = 0;
@@ -431,14 +476,20 @@ public partial class SerialPort : IDisposable
COMM_EVENT_MASK.EV_DSR
| COMM_EVENT_MASK.EV_BREAK | COMM_EVENT_MASK.EV_RLSD | COMM_EVENT_MASK.EV_RING |
COMM_EVENT_MASK.EV_ERR))
+ {
throw new CommPortException("IO Error [001]");
+ }
if (!PInvoke.WaitCommEvent(_hPort, ref eventMask, &ov))
{
if (Marshal.GetLastWin32Error() == (int)WIN32_ERROR.ERROR_IO_PENDING)
+ {
sg.WaitOne();
+ }
else
+ {
throw new CommPortException("IO Error [002]");
+ }
}
if ((eventMask & COMM_EVENT_MASK.EV_ERR) != 0)
@@ -446,13 +497,37 @@ public partial class SerialPort : IDisposable
CLEAR_COMM_ERROR_FLAGS errs;
if (PInvoke.ClearCommError(_hPort, &errs, null))
{
- var s = new StringBuilder("UART Error: ", 40);
- if (((uint)errs & Win32Com.CE_FRAME) != 0) s = s.Append("Framing,");
- if (((uint)errs & Win32Com.CE_IOE) != 0) s = s.Append("IO,");
- if (((uint)errs & Win32Com.CE_OVERRUN) != 0) s = s.Append("Overrun,");
- if (((uint)errs & Win32Com.CE_RXOVER) != 0) s = s.Append("Receive Overflow,");
- if (((uint)errs & Win32Com.CE_RXPARITY) != 0) s = s.Append("Parity,");
- if (((uint)errs & Win32Com.CE_TXFULL) != 0) s = s.Append("Transmit Overflow,");
+ StringBuilder s = new("UART Error: ", 40);
+ if (((uint)errs & Win32Com.CE_FRAME) != 0)
+ {
+ s = s.Append("Framing,");
+ }
+
+ if (((uint)errs & Win32Com.CE_IOE) != 0)
+ {
+ s = s.Append("IO,");
+ }
+
+ if (((uint)errs & Win32Com.CE_OVERRUN) != 0)
+ {
+ s = s.Append("Overrun,");
+ }
+
+ if (((uint)errs & Win32Com.CE_RXOVER) != 0)
+ {
+ s = s.Append("Receive Overflow,");
+ }
+
+ if (((uint)errs & Win32Com.CE_RXPARITY) != 0)
+ {
+ s = s.Append("Parity,");
+ }
+
+ if (((uint)errs & Win32Com.CE_TXFULL) != 0)
+ {
+ s = s.Append("Transmit Overflow,");
+ }
+
s.Length -= 1;
throw new CommPortException(s.ToString());
}
@@ -462,15 +537,15 @@ public partial class SerialPort : IDisposable
if ((eventMask & COMM_EVENT_MASK.EV_RXCHAR) != 0)
{
- uint gotbytes;
+ uint gotBytes;
do
{
- if (!PInvoke.ReadFile(_hPort, buf, 1, &gotbytes, &ov))
+ if (!PInvoke.ReadFile(_hPort, buf, 1, &gotBytes, &ov))
{
if (Marshal.GetLastWin32Error() == (int)WIN32_ERROR.ERROR_IO_PENDING)
{
Win32Com.CancelIo(_hPort.DangerousGetHandle());
- gotbytes = 0;
+ gotBytes = 0;
}
else
{
@@ -478,30 +553,59 @@ public partial class SerialPort : IDisposable
}
}
- if (gotbytes == 1) OnRxChar(buf[0]);
- } while (gotbytes > 0);
+ if (gotBytes == 1)
+ {
+ OnRxChar(buf[0]);
+ }
+ } while (gotBytes > 0);
}
- if ((eventMask & COMM_EVENT_MASK.EV_TXEMPTY) != 0) OnTxDone();
- if ((eventMask & COMM_EVENT_MASK.EV_BREAK) != 0) OnBreak();
+ if ((eventMask & COMM_EVENT_MASK.EV_TXEMPTY) != 0)
+ {
+ OnTxDone();
+ }
+
+ if ((eventMask & COMM_EVENT_MASK.EV_BREAK) != 0)
+ {
+ OnBreak();
+ }
uint i = 0;
- if ((eventMask & COMM_EVENT_MASK.EV_CTS) != 0) i |= Win32Com.MS_CTS_ON;
- if ((eventMask & COMM_EVENT_MASK.EV_DSR) != 0) i |= Win32Com.MS_DSR_ON;
- if ((eventMask & COMM_EVENT_MASK.EV_RLSD) != 0) i |= Win32Com.MS_RLSD_ON;
- if ((eventMask & COMM_EVENT_MASK.EV_RING) != 0) i |= Win32Com.MS_RING_ON;
+ if ((eventMask & COMM_EVENT_MASK.EV_CTS) != 0)
+ {
+ i |= Win32Com.MS_CTS_ON;
+ }
+
+ if ((eventMask & COMM_EVENT_MASK.EV_DSR) != 0)
+ {
+ i |= Win32Com.MS_DSR_ON;
+ }
+
+ if ((eventMask & COMM_EVENT_MASK.EV_RLSD) != 0)
+ {
+ i |= Win32Com.MS_RLSD_ON;
+ }
+
+ if ((eventMask & COMM_EVENT_MASK.EV_RING) != 0)
+ {
+ i |= Win32Com.MS_RING_ON;
+ }
+
if (i != 0)
{
uint f;
if (!Win32Com.GetCommModemStatus(_hPort.DangerousGetHandle(), out f))
+ {
throw new CommPortException("IO Error [005]");
+ }
+
OnStatusChange(new ModemStatus((MODEM_STATUS_FLAGS)i), new ModemStatus((MODEM_STATUS_FLAGS)f));
}
}
}
catch (Exception e)
{
- if (!(e is ThreadAbortException))
+ if (e is not ThreadAbortException)
{
_rxException = e;
OnRxException(e);
@@ -519,16 +623,24 @@ public partial class SerialPort : IDisposable
if (_online)
{
- uint f;
- if (Win32Com.GetHandleInformation(_hPort.DangerousGetHandle(), out f)) return true;
+ if (Win32Com.GetHandleInformation(_hPort.DangerousGetHandle(), out uint _))
+ {
+ return true;
+ }
+
ThrowException("Offline");
return false;
}
if (_auto)
+ {
if (Open())
+ {
return true;
+ }
+ }
+
ThrowException("Offline");
return false;
}
-}
\ No newline at end of file
+}