📄 commbase.cs
字号:
public long InQueueSize {get{return (long)inQueueSize;}}
/// <summary>
/// Total size of output queue (0 means information unavailable)
/// </summary>
public long OutQueueSize {get{return (long)outQueueSize;}}
public override string ToString()
{
StringBuilder m = new StringBuilder("The reception queue is ", 60);
if (inQueueSize == 0)
{
m.Append("of unknown size and ");
}
else
{
m.Append(inQueueSize.ToString() + " bytes long and ");
}
if (inQueue == 0)
{
m.Append("is empty.");
}
else if (inQueue == 1)
{
m.Append("contains 1 byte.");
}
else
{
m.Append("contains ");
m.Append(inQueue.ToString());
m.Append(" bytes.");
}
m.Append(" The transmission queue is ");
if (outQueueSize == 0)
{
m.Append("of unknown size and ");
}
else
{
m.Append(outQueueSize.ToString() + " bytes long and ");
}
if (outQueue == 0)
{
m.Append("is empty");
}
else if (outQueue == 1)
{
m.Append("contains 1 byte. It is ");
}
else
{
m.Append("contains ");
m.Append(outQueue.ToString());
m.Append(" bytes. It is ");
}
if (outQueue > 0)
{
if (ctsHold || dsrHold || rlsdHold || xoffHold || xoffSent)
{
m.Append("holding on");
if (ctsHold) m.Append(" CTS");
if (dsrHold) m.Append(" DSR");
if (rlsdHold) m.Append(" RLSD");
if (xoffHold) m.Append(" Rx XOff");
if (xoffSent) m.Append(" Tx XOff");
}
else
{
m.Append("pumping data");
}
}
m.Append(". The immediate buffer is ");
if (immediateWaiting)
m.Append("full.");
else
m.Append("empty.");
return m.ToString();
}
}
/// <summary>
/// Get the status of the queues
/// </summary>
/// <returns>Queue status object</returns>
protected QueueStatus GetQueueStatus()
{
Win32Com.COMSTAT cs;
Win32Com.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);
}
// JH 1.3. Added for this version.
/// <summary>
/// Test if the line is congested (data being queued for send faster than it is being dequeued)
/// This detects if baud rate is too slow or if handshaking is not allowing enough transmission
/// time. It should be called at reasonably long fixed intervals. If data has been sent during
/// the interval, congestion is reported if the queue was never empty during the interval.
/// </summary>
/// <returns>True if congested</returns>
protected bool IsCongested()
{
bool e;
if (!dataQueued) return false;
lock(empty) {e = empty[0]; empty[0] = false;}
dataQueued = false;
return !e;
}
/// <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))
//JH 1.3: Was 1, should be 0:
stateRTS = 0;
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>
/// Override this to provide settings. (NB this is called during Open method)
/// </summary>
/// <returns>CommBaseSettings, or derived object with required settings initialised</returns>
protected virtual CommBaseSettings CommSettings() {return new CommBaseSettings();}
/// <summary>
/// Override this to provide processing after the port is openned (i.e. to configure remote
/// device or just check presence).
/// </summary>
/// <returns>false to close the port again</returns>
protected virtual bool AfterOpen() {return true;}
/// <summary>
/// Override this to provide processing prior to port closure.
/// </summary>
/// <param name="error">True if closing due to an error</param>
protected virtual void BeforeClose(bool error) {}
/// <summary>
/// Override this to process received bytes.
/// </summary>
/// <param name="ch">The byte that was received</param>
protected virtual void OnRxChar(byte ch) {}
/// <summary>
/// Override this to take action when transmission is complete (i.e. all bytes have actually
/// been sent, not just queued).
/// </summary>
protected virtual void OnTxDone() {}
/// <summary>
/// Override this to take action when a break condition is detected on the input line.
/// </summary>
protected virtual void OnBreak() {}
//JH 1.3: Deleted OnRing() which was never called: use OnStatusChange instead (Thanks Jim Foster)
/// <summary>
/// Override this to take action when one or more modem status inputs change state
/// </summary>
/// <param name="mask">The status inputs that have changed state</param>
/// <param name="state">The state of the status inputs</param>
protected virtual void OnStatusChange(ModemStatus mask, ModemStatus state) {}
/// <summary>
/// Override this to take action when the reception thread closes due to an exception being thrown.
/// </summary>
/// <param name="e">The exception which was thrown</param>
protected virtual void OnRxException(Exception e) {}
private void ReceiveThread() {
byte[] buf = new Byte[1];
uint gotbytes;
bool starting;
starting = true;
AutoResetEvent sg = new AutoResetEvent(false);
Win32Com.OVERLAPPED ov = new Win32Com.OVERLAPPED();
IntPtr unmanagedOv;
IntPtr uMask;
uint eventMask = 0;
unmanagedOv = Marshal.AllocHGlobal(Marshal.SizeOf(ov));
uMask = Marshal.AllocHGlobal(Marshal.SizeOf(eventMask));
ov.Offset = 0; ov.OffsetHigh = 0;
ov.hEvent = sg.Handle;
Marshal.StructureToPtr(ov, unmanagedOv, true);
try
{
while(true)
{
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);
//JH 1.2: Tells the main thread that this thread is ready for action.
if (starting) {startEvent.Set(); starting = false;}
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);
if ((eventMask & Win32Com.EV_ERR) != 0)
{
UInt32 errs;
if (Win32Com.ClearCommError(hPort, out errs, IntPtr.Zero))
{
//JH 1.2: BREAK condition has an error flag and and an event flag. Not sure if both
//are always raised, so if CE_BREAK is only error flag ignore it and set the EV_BREAK
//flag for normal handling. Also made more robust by handling case were no recognised
//error was present in the flags. (Thanks to Fred Pittroff for finding this problem!)
int ec = 0;
StringBuilder s = new StringBuilder("UART Error: ", 40);
if ((errs & Win32Com.CE_FRAME) != 0) {s = s.Append("Framing,"); ec++;}
if ((errs & Win32Com.CE_IOE) != 0) {s = s.Append("IO,"); ec++;}
if ((errs & Win32Com.CE_OVERRUN) != 0) {s = s.Append("Overrun,"); ec++;}
if ((errs & Win32Com.CE_RXOVER) != 0) {s = s.Append("Receive Cverflow,"); ec++;}
if ((errs & Win32Com.CE_RXPARITY) != 0) {s = s.Append("Parity,"); ec++;}
if ((errs & Win32Com.CE_TXFULL) != 0) {s = s.Append("Transmit Overflow,"); ec++;}
if (ec > 0)
{
s.Length = s.Length - 1;
throw new CommPortException(s.ToString());
}
else
{
if (errs == Win32Com.CE_BREAK)
{
eventMask |= Win32Com.EV_BREAK;
}
else
{
throw new CommPortException("IO Error [003]");
}
}
}
else
{
throw new CommPortException("IO Error [003]");
}
}
if ((eventMask & Win32Com.EV_RXCHAR) != 0)
{
do
{
gotbytes = 0;
if (!Win32Com.ReadFile(hPort, buf, 1, out gotbytes, unmanagedOv))
{
//JH 1.1: Removed ERROR_IO_PENDING handling as comm timeouts have now
//been set so ReadFile returns immediately. This avoids use of CancelIo
//which was causing loss of data. Thanks to Daniel Moth for suggesting this
//might be a problem, and to many others for reporting that it was!
int x = Marshal.GetLastWin32Error();
throw new CommPortException("IO Error [004]");
}
if (gotbytes == 1) OnRxChar(buf[0]);
} while (gotbytes > 0);
}
if ((eventMask & Win32Com.EV_TXEMPTY) != 0)
{
//JH1.3:
lock(empty) empty[0] = true;
OnTxDone();
}
if ((eventMask & Win32Com.EV_BREAK) != 0) OnBreak();
uint i = 0;
if ((eventMask & Win32Com.EV_CTS) != 0) i |= Win32Com.MS_CTS_ON;
if ((eventMask & Win32Com.EV_DSR) != 0) i |= Win32Com.MS_DSR_ON;
if ((eventMask & Win32Com.EV_RLSD) != 0) i |= Win32Com.MS_RLSD_ON;
if ((eventMask & Win32Com.EV_RING) != 0) i |= Win32Com.MS_RING_ON;
if (i != 0)
{
uint f;
if (!Win32Com.GetCommModemStatus(hPort, out f)) throw new CommPortException("IO Error [005]");
OnStatusChange(new ModemStatus(i), new ModemStatus(f));
}
}
}
catch (Exception e)
{
//JH 1.3: Added for shutdown robustness (Thanks to Fred Pittroff, Mark Behner and Kevin Williamson!), .
Win32Com.CancelIo(hPort);
if (uMask != IntPtr.Zero) Marshal.FreeHGlobal(uMask);
if (unmanagedOv != IntPtr.Zero) Marshal.FreeHGlobal(unmanagedOv);
if (!(e is ThreadAbortException))
{
rxException = e;
OnRxException(e);
}
}
}
private bool CheckOnline()
{
if ((rxException != null) && (!rxExceptionReported))
{
rxExceptionReported = true;
ThrowException("rx");
}
if (online)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -