// // baud.exe - Measure serial port baud rate accuracy // // 08-Feb-2005 /tvb // #include #include #include #include #define WIN32_LEAN_AND_MEAN #include void CommOpen (int Port, int Baud, int Parity, int Flow); void CommWrite (char *Buffer, DWORD Size); void CommClose(void); double elapsed_seconds (void); #define PPM(a,b) ( ((a) - (b)) / (b) * 1e6 ) int main (int argc, char *argv[]) { unsigned char *buf; int port, baud, size, count, i, bits; double expected_baud, actual_baud; double expected_time, actual_time; double start_time, end_time; if (argc == 1) { fprintf(stderr, "Usage: baudrate [port] [baud] [size] [count]\n" "\n" "Options:\n" " - port is COM port number (1)\n" " - baud is baud rate (9600)\n" " - size is number of bytes to write\n" " - count is number times to write (10)\n" "\n" "Examples:\n" " baudrate 1\n" " baudrate 1 9600 1200\n" " baudrate 1 9600 4800 5\n" " baudrate 1 100 10 5\n" "\n" "Note:\n" " - Pick any unused serial port. Data will be written to it\n" " but it doesn't matter if anything is actually connected.\n" ); return 1; } port = (argc > 1) ? atoi(argv[1]) : 1; baud = (argc > 2) ? atoi(argv[2]) : 9600; size = (argc > 3) ? atoi(argv[3]) : baud; count = (argc > 4) ? atoi(argv[4]) : 10; buf = malloc(size + 10); if (buf == NULL) { perror("malloc"); exit(1); } for (i = 0; i < size; ) { buf[i++] = 0xFE; buf[i++] = 0xF0; buf[i++] = 0x80; } CommOpen(port, baud, 0, 0); printf("Writing %d bytes at %d baud", size, baud); bits = size * 10; expected_time = (double)bits / (double)baud; expected_baud = baud; printf(" (%.3lf seconds)\n", expected_time); for (i = 0; i < count; i += 1) { start_time = elapsed_seconds(); CommWrite(buf, size); end_time = elapsed_seconds(); actual_time = end_time - start_time; actual_baud = bits / actual_time; printf("%.6lf sec, %.3lf baud, %.0lf ppm error\n", actual_time, actual_baud, PPM(actual_baud, expected_baud)); } CommClose(); return 0; } // Windows serial port functions #define ASSERT_SUCCESS(Function) \ if (!Success) { \ fprintf(stderr, "File %s Line %d Function %s failed (%.8x)\n", \ __FILE__, __LINE__, #Function, GetLastError()); \ exit(1); \ } HANDLE hCom; void CommTimeout (DWORD Interval, DWORD Multiplier, DWORD Constant); void CommOpen (int Port, int Baud, int Parity, int Flow) { char CommPath[100]; DCB Dcb; BOOL Success; // Open COM port sprintf(CommPath, "\\\\.\\COM%d", Port); fprintf(stderr, "** Opening %s (%d baud)\n", CommPath, Baud); hCom = CreateFile(CommPath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); if (hCom == INVALID_HANDLE_VALUE) { fprintf(stderr, "CreateFile failed: %s (%.8x)\n", CommPath, GetLastError()); exit(1); } // Set comm parameters memset(&Dcb, 0x0, sizeof(DCB)); Dcb.DCBlength = sizeof (DCB); Success = GetCommState(hCom, &Dcb); ASSERT_SUCCESS(GetCommState); // Set parity Dcb.Parity = Parity; if (Parity == 0) { Dcb.Parity = NOPARITY; } else if (Parity & 1) { Dcb.Parity = ODDPARITY; } else { Dcb.Parity = EVENPARITY; } // Set frame size Dcb.BaudRate = Baud; Dcb.ByteSize = (Dcb.Parity == NOPARITY) ? 8 : 7; Dcb.StopBits = ONESTOPBIT; // Set raw mode Dcb.fDsrSensitivity = FALSE; Dcb.fOutxCtsFlow = FALSE; Dcb.fOutX = FALSE; Dcb.fInX = FALSE; Dcb.fNull = FALSE; Dcb.fBinary = TRUE; // PC write flow control Dcb.fOutxCtsFlow = FALSE; Dcb.fOutxDsrFlow = FALSE; // PC read flow control Dcb.fDtrControl = Flow ? DTR_CONTROL_HANDSHAKE : DTR_CONTROL_ENABLE; Dcb.fRtsControl = Flow ? RTS_CONTROL_HANDSHAKE : RTS_CONTROL_ENABLE; Success = SetCommState(hCom, &Dcb); ASSERT_SUCCESS(SetCommState); #if 1 SetupComm(hCom, 1024, Baud); #endif CommTimeout(2000, 0, 2000); return; } void CommTimeout (DWORD Interval, DWORD Multiplier, DWORD Constant) { COMMTIMEOUTS Cto; BOOL Success; Success = GetCommTimeouts(hCom, &Cto); ASSERT_SUCCESS(GetCommTimeouts); Cto.ReadIntervalTimeout = Interval; Cto.ReadTotalTimeoutMultiplier = Multiplier; Cto.ReadTotalTimeoutConstant = Constant; Success = SetCommTimeouts(hCom, &Cto); ASSERT_SUCCESS(SetCommTimeouts); return; } void CommWrite (char *Buffer, DWORD Size) { DWORD Count; BOOL Success; Success = WriteFile(hCom, Buffer, Size, &Count, 0); if (Count != Size) { fprintf(stderr, "WriteFile Count (%d) != Size (%d)\n", Count, Size); exit(1); } ASSERT_SUCCESS(WriteFile); return; } DWORD CommRead (char *Buffer, DWORD Size) { DWORD Count; BOOL Success; Success = ReadFile(hCom, Buffer, Size, &Count, 0); ASSERT_SUCCESS(ReadFile); return Count; } void CommClose (void) { CloseHandle(hCom); hCom = NULL; return; } // Return arbitrary elapsed seconds for use in interval timing double elapsed_seconds (void) { static LARGE_INTEGER base = {0, 0}; static LARGE_INTEGER freq; LARGE_INTEGER t; QueryPerformanceCounter(&t); if (base.QuadPart == 0) { if ( ! QueryPerformanceFrequency(&freq) ) { return 0; } base = t; } return (double)(t.QuadPart - base.QuadPart) / (double)freq.QuadPart; }