int main( int argc, char **argv ) { int sig; sigset_t termSig; pthread_t readSerialThreadId; pthread_t readStdinThreadId; int rc; int opt; const char *baudStr = NULL; #if defined( linux ) const char *portStr = "ttyS0"; #else const char *portStr = "com1"; #endif #if USE_I2C PKT_TextChar = PacketTextChar; PKT_SendChar = PacketSendChar; PKT_PacketReceived = PacketReceived; #endif // signal( SIGINT, ControlC ); // signal( SIGTERM, ControlC ); LogInit( stdout ); while (( opt = getopt_long( argc, argv, "b:dhmp:sv", gLongOption, NULL )) > 0 ) { switch ( opt ) { case 'b': { baudStr = optarg; break; } case 'd': { gDebug = true; break; } case 'g': { gDongle = true; break; } case 'm': { gMegaLoad = true; break; } case 'p': { portStr = optarg; break; } case 'r': { gUseRtsToReset = true; break; } case 's': { gStk500 = true; break; } case 'v': { gVerbose = true; break; } #if USE_I2C case OPT_DEBUG_DONGLE: { gSerialDongle.m_debugDongle = true; break; } case OPT_DEBUG_DONGLE_DATA: { gSerialDongle.m_debugDongleData = true; break; } #endif case '?': case 'h': { Usage(); return 1; } } } if ( optind < argc ) { if (( optind + 1 ) != argc ) { fprintf( stderr, "Only one download file supported\n" ); return 1; } gDownloadFileName = argv[ optind ]; } // Open the file to download if ( gDownloadFileName != NULL ) { // If we are asked to download a file, then read the entire file // into memory. if (( gDownloadInfo = ReadFile( gDownloadFileName )) == NULL ) { return 1; } } if ( !gSerialPort.Open( portStr, baudStr )) { return 1; } gSerialPort.UseRTStoReset( gUseRtsToReset ); gSerialPort.ResetTarget(); // Put stdin in raw mode setbuf( stdin, NULL ); setbuf( stdout, NULL ); #if defined( unix ) sigemptyset( &termSig ); sigaddset( &termSig, SIGINT ); sigaddset( &termSig, SIGTERM ); pthread_sigmask( SIG_BLOCK, &termSig, NULL ); struct termios tio_new; if ( tcgetattr( fileno( stdin ), &gTio_org ) < 0 ) { LogError( "Unable to retrieve terminal settings\n" ); return 1; } tio_new = gTio_org; tio_new.c_lflag &= ~( ICANON | ECHO ); tio_new.c_cc[VMIN] = 1; tio_new.c_cc[VTIME] = 0; if ( tcsetattr( fileno( stdin ), TCSANOW, &tio_new ) < 0 ) { LogError( "Unable to update terminal settings\n" ); return 1; } #endif const char *bootLoaderType = "*** Unknown ***"; if ( gDongle ) { bootLoaderType = "Serial Dongle"; } else if ( gMegaLoad ) { bootLoaderType = "MegaLoad v2.3"; } else if ( gStk500 ) { bootLoaderType = "STK500"; } gLogFs2 = fopen( "BootHost.log", "wb" ); Log( "BootHost - BootLoader: %s\n", bootLoaderType ); // Kick off the serial port reader thread. rc = pthread_create( &readSerialThreadId, NULL, ReadSerialThread, &gSerialPort ); if ( rc != 0 ) { fprintf( stderr, "Error creating ReadSerialThread: %d\n", rc ); return 1; } // Kick off the stdin reader thread. rc = pthread_create( &readStdinThreadId, NULL, ReadStdinThread, NULL ); if ( rc != 0 ) { fprintf( stderr, "Error creating ReadSerialThread: %d\n", rc ); return 1; } #if defined( unix ) // Wait for a termmination signal if (( rc = sigwait( &termSig, &sig )) != 0 ) { fprintf( stderr, "sigwait failed\n" ); } else { fprintf( stderr, "Exiting...\n" ); } pthread_cancel( readSerialThreadId ); pthread_cancel( readStdinThreadId ); // Restore stdin back to the way it was when we started if ( tcsetattr( fileno( stdin ), TCSANOW, &gTio_org ) == -1 ) { LogError( "Unable to restore terminal settings\n" ); } #endif #if defined( __CYGWIN__ ) // Under Windows closing the serial port and stdin will cause the reads // to unblock. Under linux, this isn't required, but it doesn't hurt // either. gSerialPort.Close(); fclose( stdin ); #endif // Unblock the termination signals so the user can kill us if we hang up // waiting for the reader threads to exit. #if defined( unix ) pthread_sigmask( SIG_UNBLOCK, &termSig, NULL ); #endif pthread_join( readSerialThreadId, NULL ); pthread_join( readStdinThreadId, NULL ); #if !defined( __CYGWIN__ ) gSerialPort.Close(); fclose( stdin ); #endif if ( gVerbose ) { printf( "Done\n" ); } return 0; } // main