text_thread.cpp
上传用户:psq1974
上传日期:2007-01-06
资源大小:1195k
文件大小:8k
- /* Copyright (C) 1998, 1999 State University of New York at Stony Brook
- Author: Andrew V. Shuvalov ( andrew@ecsl.cs.sunysb.edu )
- Software license is located in file "COPYING"
- */
- #include "stdafx.h"
- #include "text_thread.h"
- #include "protocol_thread.h"
- #include "video_thread.h"
- #define ASCII_XON 0x11
- #define ASCII_XOFF 0x13
- comport::comport( const std::string &comport_name ) :
- portname( comport_name ), port_h( (HANDLE)-1 ),
- shutdown_mutex( "lock shutdown procedure" ), dwEvtMask( 0 )
- {
- }
- void comport::init()
- {
- if ( ( port_h =
- CreateFile( portname.c_str(), GENERIC_READ | GENERIC_WRITE,
- 0, // exclusive access
- NULL, // no security attrs
- OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL |
- FILE_FLAG_OVERLAPPED, // overlapped I/O
- NULL )) == (HANDLE) -1 ) {
- port_h = (HANDLE)-1;
- throw ComportException( "CreateFile: %s", sys_errlist[ errno ] );
- }
- COMMTIMEOUTS CommTimeOuts;
- // get any early notifications
- SetCommMask( port_h, EV_RXCHAR ) ;
- // setup device buffers
- SetupComm( port_h, 4096, 4096 ) ;
- // purge any information in the buffer
- PurgeComm( port_h, PURGE_TXABORT | PURGE_RXABORT |
- PURGE_TXCLEAR | PURGE_RXCLEAR ) ;
- // set up for overlapped I/O
- CommTimeOuts.ReadIntervalTimeout = 0xFFFFFFFF ;
- CommTimeOuts.ReadTotalTimeoutMultiplier = 0 ;
- CommTimeOuts.ReadTotalTimeoutConstant = 1000 ;
- CommTimeOuts.WriteTotalTimeoutMultiplier = 0 ;
- CommTimeOuts.WriteTotalTimeoutConstant = 1000 ;
- SetCommTimeouts( port_h, &CommTimeOuts ) ;
- // set comm state
- DCB dcb ;
- dcb.DCBlength = sizeof( DCB ) ;
- GetCommState( port_h, &dcb ) ;
- dcb.BaudRate = 9600;
- dcb.ByteSize = 8;
- dcb.Parity = 0;
- dcb.StopBits = 0;
- // setup hardware flow control
- dcb.fDtrControl = DTR_CONTROL_ENABLE ;
- dcb.fRtsControl = RTS_CONTROL_ENABLE ;
- // setup software flow control
- dcb.fInX = dcb.fOutX = 1;
- dcb.XonChar = ASCII_XON ;
- dcb.XoffChar = ASCII_XOFF ;
- dcb.XonLim = 100 ;
- dcb.XoffLim = 100 ;
- // other various settings
- dcb.fBinary = TRUE ;
- dcb.fParity = TRUE ;
- BOOL fRetVal = SetCommState( port_h, &dcb ) ;
- if( fRetVal == false )
- {
- CloseHandle( port_h );
- port_h = (HANDLE) -1;
- throw ComportException( "CreateFile: %s", sys_errlist[ errno ] );
- }
- // init "overlapped" structure for the background loading
- memset( &os, 0, sizeof( OVERLAPPED ) ) ;
- // create I/O event used for overlapped read
- os.hEvent = CreateEvent( NULL, // no security
- TRUE, // explicit reset req
- FALSE, // initial event reset
- NULL ) ; // no name
- if (os.hEvent == NULL)
- {
- CloseHandle( port_h );
- port_h = (HANDLE) -1;
- throw ComportException( "CreateEvent: %s", sys_errlist[ errno ] );
- }
- if (!SetCommMask( port_h, EV_RXCHAR | EV_TXEMPTY ))
- {
- CloseHandle( port_h );
- port_h = (HANDLE) -1;
- throw ComportException( "SetCommMask: %s", sys_errlist[ errno ] );
- }
- }
- void comport::shutdown()
- {
- wait_for_mutex wm( shutdown_mutex, 3 );
-
- if( port_h == (HANDLE) -1 )
- return;
- SetCommMask( port_h, 0 ) ;
- EscapeCommFunction( port_h, CLRDTR ) ;
- // purge any outstanding reads/writes and close device handle
-
- PurgeComm( port_h, PURGE_TXABORT | PURGE_RXABORT |
- PURGE_TXCLEAR | PURGE_RXCLEAR ) ;
- CloseHandle( port_h );
- port_h = (HANDLE) -1;
- CloseHandle( os.hEvent ) ;
- }
- comport::~comport()
- {
- shutdown();
- }
- bool comport::wait_comport_event()
- {
- dwEvtMask = 0;
-
- WaitCommEvent( port_h, &dwEvtMask, NULL );
- if ((dwEvtMask & EV_RXCHAR) == EV_RXCHAR)
- return true; // data
- return false;
- }
- text_data *comport::get_data()
- {
- DWORD dwErrorFlags;
- COMSTAT ComStat;
- ClearCommError( port_h, &dwErrorFlags, &ComStat );
- if( ComStat.cbInQue == 0 )
- return NULL; // that's not the error - just nothing
- DWORD dwLength = ComStat.cbInQue; // data to load
- // remember the old data size
- unsigned oldSize = internal_buffer.length();
- /** will append data to the end of string inside internal_buffer */
- internal_buffer.resize( internal_buffer.length() + dwLength + 1 );
- // zero at the end: space was reserved with 1 extra char
- *(char*)( internal_buffer.c_str() + internal_buffer.length() ) = ' ';
- if( false == ReadFile( port_h, (void*) (internal_buffer.c_str() + oldSize),
- dwLength, &dwLength, &os ) )
- {
- if (GetLastError() == ERROR_IO_PENDING)
- {
- // We have to wait for read to complete.
- // This function will timeout according to the
- // CommTimeOuts.ReadTotalTimeoutConstant variable
- // Every time it times out, check for port errors
- while(!GetOverlappedResult( port_h,
- &os, &dwLength, TRUE ))
- {
- if( GetLastError() == ERROR_IO_INCOMPLETE )
- // normal result if not finished
- continue;
- else
- {
- // an error occurred
- ClearCommError( port_h, &dwErrorFlags, &ComStat ) ;
- dwLength = 0; // reset
- break;
- }
- }
- }
- else // error != ERROR_IO_PENDING
- {
- dwLength = 0;
- ClearCommError( port_h, &dwErrorFlags, &ComStat );
- }
- }
- // now resize the buffer to the exact size
- if( dwLength )
- internal_buffer.resize( oldSize + dwLength );
- // dwLength indicates the amount of information read
- if( !dwLength && !internal_buffer.length() )
- return NULL;
- // check if the newly allocated data contains 'n'
- // we did put zero at the end, so that's fine!
- char *pos;
- if( NULL == ( pos = strchr
- ( internal_buffer.c_str() + oldSize, 'n' )))
- {
- // in most cases it happens like this - not a full line
- return NULL;
- }
- // replace the 'n' by zero to end the string
- *pos = ' ';
- // return the new structure
- text_data *td = new text_data( internal_buffer.c_str() );
- // erase what is copied into text_data
- internal_buffer.erase( 0, pos - internal_buffer.c_str() + 1 );
- return td;
- }
- // ------------------------- text_thread ---------------------
- text_thread::text_thread( int argc, char **argv ) :
- shutdown_mutex( "lock shutdown procedure" ),
- shutdown_now( false ), com_port( NULL )
- {
- std::string portname = "COM2"; // com1 or com2, default com2
- for( int i = 1; i < argc; i++ )
- {
- std::string arg( argv[i] );
- if( arg == "-1" )
- {
- portname = "COM1";
- }
- else if( arg == "-2" )
- {
- portname = "COM2";
- }
- else if( arg == "-3" )
- {
- portname = "COM3";
- }
- else if( arg == "-4" )
- {
- portname = "COM4";
- }
- }
- com_port = new comport( portname );
- }
- // static
- void text_thread::text_thread_entry_func( void *_instance )
- {
- text_thread *instance = (text_thread *) _instance;
- try
- {
- instance->init();
- }
- catch ( ComportException e )
- {
- // the application should continue to work
- protocolThread->log(0,"com port exception: %s",e.getText().c_str());
- instance->shutdown();
- return;
- }
- // loop
- while( true )
- {
- try
- {
- instance->loop(); // until some exception
- }
- catch ( ShutdownException e )
- {
- protocolThread->log(1,"shutdown exception: %s",e.getText().c_str());
- instance->shutdown();
- break;
- }
- catch ( ComportException e )
- {
- protocolThread->log(0,"com port exception: %s",e.getText().c_str());
- instance->shutdown();
- break;
- }
- }
- }
- void text_thread::loop()
- {
- while( true )
- {
- if( shutdown_now )
- {
- protocolThread->log
- ( 0, "text thread throws ShutdownException, line %d", __LINE__ );
- throw ShutdownException( "shutdown requested" );
- }
- bool res = com_port->wait_comport_event();
- if( res == true )
- {
- // some data, will go into protocol thread
- text_data *data1 = com_port->get_data();
- // it may be null
- if( data1 )
- {
- // we need the second instance for video thread as well
- text_data *data2 = new text_data( *data1 );
- protocolThread->log
- ( 3, "got new text" );
- protocolThread->new_text_data( data1 );
- videoThread->new_text_data( data2 );
- }
- }
- }
- }