|
发表于 2015-2-3 17:11:04
|
显示全部楼层
- using System;
- using System.Collections.Generic;
- using System.Text;
- namespace SerialEngineLibrary
- {
- using System.Security;
- using Microsoft.Win32;
- using System.Diagnostics;
- using System.Threading;
- using System.Security.Permissions;
- using Microsoft.Win32.SafeHandles;
- using System.Runtime.InteropServices;
- public unsafe sealed class SerialEngine : IDisposable
- {
- public const uint MAXDWORD = 0xFFFFFFFFu;
- public delegate void DataArrivalEventHandler(byte[] data, int count);
- public delegate void EngineEventHandler(EngineEventType ev, object arg);
- public NativeAPI.COMMPROP m_commProp = default(NativeAPI.COMMPROP);
- #region 私有变量。
- private NativeAPI.COMMTIMEOUTS m_timeouts = default(NativeAPI.COMMTIMEOUTS);
- private NativeAPI.DCB m_dcb = default(NativeAPI.DCB);
- private CommEvMask m_commEventMask = CommEvMask.NONE;
- private int m_readBufferSize, m_writeBufferSize;
- private SafeFileHandle m_serialPort = null;
- private bool m_isAsyncMode = false;
- private bool m_keepLooping = false;
- private string m_portName = "COM1";
-
- #endregion
- #region 构造器。
- public SerialEngine()
- {
- m_dcb.DCBlength = (uint)Marshal.SizeOf(m_dcb);
- this.BaudRate = 9600;
- this.BinaryMode = true;
- this.Parity = ParityValue.NO;
- this.OutxCtsFlow = false;
- this.OutxDsrFlow = false;
- this.DtrControl = DtrControlValue.DISABLE;
- this.DsrSensitivity = false;
- this.TXContinueOnXoff = true;
- this.OutXEnable = false;
- this.InXEnable = false;
- this.ErrorCharEnable = false;
- this.NullDiscarded = false;
- this.RtsControl = RtsControlValue.DISABLE;
- this.AbortOnError = false;
- this.XonLim = 8;
- this.XoffLim = 1000;
- this.ByteSize = 8;
- this.StopBits = StopBitsValue.ONE;
- this.XonChar = (byte)'<';
- this.XoffChar = (byte)'>';
- this.ErrorChar = (byte)'?';
- this.EofChar = (byte)'\n';
- this.EventChar = (byte)'!';
- this.ReadBufferSize = 4096;
- this.WriteBufferSize = 2048;
- this.ReadIntervalTimeout = 30;
- this.ReadTotalTimeoutMultiplier = 0;
- this.ReadTotalTimeoutConstant = 500;
- this.WriteTotalTimeoutMultiplier = 5;
- this.WriteTotalTimeoutConstant = 1000;
- /* 开启9个受支持的串口事件侦测标志 */
- m_commEventMask = (CommEvMask)0x1FFu;
- }
- #endregion
- #region 属性。
- public SafeFileHandle Handle
- {
- get { return m_serialPort; }
- }
- public bool IsOpen
- {
- get
- {
- if (m_serialPort == null)
- {
- return false;
- }
- if (m_serialPort.IsInvalid)
- {
- m_serialPort = null;
- return false;
- }
- if (m_serialPort.IsClosed)
- {
- m_serialPort = null;
- return false;
- }
- return true;
- }
- }
- public bool IsAsyncMode
- {
- get { return m_isAsyncMode; }
- }
- public CommEvMask EventMask
- {
- get { return m_commEventMask; }
- set { m_commEventMask = value; }
- }
- public int ReadBufferSize
- {
- get { return m_readBufferSize; }
- set { m_readBufferSize = value; }
- }
- public int WriteBufferSize
- {
- get { return m_writeBufferSize; }
- set { m_writeBufferSize = value; }
- }
- public string PortName
- {
- get { return m_portName; }
- set
- {
- m_portName = value;
- }
- }
- public uint BaudRate
- {
- get { return m_dcb.BaudRate; }
- set
- {
- m_dcb.BaudRate = value;
- if (IsOpen)
- {
- if (!NativeAPI.SetCommState(m_serialPort, ref m_dcb))
- {
- throw new ApplicationException("波特率设置失败");
- }
- }
- }
- }
- public bool BinaryMode
- {
- get { return (m_dcb.GetFlag(NativeAPI.DcbFlags.fBinary, 1) != 0); }
- set { m_dcb.SetFlag(NativeAPI.DcbFlags.fBinary, 1, value ? 1u : 0u); }
- }
- public ParityValue Parity
- {
- get { return (ParityValue)m_dcb.Parity; }
- set
- {
- m_dcb.Parity = (byte)value;
- if (value == ParityValue.NO)
- {
- m_dcb.SetFlag(NativeAPI.DcbFlags.fParity, 1, 0u);
- }
- else
- {
- m_dcb.SetFlag(NativeAPI.DcbFlags.fParity, 1, 1u);
- }
- }
- }
- public bool OutxCtsFlow
- {
- get { return (m_dcb.GetFlag(NativeAPI.DcbFlags.fOutxCtsFlow, 1) != 0); }
- set { m_dcb.SetFlag(NativeAPI.DcbFlags.fOutxCtsFlow, 1, value ? 1u : 0u); }
- }
- public bool OutxDsrFlow
- {
- get { return (m_dcb.GetFlag(NativeAPI.DcbFlags.fOutxDsrFlow, 1) != 0); }
- set { m_dcb.SetFlag(NativeAPI.DcbFlags.fOutxDsrFlow, 1, value ? 1u : 0u); }
- }
- public DtrControlValue DtrControl
- {
- get { return (DtrControlValue)m_dcb.GetFlag(NativeAPI.DcbFlags.fDtrControl, 2); }
- set { m_dcb.SetFlag(NativeAPI.DcbFlags.fDtrControl, 2, (uint)value); }
- }
- public bool DsrSensitivity
- {
- get { return (m_dcb.GetFlag(NativeAPI.DcbFlags.fDsrSensitivity, 1) != 0); }
- set { m_dcb.SetFlag(NativeAPI.DcbFlags.fDsrSensitivity, 1, value ? 1u : 0u); }
- }
- public bool TXContinueOnXoff
- {
- get { return (m_dcb.GetFlag(NativeAPI.DcbFlags.fTXContinueOnXoff, 1) != 0); }
- set { m_dcb.SetFlag(NativeAPI.DcbFlags.fTXContinueOnXoff, 1, value ? 1u : 0u); }
- }
- public bool OutXEnable
- {
- get { return (m_dcb.GetFlag(NativeAPI.DcbFlags.fOutX, 1) != 0); }
- set { m_dcb.SetFlag(NativeAPI.DcbFlags.fOutX, 1, value ? 1u : 0u); }
- }
- public bool InXEnable
- {
- get { return (m_dcb.GetFlag(NativeAPI.DcbFlags.fInX, 1) != 0); }
- set { m_dcb.SetFlag(NativeAPI.DcbFlags.fInX, 1, value ? 1u : 0u); }
- }
- public bool ErrorCharEnable
- {
- get { return (m_dcb.GetFlag(NativeAPI.DcbFlags.fErrorChar, 1) != 0); }
- set { m_dcb.SetFlag(NativeAPI.DcbFlags.fErrorChar, 1, value ? 1u : 0u); }
- }
- public bool NullDiscarded
- {
- get { return (m_dcb.GetFlag(NativeAPI.DcbFlags.fNull, 1) != 0); }
- set { m_dcb.SetFlag(NativeAPI.DcbFlags.fNull, 1, value ? 1u : 0u); }
- }
- public RtsControlValue RtsControl
- {
- get { return (RtsControlValue)m_dcb.GetFlag(NativeAPI.DcbFlags.fRtsControl, 2); }
- set { m_dcb.SetFlag(NativeAPI.DcbFlags.fRtsControl, 2, (uint)value); }
- }
- public bool AbortOnError
- {
- get { return (m_dcb.GetFlag(NativeAPI.DcbFlags.fAbortOnError, 1) != 0); }
- set { m_dcb.SetFlag(NativeAPI.DcbFlags.fAbortOnError, 1, value ? 1u : 0u); }
- }
- public ushort XonLim
- {
- get { return m_dcb.XonLim; }
- set { m_dcb.XonLim = value; }
- }
- public ushort XoffLim
- {
- get { return m_dcb.XoffLim; }
- set { m_dcb.XoffLim = value; }
- }
- public byte ByteSize
- {
- get { return m_dcb.ByteSize; }
- set { m_dcb.ByteSize = value; }
- }
- public StopBitsValue StopBits
- {
- get { return (StopBitsValue)m_dcb.StopBits; }
- set { m_dcb.StopBits = (byte)value; }
- }
- public byte XonChar
- {
- get { return m_dcb.XonChar; }
- set { m_dcb.XonChar = value; }
- }
- public byte XoffChar
- {
- get { return m_dcb.XoffChar; }
- set { m_dcb.XoffChar = value; }
- }
- public byte ErrorChar
- {
- get { return m_dcb.ErrorChar; }
- set { m_dcb.ErrorChar = value; }
- }
- public byte EofChar
- {
- get { return m_dcb.EofChar; }
- set { m_dcb.EofChar = value; }
- }
- public byte EventChar
- {
- get { return m_dcb.EvtChar; }
- set { m_dcb.EvtChar = value; }
- }
- public uint ReadIntervalTimeout
- {
- get { return m_timeouts.ReadIntervalTimeout; }
- set { m_timeouts.ReadIntervalTimeout = value; }
- }
- public uint ReadTotalTimeoutMultiplier
- {
- get { return m_timeouts.ReadTotalTimeoutMultiplier; }
- set { m_timeouts.ReadTotalTimeoutMultiplier = value; }
- }
- public uint ReadTotalTimeoutConstant
- {
- get { return m_timeouts.ReadTotalTimeoutConstant; }
- set { m_timeouts.ReadTotalTimeoutConstant = value; }
- }
- public uint WriteTotalTimeoutMultiplier
- {
- get { return m_timeouts.WriteTotalTimeoutMultiplier; }
- set { m_timeouts.WriteTotalTimeoutMultiplier = value; }
- }
- public uint WriteTotalTimeoutConstant
- {
- get { return m_timeouts.WriteTotalTimeoutConstant; }
- set { m_timeouts.WriteTotalTimeoutConstant = value; }
- }
- #endregion
- #region 事件。
- public event DataArrivalEventHandler DataArrivalEvent;
- public event EngineEventHandler EngineEvent;
- #endregion
- #region 基本操作方法。
- public void Close()
- {
- m_keepLooping = false;
- if (IsOpen)
- {
- /* 使WaitCommEvent立即返回,用于通知CommEventMonitor线程 */
- NativeAPI.SetCommMask(m_serialPort, 0);
- /* 使重叠IO立即结束,用于通知BackgroundDataReceiver线程 */
- DiscardAllBuffers();
- /* 关闭端口的设备句柄 */
- m_serialPort.Close();
- m_serialPort = null;
- }
- }
- private void Dispose(bool explicitDisposing)
- {
- Close();
- if (explicitDisposing)
- {
- GC.SuppressFinalize(this);
- }
- }
- public void Dispose()
- {
- Dispose(true);
- }
- ~SerialEngine()
- {
- Dispose(false);
- }
- public bool DiscardInBuffer()
- {
- return NativeAPI.PurgeComm(m_serialPort, (NativeAPI.PurgeValue.RXABORT | NativeAPI.PurgeValue.RXCLEAR));
- }
- public bool DiscardOutBuffer()
- {
- return NativeAPI.PurgeComm(m_serialPort, (NativeAPI.PurgeValue.TXABORT | NativeAPI.PurgeValue.TXCLEAR));
- }
- public bool DiscardAllBuffers()
- {
- NativeAPI.PurgeValue flags = 0;
- flags |= (NativeAPI.PurgeValue.RXABORT | NativeAPI.PurgeValue.RXCLEAR);
- flags |= (NativeAPI.PurgeValue.TXABORT | NativeAPI.PurgeValue.TXCLEAR);
- return NativeAPI.PurgeComm(m_serialPort, flags);
- }
- public bool TransmitCommChar(byte c)
- {
- return NativeAPI.TransmitCommChar(m_serialPort, c);
- }
- public bool SetCommMask(CommEvMask mask)
- {
- m_commEventMask = mask;
- return NativeAPI.SetCommMask(m_serialPort, m_commEventMask);
- }
- public bool ClearCommError(ref CommErrors errors, ref COMSTAT stat)
- {
- if (m_serialPort == null)
- {
- return false;
- }
- return NativeAPI.ClearCommError(m_serialPort, out errors, out stat);
- }
- public bool GetCommModemStatus(ref ModemStats stat)
- {
- if (m_serialPort == null)
- {
- return false;
- }
- return NativeAPI.GetCommModemStatus(m_serialPort, out stat);
- }
- public bool EscapeCommFunction(CommEscape cmd)
- {
- return NativeAPI.EscapeCommFunction(m_serialPort, cmd);
- }
- public bool CommBreakControl(bool setBreak)
- {
- if (setBreak)
- {
- return NativeAPI.SetCommBreak(m_serialPort);
- }
- return NativeAPI.ClearCommBreak(m_serialPort);
- }
- #endregion
- #region 主体功能方法。
- public void Open(bool isAsyncMode)
- {
- if (string.IsNullOrEmpty(m_portName) || !m_portName.StartsWith("COM", StringComparison.OrdinalIgnoreCase))
- {
- throw new ApplicationException("端口名称不对");
- }
- if (IsOpen)
- {
- throw new ApplicationException("端口已经打开");
- }
- SafeFileHandle _handle = NativeAPI.CreateFile(@"\\." + m_portName,
- (NativeAPI.GENERIC_READ | NativeAPI.GENERIC_WRITE), NativeAPI.FileShare.None, IntPtr.Zero,
- NativeAPI.FileMode.OpenExisting, NativeAPI.FILE_FLAG_OVERLAPPED, IntPtr.Zero);
- if (_handle.IsInvalid)
- {
- throw new ApplicationException("无法打开端口");
- }
- try
- {
- int fileType = NativeAPI.GetFileType(_handle);
- if ((NativeAPI.FILE_TYPE_CHAR != fileType) && (NativeAPI.FILE_TYPE_UNKNOWN != fileType))
- {
- throw new ApplicationException("打开的端口不受支持");
- }
- this.m_serialPort = _handle; /* 端口的文件句柄保存到私有字段,就靠它来操作硬件的 */
- if (!NativeAPI.SetupComm(m_serialPort, m_readBufferSize, m_writeBufferSize))
- {
- throw new ApplicationException("缓冲区容量设置失败");
- }
- ModemStats modemStat = 0;
- NativeAPI.COMMPROP commProp = new NativeAPI.COMMPROP();
- commProp.wPacketLength = (ushort)Marshal.SizeOf(commProp);
- bool b1 = NativeAPI.GetCommProperties(m_serialPort, ref commProp);
- if ((!b1) || (commProp.wPacketLength != Marshal.SizeOf(commProp)))
- {
- if (commProp.wPacketLength == 0)
- {
- throw new ApplicationException("COMMPROP长度错误");
- }
- IntPtr packet = Marshal.AllocHGlobal(commProp.wPacketLength);
- try
- {
- Marshal.StructureToPtr(commProp, packet, false/* packet为新分配内存块,所以fDeleteOld为false即可 */);
- b1 = NativeAPI.GetCommProperties(m_serialPort, packet);
- Marshal.PtrToStructure(packet, commProp);
- }
- finally
- {
- /* 无论如何别忘了释放非托管内存 */
- Marshal.FreeHGlobal(packet);
- }
- }
- bool b2 = NativeAPI.GetCommModemStatus(m_serialPort, out modemStat);
- if ((!b1) || (!b2))
- {
- int errorCode = Marshal.GetLastWin32Error();
- throw new ApplicationException("端口功能不全:" + errorCode.ToString());
- }
- if ((commProp.dwMaxBaud & SettableBauds.BAUD_USER) == 0)
- {
- /* 波特率不能用户自定义,只能采用预定义的值,则检查取值是否正确 */
- if (!CheckBaudSettable(ref commProp, this.BaudRate))
- {
- throw new ApplicationException("波特率不受支持");
- }
- }
- this.m_commProp = commProp; /* 将端口设备性能数据保存起来备用 */
- if (!NativeAPI.SetCommState(m_serialPort, ref m_dcb))
- {
- throw new ApplicationException("端口配置失败");
- }
- if (!NativeAPI.SetCommTimeouts(m_serialPort, ref m_timeouts))
- {
- throw new ApplicationException("超时设置失败");
- }
- if (!NativeAPI.SetCommMask(m_serialPort, m_commEventMask))
- {
- throw new ApplicationException("事件侦听标志设置失败");
- }
- this.m_keepLooping = true; /* 事件检测线程和后台接收线程循环标志 */
- this.m_isAsyncMode = isAsyncMode;
- if (this.m_isAsyncMode)
- {
- /* 如果是异步模式,就创建后台读取线程 */
- AutoResetEvent m_rxReady = new AutoResetEvent(false);
- ThreadPool.QueueUserWorkItem(new WaitCallback(BackgroundDataReceiver), m_rxReady);
- m_rxReady.WaitOne();
- m_rxReady.Close();
- }
- /* 创建串口事件侦听线程,捕捉串口事件 */
- AutoResetEvent m_evReady = new AutoResetEvent(false);
- ThreadPool.QueueUserWorkItem(new WaitCallback(CommEventMonitor), m_evReady);
- m_evReady.WaitOne();
- m_evReady.Close();
- }
- catch
- {
- m_keepLooping = false;
- m_serialPort = null;
- _handle.Close();
- throw;
- }
- }
- private int WriteFileInternal(byte* pbuf, int num, ref NativeAPI.NativeOverlapped ov)
- {
- int numBytesWrite = 0;
- if (NativeAPI.WriteFile(m_serialPort, pbuf, num, out numBytesWrite, ref ov) == 0)
- {
- int iResult = Marshal.GetLastWin32Error();
- if (iResult != NativeAPI.ERROR_IO_PENDING)
- {
- throw new ApplicationException("WIN32ERROR=" + iResult.ToString());
- }
- if (!NativeAPI.GetOverlappedResult(m_serialPort, ref ov, out numBytesWrite, true))
- {
- iResult = Marshal.GetLastWin32Error();
- throw new ApplicationException("WIN32ERROR=" + iResult.ToString());
- }
- }
- return numBytesWrite;
- }
- public void SendData(byte[] data, int index, int count)
- {
- ManualResetEvent mev = new ManualResetEvent(false);
- try
- {
- SendData(data, index, count, mev);
- }
- catch
- {
- throw;
- }
- finally
- {
- mev.Close();
- }
- }
- public void SendData(byte[] data, int index, int count, WaitHandle waitObj)
- {
- if (!IsOpen)
- {
- throw new ApplicationException("端口未打开不能发送数据");
- }
- NativeAPI.NativeOverlapped ovl = new NativeAPI.NativeOverlapped();
- GCHandle objPin = GCHandle.Alloc(waitObj);
- try
- {
- ovl.EventHandle = waitObj.SafeWaitHandle.DangerousGetHandle();
- fixed (byte* pdata = &data[index])
- {
- WriteFileInternal(pdata, count, ref ovl);
- }
- }
- catch
- {
- throw;
- }
- finally
- {
- objPin.Free();
- }
- }
- private int ReadFileInternal(byte* pbuf, int num, ref NativeAPI.NativeOverlapped ov)
- {
- int numBytesRead = 0;
- if (NativeAPI.ReadFile(m_serialPort, pbuf, num, out numBytesRead, ref ov) == 0)
- {
- int iResult = Marshal.GetLastWin32Error();
- if (iResult != NativeAPI.ERROR_IO_PENDING)
- {
- throw new ApplicationException("WIN32ERROR=" + iResult.ToString());
- }
- if (!NativeAPI.GetOverlappedResult(m_serialPort, ref ov, out numBytesRead, true))
- {
- iResult = Marshal.GetLastWin32Error();
- throw new ApplicationException("WIN32ERROR=" + iResult.ToString());
- }
- }
- return numBytesRead;
- }
- public int ReadData(byte[] data, int index, int num)
- {
- ManualResetEvent mev = new ManualResetEvent(false);
- try
- {
- return ReadData(data, index, num, mev);
- }
- catch
- {
- throw;
- }
- finally
- {
- mev.Close();
- }
- }
- public int ReadData(byte[] data, int index, int num, WaitHandle waitObj)
- {
- if (IsAsyncMode)
- {
- throw new ApplicationException("异步模式端口不能同步操作");
- }
- if (!IsOpen)
- {
- throw new ApplicationException("端口未打开不能读取数据");
- }
- NativeAPI.NativeOverlapped ovl = new NativeAPI.NativeOverlapped();
- GCHandle objPin = GCHandle.Alloc(waitObj);
- int numBytesRead = 0;
- try
- {
- ovl.EventHandle = waitObj.SafeWaitHandle.DangerousGetHandle();
- fixed (byte* pbuf = &data[index])
- {
- numBytesRead = ReadFileInternal(pbuf, num, ref ovl);
- }
- }
- catch
- {
- throw;
- }
- finally
- {
- objPin.Free();
- }
- return numBytesRead;
- }
- private void BackgroundDataReceiver(object state)
- {
- AutoResetEvent readyEvent = state as AutoResetEvent;
- byte[] rxBuffer = new byte[2048];
- readyEvent.Set();
- readyEvent = null;
- Thread.CurrentThread.Priority = ThreadPriority.AboveNormal;
- NativeAPI.NativeOverlapped ovl = new NativeAPI.NativeOverlapped();
- ManualResetEvent mev = new ManualResetEvent(false);
- ovl.EventHandle = mev.SafeWaitHandle.DangerousGetHandle();
- __loop:
- try
- {
- while (m_keepLooping)
- {
- int numBytesRead = 0;
- fixed (byte* pbuf = rxBuffer)
- {
- numBytesRead = ReadFileInternal(pbuf, rxBuffer.Length, ref ovl);
- }
- if (m_keepLooping)
- {
- // 不管有没有收到数据,都回调数据到达函数,这个特性很有用!
- if (DataArrivalEvent != null)
- {
- DataArrivalEvent(rxBuffer, numBytesRead);
- }
- }
- }
- }
- catch (ThreadAbortException)
- {
- Thread.ResetAbort();
- }
- catch (Exception ex)
- {
- if (m_keepLooping)
- {
- if (EngineEvent != null)
- {
- EngineEvent(EngineEventType.EngineReadError, ex.Message);
- }
- if (IsOpen)
- {
- Thread.Sleep(10);
- goto __loop;
- }
- }
- }
- mev.Close();
- }
- private void CommEventMonitor(object state)
- {
- AutoResetEvent readyEvent = state as AutoResetEvent;
- readyEvent.Set();
- readyEvent = null;
- Thread.CurrentThread.Priority = ThreadPriority.AboveNormal;
- NativeAPI.NativeOverlapped ovl = new NativeAPI.NativeOverlapped();
- ManualResetEvent mev = new ManualResetEvent(false);
- ovl.EventHandle = mev.SafeWaitHandle.DangerousGetHandle();
- __loop:
- try
- {
- while (m_keepLooping)
- {
- CommEvMask evMask = CommEvMask.NONE;
- if (!NativeAPI.WaitCommEvent(m_serialPort, out evMask, ref ovl))
- {
- int iResult = Marshal.GetLastWin32Error();
- if (iResult != NativeAPI.ERROR_IO_PENDING)
- {
- throw new ApplicationException("WIN32ERROR=" + iResult.ToString());
- }
- if (!NativeAPI.GetOverlappedResult(m_serialPort, ref ovl, out iResult, true))
- {
- iResult = Marshal.GetLastWin32Error();
- throw new ApplicationException("WIN32ERROR=" + iResult.ToString());
- }
- }
- if (m_keepLooping)
- {
- // 发送侦测到的端口事件。
- if (EngineEvent != null)
- {
- EngineEvent(EngineEventType.CommEventNormal, evMask);
- }
- }
- }
- }
- catch (ThreadAbortException)
- {
- Thread.ResetAbort();
- }
- catch (Exception ex)
- {
- if (m_keepLooping)
- {
- if (EngineEvent != null)
- {
- EngineEvent(EngineEventType.EngineEventError, ex.Message);
- }
- if (IsOpen)
- {
- Thread.Sleep(10);
- goto __loop;
- }
- }
- }
- mev.Close();
- }
- public bool DefaultEngineEventCallback(EngineEventType ev, object arg)
- {
- CommEvMask commEvent;
- switch (ev)
- {
- case EngineEventType.EngineEventError:
- case EngineEventType.EngineReadError:
- if (arg != null)
- {
- string msg = arg as string;
- if (msg.StartsWith("WIN32ERROR="))
- {
- int lastErr = Convert.ToInt32(msg.Substring(11));
- if (lastErr == NativeAPI.ERROR_ACCESS_DENIED)
- {
- this.Close();
- return true;
- }
- if (lastErr == NativeAPI.ERROR_INVALID_HANDLE)
- {
- this.Close();
- return true;
- }
- }
- }
- break;
- case EngineEventType.CommEventNormal:
- commEvent = (CommEvMask)arg;
- if ((commEvent & CommEvMask.ERR) != 0)
- {
- CommErrors errors;
- if (NativeAPI.ClearCommError(m_serialPort, out errors, IntPtr.Zero))
- {
- return true;
- }
- }
- break;
- }
- return false;
- }
-
- #endregion
- #region 辅助工具。
- public readonly static PortNameComparer pnc = new PortNameComparer();
- public static string[] GetPortNames()
- {
- RegistryKey localMachine = null;
- RegistryKey serialInfoKey = null;
- List<string> portNames = new List<string>();
- new RegistryPermission(RegistryPermissionAccess.Read, @"HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM").Assert();
- try
- {
- localMachine = Registry.LocalMachine;
- serialInfoKey = localMachine.OpenSubKey(@"HARDWARE\DEVICEMAP\SERIALCOMM", false);
- if (serialInfoKey != null)
- {
- string[] valueNames = serialInfoKey.GetValueNames();
- for (int i = 0; i < valueNames.Length; i++)
- {
- string name = (string)serialInfoKey.GetValue(valueNames[i]);
- if (name.StartsWith("COM", StringComparison.OrdinalIgnoreCase))
- {
- portNames.Add(name);
- }
- }
- }
- }
- finally
- {
- if (localMachine != null)
- {
- localMachine.Close();
- }
- if (serialInfoKey != null)
- {
- serialInfoKey.Close();
- }
- CodeAccessPermission.RevertAssert();
- }
- if (portNames.Count > 1)
- {
- portNames.Sort(pnc);
- }
- return portNames.ToArray();
- }
- public static bool CheckBaudSettable(ref NativeAPI.COMMPROP prop, uint baud)
- {
- if ((prop.dwSettableBaud & SettableBauds.BAUD_USER) != 0)
- {
- return true;
- }
- uint settableBits = (uint)prop.dwSettableBaud;
- for (int i = 0; i < SettableBaudTable.Length; i++)
- {
- if ((settableBits & (1u << i)) != 0)
- {
- uint allowed = SettableBaudTable[i];
- if ((baud > (allowed - 3)) && (baud < (allowed + 3)))
- {
- return true;
- }
- }
- }
- return false;
- }
- public readonly static uint[] SettableBaudTable = new uint[19]
- {
- 75,
- 110,
- 134,
- 150,
- 300,
- 600,
- 1200,
- 1800,
- 2400,
- 4800,
- 7200,
- 9600,
- 14400,
- 19200,
- 38400,
- 56000,
- 128000,
- 115200,
- 57600,
- };
- #endregion
- }
- #region 串口名称排序比较器。
- public class PortNameComparer : IComparer<string>
- {
- public int Compare(string x, string y)
- {
- int ix = Convert.ToInt32(x.Substring(3));
- int iy = Convert.ToInt32(y.Substring(3));
- return (ix - iy);
- }
- }
- #endregion
- #region 枚举类型。
- public enum ParityValue : byte
- {
- /// <summary>
- /// 无奇偶校验
- /// </summary>
- NO = 0,
- /// <summary>
- /// 奇校验
- /// </summary>
- ODD = 1,
- /// <summary>
- /// 偶校验
- /// </summary>
- EVEN = 2,
- /// <summary>
- /// Mark parity
- /// </summary>
- MARK = 3,
- /// <summary>
- /// Space parity
- /// </summary>
- SPACE = 4,
- }
- public enum StopBitsValue : byte
- {
- /// <summary>
- /// 1 stop bit
- /// </summary>
- ONE = 0,
- /// <summary>
- /// 1.5 stop bits
- /// </summary>
- ONE5 = 1,
- /// <summary>
- /// 2 stop bits
- /// </summary>
- TWO = 2,
- }
- public enum DtrControlValue
- {
- DISABLE = 0,
- ENABLE = 1,
- HANDSHAKE = 2,
- }
- public enum RtsControlValue
- {
- DISABLE = 0,
- ENABLE = 1,
- HANDSHAKE = 2,
- TOGGLE = 3,
- }
- [Flags]
- public enum CommEvMask : uint
- {
- NONE = 0,
- BREAK = 0x0040,
- CTS = 0x0008,
- DSR = 0x0010,
- ERR = 0x0080,
- RING = 0x0100,
- RLSD = 0x0020,
- RXCHAR = 0x0001,
- RXFLAG = 0x0002,
- TXEMPTY = 0x0004,
- }
- [Flags]
- public enum ModemStats : uint
- {
- CTS_ON = 0x0010,
- DSR_ON = 0x0020,
- RING_ON = 0x0040,
- RLSD_ON = 0x0080,
- }
- [StructLayout(LayoutKind.Sequential)]
- public struct COMSTAT
- {
- public uint Flags;
- public uint cbInQue;
- public uint cbOutQue;
- public bool GetFlag(COMSTATFlags shift)
- {
- int nshift = (int)shift;
- return ((Flags & (1u << nshift)) != 0u);
- }
- public void SetFlag(COMSTATFlags shift, bool stat)
- {
- int nshift = (int)shift;
- if (stat)
- {
- Flags |= (1u << nshift);
- }
- else
- {
- Flags &= ~(1u << nshift);
- }
- }
- }
- public enum COMSTATFlags : int
- {
- fCtsHold = 0,
- fDsrHold = 1,
- fRlsdHold = 2,
- fXoffHold = 3,
- fXoffSent = 4,
- fEof = 5,
- fTxim = 6,
- }
- [Flags]
- public enum CommErrors : uint
- {
- NONE = 0,
- RXOVER = 1,
- OVERRUN = 2,
- RXPARITY = 4,
- FRAME = 8,
- BREAK = 16,
- }
- public enum CommEscape : uint
- {
- CLRBREAK = 9,
- CLRDTR = 6,
- CLRRTS = 4,
- SETBREAK = 8,
- SETDTR = 5,
- SETRTS = 3,
- SETXOFF = 1,
- SETXON = 2,
- }
- public enum EngineEventType
- {
- None = 0,
- CommEventNormal,
- EngineReadError,
- EngineEventError,
- }
- public enum BaudRateValue : uint
- {
- CBR_110 = 110,
- CBR_300 = 300,
- CBR_600 = 600,
- CBR_1200 = 1200,
- CBR_2400 = 2400,
- CBR_4800 = 4800,
- CBR_9600 = 9600,
- CBR_14400 = 14400,
- CBR_19200 = 19200,
- CBR_38400 = 38400,
- CBR_57600 = 57600,
- CBR_115200 = 115200,
- CBR_128000 = 128000,
- CBR_256000 = 256000,
- }
- [Flags]
- public enum SettableBauds : uint
- {
- BAUD_075 = 0x00000001,
- BAUD_110 = 0x00000002,
- BAUD_134_5 = 0x00000004,
- BAUD_150 = 0x00000008,
- BAUD_300 = 0x00000010,
- BAUD_600 = 0x00000020,
- BAUD_1200 = 0x00000040,
- BAUD_1800 = 0x00000080,
- BAUD_2400 = 0x00000100,
- BAUD_4800 = 0x00000200,
- BAUD_7200 = 0x00000400,
- BAUD_9600 = 0x00000800,
- BAUD_14400 = 0x00001000,
- BAUD_19200 = 0x00002000,
- BAUD_38400 = 0x00004000,
- BAUD_56K = 0x00008000,
- BAUD_57600 = 0x00040000,
- BAUD_115200 = 0x00020000,
- BAUD_128K = 0x00010000,
- BAUD_USER = 0x10000000,
- }
- public enum ProvSubType : uint
- {
- PST_FAX = 0x00000021,
- PST_LAT = 0x00000101,
- PST_MODEM = 0x00000006,
- PST_NETWORK_BRIDGE = 0x00000100,
- PST_PARALLELPORT = 0x00000002,
- PST_RS232 = 0x00000001,
- PST_RS422 = 0x00000003,
- PST_RS423 = 0x00000004,
- PST_RS449 = 0x00000005,
- PST_SCANNER = 0x00000022,
- PST_TCPIP_TELNET = 0x00000102,
- PST_UNSPECIFIED = 0x00000000,
- PST_X25 = 0x00000103,
- }
- [Flags]
- public enum ProvCapabilities : uint
- {
- PCF_16BITMODE = 0x0200,
- PCF_DTRDSR = 0x0001,
- PCF_INTTIMEOUTS = 0x0080,
- PCF_PARITY_CHECK = 0x0008,
- PCF_RLSD = 0x0004,
- PCF_RTSCTS = 0x0002,
- PCF_SETXCHAR = 0x0020,
- PCF_SPECIALCHARS = 0x0100,
- PCF_TOTALTIMEOUTS = 0x0040,
- PCF_XONXOFF = 0x0010,
- }
- [Flags]
- public enum SettableParams : uint
- {
- SP_BAUD = 0x0002,
- SP_DATABITS = 0x0004,
- SP_HANDSHAKING = 0x0010,
- SP_PARITY = 0x0001,
- SP_PARITY_CHECK = 0x0020,
- SP_RLSD = 0x0040,
- SP_STOPBITS = 0x0008,
- }
- [Flags]
- public enum SettableData : ushort
- {
- DATABITS_5 = 0x0001,
- DATABITS_6 = 0x0002,
- DATABITS_7 = 0x0004,
- DATABITS_8 = 0x0008,
- DATABITS_16 = 0x0010,
- DATABITS_16X = 0x0020,
- }
- [Flags]
- public enum SettableStopParity : ushort
- {
- STOPBITS_10 = 0x0001,
- STOPBITS_15 = 0x0002,
- STOPBITS_20 = 0x0004,
- PARITY_NONE = 0x0100,
- PARITY_ODD = 0x0200,
- PARITY_EVEN = 0x0400,
- PARITY_MARK = 0x0800,
- PARITY_SPACE = 0x1000,
- }
- #endregion
- }
复制代码 |
|