📄 commbase.cs
字号:
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() {}
/// <summary>
/// Override this to take action when a ring condition is signalled by an attached modem.
/// </summary>
protected virtual void OnRing() {}
/// <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;
AutoResetEvent sg = new AutoResetEvent(false);
Win32Com.OVERLAPPED ov = new Win32Com.OVERLAPPED();
IntPtr unmanagedOv = Marshal.AllocHGlobal(Marshal.SizeOf(ov));
ov.Offset = 0; ov.OffsetHigh = 0;
ov.hEvent = sg.Handle;
Marshal.StructureToPtr(ov, unmanagedOv, true);
uint eventMask = 0;
IntPtr uMask = Marshal.AllocHGlobal(Marshal.SizeOf(eventMask));
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);
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))
{
StringBuilder s = new StringBuilder("UART Error: ", 40);
if ((errs & Win32Com.CE_FRAME) != 0) s = s.Append("Framing,");
if ((errs & Win32Com.CE_IOE) != 0) s = s.Append("IO,");
if ((errs & Win32Com.CE_OVERRUN) != 0) s = s.Append("Overrun,");
if ((errs & Win32Com.CE_RXOVER) != 0) s = s.Append("Receive Cverflow,");
if ((errs & Win32Com.CE_RXPARITY) != 0) s = s.Append("Parity,");
if ((errs & Win32Com.CE_TXFULL) != 0) s = s.Append("Transmit Overflow,");
s.Length = s.Length - 1;
throw new CommPortException(s.ToString());
}
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))
{
if (Marshal.GetLastWin32Error() == Win32Com.ERROR_IO_PENDING)
{
Win32Com.CancelIo(hPort);
gotbytes = 0;
}
else
{
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_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)
{
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()
{
uint f;
if ((rxException != null) && (!rxExceptionReported))
{
rxExceptionReported = true;
ThrowException("rx");
}
if (online)
{
if (Win32Com.GetHandleInformation(hPort, out f)) return true;
ThrowException("Offline");
return false;
}
else
{
if (auto)
{
if (Open()) return true;
}
ThrowException("Offline");
return false;
}
}
}
/// <summary>
/// Overlays CommBase to provide line or packet oriented communications to derived classes. ASCII strings
/// are sent and received and the Transact method is added which transmits a string and then blocks until
/// a reply string has been received (subject to a timeout).
/// </summary>
public abstract class CommLine : CommBase {
private byte[] RxBuffer;
private uint RxBufferP = 0;
private ASCII RxTerm;
private ASCII[] TxTerm;
private ASCII[] RxFilter;
private string RxString = "";
private ManualResetEvent TransFlag = new ManualResetEvent(true);
private uint TransTimeout;
/// <summary>
/// Extends CommBaseSettings to add the settings used by CommLine.
/// </summary>
public class CommLineSettings : CommBase.CommBaseSettings
{
/// <summary>
/// Maximum size of received string (default: 256)
/// </summary>
public int rxStringBufferSize = 256;
/// <summary>
/// ASCII code that terminates a received string (default: CR)
/// </summary>
public ASCII rxTerminator = ASCII.CR;
/// <summary>
/// ASCII codes that will be ignored in received string (default: null)
/// </summary>
public ASCII[] rxFilter;
/// <summary>
/// Maximum time (ms) for the Transact method to complete (default: 500)
/// </summary>
public int transactTimeout = 500;
/// <summary>
/// ASCII codes transmitted after each Send string (default: null)
/// </summary>
public ASCII[] txTerminator;
public static new CommLineSettings LoadFromXML(Stream s)
{
return (CommLineSettings)LoadFromXML(s, typeof(CommLineSettings));
}
}
/// <summary>
/// Queue the ASCII representation of a string and then the set terminator bytes for sending.
/// </summary>
/// <param name="toSend">String to be sent.</param>
protected void Send(string toSend)
{
ASCIIEncoding enc = new ASCIIEncoding();
uint l = (uint)enc.GetByteCount(toSend);
if (TxTerm != null) l += (uint)TxTerm.GetLength(0);
byte[] b = new byte[l];
byte[] s = enc.GetBytes(toSend);
int i;
for (i = 0; (i <= s.GetUpperBound(0)); i++) b[i] = s[i];
if (TxTerm != null) for (int j = 0; (j <= TxTerm.GetUpperBound(0)); j++, i++) b[i] = (byte)TxTerm[j];
Send(b);
}
/// <summary>
/// Transmits the ASCII representation of a string followed by the set terminator bytes and then
/// awaits a response string.
/// </summary>
/// <param name="toSend">The string to be sent.</param>
/// <returns>The response string.</returns>
protected string Transact(string toSend) {
Send(toSend);
TransFlag.Reset();
if (!TransFlag.WaitOne((int)TransTimeout, false)) ThrowException("Timeout");
string s;
lock(RxString) {s = RxString;}
return s;
}
/// <summary>
/// If a derived class overrides ComSettings(), it must call this prior to returning the settings to
/// the base class.
/// </summary>
/// <param name="s">Class containing the appropriate settings.</param>
protected void Setup(CommLineSettings s) {
RxBuffer = new byte[s.rxStringBufferSize];
RxTerm = s.rxTerminator;
RxFilter = s.rxFilter;
TransTimeout = (uint)s.transactTimeout;
TxTerm = s.txTerminator;
}
/// <summary>
/// Override this to process unsolicited input lines (not a result of Transact).
/// </summary>
/// <param name="s">String containing the received ASCII text.</param>
protected virtual void OnRxLine(string s) {}
protected override void OnRxChar(byte ch) {
ASCII ca = (ASCII)ch;
if ((ca == RxTerm) || (RxBufferP > RxBuffer.GetUpperBound(0))) {
ASCIIEncoding enc = new ASCIIEncoding();
lock(RxString) {RxString = enc.GetString(RxBuffer, 0, (int)RxBufferP);}
RxBufferP = 0;
if (TransFlag.WaitOne(0,false)) {
OnRxLine(RxString);
} else {
TransFlag.Set();
}
} else {
bool wr = true;
if (RxFilter != null) {
for (int i=0; i <= RxFilter.GetUpperBound(0); i++) if (RxFilter[i] == ca) wr = false;
}
if (wr) {
RxBuffer[RxBufferP] = ch;
RxBufferP++;
}
}
}
}
/// <summary>
/// Exception used for all errors.
/// </summary>
public class CommPortException : ApplicationException
{
/// <summary>
/// Constructor for raising direct exceptions
/// </summary>
/// <param name="desc">Description of error</param>
public CommPortException(string desc) : base(desc) {}
/// <summary>
/// Constructor for re-raising exceptions from receive thread
/// </summary>
/// <param name="e">Inner exception raised on receive thread</param>
public CommPortException(Exception e) : base("Receive Thread Exception", e) {}
}
public class Win32Com {
/// <summary>
/// Opening Testing and Closing the Port Handle.
/// </summary>
[DllImport("kernel32.dll", SetLastError=true)]
public static extern IntPtr CreateFile(String lpFileName, UInt32 dwDesiredAccess, UInt32 dwShareMode,
IntPtr lpSecurityAttributes, UInt32 dwCreationDisposition, UInt32 dwFlagsAndAttributes,
IntPtr hTemplateFile);
//Constants for errors:
public const UInt32 ERROR_FILE_NOT_FOUND = 2;
public const UInt32 ERROR_INVALID_NAME = 123;
public const UInt32 ERROR_ACCESS_DENIED = 5;
public const UInt32 ERROR_IO_PENDING = 997;
//Constants for return value:
public const Int32 INVALID_HANDLE_VALUE = -1;
//Constants for dwFlagsAndAttributes:
public const UInt32 FILE_FLAG_OVERLAPPED = 0x40000000;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -