diff --git a/PInvokeSerialPort/SerialPort.cs b/PInvokeSerialPort/SerialPort.cs
index fcfc0d0..7f5de2c 100755
--- a/PInvokeSerialPort/SerialPort.cs
+++ b/PInvokeSerialPort/SerialPort.cs
@@ -7,27 +7,144 @@ using PInvokeSerialPort.Win32PInvoke;
namespace PInvokeSerialPort
{
///
- /// PInvokeSerialPort main class.
- /// Borrowed from http://msdn.microsoft.com/en-us/magazine/cc301786.aspx ;)
+ /// PInvokeSerialPort main class.
+ /// Borrowed from http://msdn.microsoft.com/en-us/magazine/cc301786.aspx ;)
///
public class SerialPort : IDisposable
{
- private IntPtr _hPort;
- private IntPtr _ptrUwo = IntPtr.Zero;
- private Thread _rxThread;
- private bool _online;
+ private readonly ManualResetEvent _writeEvent = new ManualResetEvent(false);
private bool _auto;
private bool _checkSends = true;
+
+ private Handshake _handShake;
+ private IntPtr _hPort;
+ private bool _online;
+ private IntPtr _ptrUwo = IntPtr.Zero;
private Exception _rxException;
private bool _rxExceptionReported;
- private int _writeCount;
- private readonly ManualResetEvent _writeEvent = new ManualResetEvent(false);
- private int _stateRts = 2;
- private int _stateDtr = 2;
+ private Thread _rxThread;
private int _stateBrk = 2;
+ private int _stateDtr = 2;
+ private int _stateRts = 2;
+ private int _writeCount;
///
- /// Class contructor
+ /// If true, the port will automatically re-open on next send if it was previously closed due
+ /// to an error (default: false)
+ ///
+ public bool AutoReopen;
+
+ ///
+ /// Baud Rate (default: 2400) unsupported rates will throw "Bad settings"
+ ///
+ public int BaudRate = 115200;
+
+ ///
+ /// If true, subsequent Send commands wait for completion of earlier ones enabling the results
+ /// to be checked. If false, errors, including timeouts, may not be detected, but performance
+ /// may be better.
+ ///
+ public bool CheckAllSends = true;
+
+ ///
+ /// Number of databits 1..8 (default: 8) unsupported values will throw "Bad settings"
+ ///
+ public int DataBits = 8;
+
+ ///
+ /// The parity checking scheme (default: none)
+ ///
+ public Parity Parity = Parity.None;
+
+ ///
+ /// If true, Xon and Xoff characters are sent to control the data flow from the remote station (default: false)
+ ///
+ public bool RxFlowX;
+
+ ///
+ /// If true, received characters are ignored unless DSR is asserted by the remote station (default: false)
+ ///
+ public bool RxGateDsr;
+
+ ///
+ /// The number of free bytes in the reception queue at which flow is disabled (default: 2048)
+ ///
+ public int RxHighWater = 2048;
+
+ ///
+ /// The number of bytes in the reception queue at which flow is re-enabled (default: 512)
+ ///
+ public int RxLowWater = 512;
+
+ ///
+ /// Requested size for receive queue (default: 0 = use operating system default)
+ ///
+ public int RxQueue;
+
+ ///
+ /// Constant. Max time for Send in ms = (Multiplier * Characters) + Constant (default: 0)
+ ///
+ public int SendTimeoutConstant;
+
+ ///
+ /// Multiplier. Max time for Send in ms = (Multiplier * Characters) + Constant
+ /// (default: 0 = No timeout)
+ ///
+ public int SendTimeoutMultiplier;
+
+ ///
+ /// Number of stop bits (default: one)
+ ///
+ public StopBits StopBits = StopBits.One;
+
+ ///
+ /// If true, transmission is halted unless CTS is asserted by the remote station (default: false)
+ ///
+ public bool TxFlowCts;
+
+ ///
+ /// If true, transmission is halted unless DSR is asserted by the remote station (default: false)
+ ///
+ public bool TxFlowDsr;
+
+ ///
+ /// If true, transmission is halted when Xoff is received and restarted when Xon is received (default: false)
+ ///
+ public bool TxFlowX;
+
+ ///
+ /// Requested size for transmit queue (default: 0 = use operating system default)
+ ///
+ public int TxQueue;
+
+ ///
+ /// If false, transmission is suspended when this station has sent Xoff to the remote station (default: true)
+ /// Set false if the remote station treats any character as an Xon.
+ ///
+ public bool TxWhenRxXoff = true;
+
+ ///
+ /// Specidies the use to which the DTR output is put (default: none)
+ ///
+ public HsOutput UseDtr = HsOutput.None;
+
+ ///
+ /// Specifies the use to which the RTS output is put (default: none)
+ ///
+ public HsOutput UseRts = HsOutput.None;
+
+ ///
+ /// The character used to signal Xoff for X flow control (default: DC3)
+ ///
+ public ASCII XoffChar = ASCII.DC3;
+
+ ///
+ /// The character used to signal Xon for X flow control (default: DC1)
+ ///
+ public ASCII XonChar = ASCII.DC1;
+
+ ///
+ /// Class contructor
///
public SerialPort(string portName)
{
@@ -35,7 +152,7 @@ namespace PInvokeSerialPort
}
///
- /// Class contructor
+ /// Class contructor
///
public SerialPort(string portName, int baudRate)
{
@@ -44,293 +161,17 @@ namespace PInvokeSerialPort
}
///
- /// Opens the com port and configures it with the required settings
+ /// True if online.
///
- /// false if the port could not be opened
- public bool Open()
- {
- var portDcb = new DCB();
- var commTimeouts = new COMMTIMEOUTS();
- var wo = new OVERLAPPED();
-
- if (_online) return false;
-
- _hPort = Win32Com.CreateFile(PortName, Win32Com.GENERIC_READ | Win32Com.GENERIC_WRITE, 0, IntPtr.Zero,
- Win32Com.OPEN_EXISTING, Win32Com.FILE_FLAG_OVERLAPPED, IntPtr.Zero);
- if (_hPort == (IntPtr)Win32Com.INVALID_HANDLE_VALUE)
- {
- if (Marshal.GetLastWin32Error() == Win32Com.ERROR_ACCESS_DENIED)
- {
- return false;
- }
- throw new CommPortException("Port Open Failure");
- }
-
- _online = true;
-
- commTimeouts.ReadIntervalTimeout = 0;
- commTimeouts.ReadTotalTimeoutConstant = 0;
- commTimeouts.ReadTotalTimeoutMultiplier = 0;
- commTimeouts.WriteTotalTimeoutConstant = SendTimeoutConstant;
- commTimeouts.WriteTotalTimeoutMultiplier = SendTimeoutMultiplier;
- portDcb.Init(((Parity == Parity.Odd) || (Parity == Parity.Even)), TxFlowCts, TxFlowDsr,
- (int)UseDtr, RxGateDsr, !TxWhenRxXoff, TxFlowX, RxFlowX, (int)UseRts);
- portDcb.BaudRate = BaudRate;
- portDcb.ByteSize = (byte)DataBits;
- portDcb.Parity = (byte)Parity;
- portDcb.StopBits = (byte)StopBits;
- portDcb.XoffChar = (byte)XoffChar;
- portDcb.XonChar = (byte)XonChar;
- portDcb.XoffLim = (short)RxHighWater;
- portDcb.XonLim = (short)RxLowWater;
- if ((RxQueue != 0) || (TxQueue != 0))
- if (!Win32Com.SetupComm(_hPort, (uint)RxQueue, (uint)TxQueue)) ThrowException("Bad queue settings");
- if (!Win32Com.SetCommState(_hPort, ref portDcb)) ThrowException("Bad com settings");
- if (!Win32Com.SetCommTimeouts(_hPort, ref commTimeouts)) ThrowException("Bad timeout settings");
-
- _stateBrk = 0;
- if (UseDtr == HsOutput.None) _stateDtr = 0;
- if (UseDtr == HsOutput.Online) _stateDtr = 1;
- if (UseRts == HsOutput.None) _stateRts = 0;
- if (UseRts == HsOutput.Online) _stateRts = 1;
-
- _checkSends = CheckAllSends;
- wo.Offset = 0;
- wo.OffsetHigh = 0;
- wo.hEvent = _checkSends ? _writeEvent.Handle : IntPtr.Zero;
- _ptrUwo = Marshal.AllocHGlobal(Marshal.SizeOf(wo));
- Marshal.StructureToPtr(wo, _ptrUwo, true);
- _writeCount = 0;
-
- _rxException = null;
- _rxExceptionReported = false;
- _rxThread = new Thread(ReceiveThread)
- {
- Name = "CommBaseRx",
- Priority = ThreadPriority.AboveNormal
- };
- //If not set to true, my application process will not exit completely after UI closed
- _rxThread.IsBackground = true;
- _rxThread.Start();
- Thread.Sleep(1); //Give rx thread time to start. By documentation, 0 should work, but it does not!
-
- _auto = false;
- if (AfterOpen())
- {
- _auto = AutoReopen;
- return true;
- }
- Close();
- return false;
- }
+ public bool Online => _online && CheckOnline();
///
- /// Closes the com port.
+ /// True if the RTS pin is controllable via the RTS property
///
- public void Close()
- {
- if (_online)
- {
- _auto = false;
- BeforeClose(false);
- InternalClose();
- _rxException = null;
- }
- }
-
- private void InternalClose()
- {
- Win32Com.CancelIo(_hPort);
- if (_rxThread != null)
- {
- _rxThread.Abort();
- _rxThread = null;
- }
- Win32Com.CloseHandle(_hPort);
- if (_ptrUwo != IntPtr.Zero) Marshal.FreeHGlobal(_ptrUwo);
- _stateRts = 2;
- _stateDtr = 2;
- _stateBrk = 2;
- _online = false;
- }
+ protected bool RtSavailable => _stateRts < 2;
///
- /// For IDisposable
- ///
- public void Dispose() { Close(); }
-
- ///
- /// Destructor (just in case)
- ///
- ~SerialPort() { Close(); }
-
- ///
- /// True if online.
- ///
- public bool Online { get { return _online && CheckOnline(); } }
-
- ///
- /// Block until all bytes in the queue have been transmitted.
- ///
- public void Flush()
- {
- CheckOnline();
- CheckResult();
- }
-
- ///
- /// Use this to throw exceptions in derived classes. Correctly handles threading issues
- /// and closes the port if necessary.
- ///
- /// Description of fault
- protected void ThrowException(string reason)
- {
- if (Thread.CurrentThread == _rxThread)
- {
- throw new CommPortException(reason);
- }
- if (_online)
- {
- BeforeClose(true);
- InternalClose();
- }
- if (_rxException == null)
- {
- throw new CommPortException(reason);
- }
- throw new CommPortException(_rxException);
- }
-
- ///
- /// Queues bytes for transmission.
- ///
- /// Array of bytes to be sent
- public void Write(byte[] toSend)
- {
- uint sent;
- CheckOnline();
- CheckResult();
- _writeCount = toSend.GetLength(0);
- if (Win32Com.WriteFile(_hPort, toSend, (uint)_writeCount, out sent, _ptrUwo))
- {
- _writeCount -= (int)sent;
- }
- else
- {
- if (Marshal.GetLastWin32Error() != Win32Com.ERROR_IO_PENDING) ThrowException("Unexpected failure");
- }
- }
-
- ///
- /// Queues string for transmission.
- ///
- /// Array of bytes to be sent
- public void Write(string toSend)
- {
- Write(new ASCIIEncoding().GetBytes(toSend));
- }
-
- ///
- /// Queues a single byte for transmission.
- ///
- /// Byte to be sent
- public void Write(byte toSend)
- {
- var b = new byte[1];
- b[0] = toSend;
- Write(b);
- }
-
- ///
- /// Queues a single char for transmission.
- ///
- /// Byte to be sent
- public void Write(char toSend)
- {
- Write(toSend.ToString());
- }
-
- ///
- /// Queues string with a new line ("\r\n") for transmission.
- ///
- /// Array of bytes to be sent
- public void WriteLine(string toSend)
- {
- Write(new ASCIIEncoding().GetBytes(toSend + Environment.NewLine));
- }
-
- private void CheckResult()
- {
- if (_writeCount <= 0) return;
- uint sent;
- if (Win32Com.GetOverlappedResult(_hPort, _ptrUwo, out sent, _checkSends))
- {
- _writeCount -= (int)sent;
- if (_writeCount != 0) ThrowException("Send Timeout");
- }
- else
- {
- if (Marshal.GetLastWin32Error() != Win32Com.ERROR_IO_PENDING) ThrowException("Unexpected failure");
- }
- }
-
- ///
- /// Sends a protocol byte immediately ahead of any queued bytes.
- ///
- /// Byte to send
- /// False if an immediate byte is already scheduled and not yet sent
- public void SendImmediate(byte tosend)
- {
- CheckOnline();
- if (!Win32Com.TransmitCommChar(_hPort, tosend)) ThrowException("Transmission failure");
- }
-
- ///
- /// Delay processing.
- ///
- /// Milliseconds to delay by
- protected void Sleep(int milliseconds)
- {
- Thread.Sleep(milliseconds);
- }
-
- ///
- /// Gets the status of the modem control input signals.
- ///
- /// Modem status object
- protected ModemStatus GetModemStatus()
- {
- uint f;
-
- CheckOnline();
- if (!Win32Com.GetCommModemStatus(_hPort, out f)) ThrowException("Unexpected failure");
- return new ModemStatus(f);
- }
-
-
- ///
- /// Get the status of the queues
- ///
- /// Queue status object
- protected QueueStatus GetQueueStatus()
- {
- COMSTAT cs;
- COMMPROP cp;
- uint er;
-
- CheckOnline();
- if (!Win32Com.ClearCommError(_hPort, out er, out cs)) ThrowException("Unexpected failure");
- if (!Win32Com.GetCommProperties(_hPort, out cp)) ThrowException("Unexpected failure");
- return new QueueStatus(cs.Flags, cs.cbInQue, cs.cbOutQue, cp.dwCurrentRxQueue, cp.dwCurrentTxQueue);
- }
-
- ///
- /// True if the RTS pin is controllable via the RTS property
- ///
- protected bool RtSavailable { get { return (_stateRts < 2); } }
-
- ///
- /// Set the state of the RTS modem control output
+ /// Set the state of the RTS modem control output
///
protected bool Rts
{
@@ -353,19 +194,16 @@ namespace PInvokeSerialPort
ThrowException("Unexpected Failure");
}
}
- get
- {
- return (_stateRts == 1);
- }
+ get => _stateRts == 1;
}
///
- /// True if the DTR pin is controllable via the DTR property
+ /// True if the DTR pin is controllable via the DTR property
///
- protected bool DtrAvailable { get { return (_stateDtr < 2); } }
+ protected bool DtrAvailable => _stateDtr < 2;
///
- /// The state of the DTR modem control output
+ /// The state of the DTR modem control output
///
protected bool Dtr
{
@@ -388,14 +226,11 @@ namespace PInvokeSerialPort
ThrowException("Unexpected Failure");
}
}
- get
- {
- return (_stateDtr == 1);
- }
+ get => _stateDtr == 1;
}
///
- /// Assert or remove a break condition from the transmission line
+ /// Assert or remove a break condition from the transmission line
///
protected bool Break
{
@@ -418,28 +253,368 @@ namespace PInvokeSerialPort
ThrowException("Unexpected Failure");
}
}
- get
+ get => _stateBrk == 1;
+ }
+
+
+ ///
+ /// Port Name
+ ///
+ public string PortName { get; set; }
+
+ public Handshake Handshake
+ {
+ get => _handShake;
+ set
{
- return (_stateBrk == 1);
+ _handShake = value;
+ switch (_handShake)
+ {
+ case Handshake.None:
+ TxFlowCts = false;
+ TxFlowDsr = false;
+ TxFlowX = false;
+ RxFlowX = false;
+ UseRts = HsOutput.Online;
+ UseDtr = HsOutput.Online;
+ TxWhenRxXoff = true;
+ RxGateDsr = false;
+ break;
+ case Handshake.XonXoff:
+ TxFlowCts = false;
+ TxFlowDsr = false;
+ TxFlowX = true;
+ RxFlowX = true;
+ UseRts = HsOutput.Online;
+ UseDtr = HsOutput.Online;
+ TxWhenRxXoff = true;
+ RxGateDsr = false;
+ XonChar = ASCII.DC1;
+ XoffChar = ASCII.DC3;
+ break;
+ case Handshake.CtsRts:
+ TxFlowCts = true;
+ TxFlowDsr = false;
+ TxFlowX = false;
+ RxFlowX = false;
+ UseRts = HsOutput.Handshake;
+ UseDtr = HsOutput.Online;
+ TxWhenRxXoff = true;
+ RxGateDsr = false;
+ break;
+ case Handshake.DsrDtr:
+ TxFlowCts = false;
+ TxFlowDsr = true;
+ TxFlowX = false;
+ RxFlowX = false;
+ UseRts = HsOutput.Online;
+ UseDtr = HsOutput.Handshake;
+ TxWhenRxXoff = true;
+ RxGateDsr = false;
+ break;
+ }
}
}
///
- /// Override this to provide processing after the port is openned (i.e. to configure remote
- /// device or just check presence).
+ /// For IDisposable
+ ///
+ public void Dispose()
+ {
+ Close();
+ }
+
+ ///
+ /// Opens the com port and configures it with the required settings
+ ///
+ /// false if the port could not be opened
+ public bool Open()
+ {
+ var portDcb = new DCB();
+ var commTimeouts = new COMMTIMEOUTS();
+ var wo = new OVERLAPPED();
+
+ if (_online) return false;
+
+ _hPort = Win32Com.CreateFile(PortName, Win32Com.GENERIC_READ | Win32Com.GENERIC_WRITE, 0, IntPtr.Zero,
+ Win32Com.OPEN_EXISTING, Win32Com.FILE_FLAG_OVERLAPPED, IntPtr.Zero);
+ if (_hPort == (IntPtr) Win32Com.INVALID_HANDLE_VALUE)
+ {
+ if (Marshal.GetLastWin32Error() == Win32Com.ERROR_ACCESS_DENIED) return false;
+ throw new CommPortException("Port Open Failure");
+ }
+
+ _online = true;
+
+ commTimeouts.ReadIntervalTimeout = 0;
+ commTimeouts.ReadTotalTimeoutConstant = 0;
+ commTimeouts.ReadTotalTimeoutMultiplier = 0;
+ commTimeouts.WriteTotalTimeoutConstant = SendTimeoutConstant;
+ commTimeouts.WriteTotalTimeoutMultiplier = SendTimeoutMultiplier;
+ portDcb.Init(Parity == Parity.Odd || Parity == Parity.Even, TxFlowCts, TxFlowDsr,
+ (int) UseDtr, RxGateDsr, !TxWhenRxXoff, TxFlowX, RxFlowX, (int) UseRts);
+ portDcb.BaudRate = BaudRate;
+ portDcb.ByteSize = (byte) DataBits;
+ portDcb.Parity = (byte) Parity;
+ portDcb.StopBits = (byte) StopBits;
+ portDcb.XoffChar = (byte) XoffChar;
+ portDcb.XonChar = (byte) XonChar;
+ portDcb.XoffLim = (short) RxHighWater;
+ portDcb.XonLim = (short) RxLowWater;
+ if (RxQueue != 0 || TxQueue != 0)
+ if (!Win32Com.SetupComm(_hPort, (uint) RxQueue, (uint) TxQueue))
+ ThrowException("Bad queue settings");
+ if (!Win32Com.SetCommState(_hPort, ref portDcb)) ThrowException("Bad com settings");
+ if (!Win32Com.SetCommTimeouts(_hPort, ref commTimeouts)) ThrowException("Bad timeout settings");
+
+ _stateBrk = 0;
+ if (UseDtr == HsOutput.None) _stateDtr = 0;
+ if (UseDtr == HsOutput.Online) _stateDtr = 1;
+ if (UseRts == HsOutput.None) _stateRts = 0;
+ if (UseRts == HsOutput.Online) _stateRts = 1;
+
+ _checkSends = CheckAllSends;
+ wo.Offset = 0;
+ wo.OffsetHigh = 0;
+ wo.hEvent = _checkSends ? _writeEvent.Handle : IntPtr.Zero;
+ _ptrUwo = Marshal.AllocHGlobal(Marshal.SizeOf(wo));
+ Marshal.StructureToPtr(wo, _ptrUwo, true);
+ _writeCount = 0;
+
+ _rxException = null;
+ _rxExceptionReported = false;
+ _rxThread = new Thread(ReceiveThread)
+ {
+ Name = "CommBaseRx",
+ Priority = ThreadPriority.AboveNormal
+ };
+ //If not set to true, my application process will not exit completely after UI closed
+ _rxThread.IsBackground = true;
+ _rxThread.Start();
+ Thread.Sleep(1); //Give rx thread time to start. By documentation, 0 should work, but it does not!
+
+ _auto = false;
+ if (AfterOpen())
+ {
+ _auto = AutoReopen;
+ return true;
+ }
+
+ Close();
+ return false;
+ }
+
+ ///
+ /// Closes the com port.
+ ///
+ public void Close()
+ {
+ if (_online)
+ {
+ _auto = false;
+ BeforeClose(false);
+ InternalClose();
+ _rxException = null;
+ }
+ }
+
+ private void InternalClose()
+ {
+ Win32Com.CancelIo(_hPort);
+ if (_rxThread != null)
+ {
+ _rxThread.Abort();
+ _rxThread = null;
+ }
+
+ Win32Com.CloseHandle(_hPort);
+ if (_ptrUwo != IntPtr.Zero) Marshal.FreeHGlobal(_ptrUwo);
+ _stateRts = 2;
+ _stateDtr = 2;
+ _stateBrk = 2;
+ _online = false;
+ }
+
+ ///
+ /// Destructor (just in case)
+ ///
+ ~SerialPort()
+ {
+ Close();
+ }
+
+ ///
+ /// Block until all bytes in the queue have been transmitted.
+ ///
+ public void Flush()
+ {
+ CheckOnline();
+ CheckResult();
+ }
+
+ ///
+ /// Use this to throw exceptions in derived classes. Correctly handles threading issues
+ /// and closes the port if necessary.
+ ///
+ /// Description of fault
+ protected void ThrowException(string reason)
+ {
+ if (Thread.CurrentThread == _rxThread) throw new CommPortException(reason);
+ if (_online)
+ {
+ BeforeClose(true);
+ InternalClose();
+ }
+
+ if (_rxException == null) throw new CommPortException(reason);
+ throw new CommPortException(_rxException);
+ }
+
+ ///
+ /// Queues bytes for transmission.
+ ///
+ /// Array of bytes to be sent
+ public void Write(byte[] toSend)
+ {
+ uint sent;
+ CheckOnline();
+ CheckResult();
+ _writeCount = toSend.GetLength(0);
+ if (Win32Com.WriteFile(_hPort, toSend, (uint) _writeCount, out sent, _ptrUwo))
+ {
+ _writeCount -= (int) sent;
+ }
+ else
+ {
+ if (Marshal.GetLastWin32Error() != Win32Com.ERROR_IO_PENDING) ThrowException("Unexpected failure");
+ }
+ }
+
+ ///
+ /// Queues string for transmission.
+ ///
+ /// Array of bytes to be sent
+ public void Write(string toSend)
+ {
+ Write(new ASCIIEncoding().GetBytes(toSend));
+ }
+
+ ///
+ /// Queues a single byte for transmission.
+ ///
+ /// Byte to be sent
+ public void Write(byte toSend)
+ {
+ var b = new byte[1];
+ b[0] = toSend;
+ Write(b);
+ }
+
+ ///
+ /// Queues a single char for transmission.
+ ///
+ /// Byte to be sent
+ public void Write(char toSend)
+ {
+ Write(toSend.ToString());
+ }
+
+ ///
+ /// Queues string with a new line ("\r\n") for transmission.
+ ///
+ /// Array of bytes to be sent
+ public void WriteLine(string toSend)
+ {
+ Write(new ASCIIEncoding().GetBytes(toSend + Environment.NewLine));
+ }
+
+ private void CheckResult()
+ {
+ if (_writeCount <= 0) return;
+ uint sent;
+ if (Win32Com.GetOverlappedResult(_hPort, _ptrUwo, out sent, _checkSends))
+ {
+ _writeCount -= (int) sent;
+ if (_writeCount != 0) ThrowException("Send Timeout");
+ }
+ else
+ {
+ if (Marshal.GetLastWin32Error() != Win32Com.ERROR_IO_PENDING) ThrowException("Unexpected failure");
+ }
+ }
+
+ ///
+ /// Sends a protocol byte immediately ahead of any queued bytes.
+ ///
+ /// Byte to send
+ /// False if an immediate byte is already scheduled and not yet sent
+ public void SendImmediate(byte tosend)
+ {
+ CheckOnline();
+ if (!Win32Com.TransmitCommChar(_hPort, tosend)) ThrowException("Transmission failure");
+ }
+
+ ///
+ /// Delay processing.
+ ///
+ /// Milliseconds to delay by
+ protected void Sleep(int milliseconds)
+ {
+ Thread.Sleep(milliseconds);
+ }
+
+ ///
+ /// Gets the status of the modem control input signals.
+ ///
+ /// Modem status object
+ protected ModemStatus GetModemStatus()
+ {
+ uint f;
+
+ CheckOnline();
+ if (!Win32Com.GetCommModemStatus(_hPort, out f)) ThrowException("Unexpected failure");
+ return new ModemStatus(f);
+ }
+
+
+ ///
+ /// Get the status of the queues
+ ///
+ /// Queue status object
+ protected QueueStatus GetQueueStatus()
+ {
+ COMSTAT cs;
+ COMMPROP cp;
+ uint er;
+
+ CheckOnline();
+ if (!Win32Com.ClearCommError(_hPort, out er, out cs)) ThrowException("Unexpected failure");
+ if (!Win32Com.GetCommProperties(_hPort, out cp)) ThrowException("Unexpected failure");
+ return new QueueStatus(cs.Flags, cs.cbInQue, cs.cbOutQue, cp.dwCurrentRxQueue, cp.dwCurrentTxQueue);
+ }
+
+ ///
+ /// Override this to provide processing after the port is openned (i.e. to configure remote
+ /// device or just check presence).
///
/// false to close the port again
- protected virtual bool AfterOpen() { return true; }
+ protected virtual bool AfterOpen()
+ {
+ return true;
+ }
///
- /// Override this to provide processing prior to port closure.
+ /// Override this to provide processing prior to port closure.
///
/// True if closing due to an error
- protected virtual void BeforeClose(bool error) { }
+ protected virtual void BeforeClose(bool error)
+ {
+ }
public event Action DataReceived;
+
///
- /// Override this to process received bytes.
+ /// Override this to process received bytes.
///
/// The byte that was received
protected void OnRxChar(byte ch)
@@ -449,42 +624,53 @@ namespace PInvokeSerialPort
}
///
- /// Override this to take action when transmission is complete (i.e. all bytes have actually
- /// been sent, not just queued).
+ /// Override this to take action when transmission is complete (i.e. all bytes have actually
+ /// been sent, not just queued).
///
- protected virtual void OnTxDone() { }
+ protected virtual void OnTxDone()
+ {
+ }
///
- /// Override this to take action when a break condition is detected on the input line.
+ /// Override this to take action when a break condition is detected on the input line.
///
- protected virtual void OnBreak() { }
+ protected virtual void OnBreak()
+ {
+ }
///
- /// Override this to take action when a ring condition is signalled by an attached modem.
+ /// Override this to take action when a ring condition is signalled by an attached modem.
///
- protected virtual void OnRing() { }
+ protected virtual void OnRing()
+ {
+ }
///
- /// Override this to take action when one or more modem status inputs change state
+ /// Override this to take action when one or more modem status inputs change state
///
/// The status inputs that have changed state
/// The state of the status inputs
- protected virtual void OnStatusChange(ModemStatus mask, ModemStatus state) { }
+ protected virtual void OnStatusChange(ModemStatus mask, ModemStatus state)
+ {
+ }
///
- /// Override this to take action when the reception thread closes due to an exception being thrown.
+ /// Override this to take action when the reception thread closes due to an exception being thrown.
///
/// The exception which was thrown
- protected virtual void OnRxException(Exception e) { }
+ protected virtual void OnRxException(Exception e)
+ {
+ }
private void ReceiveThread()
{
- var buf = new Byte[1];
+ var buf = new byte[1];
var sg = new AutoResetEvent(false);
var ov = new OVERLAPPED();
var unmanagedOv = Marshal.AllocHGlobal(Marshal.SizeOf(ov));
- ov.Offset = 0; ov.OffsetHigh = 0;
+ ov.Offset = 0;
+ ov.OffsetHigh = 0;
ov.hEvent = sg.Handle;
Marshal.StructureToPtr(ov, unmanagedOv, true);
@@ -495,27 +681,23 @@ namespace PInvokeSerialPort
{
while (true)
{
- if (!Win32Com.SetCommMask(_hPort, Win32Com.EV_RXCHAR | Win32Com.EV_TXEMPTY | Win32Com.EV_CTS | Win32Com.EV_DSR
+ if (!Win32Com.SetCommMask(_hPort,
+ Win32Com.EV_RXCHAR | Win32Com.EV_TXEMPTY | Win32Com.EV_CTS | Win32Com.EV_DSR
| Win32Com.EV_BREAK | Win32Com.EV_RLSD | Win32Com.EV_RING | Win32Com.EV_ERR))
- {
throw new CommPortException("IO Error [001]");
- }
Marshal.WriteInt32(uMask, 0);
if (!Win32Com.WaitCommEvent(_hPort, uMask, unmanagedOv))
{
if (Marshal.GetLastWin32Error() == Win32Com.ERROR_IO_PENDING)
- {
sg.WaitOne();
- }
else
- {
throw new CommPortException("IO Error [002]");
- }
}
- eventMask = (uint)Marshal.ReadInt32(uMask);
+
+ eventMask = (uint) Marshal.ReadInt32(uMask);
if ((eventMask & Win32Com.EV_ERR) != 0)
{
- UInt32 errs;
+ uint errs;
if (Win32Com.ClearCommError(_hPort, out errs, IntPtr.Zero))
{
var s = new StringBuilder("UART Error: ", 40);
@@ -528,8 +710,10 @@ namespace PInvokeSerialPort
s.Length = s.Length - 1;
throw new CommPortException(s.ToString());
}
+
throw new CommPortException("IO Error [003]");
}
+
if ((eventMask & Win32Com.EV_RXCHAR) != 0)
{
uint gotbytes;
@@ -547,14 +731,12 @@ namespace PInvokeSerialPort
throw new CommPortException("IO Error [004]");
}
}
+
if (gotbytes == 1) OnRxChar(buf[0]);
-
} while (gotbytes > 0);
}
- if ((eventMask & Win32Com.EV_TXEMPTY) != 0)
- {
- OnTxDone();
- }
+
+ if ((eventMask & Win32Com.EV_TXEMPTY) != 0) OnTxDone();
if ((eventMask & Win32Com.EV_BREAK) != 0) OnBreak();
uint i = 0;
@@ -584,11 +766,12 @@ namespace PInvokeSerialPort
private bool CheckOnline()
{
- if ((_rxException != null) && (!_rxExceptionReported))
+ if (_rxException != null && !_rxExceptionReported)
{
_rxExceptionReported = true;
ThrowException("rx");
}
+
if (_online)
{
uint f;
@@ -596,147 +779,12 @@ namespace PInvokeSerialPort
ThrowException("Offline");
return false;
}
+
if (_auto)
- {
- if (Open()) return true;
- }
+ if (Open())
+ return true;
ThrowException("Offline");
return false;
}
-
-
-
- ///
- /// Port Name
- ///
- public string PortName { get; set; }
- ///
- /// Baud Rate (default: 2400) unsupported rates will throw "Bad settings"
- ///
- public int BaudRate = 115200;
- ///
- /// The parity checking scheme (default: none)
- ///
- public Parity Parity = Parity.None;
- ///
- /// Number of databits 1..8 (default: 8) unsupported values will throw "Bad settings"
- ///
- public int DataBits = 8;
- ///
- /// Number of stop bits (default: one)
- ///
- public StopBits StopBits = StopBits.One;
- ///
- /// If true, transmission is halted unless CTS is asserted by the remote station (default: false)
- ///
- public bool TxFlowCts;
- ///
- /// If true, transmission is halted unless DSR is asserted by the remote station (default: false)
- ///
- public bool TxFlowDsr;
- ///
- /// If true, transmission is halted when Xoff is received and restarted when Xon is received (default: false)
- ///
- public bool TxFlowX;
- ///
- /// If false, transmission is suspended when this station has sent Xoff to the remote station (default: true)
- /// Set false if the remote station treats any character as an Xon.
- ///
- public bool TxWhenRxXoff = true;
- ///
- /// If true, received characters are ignored unless DSR is asserted by the remote station (default: false)
- ///
- public bool RxGateDsr;
- ///
- /// If true, Xon and Xoff characters are sent to control the data flow from the remote station (default: false)
- ///
- public bool RxFlowX;
- ///
- /// Specifies the use to which the RTS output is put (default: none)
- ///
- public HsOutput UseRts = HsOutput.None;
- ///
- /// Specidies the use to which the DTR output is put (default: none)
- ///
- public HsOutput UseDtr = HsOutput.None;
- ///
- /// The character used to signal Xon for X flow control (default: DC1)
- ///
- public ASCII XonChar = ASCII.DC1;
- ///
- /// The character used to signal Xoff for X flow control (default: DC3)
- ///
- public ASCII XoffChar = ASCII.DC3;
- ///
- /// The number of free bytes in the reception queue at which flow is disabled (default: 2048)
- ///
- public int RxHighWater = 2048;
- ///
- /// The number of bytes in the reception queue at which flow is re-enabled (default: 512)
- ///
- public int RxLowWater = 512;
- ///
- /// Multiplier. Max time for Send in ms = (Multiplier * Characters) + Constant
- /// (default: 0 = No timeout)
- ///
- public int SendTimeoutMultiplier;
- ///
- /// Constant. Max time for Send in ms = (Multiplier * Characters) + Constant (default: 0)
- ///
- public int SendTimeoutConstant;
- ///
- /// Requested size for receive queue (default: 0 = use operating system default)
- ///
- public int RxQueue;
- ///
- /// Requested size for transmit queue (default: 0 = use operating system default)
- ///
- public int TxQueue;
- ///
- /// If true, the port will automatically re-open on next send if it was previously closed due
- /// to an error (default: false)
- ///
- public bool AutoReopen;
-
- ///
- /// If true, subsequent Send commands wait for completion of earlier ones enabling the results
- /// to be checked. If false, errors, including timeouts, may not be detected, but performance
- /// may be better.
- ///
- public bool CheckAllSends = true;
-
- private Handshake _handShake;
- public Handshake Handshake
- {
- get { return _handShake; }
- set
- {
- _handShake = value;
- switch (_handShake)
- {
- case Handshake.None:
- TxFlowCts = false; TxFlowDsr = false; TxFlowX = false;
- RxFlowX = false; UseRts = HsOutput.Online; UseDtr = HsOutput.Online;
- TxWhenRxXoff = true; RxGateDsr = false;
- break;
- case Handshake.XonXoff:
- TxFlowCts = false; TxFlowDsr = false; TxFlowX = true;
- RxFlowX = true; UseRts = HsOutput.Online; UseDtr = HsOutput.Online;
- TxWhenRxXoff = true; RxGateDsr = false;
- XonChar = ASCII.DC1; XoffChar = ASCII.DC3;
- break;
- case Handshake.CtsRts:
- TxFlowCts = true; TxFlowDsr = false; TxFlowX = false;
- RxFlowX = false; UseRts = HsOutput.Handshake; UseDtr = HsOutput.Online;
- TxWhenRxXoff = true; RxGateDsr = false;
- break;
- case Handshake.DsrDtr:
- TxFlowCts = false; TxFlowDsr = true; TxFlowX = false;
- RxFlowX = false; UseRts = HsOutput.Online; UseDtr = HsOutput.Handshake;
- TxWhenRxXoff = true; RxGateDsr = false;
- break;
- }
- }
- }
}
}
\ No newline at end of file