text_thread.cpp
上传用户:psq1974
上传日期:2007-01-06
资源大小:1195k
文件大小:8k
源码类别:

mpeg/mp3

开发平台:

C/C++

  1. /* Copyright (C) 1998, 1999 State University of New York at Stony Brook
  2.    Author: Andrew V. Shuvalov ( andrew@ecsl.cs.sunysb.edu )
  3.    Software license is located in file "COPYING"
  4. */
  5. #include "stdafx.h"
  6. #include "text_thread.h"
  7. #include "protocol_thread.h"
  8. #include "video_thread.h"
  9. #define ASCII_XON       0x11
  10. #define ASCII_XOFF      0x13
  11. comport::comport( const std::string &comport_name ) :
  12.   portname( comport_name ), port_h( (HANDLE)-1 ), 
  13.   shutdown_mutex( "lock shutdown procedure" ), dwEvtMask( 0 )
  14. {
  15. }
  16. void comport::init()
  17. {
  18.   if ( ( port_h =
  19.  CreateFile( portname.c_str(), GENERIC_READ | GENERIC_WRITE,
  20.      0,                    // exclusive access
  21.      NULL,                 // no security attrs
  22.      OPEN_EXISTING,
  23.      FILE_ATTRIBUTE_NORMAL | 
  24.      FILE_FLAG_OVERLAPPED, // overlapped I/O
  25.      NULL )) == (HANDLE) -1 ) {
  26.     port_h = (HANDLE)-1;
  27.     throw ComportException( "CreateFile: %s", sys_errlist[ errno ] );
  28.   }
  29.   COMMTIMEOUTS  CommTimeOuts;
  30.   // get any early notifications
  31.   SetCommMask( port_h, EV_RXCHAR ) ;
  32.   // setup device buffers
  33.   SetupComm( port_h, 4096, 4096 ) ;
  34.   // purge any information in the buffer
  35.   PurgeComm( port_h, PURGE_TXABORT | PURGE_RXABORT |
  36.      PURGE_TXCLEAR | PURGE_RXCLEAR ) ;
  37.   // set up for overlapped I/O
  38.   CommTimeOuts.ReadIntervalTimeout = 0xFFFFFFFF ;
  39.   CommTimeOuts.ReadTotalTimeoutMultiplier = 0 ;
  40.   CommTimeOuts.ReadTotalTimeoutConstant = 1000 ;
  41.   CommTimeOuts.WriteTotalTimeoutMultiplier = 0 ;
  42.   CommTimeOuts.WriteTotalTimeoutConstant = 1000 ;
  43.   SetCommTimeouts( port_h, &CommTimeOuts ) ;
  44.   // set comm state
  45.   DCB        dcb ;
  46.   dcb.DCBlength = sizeof( DCB ) ;
  47.   GetCommState( port_h, &dcb ) ;
  48.   dcb.BaudRate = 9600;
  49.   dcb.ByteSize = 8;
  50.   dcb.Parity = 0;
  51.   dcb.StopBits = 0;
  52.   // setup hardware flow control
  53.   dcb.fDtrControl = DTR_CONTROL_ENABLE ;
  54.   dcb.fRtsControl = RTS_CONTROL_ENABLE ;
  55.   // setup software flow control
  56.   dcb.fInX = dcb.fOutX = 1;
  57.   dcb.XonChar = ASCII_XON ;
  58.   dcb.XoffChar = ASCII_XOFF ;
  59.   dcb.XonLim = 100 ;
  60.   dcb.XoffLim = 100 ;
  61.   // other various settings
  62.   dcb.fBinary = TRUE ;
  63.   dcb.fParity = TRUE ;
  64.   BOOL fRetVal = SetCommState( port_h, &dcb ) ;
  65.   if( fRetVal == false )
  66.     {
  67.       CloseHandle( port_h );
  68.       port_h = (HANDLE) -1;
  69.       throw ComportException( "CreateFile: %s", sys_errlist[ errno ] );
  70.     }
  71.   // init "overlapped" structure for the background loading
  72.   memset( &os, 0, sizeof( OVERLAPPED ) ) ;
  73.   // create I/O event used for overlapped read
  74.   os.hEvent = CreateEvent( NULL,    // no security
  75.    TRUE,    // explicit reset req
  76.    FALSE,   // initial event reset
  77.    NULL ) ; // no name
  78.   if (os.hEvent == NULL)
  79.     {
  80.       CloseHandle( port_h );
  81.       port_h = (HANDLE) -1;
  82.       throw ComportException( "CreateEvent: %s", sys_errlist[ errno ] );
  83.     }
  84.   if (!SetCommMask( port_h, EV_RXCHAR | EV_TXEMPTY ))
  85.     {
  86.       CloseHandle( port_h );
  87.       port_h = (HANDLE) -1;
  88.       throw ComportException( "SetCommMask: %s", sys_errlist[ errno ] );
  89.     }
  90. }
  91. void comport::shutdown()
  92. {
  93.   wait_for_mutex wm( shutdown_mutex, 3 );
  94.   
  95.   if( port_h == (HANDLE) -1 )
  96.     return;
  97.   SetCommMask( port_h, 0 ) ;
  98.   EscapeCommFunction( port_h, CLRDTR ) ;
  99.   // purge any outstanding reads/writes and close device handle
  100.   
  101.   PurgeComm( port_h, PURGE_TXABORT | PURGE_RXABORT |
  102.      PURGE_TXCLEAR | PURGE_RXCLEAR ) ;
  103.   CloseHandle( port_h );
  104.   port_h = (HANDLE) -1;
  105.   CloseHandle( os.hEvent ) ;
  106. }
  107. comport::~comport()
  108. {
  109.   shutdown();
  110. }
  111. bool comport::wait_comport_event()
  112. {
  113.   dwEvtMask = 0;
  114.   
  115.   WaitCommEvent( port_h, &dwEvtMask, NULL );
  116.   if ((dwEvtMask & EV_RXCHAR) == EV_RXCHAR)
  117.     return true;   // data
  118.   return false;
  119. }
  120. text_data *comport::get_data()
  121. {
  122.   DWORD dwErrorFlags;
  123.   COMSTAT ComStat;
  124.   ClearCommError( port_h, &dwErrorFlags, &ComStat );
  125.   if( ComStat.cbInQue == 0 )
  126.     return NULL;            // that's not the error - just nothing
  127.   DWORD dwLength = ComStat.cbInQue; // data to load
  128.   // remember the old data size
  129.   unsigned oldSize = internal_buffer.length();
  130.   /** will append data to the end of string inside internal_buffer */
  131.   internal_buffer.resize( internal_buffer.length() + dwLength + 1 );
  132.   // zero at the end: space was reserved with 1 extra char
  133.   *(char*)( internal_buffer.c_str() + internal_buffer.length() ) = '';
  134.   if( false == ReadFile( port_h, (void*) (internal_buffer.c_str() + oldSize),
  135.  dwLength, &dwLength, &os ) )
  136.     {
  137.       if (GetLastError() == ERROR_IO_PENDING)
  138. {
  139.   // We have to wait for read to complete. 
  140.   // This function will timeout according to the
  141.   // CommTimeOuts.ReadTotalTimeoutConstant variable
  142.   // Every time it times out, check for port errors
  143.   while(!GetOverlappedResult( port_h, 
  144.       &os, &dwLength, TRUE ))
  145.     {
  146.       if( GetLastError() == ERROR_IO_INCOMPLETE )
  147. // normal result if not finished
  148. continue;
  149.       else
  150. {
  151.   // an error occurred
  152.   ClearCommError( port_h, &dwErrorFlags, &ComStat ) ;
  153.   dwLength = 0; // reset
  154.   break;
  155. }
  156.     }
  157. }
  158.       else  // error != ERROR_IO_PENDING
  159. {
  160.   dwLength = 0;
  161.   ClearCommError( port_h, &dwErrorFlags, &ComStat );
  162. }
  163.     }
  164.   // now resize the buffer to the exact size
  165.   if( dwLength )
  166.     internal_buffer.resize( oldSize + dwLength );
  167.   //  dwLength indicates the amount of information read
  168.   if( !dwLength && !internal_buffer.length() )
  169.     return NULL;
  170.   // check if the newly allocated data contains 'n'
  171.   // we did put zero at the end, so that's fine!
  172.   char *pos;
  173.   if( NULL == ( pos = strchr
  174. ( internal_buffer.c_str() + oldSize, 'n' )))
  175.     {
  176.       // in most cases it happens like this - not a full line
  177.       return NULL;
  178.     }
  179.   // replace the 'n' by zero to end the string
  180.   *pos = '';
  181.   // return the new structure
  182.   text_data *td = new text_data( internal_buffer.c_str() );
  183.   // erase what is copied into text_data
  184.   internal_buffer.erase( 0, pos - internal_buffer.c_str() + 1 );
  185.   return td;
  186. }
  187. // ------------------------- text_thread ---------------------
  188. text_thread::text_thread( int argc, char **argv ) :
  189.   shutdown_mutex( "lock shutdown procedure" ), 
  190.   shutdown_now( false ), com_port( NULL )
  191. {
  192.   std::string portname = "COM2"; // com1 or com2, default com2
  193.   for( int i = 1; i < argc; i++ )
  194.     {
  195.       std::string arg( argv[i] );
  196.       if( arg == "-1" )
  197. {
  198.   portname = "COM1";
  199. }
  200.       else if( arg == "-2" )
  201. {
  202.   portname = "COM2";
  203. }
  204.       else if( arg == "-3" )
  205. {
  206.   portname = "COM3";
  207. }
  208.       else if( arg == "-4" )
  209. {
  210.   portname = "COM4";
  211. }
  212.     }
  213.   com_port = new comport( portname );
  214. }
  215. // static 
  216. void text_thread::text_thread_entry_func( void *_instance )
  217. {
  218.   text_thread *instance = (text_thread *) _instance;
  219.   try
  220.     {
  221.       instance->init();
  222.     }
  223.   catch ( ComportException e )
  224.     {
  225.       // the application should continue to work
  226.       protocolThread->log(0,"com port exception: %s",e.getText().c_str());
  227.       instance->shutdown();
  228.       return;
  229.     }
  230.   // loop
  231.   while( true )
  232.     {
  233.       try
  234. {
  235.   instance->loop();       // until some exception
  236. }
  237.       catch ( ShutdownException e )
  238. {
  239.   protocolThread->log(1,"shutdown exception: %s",e.getText().c_str());
  240.   instance->shutdown();
  241.   break;
  242. }
  243.       catch ( ComportException e )
  244. {
  245.   protocolThread->log(0,"com port exception: %s",e.getText().c_str());
  246.   instance->shutdown();
  247.   break;
  248. }
  249.     }
  250. }
  251. void text_thread::loop()
  252. {
  253.   while( true )
  254.     {
  255.       if( shutdown_now )
  256. {
  257.   protocolThread->log
  258.     ( 0, "text thread throws ShutdownException, line %d", __LINE__ );
  259.   throw ShutdownException( "shutdown requested" );
  260. }
  261.       bool res = com_port->wait_comport_event();
  262.       if( res == true )
  263. {
  264.   // some data, will go into protocol thread
  265.   text_data *data1 = com_port->get_data();
  266.   // it may be null
  267.   if( data1 )
  268.     {
  269.       // we need the second instance for video thread as well 
  270.       text_data *data2 = new text_data( *data1 );
  271.       protocolThread->log
  272. ( 3, "got new text" );
  273.       protocolThread->new_text_data( data1 );
  274.       videoThread->new_text_data( data2 );
  275.     }
  276. }
  277.     }
  278. }