#include "comms.h" /*===========================================================================* * * * Constants * * * *===========================================================================* */ const char * HELP_STRING = "Command line: [-?] \n"; const char * BASIC_SETTINGS = "-parenb " // No parity bit "cs8 " // 8 bit "-hup " // No hang up signal "-cstopb " // One stop bit "cread " // Allow input "clocal " // Disable modem control signals "-crtscts " // Disable RTS/CTS flow control "-ignbrk " // Do not ignore break chars "-brkint " // No signal from break chars "-istrip " // Don't strip top bit "-inlcr " // Don't translate newline to Cr "-igncr -icrnl -ixon -ixoff -tandem -iuclc -ixany -imaxbel " // Output "-opost -olcuc -ocrnl -onlcr -onocr -onlret -ofill -ofdel " "raw " "-isig -icanon -iexten -echo -echoe -echok -echonl -echoctl " "-echoke "; const char * HW_FLOWCTRL_SETTINGS = "-parenb " // No parity bit "cs8 " // 8 bit "-hup " // No hang up signal "-cstopb " // One stop bit "cread " // Allow input "clocal " // Disable modem control signals "crtscts " // Enable RTS/CTS flow control "-ignbrk " // Do not ignore break chars "-brkint " // No signal from break chars "-istrip " // Don't strip top bit "-inlcr " // Don't translate newline to Cr "-igncr -icrnl -ixon -ixoff -tandem -iuclc -ixany -imaxbel " // Output "-opost -olcuc -ocrnl -onlcr -onocr -onlret -ofill -ofdel " "raw " "-isig -icanon -iexten -echo -echoe -echok -echonl -echoctl " "-echoke "; const char * HW_FLOWCTRL_STOP = "-rtsxoff "; // Disallow input const char * HW_FLOWCTRL_GO = "rtsxoff "; // Allow input // Default foreground colour. const UINT_T FOREGROUND_COLOUR = DULL_WHITE; /*---------------------------------------------------------------------------- * Output is logged to the following filename. */ #define LOG_FILENAME "test_log" #define RED "\e[0;31m" #define GREEN "\e[0;32m" #define YELLOW "\e[0;33m" #define BLUE "\e[0;34m" #define MAGENTA "\e[0;35m" #define CYAN "\e[0;36m" #define WHITE "\e[0;36m" #define NORMAL "\e[0m" //#define OXDEBUG #ifdef OXDEBUG #define TEST_DATA_SIZE 1024 #define WINDOW_SIZE 200 #else #define TEST_DATA_SIZE 1048576 //#define WINDOW_SIZE 20000 #define WINDOW_SIZE 1024 #endif /*===========================================================================* * * * Public data * * * *===========================================================================* */ ostream * log_file_ptr; /*===========================================================================* * * * Local data * * * *===========================================================================* */ //typedef int COMM_PORT_HANDLE; #define INVALID_HANDLE_VALUE -1 //static COMM_PORT_HANDLE serial_handle = INVALID_HANDLE_VALUE; //#define ALT(letter) (225+letter-'A') //static UINT_T marker_index = 0; /*--------------------------------------------------------------------------*/ #define MAXIMUM_ESCAPE_SEQUENCE 16 /*--------------------------------------------------------------------------*/ #define MAXIMUM_INPUT 1024 unsigned char last_input[MAXIMUM_INPUT+1] = {0}; #define NUMBER_OF_OLD_LOGS 4 /*===========================================================================* * * * Local functions * * * *===========================================================================* */ static bool RunTest( char * sTestPort0, char * sTestPort1, unsigned int baudRate); static bool OpenPort( char * sTestPort, unsigned int baudRate, int * handle); bool SetRTS( int handle, int level); int GetCTS( int handle); int GetOPLevel( int handle); static void ClosePort( int handle); static void wait_for_key( void); static bool Test( unsigned int baudRate, char * sTestPort0, char * sTestPort1, Direction direction, FlowControlMode flowControlMode, BurstyMode burstyMode, unsigned int windowSize, unsigned int testDataSize); /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + main + + Purpose: + + entry point. + + Arguments: + + Number of args exactly (includes program name). + Array of args. + + Return values: + + Error code or zero. + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ int main( int argc, char * argv[]) { BOOLEAN_T failed = FALSE; //RETCODE_T rc; char * sTestPort0 = NULL; char * sTestPort1 = NULL; bool testPortSpecified = false; /*-----------------------------------------------------------------------* * Parse command line * *-----------------------------------------------------------------------* */ for (INT_T i=1; i DEBUG_LINES+1) { screen_lines = LINES-DEBUG_LINES-1; debug_lines = DEBUG_LINES; } else { screen_lines = LINES; debug_lines = 0; } #else screen_lines = LINES; debug_lines = 0; #endif screen_columns = COLS; initialise_ui(); /* * Draw the debug area. */ ui_draw_debug_area( screen_lines, debug_lines); /*-----------------------------------------------------------------------* * Start logging * *-----------------------------------------------------------------------* */ ofstream log_file(LOG_FILENAME); if (!log_file) { ui_printf(BRIGHT_RED, "Cannot open log file.\n"); failed = true; } else { log_file_ptr = &log_file; } /*-----------------------------------------------------------------------* * Print banner * *-----------------------------------------------------------------------* */ char banner[1024]; sprintf(banner, "Testing %s and %s", sTestPort0, sTestPort1); ui_middle( BRIGHT_WHITE, banner); ui_printf(DULL_WHITE, "\n"); /*-----------------------------------------------------------------------* * Run test at various baud rates * *-----------------------------------------------------------------------* */ while (!failed) { failed = !RunTest(sTestPort0, sTestPort1, 9600); if (!failed) { failed = !RunTest(sTestPort0, sTestPort1, 115200); } } ui_middle( BRIGHT_RED, "\n"); ui_middle( BRIGHT_RED, "-------------------------------------------------------------------"); ui_middle( BRIGHT_RED, " Error detected!!! "); ui_middle( BRIGHT_RED, "-------------------------------------------------------------------"); ui_middle( BRIGHT_RED, "\n"); /*-----------------------------------------------------------------------* * If failed, wait for user to press a key * *-----------------------------------------------------------------------* */ wait_for_key(); /*-----------------------------------------------------------------------* * Call all module shutdown functions * *-----------------------------------------------------------------------* */ closedown_display(); return failed; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + RunTest + + Purpose: + + Run a test between the given port and ttyS0 at the given baud rate. + + Arguments: + + Port number. + Baud rate. + + Return Values: + + true if passed. + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ static bool RunTest( char * sTestPort0, char * sTestPort1, unsigned int baudRate) { ui_printf( BRIGHT_WHITE, "\nRunning test on %s and %s at %d.\n", sTestPort0, sTestPort1, baudRate); refresh(); ui_printf( BRIGHT_CYAN, "\n Data transfer from test port 0 to test port 1.\n", sTestPort0, baudRate); refresh(); if (!Test( baudRate, sTestPort0, sTestPort1, UNIDIRECTIONAL_PORT_0_TO_PORT_1, HFCTRLTEST_OFF, BURSTYDATA_OFF, 100, 102400 )) { return false; } ui_printf( BRIGHT_CYAN, "\n Data transfer from test port 1 to test port 0.\n", sTestPort0, baudRate); refresh(); if (!Test( baudRate, sTestPort0, sTestPort1, UNIDIRECTIONAL_PORT_1_TO_PORT_0, HFCTRLTEST_OFF, BURSTYDATA_OFF, 100, 102400 )) { return false; } ui_printf( BRIGHT_CYAN, "\n Bidirectional data transfer.\n", sTestPort0, baudRate); refresh(); if (!Test( baudRate, sTestPort0, sTestPort1, BIDIRECTIONAL, HFCTRLTEST_OFF, BURSTYDATA_OFF, 1000, 1048576 )) { return false; } #if 1 ui_printf( BRIGHT_CYAN, "\n Bursty unidirectional data transfer from test port 0 to test port 1.\n", sTestPort0, baudRate); refresh(); if (!Test( baudRate, sTestPort0, sTestPort1, UNIDIRECTIONAL_PORT_0_TO_PORT_1, HFCTRLTEST_OFF, BURSTYDATA_ON, 100, 102400 )) { return false; } ui_printf( BRIGHT_CYAN, "\n Bursty unidirectional data transfer from test port 1 to test port 0.\n", sTestPort0, baudRate); refresh(); if (!Test( baudRate, sTestPort0, sTestPort1, UNIDIRECTIONAL_PORT_1_TO_PORT_0, HFCTRLTEST_OFF, BURSTYDATA_ON, 100, 102400 )) { return false; } ui_printf( BRIGHT_CYAN, "\n Bursty bidirectional data transfer.\n", sTestPort0, baudRate); refresh(); if (!Test( baudRate, sTestPort0, sTestPort1, BIDIRECTIONAL, HFCTRLTEST_OFF, BURSTYDATA_ON, 100, 102400 )) { return false; } ui_printf( BRIGHT_CYAN, "\n Data transfer from test port 0 to test port 1, with Hardware Flow Control.\n", sTestPort0, baudRate); refresh(); if (!Test( baudRate, sTestPort0, sTestPort1, UNIDIRECTIONAL_PORT_0_TO_PORT_1, HFCTRLTEST_ON, BURSTYDATA_OFF, 100, 102400 )) { return false; } ui_printf( BRIGHT_CYAN, "\n Data transfer from test port 1 to test port 0, with Hardware Flow Control.\n", sTestPort0, baudRate); refresh(); if (!Test( baudRate, sTestPort0, sTestPort1, UNIDIRECTIONAL_PORT_1_TO_PORT_0, HFCTRLTEST_ON, BURSTYDATA_OFF, 100, 102400 )) { return false; } ui_printf( BRIGHT_CYAN, "\n Bidirectional data transfer, with Hardware Flow Control.\n", sTestPort0, baudRate); refresh(); if (!Test( baudRate, sTestPort0, sTestPort1, BIDIRECTIONAL, HFCTRLTEST_ON, BURSTYDATA_OFF, 100, 102400 )) { return false; } ui_printf( BRIGHT_CYAN, "\n Bidirectional data transfer, with Hardware Flow Control.\n", sTestPort0, baudRate); refresh(); if (!Test( baudRate, sTestPort0, sTestPort1, BIDIRECTIONAL, HFCTRLTEST_ON, BURSTYDATA_OFF, 1000, 102400 )) { return false; } #endif return true; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + Test + + Purpose: + + Transmits and Receives data in both directions between the 2 serial porst, + whilst forcing flow control, comparing the data for errors + + Arguments: + + baud rate - e.g. 9600 or 115200 +. test port number 0 - e.g. /dev/ttyS0 + test port number 1 - e.g. /dev/ttyS1 + direction - One of: UNIDIRECTIONAL_PORT_0_TO_PORT_1 + UNIDIRECTIONAL_PORT_1_TO_PORT_0 + BIDIRECTIONAL + flowControlMode - One of: HFCTRLTEST_OFF, HFCTRLTEST_ON. + burstyMode - One of: BURSTYDATA_OFF, BURSTYDATA_ON + windowSize - Size of sliding window in bytes (i.e. how much + data we will transmit without receiving it). + testDataSize - Number of bytes of test data to send. + + Return Values: + + true if success. + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ static bool Test( unsigned int baudRate, char * sTestPort0, char * sTestPort1, Direction direction, FlowControlMode flowControlMode, BurstyMode burstyMode, unsigned int windowSize, unsigned int testDataSize) { unsigned int i; bool failed = false; // These are indexed by port number (0 or 1) char * portName[2]; int portHandle[2]; bool testPortOpen[2]; // The following are indexed thus: // 0 - for transfers from port 0 to port 1. // 1 - for transfers from port 1 to port 0. bool finished[2]; // This is the number of bytes we'll send between pausing. This might be // larger than the window size. unsigned int burstLength[2]; unsigned int burstDelayMilliseconds[2]; unsigned int txIndex[2]; unsigned int rxIndex[2]; unsigned int bytesLeftToBurst[2]; bool pausingBetweenBursts[2]; timeval pauseStartTime[2]; // Flow control unsigned int flowControlDelayMilliseconds[2]; unsigned int flowControlReceiveOKPeriod[2]; bool flowControlOn[2]; bool flowControlReceivePeriodOver[2]; timeval flowControlStartTime[2]; portName[0] = sTestPort0; portName[1] = sTestPort1; for (i=0; i<2; i++) { testPortOpen[i] = false; //breakFlag[i] = false; burstLength[i] = 11; burstDelayMilliseconds[i] = 20; txIndex[i] = 0; rxIndex[i] = 0; bytesLeftToBurst[i] = burstLength[i]; pausingBetweenBursts[i] = false; finished[i] = false; flowControlDelayMilliseconds[i] = 1000; flowControlReceiveOKPeriod[i] = 100; flowControlOn[i] = false; flowControlReceivePeriodOver[i] = false; } if (direction == UNIDIRECTIONAL_PORT_0_TO_PORT_1) { finished[1] = true; } if (direction == UNIDIRECTIONAL_PORT_1_TO_PORT_0) { finished[0] = true; } /*-----------------------------------------------------------------------* * Set up and open both ports * *-----------------------------------------------------------------------* * Irrespective of whether we're testing flow control, we open the ports * with hardware flow control enabled. */ for (i=0; i<2 && !failed; i++) { if (!OpenPort_Hw(portName[i], baudRate, &portHandle[i])) { ui_printf(BRIGHT_RED, "Failed to open port %s.", portName[i]); failed = true; } else { testPortOpen[i] = true; } } /*-----------------------------------------------------------------------* * Send some data to test port & wait for it on /dev/ttys0 * *-----------------------------------------------------------------------* */ unsigned char testData[testDataSize]; for (unsigned int i=0; i // <-------------> // | // Tx this much. // Indent in preparation for displaying progress bar. #define BAR_INDENT 8 for (unsigned int i=0; i flowControlReceiveOKPeriod[from] && !flowControlReceivePeriodOver[from]) { flowControlReceivePeriodOver[from] = true; } if (deltaInMilliseconds > flowControlDelayMilliseconds[from]) { flowControlOn[from] = false; flowControlReceivePeriodOver[from] = false; SetRTS(portHandle[to], 1); } } if (pausingBetweenBursts[from]) { // If we've waited for long enough, then clear the // pausingBetweenBursts flag. timeval currentTime; gettimeofday(¤tTime, 0); unsigned int deltaInMilliseconds = (currentTime.tv_sec-pauseStartTime[from].tv_sec)*1000 + (currentTime.tv_usec-pauseStartTime[from].tv_usec)/1000; if (deltaInMilliseconds > burstDelayMilliseconds[from]) { pausingBetweenBursts[from] = false; } } else if (direction == BIDIRECTIONAL || (from == 0 && direction == UNIDIRECTIONAL_PORT_0_TO_PORT_1) || (from == 1 && direction == UNIDIRECTIONAL_PORT_1_TO_PORT_0)) { unsigned int bytesLeft = testDataSize - txIndex[from]; if (bytesLeft) { // We have data left to transmit. unsigned int maximumTxIndex = rxIndex[to] + windowSize; if (txIndex[from] < maximumTxIndex) { unsigned int extraToTx = maximumTxIndex - txIndex[from]; if (extraToTx > bytesLeft) { extraToTx = bytesLeft; } if (burstyMode == BURSTYDATA_ON) { // If we're sending in bursts, then restrict to the // number of bytes in a burst. if (extraToTx > bytesLeftToBurst[from]) { extraToTx = bytesLeftToBurst[from]; } } int bytesWrittenOrError = write( portHandle[from], testData + txIndex[from], extraToTx); if (bytesWrittenOrError < 0) { #if 0 ui_printf( BRIGHT_RED, "Error writing to %s=%d \n", portName[from], bytesWrittenOrError); #endif } else { txIndex[from] += bytesWrittenOrError; if (burstyMode == BURSTYDATA_ON) { bytesLeftToBurst[from] -= bytesWrittenOrError; // If we've finish the burst, then we need to // wait before transmitting anything else. if (bytesLeftToBurst[from] == 0) { pausingBetweenBursts[from] = true; bytesLeftToBurst[from] = burstLength[from]; gettimeofday(&(pauseStartTime[from]), 0); } } } } } } } // for loop for 'from' /*-------------------------------------------------------------------* * Drain serial input * *-------------------------------------------------------------------* */ unsigned char serialByte; int port_num_r = 0 ; int port_num_wr = 0 ; unsigned char readData[TEST_DATA_SIZE]; unsigned char writtenData[TEST_DATA_SIZE]; for (unsigned int from=0; from<2; from++) { unsigned int to = 1-from; // If from is 0 : Sending from serial port 0 to serial port 1. // If from is 1 : Sending from serial port 1 to serial port 0. if (direction == BIDIRECTIONAL || (from == 0 && direction == UNIDIRECTIONAL_PORT_0_TO_PORT_1) || (from == 1 && direction == UNIDIRECTIONAL_PORT_1_TO_PORT_0)) { while (read(portHandle[to], &serialByte, 1) == 1) { if (flowControlOn[from] && flowControlReceivePeriodOver[from]) { ui_printf( BRIGHT_RED, "\n Flow control failed! %02x index %d from %d", serialByte, rxIndex[to], from); failed = true; break; } // Check it matches the data. if (serialByte != testData[rxIndex[to]]) { ui_printf( BRIGHT_RED, "Test byte %d [%d] was received as %02X, not %02X. Tx %d [%d to %d]\n", rxIndex[to], rxIndex[from], serialByte, testData[rxIndex[to]], txIndex[from], from, to); /* print what was read in driver */ port_num_r = to; if (ioctl(portHandle[to],TIOCGSERIAL,&port_num_r) == -1) { ui_printf(BRIGHT_RED, "Set port number failed \n"); } else { if (ioctl(portHandle[to],TIOCSERGETLSR,readData) == -1) { ui_printf(BRIGHT_RED, "failed getting buffer address \n"); } else { ui_printf(BRIGHT_RED, "Read byte[%d] = 0x%x on port no %d \n", rxIndex[to],readData[rxIndex[to]],to); } } /* print what was read in driver*/ port_num_wr = from; if (ioctl(portHandle[to],TIOCGSERIAL,&port_num_wr) == -1) { ui_printf(BRIGHT_RED, "Set port number failed \n"); } else { if (ioctl(portHandle[to],TIOCGICOUNT,writtenData) == -1) { ui_printf(BRIGHT_RED, "failed getting buffer address \n"); } else { ui_printf(BRIGHT_RED, "Written byte[%d] from port no %d= 0x%x \n", rxIndex[to],from,writtenData[rxIndex[to]]); } } } rxIndex[to]++; // Try and force some hardware flow control if ((rxIndex[to] % 300 == 0) && flowControlMode == HFCTRLTEST_ON) { SetRTS(portHandle[to], 0); flowControlOn[from] = true; flowControlReceivePeriodOver[from] = false; gettimeofday(&(flowControlStartTime[from]), 0); } } if (rxIndex[to] == testDataSize) { finished[from] = true; } if (rxIndex[to] > testDataSize) { ui_printf(BRIGHT_RED, "Failed! Received too much data.\n"); failed = true; } } } /*-------------------------------------------------------------------* * Update bar * *-------------------------------------------------------------------* */ unsigned int barCharsNeeded; if (direction == UNIDIRECTIONAL_PORT_0_TO_PORT_1) { barCharsNeeded = rxIndex[1] * barLength / testDataSize; } else if (direction == UNIDIRECTIONAL_PORT_1_TO_PORT_0) { barCharsNeeded = rxIndex[0] * barLength / testDataSize; } else { unsigned int temp = (rxIndex[1] > rxIndex[0] ? rxIndex[1] : rxIndex[0]); barCharsNeeded = temp * barLength / testDataSize; } if (barCharsNeeded > barCharsPrinted) { unsigned int toPrint = barCharsNeeded - barCharsPrinted; for (unsigned int i=0; i