/// <summary> /// Open the current port /// </summary> /// <returns>true if successful, false if it fails</returns> public bool Open() { if(isOpen) return false; if(CommAPI.FullFramework) { // set up the overlapped tx IO // AutoResetEvent are = new AutoResetEvent(false); OVERLAPPED o = new OVERLAPPED(); txOverlapped = LocalAlloc(0x40, Marshal.SizeOf(o)); o.Offset = 0; o.OffsetHigh = 0; o.hEvent = IntPtr.Zero; Marshal.StructureToPtr(o, txOverlapped, true); } hPort = m_CommAPI.CreateFile(portName); if(hPort == (IntPtr)CommAPI.INVALID_HANDLE_VALUE) { int e = Marshal.GetLastWin32Error(); if(e == (int)APIErrors.ERROR_ACCESS_DENIED) { // port is unavailable return false; } // ClearCommError failed! string error = String.Format("CreateFile Failed: {0}", e); throw new CommPortException(error); } isOpen = true; // set queue sizes m_CommAPI.SetupComm(hPort, rxBufferSize, txBufferSize); // transfer the port settings to a DCB structure dcb.BaudRate = (uint)portSettings.BasicSettings.BaudRate; dcb.ByteSize = portSettings.BasicSettings.ByteSize; dcb.EofChar = (sbyte)portSettings.EOFChar; dcb.ErrorChar = (sbyte)portSettings.ErrorChar; dcb.EvtChar = (sbyte)portSettings.EVTChar; dcb.fAbortOnError = portSettings.AbortOnError; dcb.fBinary = true; dcb.fDsrSensitivity = portSettings.DSRSensitive; dcb.fDtrControl = (DCB.DtrControlFlags)portSettings.DTRControl; dcb.fErrorChar = portSettings.ReplaceErrorChar; dcb.fInX = portSettings.InX; dcb.fNull = portSettings.DiscardNulls; dcb.fOutX = portSettings.OutX; dcb.fOutxCtsFlow = portSettings.OutCTS; dcb.fOutxDsrFlow = portSettings.OutDSR; dcb.fParity = (portSettings.BasicSettings.Parity == Parity.none) ? false : true; dcb.fRtsControl = (DCB.RtsControlFlags)portSettings.RTSControl; dcb.fTXContinueOnXoff = portSettings.TxContinueOnXOff; dcb.Parity = (byte)portSettings.BasicSettings.Parity; dcb.StopBits = (byte)portSettings.BasicSettings.StopBits; dcb.XoffChar = (sbyte)portSettings.XoffChar; dcb.XonChar = (sbyte)portSettings.XonChar; dcb.XonLim = dcb.XoffLim = (ushort)(rxBufferSize / 10); m_CommAPI.SetCommState(hPort, dcb); // store some state values brk = 0; dtr = dcb.fDtrControl == DCB.DtrControlFlags.Enable ? 1 : 0; rts = dcb.fRtsControl == DCB.RtsControlFlags.Enable ? 1 : 0; // set the Comm timeouts CommTimeouts ct = new CommTimeouts(); // reading we'll return immediately // this doesn't seem to work as documented ct.ReadIntervalTimeout = uint.MaxValue; // this = 0xffffffff ct.ReadTotalTimeoutConstant = 0; ct.ReadTotalTimeoutMultiplier = 0; // writing we'll give 5 seconds ct.WriteTotalTimeoutConstant = 5000; ct.WriteTotalTimeoutMultiplier = 0; m_CommAPI.SetCommTimeouts(hPort, ct); // read the ports capabilities bool status=GetPortProperties(); // start the receive thread eventThread = new Thread(new ThreadStart(CommEventThread)); eventThread.Priority = ThreadPriority.Highest; eventThread.Start(); // wait for the thread to actually get spun up threadStarted.WaitOne(); return true; }
private void CommEventThread() { CommEventFlags eventFlags = new CommEventFlags(); byte[] readbuffer = new Byte[rxBufferSize]; int bytesread = 0; AutoResetEvent rxevent = new AutoResetEvent(false); // specify the set of events to be monitored for the port. if(CommAPI.FullFramework) { m_CommAPI.SetCommMask(hPort, CommEventFlags.ALLPC); // set up the overlapped IO OVERLAPPED o = new OVERLAPPED(); rxOverlapped = LocalAlloc(0x40, Marshal.SizeOf(o)); o.Offset = 0; o.OffsetHigh = 0; o.hEvent = rxevent.Handle; Marshal.StructureToPtr(o, rxOverlapped, true); } else { m_CommAPI.SetCommMask(hPort, CommEventFlags.ALLCE); } try { // let Open() know we're started threadStarted.Set(); #region >>>> thread loop <<<< while(hPort != (IntPtr)CommAPI.INVALID_HANDLE_VALUE) { // wait for a Comm event if(!m_CommAPI.WaitCommEvent(hPort, ref eventFlags)) { int e = Marshal.GetLastWin32Error(); if(e == (int)APIErrors.ERROR_IO_PENDING) { // IO pending so just wait and try again rxevent.WaitOne(); Thread.Sleep(0); continue; } if(e == (int)APIErrors.ERROR_INVALID_HANDLE) { // Calling Port.Close() causes hPort to become invalid // Since Thread.Abort() is unsupported in the CF, we must // accept that calling Close will throw an error here. // Close signals the closeEvent, so wait on it // We wait 1 second, though Close should happen much sooner int eventResult = m_CommAPI.WaitForSingleObject(closeEvent, 1000); if(eventResult == (int)APIConstants.WAIT_OBJECT_0) { // the event was set so close was called hPort = (IntPtr)CommAPI.INVALID_HANDLE_VALUE; // reset our ResetEvent for the next call to Open threadStarted.Reset(); if(isOpen) // this should not be the case...if so, throw an exception for the owner { string error = String.Format("Wait Failed: {0}", e); throw new CommPortException(error); } return; } } // WaitCommEvent failed // 995 means an exit was requested (thread killed) if(e == 995) { return; } else { string error = String.Format("Wait Failed: {0}", e); throw new CommPortException(error); } } // Re-specify the set of events to be monitored for the port. if(CommAPI.FullFramework) { m_CommAPI.SetCommMask(hPort, CommEventFlags.ALLPC); } else { m_CommAPI.SetCommMask(hPort, CommEventFlags.ALLCE); } // check the event for errors #region >>>> error checking <<<< if(((uint)eventFlags & (uint)CommEventFlags.ERR) != 0) { CommErrorFlags errorFlags = new CommErrorFlags(); CommStat commStat = new CommStat(); // get the error status if(!m_CommAPI.ClearCommError(hPort, ref errorFlags, commStat)) { // ClearCommError failed! string error = String.Format("ClearCommError Failed: {0}", Marshal.GetLastWin32Error()); throw new CommPortException(error); } if(((uint)errorFlags & (uint)CommErrorFlags.BREAK) != 0) { // BREAK can set an error, so make sure the BREAK bit is set an continue eventFlags |= CommEventFlags.BREAK; } else { // we have an error. Build a meaningful string and throw an exception StringBuilder s = new StringBuilder("UART Error: ", 80); if ((errorFlags & CommErrorFlags.FRAME) != 0) { s = s.Append("Framing,"); } if ((errorFlags & CommErrorFlags.IOE) != 0) { s = s.Append("IO,"); } if ((errorFlags & CommErrorFlags.OVERRUN) != 0) { s = s.Append("Overrun,"); } if ((errorFlags & CommErrorFlags.RXOVER) != 0) { s = s.Append("Receive Overflow,"); } if ((errorFlags & CommErrorFlags.RXPARITY) != 0) { s = s.Append("Parity,"); } if ((errorFlags & CommErrorFlags.TXFULL) != 0) { s = s.Append("Transmit Overflow,"); } // no known bits are set if(s.Length == 12) { s = s.Append("Unknown"); } // raise an error event if(OnError != null) OnError(s.ToString()); continue; } } // if(((uint)eventFlags & (uint)CommEventFlags.ERR) != 0) #endregion #region >>>> Receive data subsection <<<< // check for RXCHAR if((eventFlags & CommEventFlags.RXCHAR) != 0) { do { // make sure the port handle is valid if(hPort == (IntPtr)CommAPI.INVALID_HANDLE_VALUE) { bytesread = 0; break; } // data came in, put it in the buffer and set the event if (!m_CommAPI.ReadFile(hPort, readbuffer, rxBufferSize, ref bytesread, rxOverlapped)) { string errString = String.Format("ReadFile Failed: {0}", Marshal.GetLastWin32Error()); if(OnError != null) OnError(errString); return; } if (bytesread >= 1) { // take the mutex rxBufferBusy.WaitOne(); // put the data into the fifo // this *may* be a perf problem and needs testing for(int b = 0 ; b < bytesread ; b++) rxFIFO.Enqueue(readbuffer[b]); // get the FIFO length int fifoLength = rxFIFO.Count; // release the mutex rxBufferBusy.ReleaseMutex(); // fire the DataReceived event every RThreshold bytes if((DataReceived != null) && (rthreshold != 0) && (fifoLength >= rthreshold)) { DataReceived(); } } } while (bytesread > 0); } // if((eventFlags & CommEventFlags.RXCHAR) != 0) #endregion #region >>>> line status checking <<<< // check for status changes uint status = 0; m_CommAPI.GetCommModemStatus(hPort, ref status); // check the CTS if(((uint)eventFlags & (uint)CommEventFlags.CTS) != 0) { if(CTSChange != null) CTSChange((status & (uint)CommModemStatusFlags.MS_CTS_ON) != 0); } // check the DSR if(((uint)eventFlags & (uint)CommEventFlags.DSR) != 0) { if(DSRChange != null) DSRChange((status & (uint)CommModemStatusFlags.MS_DSR_ON) != 0); } // check for a RING if(((uint)eventFlags & (uint)CommEventFlags.RING) != 0) { if(RingChange != null) RingChange((status & (uint)CommModemStatusFlags.MS_RING_ON) != 0); } // check for a RLSD if(((uint)eventFlags & (uint)CommEventFlags.RLSD) != 0) { if(RLSDChange != null) RLSDChange((status & (uint)CommModemStatusFlags.MS_RLSD_ON) != 0); } // check for TXEMPTY if(((uint)eventFlags & (uint)CommEventFlags.TXEMPTY) != 0) if(TxDone != null) { TxDone(); } // check for RXFLAG if(((uint)eventFlags & (uint)CommEventFlags.RXFLAG) != 0) if(FlagCharReceived != null) { FlagCharReceived(); } // check for POWER if(((uint)eventFlags & (uint)CommEventFlags.POWER) != 0) if(PowerEvent != null) { PowerEvent(); } // check for high-water state if((eventFlags & CommEventFlags.RX80FULL) != 0) if(HighWater != null) { HighWater(); } #endregion } // while(true) #endregion } // try catch(Exception e) { if(rxOverlapped != IntPtr.Zero) LocalFree(rxOverlapped); if(OnError != null) OnError(e.Message); return; } }
/// <summary> /// Open the current port /// </summary> /// <returns>true if successful, false if it fails</returns> public bool Open() { if (isOpen) { return(false); } if (CommAPI.FullFramework) { // set up the overlapped tx IO // AutoResetEvent are = new AutoResetEvent(false); OVERLAPPED o = new OVERLAPPED(); txOverlapped = LocalAlloc(0x40, Marshal.SizeOf(o)); o.Offset = 0; o.OffsetHigh = 0; o.hEvent = IntPtr.Zero; Marshal.StructureToPtr(o, txOverlapped, true); } hPort = m_CommAPI.CreateFile(portName); if (hPort == (IntPtr)CommAPI.INVALID_HANDLE_VALUE) { int e = Marshal.GetLastWin32Error(); if (e == (int)APIErrors.ERROR_ACCESS_DENIED) { // port is unavailable return(false); } // ClearCommError failed! string error = String.Format("CreateFile Failed: {0}", e); throw new CommPortException(error); } isOpen = true; // set queue sizes m_CommAPI.SetupComm(hPort, rxBufferSize, txBufferSize); // transfer the port settings to a DCB structure dcb.BaudRate = (uint)portSettings.BasicSettings.BaudRate; dcb.ByteSize = portSettings.BasicSettings.ByteSize; dcb.EofChar = (sbyte)portSettings.EOFChar; dcb.ErrorChar = (sbyte)portSettings.ErrorChar; dcb.EvtChar = (sbyte)portSettings.EVTChar; dcb.fAbortOnError = portSettings.AbortOnError; dcb.fBinary = true; dcb.fDsrSensitivity = portSettings.DSRSensitive; dcb.fDtrControl = (byte)portSettings.DTRControl; dcb.fErrorChar = portSettings.ReplaceErrorChar; dcb.fInX = portSettings.InX; dcb.fNull = portSettings.DiscardNulls; dcb.fOutX = portSettings.OutX; dcb.fOutxCtsFlow = portSettings.OutCTS; dcb.fOutxDsrFlow = portSettings.OutDSR; dcb.fParity = (portSettings.BasicSettings.Parity == Parity.none) ? false : true; dcb.fRtsControl = (byte)portSettings.RTSControl; dcb.fTXContinueOnXoff = portSettings.TxContinueOnXOff; dcb.Parity = (byte)portSettings.BasicSettings.Parity; dcb.StopBits = (byte)portSettings.BasicSettings.StopBits; dcb.XoffChar = (sbyte)portSettings.XoffChar; dcb.XonChar = (sbyte)portSettings.XonChar; dcb.XonLim = dcb.XoffLim = (ushort)(rxBufferSize / 10); m_CommAPI.SetCommState(hPort, dcb); // store some state values brk = 0; dtr = dcb.fDtrControl == (byte)DCB.DtrControlFlags.Enable ? 1 : 0; rts = dcb.fRtsControl == (byte)DCB.RtsControlFlags.Enable ? 1 : 0; // set the Comm timeouts CommTimeouts ct = new CommTimeouts(); // reading we'll return immediately // this doesn't seem to work as documented ct.ReadIntervalTimeout = uint.MaxValue; // this = 0xffffffff ct.ReadTotalTimeoutConstant = 0; ct.ReadTotalTimeoutMultiplier = 0; // writing we'll give 5 seconds ct.WriteTotalTimeoutConstant = 5000; ct.WriteTotalTimeoutMultiplier = 0; m_CommAPI.SetCommTimeouts(hPort, ct); // read the ports capabilities bool status = GetPortProperties(); // start the receive thread eventThread = new Thread(new ThreadStart(CommEventThread)); eventThread.Priority = ThreadPriority.Highest; eventThread.Start(); // wait for the thread to actually get spun up threadStarted.WaitOne(); return(true); }
private void CommEventThread() { CommEventFlags eventFlags = new CommEventFlags(); byte[] readbuffer = new Byte[rxBufferSize]; int bytesread = 0; AutoResetEvent rxevent = new AutoResetEvent(false); // specify the set of events to be monitored for the port. if (CommAPI.FullFramework) { m_CommAPI.SetCommMask(hPort, CommEventFlags.ALLPC); // set up the overlapped IO OVERLAPPED o = new OVERLAPPED(); rxOverlapped = LocalAlloc(0x40, Marshal.SizeOf(o)); o.Offset = 0; o.OffsetHigh = 0; o.hEvent = rxevent.Handle; Marshal.StructureToPtr(o, rxOverlapped, true); } else { m_CommAPI.SetCommMask(hPort, CommEventFlags.ALLCE); } try { // let Open() know we're started threadStarted.Set(); #region >>>> thread loop <<<< while (hPort != (IntPtr)CommAPI.INVALID_HANDLE_VALUE) { // wait for a Comm event if (!m_CommAPI.WaitCommEvent(hPort, ref eventFlags)) { int e = Marshal.GetLastWin32Error(); if (e == (int)APIErrors.ERROR_IO_PENDING) { // IO pending so just wait and try again rxevent.WaitOne(); Thread.Sleep(0); continue; } if (e == (int)APIErrors.ERROR_INVALID_HANDLE) { // Calling Port.Close() causes hPort to become invalid // Since Thread.Abort() is unsupported in the CF, we must // accept that calling Close will throw an error here. // Close signals the closeEvent, so wait on it // We wait 1 second, though Close should happen much sooner int eventResult = m_CommAPI.WaitForSingleObject(closeEvent, 1000); if (eventResult == (int)APIConstants.WAIT_OBJECT_0) { // the event was set so close was called hPort = (IntPtr)CommAPI.INVALID_HANDLE_VALUE; // reset our ResetEvent for the next call to Open threadStarted.Reset(); if (isOpen) // this should not be the case...if so, throw an exception for the owner { string error = String.Format("Wait Failed: {0}", e); throw new CommPortException(error); } return; } } // WaitCommEvent failed // 995 means an exit was requested (thread killed) if (e == 995) { return; } else { string error = String.Format("Wait Failed: {0}", e); throw new CommPortException(error); } } // Re-specify the set of events to be monitored for the port. if (CommAPI.FullFramework) { m_CommAPI.SetCommMask(hPort, CommEventFlags.ALLPC); } else { m_CommAPI.SetCommMask(hPort, CommEventFlags.ALLCE); } // check the event for errors #region >>>> error checking <<<< if (((uint)eventFlags & (uint)CommEventFlags.ERR) != 0) { CommErrorFlags errorFlags = new CommErrorFlags(); CommStat commStat = new CommStat(); // get the error status if (!m_CommAPI.ClearCommError(hPort, ref errorFlags, commStat)) { // ClearCommError failed! string error = String.Format("ClearCommError Failed: {0}", Marshal.GetLastWin32Error()); throw new CommPortException(error); } if (((uint)errorFlags & (uint)CommErrorFlags.BREAK) != 0) { // BREAK can set an error, so make sure the BREAK bit is set an continue eventFlags |= CommEventFlags.BREAK; } else { // we have an error. Build a meaningful string and throw an exception StringBuilder s = new StringBuilder("UART Error: ", 80); if ((errorFlags & CommErrorFlags.FRAME) != 0) { s = s.Append("Framing,"); } if ((errorFlags & CommErrorFlags.IOE) != 0) { s = s.Append("IO,"); } if ((errorFlags & CommErrorFlags.OVERRUN) != 0) { s = s.Append("Overrun,"); } if ((errorFlags & CommErrorFlags.RXOVER) != 0) { s = s.Append("Receive Overflow,"); } if ((errorFlags & CommErrorFlags.RXPARITY) != 0) { s = s.Append("Parity,"); } if ((errorFlags & CommErrorFlags.TXFULL) != 0) { s = s.Append("Transmit Overflow,"); } // no known bits are set if (s.Length == 12) { s = s.Append("Unknown"); } // raise an error event if (OnError != null) { OnError(s.ToString()); } continue; } } // if(((uint)eventFlags & (uint)CommEventFlags.ERR) != 0) #endregion #region >>>> Receive data subsection <<<< // check for RXCHAR if ((eventFlags & CommEventFlags.RXCHAR) != 0) { do { // make sure the port handle is valid if (hPort == (IntPtr)CommAPI.INVALID_HANDLE_VALUE) { bytesread = 0; break; } // data came in, put it in the buffer and set the event if (!m_CommAPI.ReadFile(hPort, readbuffer, rxBufferSize, ref bytesread, rxOverlapped)) { if (Marshal.GetLastWin32Error() == CommAPI.ERROR_IO_PENDING) { // Thanks to Geoff McIlraith: // Read operation was not completed on ReadFile call...block until // complete, and grab result. if (!m_CommAPI.GetOverlappedResult(hPort, rxOverlapped, out bytesread, true)) { string errString = String.Format("GetOverlappedResult Failed: {0}", Marshal.GetLastWin32Error()); if (OnError != null) { OnError(errString); } return; } } else { string errString = String.Format("ReadFile Failed: {0}", Marshal.GetLastWin32Error()); if (OnError != null) { OnError(errString); } return; } } if (bytesread >= 1) { // take the mutex rxBufferBusy.WaitOne(); // put the data into the fifo // this *may* be a perf problem and needs testing for (int b = 0; b < bytesread; b++) { rxFIFO.Enqueue(readbuffer[b]); } // get the FIFO length int fifoLength = rxFIFO.Count; // release the mutex rxBufferBusy.ReleaseMutex(); // fire the DataReceived event every RThreshold bytes if ((DataReceived != null) && (rthreshold != 0) && (fifoLength >= rthreshold)) { DataReceived(); } } } while (bytesread > 0); } // if((eventFlags & CommEventFlags.RXCHAR) != 0) #endregion #region >>>> line status checking <<<< // check for status changes uint status = 0; m_CommAPI.GetCommModemStatus(hPort, ref status); // check the CTS if (((uint)eventFlags & (uint)CommEventFlags.CTS) != 0) { if (CTSChange != null) { CTSChange((status & (uint)CommModemStatusFlags.MS_CTS_ON) != 0); } } // check the DSR if (((uint)eventFlags & (uint)CommEventFlags.DSR) != 0) { if (DSRChange != null) { DSRChange((status & (uint)CommModemStatusFlags.MS_DSR_ON) != 0); } } // check for a RING if (((uint)eventFlags & (uint)CommEventFlags.RING) != 0) { if (RingChange != null) { RingChange((status & (uint)CommModemStatusFlags.MS_RING_ON) != 0); } } // check for a RLSD if (((uint)eventFlags & (uint)CommEventFlags.RLSD) != 0) { if (RLSDChange != null) { RLSDChange((status & (uint)CommModemStatusFlags.MS_RLSD_ON) != 0); } } // check for TXEMPTY if (((uint)eventFlags & (uint)CommEventFlags.TXEMPTY) != 0) { if (TxDone != null) { TxDone(); } } // check for RXFLAG if (((uint)eventFlags & (uint)CommEventFlags.RXFLAG) != 0) { if (FlagCharReceived != null) { FlagCharReceived(); } } // check for POWER if (((uint)eventFlags & (uint)CommEventFlags.POWER) != 0) { if (PowerEvent != null) { PowerEvent(); } } // check for high-water state if ((eventFlags & CommEventFlags.RX80FULL) != 0) { if (HighWater != null) { HighWater(); } } #endregion } // while(true) #endregion } // try catch (Exception e) { if (rxOverlapped != IntPtr.Zero) { LocalFree(rxOverlapped); } if (OnError != null) { OnError(e.Message); } return; } }
/// <summary> /// Opens a new serial port connection. /// </summary> public void Open() { if(this.mIsOpen) throw new InvalidOperationException("Comm Port is already open!"); if(CommAPI.FullFramework) { // set up the overlapped tx IO OVERLAPPED o = new OVERLAPPED(); this.mTxOverlapped = LocalAlloc(0x40, Marshal.SizeOf(o)); o.Offset = 0; o.OffsetHigh = 0; o.hEvent = IntPtr.Zero; Marshal.StructureToPtr(o, this.mTxOverlapped, true); } hPort = m_CommAPI.CreateFile(this.mPortName); if(hPort == (IntPtr)CommAPI.INVALID_HANDLE_VALUE) { int e = Marshal.GetLastWin32Error(); if(e == (int)APIErrors.ERROR_ACCESS_DENIED) { // port is unavailable throw new ApplicationException("ERROR_ACCESS_DENIED"); } // ClearCommError failed! string error = String.Format("CreateFile Failed: {0}", e); throw new ApplicationException(error); } this.mIsOpen = true; // clear errors CommErrorFlags errorFlags = new CommErrorFlags(); CommStat commStat = new CommStat(); if(!m_CommAPI.ClearCommError(hPort, ref errorFlags, commStat)) { throw new ApplicationException("Failed to clear error/read"); } // set queue sizes m_CommAPI.SetupComm(hPort, this.mRxBufferSize, this.mTxBufferSize); // update dcb this.UpdateSettings(); // store some state values this.mInBreak = false; // read/write timeouts this.UpdateTimeouts(); // start the receive thread this.mEventThread = new Thread(new ThreadStart(CommEventThread)); this.mEventThread.Priority = ThreadPriority.Normal; //by design this.mEventThread.Start(); // wait for the thread to actually get spun up this.mThreadStarted.WaitOne(); }
private void CommEventThread() { CommEventFlags eventFlags = new CommEventFlags(); AutoResetEvent rxevent = new AutoResetEvent(false); // specify the set of events to be monitored for the port. bool b; if(CommAPI.FullFramework) { b = m_CommAPI.SetCommMask(hPort, CommEventFlags.ALLPC); // set up the overlapped IO OVERLAPPED o = new OVERLAPPED(); this.mRxOverlapped = LocalAlloc(0x40, Marshal.SizeOf(o)); o.Offset = 0; o.OffsetHigh = 0; o.hEvent = rxevent.Handle; Marshal.StructureToPtr(o, this.mRxOverlapped, true); } else { b = m_CommAPI.SetCommMask(hPort, CommEventFlags.ALLCE_2); } try { // let Open() know we're started this.mThreadStarted.Set(); #region >>>> thread loop <<<< while(hPort != (IntPtr)CommAPI.INVALID_HANDLE_VALUE) { // wait for a Comm event if(!m_CommAPI.WaitCommEvent(hPort, ref eventFlags)) { int e = Marshal.GetLastWin32Error(); if(e == (int)APIErrors.ERROR_IO_PENDING) { // IO pending so just wait and try again rxevent.WaitOne(); Thread.Sleep(0); continue; } if(e == (int)APIErrors.ERROR_INVALID_HANDLE) { // Calling Port.Close() causes hPort to become invalid // Since Thread.Abort() is unsupported in the CF, we must // accept that calling Close will throw an error here. // Close signals the this.mCloseEvent, so wait on it // We wait 1 second, though Close should happen much sooner int eventResult = m_CommAPI.WaitForSingleObject(this.mCloseEvent, 1000); if(eventResult == (int)APIConstants.WAIT_OBJECT_0) { // the event was set so close was called hPort = (IntPtr)CommAPI.INVALID_HANDLE_VALUE; // reset our ResetEvent for the next call to Open this.mThreadStarted.Reset(); if(this.mIsOpen) { // this should not be the case...if so, throw an exception for the owner string error = String.Format("Wait Failed: {0}", e); throw new ApplicationException(error); } return; } } // WaitCommEvent failed // 995 means an exit was requested (thread killed) if(e == 995) { return; } else { string error = String.Format("Wait Failed: {0}", e); throw new ApplicationException(error); } } // Re-specify the set of events to be monitored for the port. if(CommAPI.FullFramework) { m_CommAPI.SetCommMask(hPort, CommEventFlags.ALLPC); } else { m_CommAPI.SetCommMask(hPort, CommEventFlags.ALLCE); } // Process the flag - extracted main handling into its own method //ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessEvents), eventFlags); this.ProcessEvents(eventFlags); } // while(not invalid handle) #endregion } // try catch{ if(this.mRxOverlapped != IntPtr.Zero) LocalFree(this.mRxOverlapped); throw; } }
public void SetDCB() { if (isOpen) return; if (CommAPI.FullFramework) { // set up the overlapped tx IO // AutoResetEvent are = new AutoResetEvent(false); OVERLAPPED o = new OVERLAPPED(); txOverlapped = LocalAlloc(0x40, Marshal.SizeOf(o)); o.Offset = 0; o.OffsetHigh = 0; o.hEvent = IntPtr.Zero; Marshal.StructureToPtr(o, txOverlapped, true); } hPort = m_CommAPI.CreateFile(portName); if (hPort == (IntPtr)CommAPI.INVALID_HANDLE_VALUE) { int e = Marshal.GetLastWin32Error(); if (e == (int)APIErrors.ERROR_ACCESS_DENIED) { // port is unavailable return; } // ClearCommError failed! string error = String.Format("CreateFile Failed: {0}", e); throw new CommPortException(error); } isOpen = true; // set queue sizes m_CommAPI.SetupComm(hPort, rxBufferSize, txBufferSize); // transfer the port settings to a DCB structure dcb.BaudRate = (uint)portSettings.BasicSettings.BaudRate; dcb.ByteSize = portSettings.BasicSettings.ByteSize; dcb.EofChar = (sbyte)portSettings.EOFChar; dcb.ErrorChar = (sbyte)portSettings.ErrorChar; dcb.EvtChar = (sbyte)portSettings.EVTChar; dcb.fAbortOnError = portSettings.AbortOnError; dcb.fBinary = true; dcb.fDsrSensitivity = portSettings.DSRSensitive; dcb.fDtrControl = (DCB.DtrControlFlags)portSettings.DTRControl; dcb.fErrorChar = portSettings.ReplaceErrorChar; dcb.fInX = portSettings.InX; dcb.fNull = portSettings.DiscardNulls; dcb.fOutX = portSettings.OutX; dcb.fOutxCtsFlow = portSettings.OutCTS; dcb.fOutxDsrFlow = portSettings.OutDSR; dcb.fParity = (portSettings.BasicSettings.Parity == Parity.none) ? false : true; dcb.fRtsControl = (DCB.RtsControlFlags)portSettings.RTSControl; dcb.fTXContinueOnXoff = portSettings.TxContinueOnXOff; dcb.Parity = (byte)portSettings.BasicSettings.Parity; dcb.StopBits = (byte)portSettings.BasicSettings.StopBits; dcb.XoffChar = (sbyte)portSettings.XoffChar; dcb.XonChar = (sbyte)portSettings.XonChar; dcb.XonLim = dcb.XoffLim = (ushort)(rxBufferSize / 10); m_CommAPI.SetCommState(hPort, dcb); }
/// <summary> /// Open the current port /// </summary> /// <param name="isThreaded">Set to true to use threading. Otherwise poll</param> /// <returns></returns> public bool OpenThreaded(bool isThreaded) { this.isThreaded = isThreaded; if(isOpen) return false; if(CommAPI.FullFramework) { // set up the overlapped tx IO // AutoResetEvent are = new AutoResetEvent(false); OVERLAPPED o = new OVERLAPPED(); txOverlapped = LocalAlloc(0x40, Marshal.SizeOf(o)); o.Offset = 0; o.OffsetHigh = 0; o.hEvent = IntPtr.Zero; Marshal.StructureToPtr(o, txOverlapped, true); } hPort = m_CommAPI.CreateFile(portName); if(hPort == (IntPtr)CommAPI.INVALID_HANDLE_VALUE) { int e = Marshal.GetLastWin32Error(); if(e == (int)APIErrors.ERROR_ACCESS_DENIED) { // port is unavailable return false; } // ClearCommError failed! string error = String.Format("CreateFile Failed: {0}", e); throw new CommPortException(error); } isOpen = true; // set queue sizes m_CommAPI.SetupComm(hPort, rxBufferSize, txBufferSize); // transfer the port settings to a DCB structure dcb.BaudRate = (uint)portSettings.BasicSettings.BaudRate; dcb.ByteSize = portSettings.BasicSettings.ByteSize; dcb.EofChar = (sbyte)portSettings.EOFChar; dcb.ErrorChar = (sbyte)portSettings.ErrorChar; dcb.EvtChar = (sbyte)portSettings.EVTChar; dcb.fAbortOnError = portSettings.AbortOnError; dcb.fBinary = true; dcb.fDsrSensitivity = portSettings.DSRSensitive; dcb.fDtrControl = (DCB.DtrControlFlags)portSettings.DTRControl; dcb.fErrorChar = portSettings.ReplaceErrorChar; dcb.fInX = portSettings.InX; dcb.fNull = portSettings.DiscardNulls; dcb.fOutX = portSettings.OutX; dcb.fOutxCtsFlow = portSettings.OutCTS; dcb.fOutxDsrFlow = portSettings.OutDSR; dcb.fParity = (portSettings.BasicSettings.Parity == Parity.none) ? false : true; dcb.fRtsControl = (DCB.RtsControlFlags)portSettings.RTSControl; dcb.fTXContinueOnXoff = portSettings.TxContinueOnXOff; dcb.Parity = (byte)portSettings.BasicSettings.Parity; dcb.StopBits = (byte)portSettings.BasicSettings.StopBits; dcb.XoffChar = (sbyte)portSettings.XoffChar; dcb.XonChar = (sbyte)portSettings.XonChar; dcb.XonLim = dcb.XoffLim = (ushort)(rxBufferSize / 10); m_CommAPI.SetCommState(hPort, dcb); // store some state values brk = 0; dtr = dcb.fDtrControl == DCB.DtrControlFlags.Enable ? 1 : 0; rts = dcb.fRtsControl == DCB.RtsControlFlags.Enable ? 1 : 0; // set the Comm timeouts CommTimeouts ct = new CommTimeouts(); /* If an application sets ReadIntervalTimeout and ReadTotalTimeoutMultiplier to MAXDWORD and sets ReadTotalTimeoutConstant to a value greater than zero and less than MAXDWORD, one of the following occurs when the ReadFile function is called: a.. If there are any characters in the input buffer, ReadFile returns immediately with the characters in the buffer. b.. If there are no characters in the input buffer, ReadFile waits until a character arrives and then returns immediately. c.. If no character arrives within the time specified by ReadTotalTimeoutConstant, ReadFile times out. */ // reading we'll return immediately // this doesn't seem to work as documented #if PPC ct.ReadIntervalTimeout = uint.MaxValue; // On the Smartphone, MaxValue blocks, so set to 1 instead but this doesn't work either ct.ReadTotalTimeoutConstant = 0; ct.ReadTotalTimeoutMultiplier = 0; #else ct.ReadIntervalTimeout = uint.MaxValue; // On the PC definitely needs to be this, doesn't block. On PPC and SP, this blocks ct.ReadTotalTimeoutConstant = 0; ct.ReadTotalTimeoutMultiplier = 0; #endif // writing we'll give 5 seconds ct.WriteTotalTimeoutConstant = 5000; ct.WriteTotalTimeoutMultiplier = 0; m_CommAPI.SetCommTimeouts(hPort, ct); // read the ports capabilities bool status=GetPortProperties(); if (isThreaded) { // start the receive thread eventThread = new Thread(new ThreadStart(CommEventThread)); eventThread.Priority = ThreadPriority.AboveNormal; //SSI changed from highest eventThread.Start(); // wait for the thread to actually get spun up threadStarted.WaitOne(); } else { GrabDataSetup(); } return true; }
/// <summary> /// /// </summary> public void GrabDataSetup() { if (isThreaded) { Console.WriteLine ("SHOULD NOT BE CALLING THIS BECAUSE NOT DIRECT READ"); } grabRxevent = new AutoResetEvent(false); // specify the set of events to be monitored for the port. if(CommAPI.FullFramework) { m_CommAPI.SetCommMask(hPort, CommEventFlags.ALLPC); // set up the overlapped IO OVERLAPPED o = new OVERLAPPED(); rxOverlapped = LocalAlloc(0x40, Marshal.SizeOf(o)); o.Offset = 0; o.OffsetHigh = 0; #if (PocketPC) o.hEvent = grabRxevent.Handle; #else o.hEvent = grabRxevent.SafeWaitHandle.DangerousGetHandle(); #endif Marshal.StructureToPtr(o, rxOverlapped, true); } else { m_CommAPI.SetCommMask(hPort, CommEventFlags.ALLCE); } }