/// <summary> /// Closes and destroys the com port. /// </summary> protected void Destroy() { // Cancel I/O, kill receiver & close port. if (this.portOpen) { this.port.Cancel(); if (this.rxThread != null) { this.rxThread.Abort(); this.rxThread = null; } this.port.Close(); this.portOpen = false; } // Reinit resources. this.dcb = null; this.port = null; this.stats = null; this.props = null; this.tmout = null; this.rxOvr = null; this.txOvr = null; this.escape = null; this.writeEvent = null; this.recvrEvent = null; return; }
/// <summary> /// Main receiver thread for this com port instance. /// </summary> private void ReceiveThread() { // Create locals. uint firedEvent = 0; uint nBytes = 0; byte[] buf = new Byte[1]; // Create thread signal (initial state is non-signaled). AutoResetEvent signal = new AutoResetEvent(false); // Create overlap memory pointer. Install signal. this.rxOvr = new Win32Ovrlap(port.Handle, signal.Handle); // Instantiate the event class. this.events = new Win32Events(rxOvr.MemPtr); // Instantiate the modem signal class. this.modem = new Win32Modem(); // Set initial modem signal states. this.Signals(); // Signal the main thread that // the receive thread is started. this.recvrEvent.Set(); try { while (true) { // Arm the event monitoring mask. // if(this.events.Set(this.port.Handle, Win32Events.EV_DEFAULT)) if (this.events.Set(this.port.Handle, Win32Events.EV_TXEMPTY)) { // Wait for any armed event to occur. this.events.Wait(this.port.Handle, signal); // Get mask of fired events. firedEvent = this.events.GetMask; // Error event (override). if ((firedEvent & Win32Events.EV_ERR) != 0) { if (this.stats.Reset(this.port.Handle) == false) { if (this.stats.Status == Win32Status.CE_BREAK) { firedEvent &= ~Win32Events.EV_BREAK; } else { this.CommError(this.stats.Fault); } } } else { // Receive event (override). if (((firedEvent & Win32Events.EV_RXCHAR) != 0) && (this.immediate)) { do { nBytes = 0; if (this.port.Read(buf, 1, out nBytes, this.rxOvr.MemPtr)) { if (nBytes == 1) { this.OnRxChar(buf); } } } while(nBytes > 0); } // TX queue empty event (override). if ((firedEvent & Win32Events.EV_TXEMPTY) != 0) { this.OnTxDone(); } // Line break event (override). if ((firedEvent & Win32Events.EV_BREAK) != 0) { this.OnBreak(); } // Modem signal change event(s) (override). if ((firedEvent & Win32Events.EV_MODEM) > 0) { this.modem.Get(this.port.Handle); if ((firedEvent & Win32Events.EV_CTS) > 0) { this.OnCTS(this.modem.CtsState); } if ((firedEvent & Win32Events.EV_DSR) > 0) { this.OnDSR(this.modem.DsrState); } if ((firedEvent & Win32Events.EV_RLSD) > 0) { this.OnRLSD(this.modem.RlsdState); } if ((firedEvent & Win32Events.EV_RING) > 0) { this.OnRING(this.modem.RingState); } } } } } } catch (Exception e) { if ((e is ThreadAbortException)) { this.modem = null; this.events = null; this.rxOvr = null; } else { this.CommError("Receiver Exception: " + e.Message); } } }
/// <summary> /// Create & opens the com port and configures it with the required settings. /// </summary> /// <param name="cfg">Reference to port user config.</param> /// <returns>True if port opened successfully.</returns> protected bool Create(SerialCnfg cfg) { // If port already open, return. if (portOpen) { this.CommError("Com Port Already Open."); return(false); } // Init members. this.fault = ""; this.rxThread = null; this.writeEvent = new ManualResetEvent(false); this.recvrEvent = new ManualResetEvent(false); // Copy config to DCB. this.dcb = new Win32DCB(cfg); // Create handle to comm port. this.port = new Win32Com(); if ((this.portOpen = this.port.Open(cfg.PortName, true)) == false) { this.CommError(this.port.Fault); return(false); } this.portName = cfg.PortName; // Instantiate support classes. this.stats = new Win32Status(); this.tmout = new Win32Tmout(); this.props = new Win32Props(); this.escape = new Win32Escape(port.Handle); // Set read/write timeouts. this.tmout.WriteConstant = cfg.TxTmoConst; this.tmout.WriteMultiplier = cfg.TxTmoMulti; if (this.tmout.Set(this.port.Handle) == false) { this.Destroy(); this.CommError(this.tmout.Fault); return(false); } // Overide OS default queue sizes. if ((cfg.RxQueLen != 0) || (cfg.TxQueLen != 0)) { if (this.props.Set(this.port.Handle, (uint)cfg.RxQueLen, (uint)cfg.TxQueLen) == false) { this.Destroy(); this.CommError(this.props.Fault); return(false); } } // Get the current properties. if (this.props.Get(this.port.Handle) == false) { this.Destroy(); this.CommError(this.props.Fault); return(false); } // Set flow control limits. this.dcb.Limits(cfg, this.props.RxCurSize); // Update the port settings. if (this.dcb.Set(this.port.Handle) == false) { this.Destroy(); this.CommError(this.dcb.Fault); return(false); } // XON/OFF extended functionality. this.escape.XOFFavailable = true; // RTS extended functionality. if (cfg.RtsControl == PinState.Disable) { this.escape.RTS = false; } else if (cfg.RtsControl == PinState.Enable) { this.escape.RTS = true; } else if (cfg.RtsControl == PinState.Handshake) { this.escape.RTSavailable = false; } // DTR extended functionality. if (cfg.DtrControl == PinState.Disable) { this.escape.DTR = false; } else if (cfg.DtrControl == PinState.Enable) { this.escape.DTR = true; } else if (cfg.DtrControl == PinState.Toggle) { this.escape.DTR = false; } else if (cfg.DtrControl == PinState.Handshake) { this.escape.DTRavailable = false; } // Create TX overlap memory pointer. this.txOvr = new Win32Ovrlap(this.port.Handle, this.writeEvent.Handle); // Set the receiver mode. this.immediate = cfg.ReceiveMode; // Start the receiver thread. this.rxThread = new Thread(new ThreadStart(ReceiveThread)); this.rxThread.Name = "COMReceiver"; this.rxThread.Priority = ThreadPriority.AboveNormal; this.rxThread.Start(); // Wait for receive thread to start. this.recvrEvent.WaitOne(500, false); // Port opened OK. return(true); }
/// <summary> /// Write data to a comm object. /// </summary> /// <param name="buf">Buffer to write from</param> /// <param name="nToSend">Number to buyes to send.</param> /// <param name="nSent">Number of actually bytes sent.</param> /// <param name="olMem">Pointer to overlap struct.</param> /// <returns>True if executed successfully.</returns> internal bool Write(byte[] buf, uint nToSend, out uint nSent, Win32Ovrlap ovlap) { // Write done pre/post check. bool postCheck = true; // Wait until last write done. if (postCheck == false) { if (ovlap.MemPtr != IntPtr.Zero) { while (this.nUnsent > 0) { if (ovlap.Get(out nSent, true)) { this.nUnsent -= nSent; } } } } // Send data buffer. bool status = WriteFile(this.handle, buf, nToSend, out nSent, ovlap.MemPtr); this.nUnsent = nToSend - nSent; // Return status. if (status == false) { int error = Marshal.GetLastWin32Error(); // Wait until this write done. if (postCheck == true) { if (error == ERROR_IO_PENDING) { while (this.nUnsent > 0) { if (ovlap.Get(out nSent, true)) { this.nUnsent -= nSent; } } } else { this.SetFault("WriteFile()", error); return(false); } } else { if (error != ERROR_IO_PENDING) { this.SetFault("WriteFile()", error); return(false); } nSent = nToSend; // assume write will pass. } } return(true); }