// code by SASANO Takayoshi, CC BY-SA #include #include #include #include #include #include #include static int char_length = 8; static int stop_length = 1; static int use_parity = 0; static int odd_parity = 0; static int use_rtscts = 0; static int serial_bps = 38400; #define BUFSIZE 256 static void tx_test(int fd) { uint8_t i, m, n; uint8_t buf[BUFSIZE + 1]; buf[0] = 1; m = (1 << char_length) - 1; for (i = 0; ; i++) { n = i & m; if (n < 2) continue; memset(buf + 1, n, BUFSIZE); write(fd, buf, sizeof(buf)); printf("."); fflush(stdout); } } static void rx_test(int fd) { int rxchar; uint8_t buf; uint32_t good, bad; rxchar = -1; good = bad = 0; while (1) { read(fd, &buf, sizeof(buf)); if (buf == 1) { /* reset, show prev result */ if (rxchar >= 0) { if (good == BUFSIZE && bad == 0) { printf("o"); } else { printf("x(%d/%d)", good, bad); } fflush(stdout); rxchar = -1; } } else if (rxchar < 0) { /* 1st char */ rxchar = buf; good = 1; bad = 0; } else { /* 2nd and later */ if (buf == rxchar) good++; else bad++; } } } static void parse_serialmode(char *p) { int i; for (i = 0; ; i++) { if (*p == '\0') break; switch (i) { case 0: /* character length */ if (*p >= '5' && *p <= '8') char_length = *p - '0'; break; case 1: /* parity bit */ use_parity = (*p == 'E' || *p == 'e' || *p == 'O' || *p == 'o'); odd_parity = (*p == 'O' || *p == 'o'); break; case 2: /* stop bits */ if (*p >= '1' && *p <= '3') stop_length = *p - '0'; break; case 3: /* X flow control (not supported) */ /* do nothing */ break; case 4: /* RTS/CTS flow control */ use_rtscts = (*p == 'H' || *p == 'h'); break; default: /* do nothing */ break; } p++; } } static int get_baud(int baud) { switch (baud) { case 50: return B50; case 75: return B75; case 110: return B110; case 134: return B134; case 150: return B150; case 200: return B200; case 300: return B300; case 600: return B600; case 1200: return B1200; case 1800: return B1800; case 2400: return B2400; case 4800: return B4800; case 9600: return B9600; case 19200: return B19200; case 38400: return B38400; #ifdef B7200 case 7200: return B7200; #endif #ifdef B14400 case 14400: return B14400; #endif #ifdef B28800 case 28800: return B28800; #endif #ifdef B57600 case 57600: return B57600; #endif #ifdef B76800 case 76800: return B76800; #endif #ifdef B115200 case 115200: return B115200; #endif #ifdef B230400 case 230400: return B230400; #endif #ifdef B460800 case 460800: return B460800; #endif #ifdef B500000 case 500000: return B500000; #endif #ifdef B576000 case 576000: return B576000; #endif #ifdef B921600 case 921600: return B921600; #endif #ifdef B1000000 case 1000000: return B1000000; #endif #ifdef B1152000 case 1152000: return B1152000; #endif #ifdef B2000000 case 2000000: return B2000000; #endif #ifdef B2500000 case 2500000: return B2500000; #endif #ifdef B3000000 case 3000000: return B3000000; #endif #ifdef B3500000 case 3500000: return B3500000; #endif #ifdef B4000000 case 4000000: return B4000000; #endif default: return -1; } } static int setup_serial(int fd) { struct termios t; static int cs[] = {CS5, CS6, CS7, CS8}; int baud; memset(&t, 0, sizeof(t)); baud = get_baud(serial_bps); if (baud < 0) goto fail; cfsetospeed(&t, baud); cfsetispeed(&t, baud); t.c_cflag = CREAD | CLOCAL | cs[char_length - 5];; if (stop_length - 1) t.c_cflag |= CSTOPB; if (use_parity) t.c_cflag |= PARENB; if (odd_parity) t.c_cflag |= PARODD; if (use_rtscts) t.c_cflag |= CRTSCTS; t.c_iflag = INPCK; t.c_oflag = 0; t.c_lflag = 0; t.c_cc[VTIME] = 0; t.c_cc[VMIN] = 1; tcflush(fd, TCIFLUSH); if (tcsetattr(fd, TCSANOW, &t) < 0) goto fail; return 0; fail: return -1; } int main(int argc, char *argv[]) { int fd; if (argc < 5) { printf("%s [device] [mode] [bps] [tx|rx]\n", argv[0]); goto fin0; } fd = open(argv[1], O_RDWR | O_NOCTTY); if (fd < 0) { printf("device open error\n"); goto fin0; } parse_serialmode(argv[2]); serial_bps = atoi(argv[3]); if (setup_serial(fd) < 0) { printf("serial parameter error\n"); goto fin1; } switch (argv[4][0]) { case 't': tx_test(fd); break; case 'r': rx_test(fd); break; default: printf("undefined test\n"); break; } fin1: close(fd); fin0: return 0; }