More refactoring
This commit is contained in:
parent
55c3aefa2d
commit
33e68a0745
@ -12,19 +12,136 @@ namespace PInvokeSerialPort
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class SerialPort : IDisposable
|
public class SerialPort : IDisposable
|
||||||
{
|
{
|
||||||
private IntPtr _hPort;
|
private readonly ManualResetEvent _writeEvent = new ManualResetEvent(false);
|
||||||
private IntPtr _ptrUwo = IntPtr.Zero;
|
|
||||||
private Thread _rxThread;
|
|
||||||
private bool _online;
|
|
||||||
private bool _auto;
|
private bool _auto;
|
||||||
private bool _checkSends = true;
|
private bool _checkSends = true;
|
||||||
|
|
||||||
|
private Handshake _handShake;
|
||||||
|
private IntPtr _hPort;
|
||||||
|
private bool _online;
|
||||||
|
private IntPtr _ptrUwo = IntPtr.Zero;
|
||||||
private Exception _rxException;
|
private Exception _rxException;
|
||||||
private bool _rxExceptionReported;
|
private bool _rxExceptionReported;
|
||||||
private int _writeCount;
|
private Thread _rxThread;
|
||||||
private readonly ManualResetEvent _writeEvent = new ManualResetEvent(false);
|
|
||||||
private int _stateRts = 2;
|
|
||||||
private int _stateDtr = 2;
|
|
||||||
private int _stateBrk = 2;
|
private int _stateBrk = 2;
|
||||||
|
private int _stateDtr = 2;
|
||||||
|
private int _stateRts = 2;
|
||||||
|
private int _writeCount;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If true, the port will automatically re-open on next send if it was previously closed due
|
||||||
|
/// to an error (default: false)
|
||||||
|
/// </summary>
|
||||||
|
public bool AutoReopen;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Baud Rate (default: 2400) unsupported rates will throw "Bad settings"
|
||||||
|
/// </summary>
|
||||||
|
public int BaudRate = 115200;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
public bool CheckAllSends = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Number of databits 1..8 (default: 8) unsupported values will throw "Bad settings"
|
||||||
|
/// </summary>
|
||||||
|
public int DataBits = 8;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The parity checking scheme (default: none)
|
||||||
|
/// </summary>
|
||||||
|
public Parity Parity = Parity.None;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If true, Xon and Xoff characters are sent to control the data flow from the remote station (default: false)
|
||||||
|
/// </summary>
|
||||||
|
public bool RxFlowX;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If true, received characters are ignored unless DSR is asserted by the remote station (default: false)
|
||||||
|
/// </summary>
|
||||||
|
public bool RxGateDsr;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The number of free bytes in the reception queue at which flow is disabled (default: 2048)
|
||||||
|
/// </summary>
|
||||||
|
public int RxHighWater = 2048;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The number of bytes in the reception queue at which flow is re-enabled (default: 512)
|
||||||
|
/// </summary>
|
||||||
|
public int RxLowWater = 512;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Requested size for receive queue (default: 0 = use operating system default)
|
||||||
|
/// </summary>
|
||||||
|
public int RxQueue;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constant. Max time for Send in ms = (Multiplier * Characters) + Constant (default: 0)
|
||||||
|
/// </summary>
|
||||||
|
public int SendTimeoutConstant;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Multiplier. Max time for Send in ms = (Multiplier * Characters) + Constant
|
||||||
|
/// (default: 0 = No timeout)
|
||||||
|
/// </summary>
|
||||||
|
public int SendTimeoutMultiplier;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Number of stop bits (default: one)
|
||||||
|
/// </summary>
|
||||||
|
public StopBits StopBits = StopBits.One;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If true, transmission is halted unless CTS is asserted by the remote station (default: false)
|
||||||
|
/// </summary>
|
||||||
|
public bool TxFlowCts;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If true, transmission is halted unless DSR is asserted by the remote station (default: false)
|
||||||
|
/// </summary>
|
||||||
|
public bool TxFlowDsr;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If true, transmission is halted when Xoff is received and restarted when Xon is received (default: false)
|
||||||
|
/// </summary>
|
||||||
|
public bool TxFlowX;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Requested size for transmit queue (default: 0 = use operating system default)
|
||||||
|
/// </summary>
|
||||||
|
public int TxQueue;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
public bool TxWhenRxXoff = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specidies the use to which the DTR output is put (default: none)
|
||||||
|
/// </summary>
|
||||||
|
public HsOutput UseDtr = HsOutput.None;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies the use to which the RTS output is put (default: none)
|
||||||
|
/// </summary>
|
||||||
|
public HsOutput UseRts = HsOutput.None;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The character used to signal Xoff for X flow control (default: DC3)
|
||||||
|
/// </summary>
|
||||||
|
public ASCII XoffChar = ASCII.DC3;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The character used to signal Xon for X flow control (default: DC1)
|
||||||
|
/// </summary>
|
||||||
|
public ASCII XonChar = ASCII.DC1;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class contructor
|
/// Class contructor
|
||||||
@ -43,6 +160,170 @@ namespace PInvokeSerialPort
|
|||||||
BaudRate = baudRate;
|
BaudRate = baudRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// True if online.
|
||||||
|
/// </summary>
|
||||||
|
public bool Online => _online && CheckOnline();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// True if the RTS pin is controllable via the RTS property
|
||||||
|
/// </summary>
|
||||||
|
protected bool RtSavailable => _stateRts < 2;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set the state of the RTS modem control output
|
||||||
|
/// </summary>
|
||||||
|
protected bool Rts
|
||||||
|
{
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_stateRts > 1) return;
|
||||||
|
CheckOnline();
|
||||||
|
if (value)
|
||||||
|
{
|
||||||
|
if (Win32Com.EscapeCommFunction(_hPort, Win32Com.SETRTS))
|
||||||
|
_stateRts = 1;
|
||||||
|
else
|
||||||
|
ThrowException("Unexpected Failure");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (Win32Com.EscapeCommFunction(_hPort, Win32Com.CLRRTS))
|
||||||
|
_stateRts = 1;
|
||||||
|
else
|
||||||
|
ThrowException("Unexpected Failure");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
get => _stateRts == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// True if the DTR pin is controllable via the DTR property
|
||||||
|
/// </summary>
|
||||||
|
protected bool DtrAvailable => _stateDtr < 2;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The state of the DTR modem control output
|
||||||
|
/// </summary>
|
||||||
|
protected bool Dtr
|
||||||
|
{
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_stateDtr > 1) return;
|
||||||
|
CheckOnline();
|
||||||
|
if (value)
|
||||||
|
{
|
||||||
|
if (Win32Com.EscapeCommFunction(_hPort, Win32Com.SETDTR))
|
||||||
|
_stateDtr = 1;
|
||||||
|
else
|
||||||
|
ThrowException("Unexpected Failure");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (Win32Com.EscapeCommFunction(_hPort, Win32Com.CLRDTR))
|
||||||
|
_stateDtr = 0;
|
||||||
|
else
|
||||||
|
ThrowException("Unexpected Failure");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
get => _stateDtr == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Assert or remove a break condition from the transmission line
|
||||||
|
/// </summary>
|
||||||
|
protected bool Break
|
||||||
|
{
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_stateBrk > 1) return;
|
||||||
|
CheckOnline();
|
||||||
|
if (value)
|
||||||
|
{
|
||||||
|
if (Win32Com.EscapeCommFunction(_hPort, Win32Com.SETBREAK))
|
||||||
|
_stateBrk = 0;
|
||||||
|
else
|
||||||
|
ThrowException("Unexpected Failure");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (Win32Com.EscapeCommFunction(_hPort, Win32Com.CLRBREAK))
|
||||||
|
_stateBrk = 0;
|
||||||
|
else
|
||||||
|
ThrowException("Unexpected Failure");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
get => _stateBrk == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Port Name
|
||||||
|
/// </summary>
|
||||||
|
public string PortName { get; set; }
|
||||||
|
|
||||||
|
public Handshake Handshake
|
||||||
|
{
|
||||||
|
get => _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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// For IDisposable
|
||||||
|
/// </summary>
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Opens the com port and configures it with the required settings
|
/// Opens the com port and configures it with the required settings
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -59,10 +340,7 @@ namespace PInvokeSerialPort
|
|||||||
Win32Com.OPEN_EXISTING, Win32Com.FILE_FLAG_OVERLAPPED, IntPtr.Zero);
|
Win32Com.OPEN_EXISTING, Win32Com.FILE_FLAG_OVERLAPPED, IntPtr.Zero);
|
||||||
if (_hPort == (IntPtr) Win32Com.INVALID_HANDLE_VALUE)
|
if (_hPort == (IntPtr) Win32Com.INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
if (Marshal.GetLastWin32Error() == Win32Com.ERROR_ACCESS_DENIED)
|
if (Marshal.GetLastWin32Error() == Win32Com.ERROR_ACCESS_DENIED) return false;
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
throw new CommPortException("Port Open Failure");
|
throw new CommPortException("Port Open Failure");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,7 +351,7 @@ namespace PInvokeSerialPort
|
|||||||
commTimeouts.ReadTotalTimeoutMultiplier = 0;
|
commTimeouts.ReadTotalTimeoutMultiplier = 0;
|
||||||
commTimeouts.WriteTotalTimeoutConstant = SendTimeoutConstant;
|
commTimeouts.WriteTotalTimeoutConstant = SendTimeoutConstant;
|
||||||
commTimeouts.WriteTotalTimeoutMultiplier = SendTimeoutMultiplier;
|
commTimeouts.WriteTotalTimeoutMultiplier = SendTimeoutMultiplier;
|
||||||
portDcb.Init(((Parity == Parity.Odd) || (Parity == Parity.Even)), TxFlowCts, TxFlowDsr,
|
portDcb.Init(Parity == Parity.Odd || Parity == Parity.Even, TxFlowCts, TxFlowDsr,
|
||||||
(int) UseDtr, RxGateDsr, !TxWhenRxXoff, TxFlowX, RxFlowX, (int) UseRts);
|
(int) UseDtr, RxGateDsr, !TxWhenRxXoff, TxFlowX, RxFlowX, (int) UseRts);
|
||||||
portDcb.BaudRate = BaudRate;
|
portDcb.BaudRate = BaudRate;
|
||||||
portDcb.ByteSize = (byte) DataBits;
|
portDcb.ByteSize = (byte) DataBits;
|
||||||
@ -83,8 +361,9 @@ namespace PInvokeSerialPort
|
|||||||
portDcb.XonChar = (byte) XonChar;
|
portDcb.XonChar = (byte) XonChar;
|
||||||
portDcb.XoffLim = (short) RxHighWater;
|
portDcb.XoffLim = (short) RxHighWater;
|
||||||
portDcb.XonLim = (short) RxLowWater;
|
portDcb.XonLim = (short) RxLowWater;
|
||||||
if ((RxQueue != 0) || (TxQueue != 0))
|
if (RxQueue != 0 || TxQueue != 0)
|
||||||
if (!Win32Com.SetupComm(_hPort, (uint)RxQueue, (uint)TxQueue)) ThrowException("Bad queue settings");
|
if (!Win32Com.SetupComm(_hPort, (uint) RxQueue, (uint) TxQueue))
|
||||||
|
ThrowException("Bad queue settings");
|
||||||
if (!Win32Com.SetCommState(_hPort, ref portDcb)) ThrowException("Bad com settings");
|
if (!Win32Com.SetCommState(_hPort, ref portDcb)) ThrowException("Bad com settings");
|
||||||
if (!Win32Com.SetCommTimeouts(_hPort, ref commTimeouts)) ThrowException("Bad timeout settings");
|
if (!Win32Com.SetCommTimeouts(_hPort, ref commTimeouts)) ThrowException("Bad timeout settings");
|
||||||
|
|
||||||
@ -120,6 +399,7 @@ namespace PInvokeSerialPort
|
|||||||
_auto = AutoReopen;
|
_auto = AutoReopen;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Close();
|
Close();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -146,6 +426,7 @@ namespace PInvokeSerialPort
|
|||||||
_rxThread.Abort();
|
_rxThread.Abort();
|
||||||
_rxThread = null;
|
_rxThread = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Win32Com.CloseHandle(_hPort);
|
Win32Com.CloseHandle(_hPort);
|
||||||
if (_ptrUwo != IntPtr.Zero) Marshal.FreeHGlobal(_ptrUwo);
|
if (_ptrUwo != IntPtr.Zero) Marshal.FreeHGlobal(_ptrUwo);
|
||||||
_stateRts = 2;
|
_stateRts = 2;
|
||||||
@ -154,20 +435,13 @@ namespace PInvokeSerialPort
|
|||||||
_online = false;
|
_online = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// For IDisposable
|
|
||||||
/// </summary>
|
|
||||||
public void Dispose() { Close(); }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Destructor (just in case)
|
/// Destructor (just in case)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
~SerialPort() { Close(); }
|
~SerialPort()
|
||||||
|
{
|
||||||
/// <summary>
|
Close();
|
||||||
/// True if online.
|
}
|
||||||
/// </summary>
|
|
||||||
public bool Online { get { return _online && CheckOnline(); } }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Block until all bytes in the queue have been transmitted.
|
/// Block until all bytes in the queue have been transmitted.
|
||||||
@ -185,19 +459,14 @@ namespace PInvokeSerialPort
|
|||||||
/// <param name="reason">Description of fault</param>
|
/// <param name="reason">Description of fault</param>
|
||||||
protected void ThrowException(string reason)
|
protected void ThrowException(string reason)
|
||||||
{
|
{
|
||||||
if (Thread.CurrentThread == _rxThread)
|
if (Thread.CurrentThread == _rxThread) throw new CommPortException(reason);
|
||||||
{
|
|
||||||
throw new CommPortException(reason);
|
|
||||||
}
|
|
||||||
if (_online)
|
if (_online)
|
||||||
{
|
{
|
||||||
BeforeClose(true);
|
BeforeClose(true);
|
||||||
InternalClose();
|
InternalClose();
|
||||||
}
|
}
|
||||||
if (_rxException == null)
|
|
||||||
{
|
if (_rxException == null) throw new CommPortException(reason);
|
||||||
throw new CommPortException(reason);
|
|
||||||
}
|
|
||||||
throw new CommPortException(_rxException);
|
throw new CommPortException(_rxException);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -324,120 +593,26 @@ namespace PInvokeSerialPort
|
|||||||
return new QueueStatus(cs.Flags, cs.cbInQue, cs.cbOutQue, cp.dwCurrentRxQueue, cp.dwCurrentTxQueue);
|
return new QueueStatus(cs.Flags, cs.cbInQue, cs.cbOutQue, cp.dwCurrentRxQueue, cp.dwCurrentTxQueue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// True if the RTS pin is controllable via the RTS property
|
|
||||||
/// </summary>
|
|
||||||
protected bool RtSavailable { get { return (_stateRts < 2); } }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Set the state of the RTS modem control output
|
|
||||||
/// </summary>
|
|
||||||
protected bool Rts
|
|
||||||
{
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (_stateRts > 1) return;
|
|
||||||
CheckOnline();
|
|
||||||
if (value)
|
|
||||||
{
|
|
||||||
if (Win32Com.EscapeCommFunction(_hPort, Win32Com.SETRTS))
|
|
||||||
_stateRts = 1;
|
|
||||||
else
|
|
||||||
ThrowException("Unexpected Failure");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (Win32Com.EscapeCommFunction(_hPort, Win32Com.CLRRTS))
|
|
||||||
_stateRts = 1;
|
|
||||||
else
|
|
||||||
ThrowException("Unexpected Failure");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return (_stateRts == 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// True if the DTR pin is controllable via the DTR property
|
|
||||||
/// </summary>
|
|
||||||
protected bool DtrAvailable { get { return (_stateDtr < 2); } }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The state of the DTR modem control output
|
|
||||||
/// </summary>
|
|
||||||
protected bool Dtr
|
|
||||||
{
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (_stateDtr > 1) return;
|
|
||||||
CheckOnline();
|
|
||||||
if (value)
|
|
||||||
{
|
|
||||||
if (Win32Com.EscapeCommFunction(_hPort, Win32Com.SETDTR))
|
|
||||||
_stateDtr = 1;
|
|
||||||
else
|
|
||||||
ThrowException("Unexpected Failure");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (Win32Com.EscapeCommFunction(_hPort, Win32Com.CLRDTR))
|
|
||||||
_stateDtr = 0;
|
|
||||||
else
|
|
||||||
ThrowException("Unexpected Failure");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return (_stateDtr == 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Assert or remove a break condition from the transmission line
|
|
||||||
/// </summary>
|
|
||||||
protected bool Break
|
|
||||||
{
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (_stateBrk > 1) return;
|
|
||||||
CheckOnline();
|
|
||||||
if (value)
|
|
||||||
{
|
|
||||||
if (Win32Com.EscapeCommFunction(_hPort, Win32Com.SETBREAK))
|
|
||||||
_stateBrk = 0;
|
|
||||||
else
|
|
||||||
ThrowException("Unexpected Failure");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (Win32Com.EscapeCommFunction(_hPort, Win32Com.CLRBREAK))
|
|
||||||
_stateBrk = 0;
|
|
||||||
else
|
|
||||||
ThrowException("Unexpected Failure");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return (_stateBrk == 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Override this to provide processing after the port is openned (i.e. to configure remote
|
/// Override this to provide processing after the port is openned (i.e. to configure remote
|
||||||
/// device or just check presence).
|
/// device or just check presence).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>false to close the port again</returns>
|
/// <returns>false to close the port again</returns>
|
||||||
protected virtual bool AfterOpen() { return true; }
|
protected virtual bool AfterOpen()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Override this to provide processing prior to port closure.
|
/// Override this to provide processing prior to port closure.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="error">True if closing due to an error</param>
|
/// <param name="error">True if closing due to an error</param>
|
||||||
protected virtual void BeforeClose(bool error) { }
|
protected virtual void BeforeClose(bool error)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public event Action<byte> DataReceived;
|
public event Action<byte> DataReceived;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Override this to process received bytes.
|
/// Override this to process received bytes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -452,39 +627,50 @@ namespace PInvokeSerialPort
|
|||||||
/// Override this to take action when transmission is complete (i.e. all bytes have actually
|
/// Override this to take action when transmission is complete (i.e. all bytes have actually
|
||||||
/// been sent, not just queued).
|
/// been sent, not just queued).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual void OnTxDone() { }
|
protected virtual void OnTxDone()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 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.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual void OnBreak() { }
|
protected virtual void OnBreak()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 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.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual void OnRing() { }
|
protected virtual void OnRing()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 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
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="mask">The status inputs that have changed state</param>
|
/// <param name="mask">The status inputs that have changed state</param>
|
||||||
/// <param name="state">The state of the status inputs</param>
|
/// <param name="state">The state of the status inputs</param>
|
||||||
protected virtual void OnStatusChange(ModemStatus mask, ModemStatus state) { }
|
protected virtual void OnStatusChange(ModemStatus mask, ModemStatus state)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 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.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="e">The exception which was thrown</param>
|
/// <param name="e">The exception which was thrown</param>
|
||||||
protected virtual void OnRxException(Exception e) { }
|
protected virtual void OnRxException(Exception e)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
private void ReceiveThread()
|
private void ReceiveThread()
|
||||||
{
|
{
|
||||||
var buf = new Byte[1];
|
var buf = new byte[1];
|
||||||
|
|
||||||
var sg = new AutoResetEvent(false);
|
var sg = new AutoResetEvent(false);
|
||||||
var ov = new OVERLAPPED();
|
var ov = new OVERLAPPED();
|
||||||
var unmanagedOv = Marshal.AllocHGlobal(Marshal.SizeOf(ov));
|
var unmanagedOv = Marshal.AllocHGlobal(Marshal.SizeOf(ov));
|
||||||
ov.Offset = 0; ov.OffsetHigh = 0;
|
ov.Offset = 0;
|
||||||
|
ov.OffsetHigh = 0;
|
||||||
ov.hEvent = sg.Handle;
|
ov.hEvent = sg.Handle;
|
||||||
Marshal.StructureToPtr(ov, unmanagedOv, true);
|
Marshal.StructureToPtr(ov, unmanagedOv, true);
|
||||||
|
|
||||||
@ -495,27 +681,23 @@ namespace PInvokeSerialPort
|
|||||||
{
|
{
|
||||||
while (true)
|
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))
|
| Win32Com.EV_BREAK | Win32Com.EV_RLSD | Win32Com.EV_RING | Win32Com.EV_ERR))
|
||||||
{
|
|
||||||
throw new CommPortException("IO Error [001]");
|
throw new CommPortException("IO Error [001]");
|
||||||
}
|
|
||||||
Marshal.WriteInt32(uMask, 0);
|
Marshal.WriteInt32(uMask, 0);
|
||||||
if (!Win32Com.WaitCommEvent(_hPort, uMask, unmanagedOv))
|
if (!Win32Com.WaitCommEvent(_hPort, uMask, unmanagedOv))
|
||||||
{
|
{
|
||||||
if (Marshal.GetLastWin32Error() == Win32Com.ERROR_IO_PENDING)
|
if (Marshal.GetLastWin32Error() == Win32Com.ERROR_IO_PENDING)
|
||||||
{
|
|
||||||
sg.WaitOne();
|
sg.WaitOne();
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
throw new CommPortException("IO Error [002]");
|
throw new CommPortException("IO Error [002]");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
eventMask = (uint) Marshal.ReadInt32(uMask);
|
eventMask = (uint) Marshal.ReadInt32(uMask);
|
||||||
if ((eventMask & Win32Com.EV_ERR) != 0)
|
if ((eventMask & Win32Com.EV_ERR) != 0)
|
||||||
{
|
{
|
||||||
UInt32 errs;
|
uint errs;
|
||||||
if (Win32Com.ClearCommError(_hPort, out errs, IntPtr.Zero))
|
if (Win32Com.ClearCommError(_hPort, out errs, IntPtr.Zero))
|
||||||
{
|
{
|
||||||
var s = new StringBuilder("UART Error: ", 40);
|
var s = new StringBuilder("UART Error: ", 40);
|
||||||
@ -528,8 +710,10 @@ namespace PInvokeSerialPort
|
|||||||
s.Length = s.Length - 1;
|
s.Length = s.Length - 1;
|
||||||
throw new CommPortException(s.ToString());
|
throw new CommPortException(s.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new CommPortException("IO Error [003]");
|
throw new CommPortException("IO Error [003]");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((eventMask & Win32Com.EV_RXCHAR) != 0)
|
if ((eventMask & Win32Com.EV_RXCHAR) != 0)
|
||||||
{
|
{
|
||||||
uint gotbytes;
|
uint gotbytes;
|
||||||
@ -547,14 +731,12 @@ namespace PInvokeSerialPort
|
|||||||
throw new CommPortException("IO Error [004]");
|
throw new CommPortException("IO Error [004]");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (gotbytes == 1) OnRxChar(buf[0]);
|
|
||||||
|
|
||||||
|
if (gotbytes == 1) OnRxChar(buf[0]);
|
||||||
} while (gotbytes > 0);
|
} while (gotbytes > 0);
|
||||||
}
|
}
|
||||||
if ((eventMask & Win32Com.EV_TXEMPTY) != 0)
|
|
||||||
{
|
if ((eventMask & Win32Com.EV_TXEMPTY) != 0) OnTxDone();
|
||||||
OnTxDone();
|
|
||||||
}
|
|
||||||
if ((eventMask & Win32Com.EV_BREAK) != 0) OnBreak();
|
if ((eventMask & Win32Com.EV_BREAK) != 0) OnBreak();
|
||||||
|
|
||||||
uint i = 0;
|
uint i = 0;
|
||||||
@ -584,11 +766,12 @@ namespace PInvokeSerialPort
|
|||||||
|
|
||||||
private bool CheckOnline()
|
private bool CheckOnline()
|
||||||
{
|
{
|
||||||
if ((_rxException != null) && (!_rxExceptionReported))
|
if (_rxException != null && !_rxExceptionReported)
|
||||||
{
|
{
|
||||||
_rxExceptionReported = true;
|
_rxExceptionReported = true;
|
||||||
ThrowException("rx");
|
ThrowException("rx");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_online)
|
if (_online)
|
||||||
{
|
{
|
||||||
uint f;
|
uint f;
|
||||||
@ -596,147 +779,12 @@ namespace PInvokeSerialPort
|
|||||||
ThrowException("Offline");
|
ThrowException("Offline");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_auto)
|
if (_auto)
|
||||||
{
|
if (Open())
|
||||||
if (Open()) return true;
|
return true;
|
||||||
}
|
|
||||||
ThrowException("Offline");
|
ThrowException("Offline");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Port Name
|
|
||||||
/// </summary>
|
|
||||||
public string PortName { get; set; }
|
|
||||||
/// <summary>
|
|
||||||
/// Baud Rate (default: 2400) unsupported rates will throw "Bad settings"
|
|
||||||
/// </summary>
|
|
||||||
public int BaudRate = 115200;
|
|
||||||
/// <summary>
|
|
||||||
/// The parity checking scheme (default: none)
|
|
||||||
/// </summary>
|
|
||||||
public Parity Parity = Parity.None;
|
|
||||||
/// <summary>
|
|
||||||
/// Number of databits 1..8 (default: 8) unsupported values will throw "Bad settings"
|
|
||||||
/// </summary>
|
|
||||||
public int DataBits = 8;
|
|
||||||
/// <summary>
|
|
||||||
/// Number of stop bits (default: one)
|
|
||||||
/// </summary>
|
|
||||||
public StopBits StopBits = StopBits.One;
|
|
||||||
/// <summary>
|
|
||||||
/// If true, transmission is halted unless CTS is asserted by the remote station (default: false)
|
|
||||||
/// </summary>
|
|
||||||
public bool TxFlowCts;
|
|
||||||
/// <summary>
|
|
||||||
/// If true, transmission is halted unless DSR is asserted by the remote station (default: false)
|
|
||||||
/// </summary>
|
|
||||||
public bool TxFlowDsr;
|
|
||||||
/// <summary>
|
|
||||||
/// If true, transmission is halted when Xoff is received and restarted when Xon is received (default: false)
|
|
||||||
/// </summary>
|
|
||||||
public bool TxFlowX;
|
|
||||||
/// <summary>
|
|
||||||
/// 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.
|
|
||||||
/// </summary>
|
|
||||||
public bool TxWhenRxXoff = true;
|
|
||||||
/// <summary>
|
|
||||||
/// If true, received characters are ignored unless DSR is asserted by the remote station (default: false)
|
|
||||||
/// </summary>
|
|
||||||
public bool RxGateDsr;
|
|
||||||
/// <summary>
|
|
||||||
/// If true, Xon and Xoff characters are sent to control the data flow from the remote station (default: false)
|
|
||||||
/// </summary>
|
|
||||||
public bool RxFlowX;
|
|
||||||
/// <summary>
|
|
||||||
/// Specifies the use to which the RTS output is put (default: none)
|
|
||||||
/// </summary>
|
|
||||||
public HsOutput UseRts = HsOutput.None;
|
|
||||||
/// <summary>
|
|
||||||
/// Specidies the use to which the DTR output is put (default: none)
|
|
||||||
/// </summary>
|
|
||||||
public HsOutput UseDtr = HsOutput.None;
|
|
||||||
/// <summary>
|
|
||||||
/// The character used to signal Xon for X flow control (default: DC1)
|
|
||||||
/// </summary>
|
|
||||||
public ASCII XonChar = ASCII.DC1;
|
|
||||||
/// <summary>
|
|
||||||
/// The character used to signal Xoff for X flow control (default: DC3)
|
|
||||||
/// </summary>
|
|
||||||
public ASCII XoffChar = ASCII.DC3;
|
|
||||||
/// <summary>
|
|
||||||
/// The number of free bytes in the reception queue at which flow is disabled (default: 2048)
|
|
||||||
/// </summary>
|
|
||||||
public int RxHighWater = 2048;
|
|
||||||
/// <summary>
|
|
||||||
/// The number of bytes in the reception queue at which flow is re-enabled (default: 512)
|
|
||||||
/// </summary>
|
|
||||||
public int RxLowWater = 512;
|
|
||||||
/// <summary>
|
|
||||||
/// Multiplier. Max time for Send in ms = (Multiplier * Characters) + Constant
|
|
||||||
/// (default: 0 = No timeout)
|
|
||||||
/// </summary>
|
|
||||||
public int SendTimeoutMultiplier;
|
|
||||||
/// <summary>
|
|
||||||
/// Constant. Max time for Send in ms = (Multiplier * Characters) + Constant (default: 0)
|
|
||||||
/// </summary>
|
|
||||||
public int SendTimeoutConstant;
|
|
||||||
/// <summary>
|
|
||||||
/// Requested size for receive queue (default: 0 = use operating system default)
|
|
||||||
/// </summary>
|
|
||||||
public int RxQueue;
|
|
||||||
/// <summary>
|
|
||||||
/// Requested size for transmit queue (default: 0 = use operating system default)
|
|
||||||
/// </summary>
|
|
||||||
public int TxQueue;
|
|
||||||
/// <summary>
|
|
||||||
/// If true, the port will automatically re-open on next send if it was previously closed due
|
|
||||||
/// to an error (default: false)
|
|
||||||
/// </summary>
|
|
||||||
public bool AutoReopen;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 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.
|
|
||||||
/// </summary>
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user