private void ReceiveThread() { 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.hEvent = sg.Handle; Marshal.StructureToPtr(ov, unmanagedOv, true); uint eventMask = 0; var 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)) { var 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()); } throw new CommPortException("IO Error [003]"); } if ((eventMask & Win32Com.EV_RXCHAR) != 0) { uint gotbytes; do { 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); } } }
/// <summary> /// Opens the com port and configures it with the required settings /// </summary> /// <returns>false if the port could not be opened</returns> 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 }; _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; }