#define _GNU_SOURCE /*---------------------------------------------------------------------------*/ #include "tools-utils.h" #include #include #include #include #include #include #include #include #include #include /*---------------------------------------------------------------------------*/ #define BAUDRATE B115200 #define BAUDRATE_S "115200" speed_t b_rate = BAUDRATE; /*---------------------------------------------------------------------------*/ #ifdef linux #define MODEMDEVICE "/dev/ttyS0" #else #define MODEMDEVICE "/dev/com1" #endif /* linux */ /*---------------------------------------------------------------------------*/ #define SLIP_END 0300 #define SLIP_ESC 0333 #define SLIP_ESC_END 0334 #define SLIP_ESC_ESC 0335 #define CSNA_INIT 0x01 #define BUFSIZE 40 #define HCOLS 20 #define ICOLS 18 #define MODE_START_DATE 0 #define MODE_DATE 1 #define MODE_START_TEXT 2 #define MODE_TEXT 3 #define MODE_INT 4 #define MODE_HEX 5 #define MODE_SLIP_AUTO 6 #define MODE_SLIP 7 #define MODE_SLIP_HIDE 8 /*---------------------------------------------------------------------------*/ #ifndef O_SYNC #define O_SYNC 0 #endif #define OPEN_FLAGS (O_RDWR | O_NOCTTY | O_NDELAY | O_SYNC) /*---------------------------------------------------------------------------*/ static unsigned char rxbuf[2048]; /*---------------------------------------------------------------------------*/ static int usage(int result) { printf("Usage: serialdump [-x] [-s[on]] [-i] [-bSPEED] T[format] [SERIALDEVICE]\n"); printf(" -x for hexadecimal output\n"); printf(" -i for decimal output\n"); printf(" -s for automatic SLIP mode\n"); printf(" -so for SLIP only mode (all data is SLIP packets)\n"); printf(" -sn to hide SLIP packages\n"); printf(" -T[format] to add time for each text line\n"); printf(" (see man page for strftime() for format description)\n"); return result; } /*---------------------------------------------------------------------------*/ static void print_hex_line(char *prefix, unsigned char *outbuf, int index) { int i; printf("\r%s", prefix); for(i = 0; i < index; i++) { if((i % 4) == 0) { printf(" "); } printf("%02X", outbuf[i] & 0xFF); } printf(" "); for(i = index; i < HCOLS; i++) { if((i % 4) == 0) { printf(" "); } printf(" "); } for(i = 0; i < index; i++) { if(outbuf[i] < 30 || outbuf[i] > 126) { printf("."); } else { printf("%c", outbuf[i]); } } } /*---------------------------------------------------------------------------*/ static void intHandler(int sig) { exit(0); } /*---------------------------------------------------------------------------*/ int main(int argc, char **argv) { signal(SIGINT, intHandler); struct termios options; fd_set mask, smask; int fd; int baudrate = BUNKNOWN; char *device = MODEMDEVICE; char *timeformat = NULL; unsigned char buf[BUFSIZE]; char outbuf[HCOLS]; unsigned char mode = MODE_START_TEXT; int nfound, flags = 0; unsigned char lastc = '\0'; int index = 1; while(index < argc) { if(argv[index][0] == '-') { switch(argv[index][1]) { case 'b': baudrate = atoi(&argv[index][2]); break; case 'x': mode = MODE_HEX; break; case 'i': mode = MODE_INT; break; case 's': switch(argv[index][2]) { case 'n': mode = MODE_SLIP_HIDE; break; case 'o': mode = MODE_SLIP; break; default: mode = MODE_SLIP_AUTO; break; } break; case 'T': if(strlen(&argv[index][2]) == 0) { timeformat = "%Y-%m-%d %H:%M:%S"; } else { timeformat = &argv[index][2]; } mode = MODE_START_DATE; break; case 'h': return usage(0); default: fprintf(stderr, "unknown option '%c'\n", argv[index][1]); return usage(1); } index++; } else { device = argv[index++]; if(index < argc) { fprintf(stderr, "too many arguments\n"); return usage(1); } } } if(baudrate != BUNKNOWN) { b_rate = select_baudrate(baudrate); if(b_rate == 0) { fprintf(stderr, "unknown baudrate %d\n", baudrate); exit(-1); } } fprintf(stderr, "connecting to %s", device); fd = open(device, OPEN_FLAGS); if(fd < 0) { fprintf(stderr, "\n"); perror("open"); exit(-1); } fprintf(stderr, " [OK]\n"); if(fcntl(fd, F_SETFL, 0) < 0) { perror("could not set fcntl"); exit(-1); } if(tcgetattr(fd, &options) < 0) { perror("could not get options"); exit(-1); } cfsetispeed(&options, b_rate); cfsetospeed(&options, b_rate); /* Enable the receiver and set local mode */ options.c_cflag |= (CLOCAL | CREAD); /* Mask the character size bits and turn off (odd) parity */ options.c_cflag &= ~(CSIZE | PARENB | PARODD); /* Select 8 data bits */ options.c_cflag |= CS8; /* Raw input */ options.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); /* Raw output */ options.c_oflag &= ~OPOST; if(tcsetattr(fd, TCSANOW, &options) < 0) { perror("could not set options"); exit(-1); } FD_ZERO(&mask); FD_SET(fd, &mask); FD_SET(fileno(stdin), &mask); index = 0; for(;;) { smask = mask; nfound = select(FD_SETSIZE, &smask, (fd_set *)0, (fd_set *)0, (struct timeval *)0); if(nfound < 0) { if(errno == EINTR) { fprintf(stderr, "interrupted system call\n"); continue; } /* something is very wrong! */ perror("select"); exit(1); } if(FD_ISSET(fileno(stdin), &smask)) { /* data from standard in */ int n = read(fileno(stdin), buf, sizeof(buf)); if(n < 0) { perror("could not read"); exit(-1); } else if(n > 0) { /* because commands might need parameters, lines needs to be separated which means the terminating LF must be sent */ /* while(n > 0 && buf[n - 1] < 32) { */ /* n--; */ /* } */ if(n > 0) { int i; /* fprintf(stderr, "SEND %d bytes\n", n);*/ /* write slowly */ for(i = 0; i < n; i++) { if(write(fd, &buf[i], 1) <= 0) { perror("write"); exit(1); } else { fflush(NULL); usleep(6000); } } } } else { /* End of input, exit. */ exit(0); } } if(FD_ISSET(fd, &smask)) { int i, n = read(fd, buf, sizeof(buf)); if(n < 0) { perror("could not read"); exit(-1); } if(n == 0) { errno = EBADF; perror("serial device disconnected"); exit(-1); } for(i = 0; i < n; i++) { switch(mode) { case MODE_START_TEXT: case MODE_TEXT: printf("%c", buf[i]); break; case MODE_START_DATE: { time_t t; t = time(&t); strftime(outbuf, HCOLS, timeformat, localtime(&t)); printf("[%s] ", outbuf); mode = MODE_DATE; } /* continue into the MODE_DATE */ case MODE_DATE: printf("%c", buf[i]); if(buf[i] == '\n') { mode = MODE_START_DATE; } break; case MODE_INT: printf("%03d ", buf[i]); if(++index >= ICOLS) { index = 0; printf("\n"); } break; case MODE_HEX: rxbuf[index++] = buf[i]; if(index >= HCOLS) { print_hex_line("", rxbuf, index); index = 0; printf("\n"); } break; case MODE_SLIP_AUTO: case MODE_SLIP_HIDE: if(!flags && (buf[i] != SLIP_END)) { /* Not a SLIP packet? */ printf("%c", buf[i]); break; } /* continue to slip only mode */ case MODE_SLIP: switch(buf[i]) { case SLIP_ESC: lastc = SLIP_ESC; break; case SLIP_END: if(index > 0) { if(flags != 2 && mode != MODE_SLIP_HIDE) { /* not overflowed: show packet */ print_hex_line("SLIP: ", rxbuf, index > HCOLS ? HCOLS : index); printf("\n"); } lastc = '\0'; index = 0; flags = 0; } else { flags = !flags; } break; default: if(lastc == SLIP_ESC) { lastc = '\0'; /* Previous read byte was an escape byte, so this byte will be interpreted differently from others. */ switch(buf[i]) { case SLIP_ESC_END: buf[i] = SLIP_END; break; case SLIP_ESC_ESC: buf[i] = SLIP_ESC; break; } } rxbuf[index++] = buf[i]; if(index >= sizeof(rxbuf)) { fprintf(stderr, "**** slip overflow\n"); index = 0; flags = 2; } break; } break; } } /* after processing for some output modes */ if(index > 0) { switch(mode) { case MODE_HEX: print_hex_line("", rxbuf, index); break; } } fflush(stdout); } } }