📄 nativeserial_win32.cpp
字号:
//$Id: NativeSerial_win32.cpp,v 1.4 2006/12/12 18:23:02 vlahan Exp $/* "Copyright (c) 2000-2003 The Regents of the University of California. * All rights reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose, without fee, and without written agreement * is hereby granted, provided that the above copyright notice, the following * two paragraphs and the author appear in all copies of this software. * * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY * OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS." *///@author Cory Sharp <cssharp@eecs.berkeley.edu>#include <windows.h>#include <stdexcept>#include <sstream>#include <iostream>#include "NativeSerialEnums.h"using namespace NativeSerialEnums;class comm_port_error : public std::runtime_error{ public: comm_port_error( const char* msg ): std::runtime_error(msg) { }};class W32Overlapped{public: OVERLAPPED o; W32Overlapped() { o.hEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); o.Internal = 0; o.InternalHigh = 0; o.Offset = 0; o.OffsetHigh = 0; if( o.hEvent == NULL ) throw comm_port_error("could not create Overlapped event"); } ~W32Overlapped() { if( o.hEvent != NULL ) CloseHandle( o.hEvent ); }};class NativeSerial{private: HANDLE hComm; W32Overlapped oread; W32Overlapped owrite; W32Overlapped owait; W32Overlapped oavail; std::string m_portname; int m_events_in; int m_events_out; bool m_dtr; bool m_rts;protected: void test_comm_success( bool success, const char* extra_msg ) { if( !success ) { DWORD err = GetLastError(); std::ostringstream os; char msg[1024]; FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 0, msg, sizeof(msg), NULL ); os << "Error " << err << ".\n " << msg; if( extra_msg != NULL ) { os << " in " << extra_msg; } throw comm_port_error(os.str().c_str()); } } DCB get_comm_state() { DCB dcb; test_comm_success( GetCommState( hComm, &dcb ), "get_comm_state.GetCommState" ); return dcb; } DWORD get_modem_status() { DWORD status = 0; test_comm_success( GetCommModemStatus( hComm, &status ), "get_modem_stauts.GetCommModemStatus" ); return status; } static DWORD map_events_to_win32( int event ) { DWORD ev = 0; if( event & DATA_AVAILABLE ) ev |= EV_RXCHAR; if( event & OUTPUT_EMPTY ) ev |= EV_TXEMPTY; if( event & CTS ) ev |= EV_CTS; if( event & DSR ) ev |= EV_DSR; if( event & RING_INDICATOR ) ev |= EV_RING; if( event & CARRIER_DETECT ) ev |= EV_RLSD; if( event & OVERRUN_ERROR ) ev |= EV_ERR; if( event & PARITY_ERROR ) ev |= EV_ERR; if( event & FRAMING_ERROR ) ev |= EV_ERR; if( event & BREAK_INTERRUPT ) ev |= EV_BREAK; return ev; } static int map_events_from_win32( DWORD ev, DWORD errors ) { int event = 0; if( ev & EV_RXCHAR ) event |= DATA_AVAILABLE; if( ev & EV_TXEMPTY ) event |= OUTPUT_EMPTY; if( ev & EV_CTS ) event |= CTS; if( ev & EV_DSR ) event |= DSR; if( ev & EV_RING ) event |= RING_INDICATOR; if( ev & EV_RLSD ) event |= CARRIER_DETECT; if( ev & EV_ERR ) { if( errors & CE_BREAK ) event |= BREAK_INTERRUPT; if( errors & CE_FRAME ) event |= FRAMING_ERROR; if( errors & CE_IOE ) throw comm_port_error("Win32 Comm IO Error"); if( errors & CE_MODE ) throw comm_port_error("Win32 Comm Invalid Mode"); if( errors & CE_OVERRUN ) event |= OVERRUN_ERROR; if( errors & CE_RXOVER ) event |= OVERRUN_ERROR; //?? okay if( errors & CE_RXPARITY ) event |= PARITY_ERROR; if( errors & CE_TXFULL ) event |= OVERRUN_ERROR; //?? okay } if( ev & EV_BREAK ) event |= BREAK_INTERRUPT; return event; }public: void setSerialPortParams( int baudrate, int databits, int stopbits, bool parity ) { DCB dcb = get_comm_state(); dcb.BaudRate = baudrate; dcb.ByteSize = databits; switch( stopbits ) { case 0: dcb.StopBits = ONE5STOPBITS; break; case 2: dcb.StopBits = TWOSTOPBITS; break; default: dcb.StopBits = ONESTOPBIT; } dcb.Parity = (parity ? 1 : 0); test_comm_success( SetCommState( hComm, &dcb ), "set_params.SetCommState" ); } int getBaudRate() { int baud_rate = get_comm_state().BaudRate; switch( baud_rate ) { case CBR_110: return 110; case CBR_300: return 300; case CBR_600: return 600; case CBR_1200: return 1200; case CBR_2400: return 2400; case CBR_4800: return 4800; case CBR_9600: return 9600; case CBR_14400: return 14400; case CBR_19200: return 19200; case CBR_38400: return 38400; case CBR_56000: return 56000; case CBR_57600: return 57600; case CBR_115200: return 115200; case CBR_128000: return 128000; case CBR_256000: return 256000; } return baud_rate; } int getDataBits() { return get_comm_state().ByteSize; } int getStopBits() { switch( get_comm_state().StopBits ) { case ONESTOPBIT: return 0; case ONE5STOPBITS: return 1; case TWOSTOPBITS: return 2; } return 0; } bool getParity() { return (get_comm_state().fParity != 0); } int read( signed char* buffer, int off, int len ) { DWORD nread = 0; if( !ReadFile( hComm, buffer+off, len, &nread, &oread.o ) ) { test_comm_success( GetLastError() == ERROR_IO_PENDING, "read.WriteFile" ); DWORD rvwait = WaitForSingleObject(oread.o.hEvent,INFINITE); test_comm_success( rvwait != WAIT_FAILED, "read.WaitForSingleObject" ); if( rvwait != WAIT_OBJECT_0 ) return 0; test_comm_success( GetOverlappedResult(hComm,&oread.o,&nread,TRUE), "read.GetOverlappedresult" ); } return nread; } int write( const signed char* buffer, int off, int len ) { DWORD nread = 0; DWORD nwritten = 0; if( !WriteFile( hComm, buffer+off, len, &nwritten, &owrite.o ) ) { test_comm_success( GetLastError() == ERROR_IO_PENDING, "write.WriteFile" ); DWORD rvwait = WaitForSingleObject(owrite.o.hEvent,INFINITE); test_comm_success( rvwait != WAIT_FAILED, "write.WaitForSingleObject" ); if( rvwait != WAIT_OBJECT_0 ) return 0; test_comm_success( GetOverlappedResult(hComm,&owrite.o,&nwritten,TRUE), "write.GetOverlappedresult" ); } return nwritten; } int read() { signed char byte; return (read(&byte,0,1) > 0) ? ((unsigned char)byte) : -1; } int write( int b ) { signed char byte = b; return write( &byte, 0, 1 ); } int available() { COMSTAT cs; DWORD errors = 0; test_comm_success( ClearCommError( hComm, &errors, &cs ), "available.ClearCommError" ); return cs.cbInQue; } void notifyOn( int event, bool enable ) { if( enable ) m_events_in |= event; else m_events_in &= ~event; test_comm_success( SetEvent( owait.o.hEvent ), "enable_event.SetEvent" ); } bool isNotifyOn( int event ) { return (m_events_in & event) != 0; } bool waitForEvent() { DWORD evMaskIn = map_events_to_win32( m_events_in ); DWORD evMaskOut = 0; m_events_out = 0; if( evMaskIn != 0 ) { test_comm_success( SetCommMask( hComm, evMaskIn ), "wait_for_event.SetCommMask" ); if( !WaitCommEvent(hComm,&evMaskOut,&owait.o) ) { DWORD nbytes = 0; test_comm_success( GetLastError() == ERROR_IO_PENDING, "wait_for_event.WaitCommEvent" ); DWORD rvwait = WaitForSingleObject(owait.o.hEvent,INFINITE); test_comm_success( rvwait != WAIT_FAILED, "wait_for_event.WaitForSingleObject" ); if( rvwait != WAIT_OBJECT_0 ) return 0; test_comm_success( GetOverlappedResult(hComm,&owait.o,&nbytes,TRUE), "write.GetOverlappedresult" ); } //evMaskOut &= evMaskIn; DWORD errors = 0; test_comm_success( ClearCommError( hComm, &errors, NULL ), "wait_for_event.ClearCommError" ); m_events_out = map_events_from_win32( evMaskOut, errors ); } else { test_comm_success( ResetEvent( owait.o.hEvent ), "wait_for_event.ResetEvent" ); DWORD rvwait = WaitForSingleObject( owait.o.hEvent, INFINITE ); test_comm_success( rvwait != WAIT_FAILED, "wait_for_event.WaitForSingleObject" ); } return (m_events_out != 0); } bool cancelWait() { test_comm_success( SetEvent( owait.o.hEvent ), "cancel_wait.SetEvent" ); return true; } bool didEventOccur( int event ) { return (m_events_out & event) != 0; } void setDTR( bool high ) { test_comm_success( EscapeCommFunction( hComm, (high ? SETDTR : CLRDTR) ), "setDTR.EscapeCommFunction" ); m_dtr = high; } void setRTS( bool high ) { test_comm_success( EscapeCommFunction( hComm, (high ? SETRTS : CLRRTS) ), "setRTS.EscapeCommFunction" ); m_rts = high; } bool isDTR() { return m_dtr; } bool isRTS() { return m_rts; } bool isCTS() { return (get_modem_status() & MS_CTS_ON) != 0; } bool isDSR() { return (get_modem_status() & MS_DSR_ON) != 0; } bool isRI() { return (get_modem_status() & MS_RING_ON) != 0; } bool isCD() { return (get_modem_status() & MS_RLSD_ON) != 0; } void sendBreak( int millis ) { } NativeSerial( const char* portname ): m_events_in(0), m_events_out(0), m_dtr(false), m_rts(false) { hComm = CreateFile( portname, GENERIC_READ | GENERIC_WRITE, 0, // exclusive access NULL, // default security attributes OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL ); test_comm_success( hComm != INVALID_HANDLE_VALUE, "NativeSerialPort.CreateFile" ); setDTR(false); setRTS(false); DWORD errors; test_comm_success( PurgeComm( hComm, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR ), "NativeSerialPort.PurgeComm" ); test_comm_success( ClearCommError( hComm, &errors, NULL ), "NativeSerialPort.ClearCommErrors" ); } ~NativeSerial() { close(); } void close() { CloseHandle( hComm ); SetEvent( oread.o.hEvent ); SetEvent( owrite.o.hEvent ); SetEvent( owait.o.hEvent ); SetEvent( oavail.o.hEvent ); } static std::string getTOSCommMap() { const char* env = getenv( "TOSCOMMMAP" ); return (env == NULL) ? "com1=COM1:com10=\\\\.\\COM10" : env; }};#include "TOSComm_wrap.cxx"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -