From f222ad1cc8fe3723ab16c2a6cacc1c736f488546 Mon Sep 17 00:00:00 2001 From: Paul Reimer Date: Tue, 11 Dec 2018 20:55:43 -0800 Subject: [PATCH 01/15] Add additional (faster) common baud rates --- ttylog.8 | 2 +- ttylog.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ttylog.8 b/ttylog.8 index a615054..178ac93 100644 --- a/ttylog.8 +++ b/ttylog.8 @@ -24,7 +24,7 @@ Version number of ttylog plus Copyright information .TP .B -b, --baud Baud rate of the device. Available baud rates: -300, 1200, 2400, 4800, 9600, 19200, 38400, 57600 and 115200 +300, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600, and 2000000 .TP .B -d --device The serial device. For example /dev/ttyS1 diff --git a/ttylog.c b/ttylog.c index 41e9151..f496c51 100644 --- a/ttylog.c +++ b/ttylog.c @@ -40,10 +40,10 @@ char flush = 0; char *BAUD_T[] = -{"300", "1200", "2400", "4800", "9600", "19200", "38400", "57600", "115200"}; +{"300", "1200", "2400", "4800", "9600", "19200", "38400", "57600", "115200", "230400", "460800", "921600", "2000000"}; int BAUD_B[] = -{B300, B1200, B2400, B4800, B9600, B19200, B38400, B57600, B115200}; +{B300, B1200, B2400, B4800, B9600, B19200, B38400, B57600, B115200, B230400, B460800, B921600, B2000000}; int main (int argc, char *argv[]) From 14158bbfae705abf7c0bc09e78a4f5b42fb7a18d Mon Sep 17 00:00:00 2001 From: Paul Reimer Date: Tue, 11 Dec 2018 21:21:34 -0800 Subject: [PATCH 02/15] Extend BAUDN to 13 to account for new faster baud rates --- ttylog.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ttylog.c b/ttylog.c index f496c51..a410a41 100644 --- a/ttylog.c +++ b/ttylog.c @@ -35,7 +35,7 @@ #include "config.h" -#define BAUDN 9 +#define BAUDN 13 char flush = 0; From 96c0bac040bca1ede4383cb09986f17089dd5b51 Mon Sep 17 00:00:00 2001 From: Mario Ivancic Date: Sun, 19 Oct 2025 00:41:33 +0200 Subject: [PATCH 03/15] Fix printf call for -t when time span is NULL. --- ttylog.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ttylog.c b/ttylog.c index a410a41..96327ce 100644 --- a/ttylog.c +++ b/ttylog.c @@ -78,8 +78,8 @@ main (int argc, char *argv[]) { printf ("ttylog version %s\n", TTYLOG_VERSION); printf ("Usage: ttylog [-b|--baud] [-d|--device] [-f|--flush] [-s|--stamp] [-t|--timeout] > /path/to/logfile\n"); - printf (" -h, --help This help\n -v, --version Version number\n -b, --baud Baud rate\n"); - printf (" -d, --device Serial device (eg. /dev/ttyS1)\n -f, --flush Flush output\n"); + printf (" -h, --help This help\n -v, --version Version number\n -b, --baud Baud rate\n"); + printf (" -d, --device Serial device (eg. /dev/ttyS1)\n -f, --flush Flush output\n"); printf (" -s, --stamp\tPrefix each line with datestamp\n"); printf (" -t, --timeout How long to run, in seconds.\n"); printf ("ttylog home page: \n\n"); @@ -143,7 +143,7 @@ main (int argc, char *argv[]) { if (argv[i + 1] == NULL) { - printf ("%s: invalid time span %s\n", argv[0], argv[i + 1]); + printf ("%s: invalid time span\n", argv[0]); exit(0); } if (timer_create (CLOCK_REALTIME, &sevp, &timerid) == -1) @@ -183,8 +183,8 @@ main (int argc, char *argv[]) } fd = fileno (logfile); - tcgetattr (fd, &oldtio); /* save current serial port settings */ - bzero (&newtio, sizeof (newtio)); /* clear struct for new port settings */ + tcgetattr (fd, &oldtio); /* save current serial port settings */ + bzero (&newtio, sizeof (newtio)); /* clear struct for new port settings */ newtio.c_cflag = CRTSCTS | CS8 | CLOCAL | CREAD; newtio.c_iflag = IGNPAR | IGNCR; From 42845a31fcab9bb6c1fd7d2905a6163258e59908 Mon Sep 17 00:00:00 2001 From: Mario Ivancic Date: Sun, 19 Oct 2025 19:36:26 +0200 Subject: [PATCH 04/15] Add .gitignore file. --- .gitignore | 5 +++++ ttylog.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fbe83e9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +bin +obj +build +config.h +ttylog.cbp diff --git a/ttylog.c b/ttylog.c index 96327ce..33afb49 100644 --- a/ttylog.c +++ b/ttylog.c @@ -37,6 +37,15 @@ #define BAUDN 13 +// constants for output format +enum +{ + FMT_ACSII = 0, + FMT_hex = 1, + FMT_HEX = 2, + FMT_RAW = 3, +}; + char flush = 0; char *BAUD_T[] = @@ -62,6 +71,7 @@ main (int argc, char *argv[]) time_t rawtime; struct tm *timeinfo; char *timestr; + int output_fmt = FMT_ACSII; modem_device[0] = 0; @@ -82,6 +92,7 @@ main (int argc, char *argv[]) printf (" -d, --device Serial device (eg. /dev/ttyS1)\n -f, --flush Flush output\n"); printf (" -s, --stamp\tPrefix each line with datestamp\n"); printf (" -t, --timeout How long to run, in seconds.\n"); + printf (" -F, --format Set output format to one of h[ex], H[EX], a[scii], r[aw].\n"); printf ("ttylog home page: \n\n"); exit (0); } @@ -168,6 +179,25 @@ main (int argc, char *argv[]) exit (0); } } + if (!strcmp (argv[i], "-F") || !strcmp (argv[i], "--format")) + { + if ((i + 1) >= argc) + { + printf ("%s: output format not specified\n", argv[0]); + exit(0); + } + + int f = argv[i + 1][0]; + if(f == 'a') output_fmt = FMT_ACSII; + else if(f == 'h') output_fmt = FMT_hex; + else if(f == 'H') output_fmt = FMT_HEX; + else if(f == 'r') output_fmt = FMT_RAW; + else + { + printf ("%s: invalid output format '%s'\n", argv[0], argv[i + 1]); + exit(0); + } + } } if (!strlen(modem_device)) { From 012022ec1dfc23860e84e11a241f64cf4c8bf092 Mon Sep 17 00:00:00 2001 From: Mario Ivancic Date: Sun, 19 Oct 2025 22:27:13 +0200 Subject: [PATCH 05/15] Add output format (-F --format) and line lingth limit (-l --limit) features. --- .gitignore | 3 + ttylog.8 | 12 +++- ttylog.c | 184 +++++++++++++++++++++++++++++++++++++++-------------- 3 files changed, 150 insertions(+), 49 deletions(-) diff --git a/.gitignore b/.gitignore index fbe83e9..ac4d924 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,6 @@ obj build config.h ttylog.cbp +*.layout +*.depend + diff --git a/ttylog.8 b/ttylog.8 index 178ac93..8eaeec0 100644 --- a/ttylog.8 +++ b/ttylog.8 @@ -3,7 +3,7 @@ ttylog \- serial device logger .SH SYNOPSIS .B ttylog -[-b|--baud] [-d|--device] [-f|--flush] [-t|--timeout] > /path/to/logfile +[-b|--baud] [-d|--device] [-f|--flush] [-t|--timeout] [-F|--format] [-l|--limit] > /path/to/logfile .PP If you are not using the timeout option, you can stop it running by pressing a ctrl-c when it's going to the screen or doing "kill -HUP nnnn" (where nnnn is @@ -34,6 +34,16 @@ Output buffers are flushed after every write. .TP .B -t --timeout How long to run ttylog, in seconds. +.B -F --format +Set output format to one of a[scii] (default), h[ex], H[EX], r[aw]. +Output format ascii is the same as in previous versions of ttylog, ttylog expects +EOL characters in the strem. +Output format hex is for HEX output using lowercase abcdef characters. +Output format HEX is for HEX output using uppercase ABCDEF characters. +Output format raw is the same as ascii, but fread() is used instead fgets(). +.B -l --limit +Limit line length. +If format is hex or HEX this is actually a byte count limit, not line length limit. .SH AUTHOR This manual page was originally written by Tibor Koleszar , for the Debian GNU/Linux system. Modifications and updates written by diff --git a/ttylog.c b/ttylog.c index 33afb49..736e519 100644 --- a/ttylog.c +++ b/ttylog.c @@ -37,15 +37,19 @@ #define BAUDN 13 -// constants for output format +/* Constants for output format. */ enum { - FMT_ACSII = 0, - FMT_hex = 1, - FMT_HEX = 2, - FMT_RAW = 3, + FMT_ACSII = 0, /* Old ttylog ascii output format. */ + FMT_HEX_LC = 1, /* HEX output using lowercase abcdef characters. */ + FMT_HEX_UC = 2, /* HEX output using uppercase ABCDEF characters. */ + FMT_RAW = 3, /* Raw output format, EOL character is not added by ttylog. */ }; +/* Function that prints line in specified output format. Timestamp is optional. + Buffer should be at least 4 times the line length. */ +void print_line(char* line, int line_len, char* buffer, const char* time_stamp, int fmt); + char flush = 0; char *BAUD_T[] = @@ -66,12 +70,15 @@ main (int argc, char *argv[]) sevp.sigev_notify = SIGEV_SIGNAL; sevp.sigev_signo = SIGINT; int fd; - char line[1024], modem_device[512]; + char line[1024]; + char buffer[4 * sizeof(line)]; + char modem_device[512]; struct termios oldtio, newtio; time_t rawtime; struct tm *timeinfo; char *timestr; int output_fmt = FMT_ACSII; + int line_len_limit = sizeof(line) - 1; modem_device[0] = 0; @@ -87,12 +94,13 @@ main (int argc, char *argv[]) if (!strcmp (argv[i], "-h") || !strcmp (argv[i], "--help")) { printf ("ttylog version %s\n", TTYLOG_VERSION); - printf ("Usage: ttylog [-b|--baud] [-d|--device] [-f|--flush] [-s|--stamp] [-t|--timeout] > /path/to/logfile\n"); - printf (" -h, --help This help\n -v, --version Version number\n -b, --baud Baud rate\n"); - printf (" -d, --device Serial device (eg. /dev/ttyS1)\n -f, --flush Flush output\n"); - printf (" -s, --stamp\tPrefix each line with datestamp\n"); + printf ("Usage: ttylog [-b|--baud] [-d|--device] [-f|--flush] [-s|--stamp] [-t|--timeout] [-F|--format] [-l|--limit] > /path/to/logfile\n"); + printf (" -h, --help This help\n -v, --version Version number\n -b, --baud Baud rate\n"); + printf (" -d, --device Serial device (eg. /dev/ttyS1)\n -f, --flush Flush output\n"); + printf (" -s, --stamp Prefix each line with datestamp\n"); printf (" -t, --timeout How long to run, in seconds.\n"); - printf (" -F, --format Set output format to one of h[ex], H[EX], a[scii], r[aw].\n"); + printf (" -F, --format Set output format to one of a[scii] (default), h[ex], H[EX], r[aw].\n"); + printf (" -l, --limit Limit line length.\n"); printf ("ttylog home page: \n\n"); exit (0); } @@ -189,14 +197,33 @@ main (int argc, char *argv[]) int f = argv[i + 1][0]; if(f == 'a') output_fmt = FMT_ACSII; - else if(f == 'h') output_fmt = FMT_hex; - else if(f == 'H') output_fmt = FMT_HEX; - else if(f == 'r') output_fmt = FMT_RAW; + else if(f == 'h') { output_fmt = FMT_HEX_LC; } + else if(f == 'H') { output_fmt = FMT_HEX_UC; } + else if(f == 'r') { output_fmt = FMT_RAW; } else { - printf ("%s: invalid output format '%s'\n", argv[0], argv[i + 1]); + fprintf (stderr, "%s: invalid output format '%s'\n", argv[0], argv[i + 1]); exit(0); } + i++; + } + if (!strcmp (argv[i], "-l") || !strcmp (argv[i], "--limit")) + { + if ((i + 1) >= argc) + { + fprintf (stderr, "%s: line length limit not specified\n", argv[0]); + exit(0); + } + + int len = atoi(argv[i + 1]); + if (!len) + { + fprintf (stderr, "%s: invalid line length limit %s\n", argv[0], argv[i + 1]); + exit(0); + } + + line_len_limit = len; + i++; } } @@ -213,27 +240,31 @@ main (int argc, char *argv[]) } fd = fileno (logfile); - tcgetattr (fd, &oldtio); /* save current serial port settings */ - bzero (&newtio, sizeof (newtio)); /* clear struct for new port settings */ - - newtio.c_cflag = CRTSCTS | CS8 | CLOCAL | CREAD; - newtio.c_iflag = IGNPAR | IGNCR; - newtio.c_oflag = 0; - newtio.c_lflag = ICANON; - /* Only truly portable method of setting speed. */ - cfsetispeed (&newtio, BAUD_B[baud]); - cfsetospeed (&newtio, BAUD_B[baud]); - - tcflush (fd, TCIFLUSH); - tcsetattr (fd, TCSANOW, &newtio); - - /* Clear the device */ - { - int flags = fcntl (fd, F_GETFL, 0); - fcntl (fd, F_SETFL, flags | O_NONBLOCK); - while (fgets (line, 1024, logfile) ); - fcntl (fd, F_SETFL, flags); - } + /* Check are we connected to serial port and if yes, save current serial port settings */ + int serial_port = (0 == tcgetattr (fd, &oldtio)); + if(serial_port) + { + bzero (&newtio, sizeof (newtio)); /* clear struct for new port settings */ + + newtio.c_cflag = CRTSCTS | CS8 | CLOCAL | CREAD; + newtio.c_iflag = IGNPAR | IGNCR; + newtio.c_oflag = 0; + newtio.c_lflag = ICANON; + /* Only truly portable method of setting speed. */ + cfsetispeed (&newtio, BAUD_B[baud]); + cfsetospeed (&newtio, BAUD_B[baud]); + + tcflush (fd, TCIFLUSH); + tcsetattr (fd, TCSANOW, &newtio); + + /* Clear the device */ + { + int flags = fcntl (fd, F_GETFL, 0); + fcntl (fd, F_SETFL, flags | O_NONBLOCK); + while (fread (line, 1, sizeof(line), logfile) > 0 ); + fcntl (fd, F_SETFL, flags); + } + } if (flush) setbuf(stdout, NULL); @@ -245,28 +276,85 @@ main (int argc, char *argv[]) retval = select (fd + 1, &rfds, NULL, NULL, NULL); if (retval > 0) { - if (!fgets (line, 1024, logfile)) - { - if (ferror (logfile)) { break; } - } - if (stamp) + size_t len = 0; + if(output_fmt == FMT_ACSII) { - time(&rawtime); - timeinfo = localtime(&rawtime); - timestr = asctime(timeinfo); - timestr[strlen(timestr) - 1] = 0; - printf ("[%s] %s", timestr, line); + if (!fgets (line, line_len_limit + 1, logfile)) + { + if (ferror (logfile)) { break; } + if (feof (logfile)) { break; } /* Used with files, for testing. */ + } } else { - fputs (line, stdout); + len = fread (line, 1, line_len_limit, logfile); + if (!len) + { + if (ferror (logfile)) { break; } + if (feof (logfile)) { break; } + } + line[len - 1] = 0; } + if (stamp) + { + time(&rawtime); + timeinfo = localtime(&rawtime); + timestr = asctime(timeinfo); + timestr[strlen(timestr) - 1] = 0; + } else { + timestr = NULL; + } + + if(!len){ len = strlen(line); } + print_line(line, len, buffer, timestr, output_fmt); + if (flush) { fflush(stdout); } } else if (retval < 0) { break; } } fclose (logfile); - tcsetattr (fd, TCSANOW, &oldtio); + if(serial_port) { tcsetattr (fd, TCSANOW, &oldtio); } return 0; +} + +/* Function that prints line in specified output format. Timestamp is optional. + Buffer should be at least 4 times the line length. */ +void print_line(char* line, int line_len, char* buffer, const char* time_stamp, int fmt) +{ + static const char* hex_chars_lc = "0123456789abcdef"; + static const char* hex_chars_uc = "0123456789ABCDEF"; + if(fmt == FMT_ACSII || fmt == FMT_RAW) + { + if (time_stamp) + { + /* If timestamps are printed we have to be sure that timestamp is at + the beginning of the line. */ + if(line[line_len - 1] == '\n') { line[line_len - 1] = 0; } + + printf ("[%s] %s\n", time_stamp, line); + } else { + fputs (line, stdout); + } + } else if(fmt == FMT_HEX_LC || fmt == FMT_HEX_UC) { + int buff_len = 0; + const char* hex_chars = (fmt == FMT_HEX_LC) ? hex_chars_lc : hex_chars_uc; + for(int i = 0; i < line_len; i++) + { + unsigned char d = line[i]; + buffer[buff_len++] = hex_chars[(d >> 4) & 0x0F]; + buffer[buff_len++] = hex_chars[d & 0x0F]; + buffer[buff_len++] = ' '; + } + + buffer[buff_len++] = '\n'; + buffer[buff_len] = 0; + + if (time_stamp) + { + printf ("[%s] %s", time_stamp, buffer); + } else { + fputs (buffer, stdout); + } + } } From d5ffbf06fb4859861c412040903176382a2b52f8 Mon Sep 17 00:00:00 2001 From: Mario Ivancic Date: Sun, 19 Oct 2025 23:04:06 +0200 Subject: [PATCH 06/15] Fix parameter parsing code. --- ttylog.c | 183 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 99 insertions(+), 84 deletions(-) diff --git a/ttylog.c b/ttylog.c index 736e519..c71e75d 100644 --- a/ttylog.c +++ b/ttylog.c @@ -52,7 +52,7 @@ void print_line(char* line, int line_len, char* buffer, const char* time_stamp, char flush = 0; -char *BAUD_T[] = +const char* BAUD_T[] = {"300", "1200", "2400", "4800", "9600", "19200", "38400", "57600", "115200", "230400", "460800", "921600", "2000000"}; int BAUD_B[] = @@ -79,119 +79,122 @@ main (int argc, char *argv[]) char *timestr; int output_fmt = FMT_ACSII; int line_len_limit = sizeof(line) - 1; + const char* baud_str = NULL; - modem_device[0] = 0; + memset (modem_device, '\0', sizeof(modem_device)); if (argc < 2) { - printf ("%s: no params. try %s -h\n", argv[0], argv[0]); + fprintf (stderr, "%s: no params. try %s -h\n", argv[0], argv[0]); exit (0); } for (i = 1; i < argc; i++) { - if (!strcmp (argv[i], "-h") || !strcmp (argv[i], "--help")) { - printf ("ttylog version %s\n", TTYLOG_VERSION); - printf ("Usage: ttylog [-b|--baud] [-d|--device] [-f|--flush] [-s|--stamp] [-t|--timeout] [-F|--format] [-l|--limit] > /path/to/logfile\n"); - printf (" -h, --help This help\n -v, --version Version number\n -b, --baud Baud rate\n"); - printf (" -d, --device Serial device (eg. /dev/ttyS1)\n -f, --flush Flush output\n"); - printf (" -s, --stamp Prefix each line with datestamp\n"); - printf (" -t, --timeout How long to run, in seconds.\n"); - printf (" -F, --format Set output format to one of a[scii] (default), h[ex], H[EX], r[aw].\n"); - printf (" -l, --limit Limit line length.\n"); - printf ("ttylog home page: \n\n"); + fprintf (stderr, "ttylog version %s\n", TTYLOG_VERSION); + fprintf (stderr, "Usage: ttylog [-b|--baud] [-d|--device] [-f|--flush] [-s|--stamp] [-t|--timeout] [-F|--format] [-l|--limit] > /path/to/logfile\n"); + fprintf (stderr, " -h, --help This help\n"); + fprintf (stderr, " -v, --version Version number\n"); + fprintf (stderr, " -b, --baud Baud rate\n"); + fprintf (stderr, " -d, --device Serial device (eg. /dev/ttyS1)\n"); + fprintf (stderr, " -f, --flush Flush output\n"); + fprintf (stderr, " -s, --stamp Prefix each line with datestamp\n"); + fprintf (stderr, " -t, --timeout How long to run, in seconds.\n"); + fprintf (stderr, " -F, --format Set output format to one of a[scii] (default), h[ex], H[EX], r[aw].\n"); + fprintf (stderr, " -l, --limit Limit line length.\n"); + fprintf (stderr, "ttylog home page: \n\n"); exit (0); } - - if (!strcmp (argv[i], "-v") || !strcmp (argv[i], "--version")) + else if (!strcmp (argv[i], "-v") || !strcmp (argv[i], "--version")) { - printf ("ttylog version %s\n", TTYLOG_VERSION); - printf ("Copyright (C) 2018 Robert James Clay \n"); - printf ("Copyright (C) 2018 Guy Shapiro \n"); - printf ("Copyright (C) 2016 Donald Gordon \n"); - printf ("Copyright (C) 2016 Logan Rosen \n"); - printf ("Copyright (C) 2016 Alexander (MrMontag) Fust \n"); - printf ("Copyright (C) 2002 Tibor Koleszar \n"); - printf ("License GPLv2+: \n"); - printf ("This is free software: you are free to change and redistribute it.\n"); - printf ("There is NO WARRANTY, to the extent permitted by law.\n\n"); + fprintf (stderr, "ttylog version %s\n", TTYLOG_VERSION); + fprintf (stderr, "Copyright (C) 2018 Robert James Clay \n"); + fprintf (stderr, "Copyright (C) 2018 Guy Shapiro \n"); + fprintf (stderr, "Copyright (C) 2016 Donald Gordon \n"); + fprintf (stderr, "Copyright (C) 2016 Logan Rosen \n"); + fprintf (stderr, "Copyright (C) 2016 Alexander (MrMontag) Fust \n"); + fprintf (stderr, "Copyright (C) 2002 Tibor Koleszar \n"); + fprintf (stderr, "License GPLv2+: \n"); + fprintf (stderr, "This is free software: you are free to change and redistribute it.\n"); + fprintf (stderr, "There is NO WARRANTY, to the extent permitted by law.\n\n"); exit (0); } - - if (!strcmp (argv[i], "-f") || !strcmp (argv[i], "--flush")) + else if (!strcmp (argv[i], "-f") || !strcmp (argv[i], "--flush")) { flush = 1; } - - if (!strcmp (argv[i], "-s") || !strcmp (argv[i], "--stamp")) + else if (!strcmp (argv[i], "-s") || !strcmp (argv[i], "--stamp")) { stamp = 1; } - - if (!strcmp (argv[i], "-b") || !strcmp (argv[i], "--baud")) + else if (!strcmp (argv[i], "-b") || !strcmp (argv[i], "--baud")) { - if (argv[i + 1] != NULL) - { - for (j = 0; j < BAUDN; j++) - if (!strcmp (argv[i + 1], BAUD_T[j])) - baud = j; - } - if (baud == -1) + if ((i + 1) >= argc) { - printf ("%s: invalid baud rate %s\n", argv[0], argv[i + 1]); + fprintf (stderr, "%s: baud rate not specified\n", argv[0]); exit (0); } - } - if (!strcmp (argv[i], "-d") || !strcmp (argv[i], "--device")) - { - if (argv[i + 1] != NULL) - { - memset (modem_device, '\0', sizeof(modem_device)); - strncpy (modem_device, argv[i + 1], sizeof(modem_device)-1); - modem_device[(sizeof(modem_device)-1)] = '\0'; - } - else + baud_str = argv[i + 1]; + i++; + for (j = 0; j < BAUDN; j++) { + if (!strcmp (baud_str, BAUD_T[j])) + { + baud = j; + break; + } } - } + } + else if (!strcmp (argv[i], "-d") || !strcmp (argv[i], "--device")) + { + if ((i + 1) >= argc) + { + fprintf (stderr, "%s: serial device not specified\n", argv[0]); + exit(0); + } - if (!strcmp (argv[i], "-t") || !strcmp (argv[i], "--timeout")) - { - if (argv[i + 1] == NULL) - { - printf ("%s: invalid time span\n", argv[0]); - exit(0); - } - if (timer_create (CLOCK_REALTIME, &sevp, &timerid) == -1) - { - printf ("%s: unable to create timer: %s\n", argv[0], strerror(errno)); - exit (0); - } - struct itimerspec new_value; - new_value.it_interval.tv_sec = 0; - new_value.it_interval.tv_nsec = 0; - int sec = atoi(argv[i + 1]); - if (!sec) - { - printf ("%s: invalid time span %s\n", argv[0], argv[i + 1]); - exit(0); - } - new_value.it_value.tv_sec = atoi(argv[i + 1]); - new_value.it_value.tv_nsec = 0; - if (timer_settime(timerid, 0, &new_value, NULL) == -1) - { - printf ("%s: unable to set timer time: %s\n", argv[0], strerror(errno)); - exit (0); - } - } - if (!strcmp (argv[i], "-F") || !strcmp (argv[i], "--format")) + strncpy (modem_device, argv[i + 1], sizeof(modem_device) - 1); + i++; + } + else if (!strcmp (argv[i], "-t") || !strcmp (argv[i], "--timeout")) + { + if ((i + 1) >= argc) + { + fprintf (stderr, "%s: invalid time span\n", argv[0]); + exit(0); + } + if (timer_create (CLOCK_REALTIME, &sevp, &timerid) == -1) + { + fprintf (stderr, "%s: unable to create timer: %s\n", argv[0], strerror(errno)); + exit (0); + } + struct itimerspec new_value; + new_value.it_interval.tv_sec = 0; + new_value.it_interval.tv_nsec = 0; + int sec = atoi(argv[i + 1]); + if (!sec) + { + fprintf (stderr, "%s: invalid time span %s\n", argv[0], argv[i + 1]); + exit(0); + } + new_value.it_value.tv_sec = atoi(argv[i + 1]); + new_value.it_value.tv_nsec = 0; + if (timer_settime(timerid, 0, &new_value, NULL) == -1) + { + fprintf (stderr, "%s: unable to set timer time: %s\n", argv[0], strerror(errno)); + exit (0); + } + + i++; + } + else if (!strcmp (argv[i], "-F") || !strcmp (argv[i], "--format")) { if ((i + 1) >= argc) { - printf ("%s: output format not specified\n", argv[0]); + fprintf (stderr, "%s: output format not specified\n", argv[0]); exit(0); } @@ -207,7 +210,7 @@ main (int argc, char *argv[]) } i++; } - if (!strcmp (argv[i], "-l") || !strcmp (argv[i], "--limit")) + else if (!strcmp (argv[i], "-l") || !strcmp (argv[i], "--limit")) { if ((i + 1) >= argc) { @@ -227,15 +230,27 @@ main (int argc, char *argv[]) } } + if (baud_str == NULL) + { + fprintf (stderr, "%s: baud rate not specified\n", argv[0]); + exit (0); + } + + if (baud == -1) + { + fprintf (stderr, "%s: invalid baud rate %s\n", argv[0], baud_str); + exit (0); + } + if (!strlen(modem_device)) { - printf ("%s: no device is set. Use %s -h for more information.\n", argv[0], argv[0]); + fprintf (stderr, "%s: no device is set. Use %s -h for more information.\n", argv[0], argv[0]); exit (0); } logfile = fopen (modem_device, "rb"); if (logfile == NULL) { - printf ("%s: invalid device %s\n", argv[0], modem_device); + fprintf (stderr, "%s: invalid device %s\n", argv[0], modem_device); exit (0); } fd = fileno (logfile); From 21f75f88940021dcbd68d3a201739cc2c36b6470 Mon Sep 17 00:00:00 2001 From: Mario Ivancic Date: Mon, 20 Oct 2025 20:56:30 +0200 Subject: [PATCH 07/15] Add serial port mode option (-m|--mode). Add some new baud rates. --- ttylog.c | 196 +++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 169 insertions(+), 27 deletions(-) diff --git a/ttylog.c b/ttylog.c index c71e75d..baca04d 100644 --- a/ttylog.c +++ b/ttylog.c @@ -46,25 +46,23 @@ enum FMT_RAW = 3, /* Raw output format, EOL character is not added by ttylog. */ }; + + /* Function that prints line in specified output format. Timestamp is optional. Buffer should be at least 4 times the line length. */ void print_line(char* line, int line_len, char* buffer, const char* time_stamp, int fmt); -char flush = 0; - -const char* BAUD_T[] = -{"300", "1200", "2400", "4800", "9600", "19200", "38400", "57600", "115200", "230400", "460800", "921600", "2000000"}; - -int BAUD_B[] = -{B300, B1200, B2400, B4800, B9600, B19200, B38400, B57600, B115200, B230400, B460800, B921600, B2000000}; int main (int argc, char *argv[]) { FILE *logfile; fd_set rfds; - int retval, i, j, baud = -1; + int retval; + int i; + speed_t baud = 0; int stamp = 0; + int flush = 0; timer_t timerid; struct sigevent sevp; sevp.sigev_notify = SIGEV_SIGNAL; @@ -80,6 +78,10 @@ main (int argc, char *argv[]) int output_fmt = FMT_ACSII; int line_len_limit = sizeof(line) - 1; const char* baud_str = NULL; + int data_bits = 8; /* 7 or 8 data bits. */ + int stop_bits = 1; /* 1 or 2 stop bits. */ + int parity = 'N'; /* No parity (N), Even (E), Odd (O), Mark (M) or Space (S) */ + const char* port_mode = "8N1"; memset (modem_device, '\0', sizeof(modem_device)); @@ -94,10 +96,11 @@ main (int argc, char *argv[]) if (!strcmp (argv[i], "-h") || !strcmp (argv[i], "--help")) { fprintf (stderr, "ttylog version %s\n", TTYLOG_VERSION); - fprintf (stderr, "Usage: ttylog [-b|--baud] [-d|--device] [-f|--flush] [-s|--stamp] [-t|--timeout] [-F|--format] [-l|--limit] > /path/to/logfile\n"); + fprintf (stderr, "Usage: ttylog [-b|--baud] [-m|--mode] [-d|--device] [-f|--flush] [-s|--stamp] [-t|--timeout] [-F|--format] [-l|--limit] > /path/to/logfile\n"); fprintf (stderr, " -h, --help This help\n"); fprintf (stderr, " -v, --version Version number\n"); fprintf (stderr, " -b, --baud Baud rate\n"); + fprintf (stderr, " -m, --mode Serial port mode (default: 8N1)\n"); fprintf (stderr, " -d, --device Serial device (eg. /dev/ttyS1)\n"); fprintf (stderr, " -f, --flush Flush output\n"); fprintf (stderr, " -s, --stamp Prefix each line with datestamp\n"); @@ -133,26 +136,76 @@ main (int argc, char *argv[]) { if ((i + 1) >= argc) { - fprintf (stderr, "%s: baud rate not specified\n", argv[0]); + fprintf (stderr, "%s: baud rate not is specified\n", argv[0]); exit (0); } baud_str = argv[i + 1]; i++; - for (j = 0; j < BAUDN; j++) + long long b = strtoll(baud_str, NULL, 10); + switch(b) { - if (!strcmp (baud_str, BAUD_T[j])) - { - baud = j; - break; - } + case 300: baud = B300; break; + case 600: baud = B600; break; + case 1200: baud = B1200; break; + case 2400: baud = B2400; break; + case 4800: baud = B4800; break; + case 9600: baud = B9600; break; + case 19200: baud = B19200; break; +#if defined(B28800) + case 28800: baud = B28800; break; +#endif // defined + case 38400: baud = B38400; break; + case 57600: baud = B57600; break; +#if defined(B115200) + case 115200: baud = B115200; break; +#endif // defined +#if defined(B230400) + case 230400: baud = B230400; break; +#endif // defined +#if defined(B460800) + case 460800: baud = B460800; break; +#endif // defined +#if defined(B500000) + case 500000: baud = B500000; break; +#endif // defined +#if defined(B576000) + case 576000: baud = B576000; break; +#endif // defined +#if defined(B921600) + case 921600: baud = B921600; break; +#endif // defined +#if defined(B1000000) + case 1000000: baud = B1000000; break; +#endif // defined +#if defined(B1152000) + case 1152000: baud = B1152000; break; +#endif // defined +#if defined(B1500000) + case 1500000: baud = B1500000; break; +#endif // defined +#if defined(B2000000) + case 2000000: baud = B2000000; break; +#endif // defined +#if defined(B2500000) + case 2500000: baud = B2500000; break; +#endif // defined +#if defined(B3000000) + case 3000000: baud = B3000000; break; +#endif // defined +#if defined(B3500000) + case 3500000: baud = B3500000; break; +#endif // defined +#if defined(B4000000) + case 4000000: baud = B4000000; break; +#endif // defined } } else if (!strcmp (argv[i], "-d") || !strcmp (argv[i], "--device")) { if ((i + 1) >= argc) { - fprintf (stderr, "%s: serial device not specified\n", argv[0]); + fprintf (stderr, "%s: serial device is not specified\n", argv[0]); exit(0); } @@ -194,7 +247,7 @@ main (int argc, char *argv[]) { if ((i + 1) >= argc) { - fprintf (stderr, "%s: output format not specified\n", argv[0]); + fprintf (stderr, "%s: output format is not specified\n", argv[0]); exit(0); } @@ -214,7 +267,7 @@ main (int argc, char *argv[]) { if ((i + 1) >= argc) { - fprintf (stderr, "%s: line length limit not specified\n", argv[0]); + fprintf (stderr, "%s: line length limit is not specified\n", argv[0]); exit(0); } @@ -228,15 +281,53 @@ main (int argc, char *argv[]) line_len_limit = len; i++; } + else if (!strcmp (argv[i], "-m") || !strcmp (argv[i], "--mode")) + { + if ((i + 1) >= argc) + { + fprintf (stderr, "%s: serial port mode is not specified\n", argv[0]); + exit(0); + } + + port_mode = argv[i + 1]; + i++; + + if(port_mode[0] == '7') { data_bits = 7; } + else if(port_mode[0] == '8') { data_bits = 8; } + else + { + fprintf (stderr, "%s: invalid serial port mode %s: invalid data bits.\n", argv[0], port_mode); + exit(0); + } + + if(port_mode[1] == 'N') { parity = 'N'; } + else if(port_mode[1] == 'E') { parity = 'E'; } + else if(port_mode[1] == 'O') { parity = 'O'; } + else if(port_mode[1] == 'M') { parity = 'M'; } + else if(port_mode[1] == 'S') { parity = 'S'; } + else + { + fprintf (stderr, "%s: invalid serial port mode %s: invalid parity.\n", argv[0], port_mode); + exit(0); + } + + if(port_mode[2] == '1') { stop_bits = 1; } + else if(port_mode[2] == '2') { stop_bits = 2; } + else + { + fprintf (stderr, "%s: invalid serial port mode %s: invalid stop bits.\n", argv[0], port_mode); + exit(0); + } + } } if (baud_str == NULL) { - fprintf (stderr, "%s: baud rate not specified\n", argv[0]); + fprintf (stderr, "%s: baud rate is not specified\n", argv[0]); exit (0); } - if (baud == -1) + if (baud == 0) { fprintf (stderr, "%s: invalid baud rate %s\n", argv[0], baud_str); exit (0); @@ -259,15 +350,66 @@ main (int argc, char *argv[]) int serial_port = (0 == tcgetattr (fd, &oldtio)); if(serial_port) { - bzero (&newtio, sizeof (newtio)); /* clear struct for new port settings */ + memset (&newtio, 0, sizeof (newtio)); /* clear struct for new port settings */ + + /* Enable RTS/CTS (hardware) flow control. */ + /* newtio.c_cflag |= CRTSCTS; */ + + /* Character size mask. */ + if(data_bits == 7) { newtio.c_cflag |= CS7; } + else { newtio.c_cflag |= CS8; } + + /* Ignore modem control lines. */ + newtio.c_cflag |= CLOCAL; + + /* Enable receiver. */ + newtio.c_cflag |= CREAD; + + /* Set stop bits. */ + if(stop_bits == 2) { newtio.c_cflag |= CSTOPB; } + + if(parity == 'E') + { + newtio.c_cflag &= ~(PARODD | CMSPAR); + newtio.c_cflag |= PARENB; + } + else if(parity == 'O') + { + newtio.c_cflag |= PARENB | PARODD; + newtio.c_cflag &= ~CMSPAR; + } + else if(parity == 'M') + { + newtio.c_cflag |= PARENB | PARODD | CMSPAR; + } + else if(parity == 'S') + { + newtio.c_cflag |= PARENB | CMSPAR; + newtio.c_cflag &= ~PARODD; + } + + /* Ignore framing errors and parity errors. */ + newtio.c_iflag |= IGNPAR; + /* Ignore carriage return on input. */ + newtio.c_iflag |= IGNCR; + /* Ignore BREAK condition on input. */ + newtio.c_iflag |= IGNBRK; - newtio.c_cflag = CRTSCTS | CS8 | CLOCAL | CREAD; - newtio.c_iflag = IGNPAR | IGNCR; newtio.c_oflag = 0; - newtio.c_lflag = ICANON; + + if(output_fmt == FMT_ACSII) + { + /* Enable canonical mode. */ + newtio.c_lflag = ICANON; + } + + /* Set blocking read, no timeouts. */ + newtio.c_cc[VTIME] = 0; + newtio.c_cc[VMIN] = 1; + /* Only truly portable method of setting speed. */ - cfsetispeed (&newtio, BAUD_B[baud]); - cfsetospeed (&newtio, BAUD_B[baud]); + cfsetispeed (&newtio, baud); + cfsetospeed (&newtio, baud); tcflush (fd, TCIFLUSH); tcsetattr (fd, TCSANOW, &newtio); From a24b5efdf920d33c94a27fa0bacf892fd6ceb15e Mon Sep 17 00:00:00 2001 From: Mario Ivancic Date: Mon, 20 Oct 2025 21:15:25 +0200 Subject: [PATCH 08/15] Add serial port mode and new baud rates to man page. --- ttylog.8 | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/ttylog.8 b/ttylog.8 index 8eaeec0..b47258a 100644 --- a/ttylog.8 +++ b/ttylog.8 @@ -3,7 +3,7 @@ ttylog \- serial device logger .SH SYNOPSIS .B ttylog -[-b|--baud] [-d|--device] [-f|--flush] [-t|--timeout] [-F|--format] [-l|--limit] > /path/to/logfile +[-b|--baud] [-m|--mode] [-d|--device] [-f|--flush] [-t|--timeout] [-F|--format] [-l|--limit] > /path/to/logfile .PP If you are not using the timeout option, you can stop it running by pressing a ctrl-c when it's going to the screen or doing "kill -HUP nnnn" (where nnnn is @@ -22,9 +22,19 @@ Displays a little help .B -v, --version Version number of ttylog plus Copyright information .TP +.B -s --stamp +Prefix each line with timestamp, like 'Mon Oct 20 21:13:53 2025'. +.TP .B -b, --baud -Baud rate of the device. Available baud rates: -300, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600, and 2000000 +Baud rate of the device. Available standard baud rates: +300, 1200, 2400, 4800, 9600, 19200, 38400, 57600 +Additional baud rates, available if supported by the system: +28800, 115200, 230400, 460800, 500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000, 2500000, 3000000, 3500000, 4000000. +.TP +.B -m --mode +Set serial port mode. Default mode is 8N1 (8 data bits, no parity, 1 stop bits). +Possible options are: 7 or 8 for data bits, 1 or 2 for stop bits. +For parity: N (no parity), E (even parity), O (odd parity), M (mark parity), S (space parity). .TP .B -d --device The serial device. For example /dev/ttyS1 @@ -34,6 +44,7 @@ Output buffers are flushed after every write. .TP .B -t --timeout How long to run ttylog, in seconds. +.TP .B -F --format Set output format to one of a[scii] (default), h[ex], H[EX], r[aw]. Output format ascii is the same as in previous versions of ttylog, ttylog expects @@ -41,6 +52,7 @@ EOL characters in the strem. Output format hex is for HEX output using lowercase abcdef characters. Output format HEX is for HEX output using uppercase ABCDEF characters. Output format raw is the same as ascii, but fread() is used instead fgets(). +.TP .B -l --limit Limit line length. If format is hex or HEX this is actually a byte count limit, not line length limit. From 7f93bc935ba17cb0611e19b224300b1e38f7cdb4 Mon Sep 17 00:00:00 2001 From: Mario Ivancic Date: Mon, 20 Oct 2025 22:54:49 +0200 Subject: [PATCH 09/15] Add optional argument to -s|--stamp option to specify timestamp format (none, old, iso, ms, us). --- ttylog.8 | 12 ++-- ttylog.c | 176 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 169 insertions(+), 19 deletions(-) diff --git a/ttylog.8 b/ttylog.8 index b47258a..5ebe3c1 100644 --- a/ttylog.8 +++ b/ttylog.8 @@ -3,7 +3,7 @@ ttylog \- serial device logger .SH SYNOPSIS .B ttylog -[-b|--baud] [-m|--mode] [-d|--device] [-f|--flush] [-t|--timeout] [-F|--format] [-l|--limit] > /path/to/logfile +[-b|--baud] [-m|--mode] [-d|--device] [-f|--flush] [-s|--stamp] [-t|--timeout] [-F|--format] [-l|--limit] > /path/to/logfile .PP If you are not using the timeout option, you can stop it running by pressing a ctrl-c when it's going to the screen or doing "kill -HUP nnnn" (where nnnn is @@ -22,9 +22,6 @@ Displays a little help .B -v, --version Version number of ttylog plus Copyright information .TP -.B -s --stamp -Prefix each line with timestamp, like 'Mon Oct 20 21:13:53 2025'. -.TP .B -b, --baud Baud rate of the device. Available standard baud rates: 300, 1200, 2400, 4800, 9600, 19200, 38400, 57600 @@ -42,6 +39,13 @@ The serial device. For example /dev/ttyS1 .B -f --flush Output buffers are flushed after every write. .TP +.B -s --stamp +Prefix each line with timestamp. Timestamp format can be none, old, iso, ms, us. +In case of no format, old format is assumed, like 'WDAY MON DD HH:mm:ss YYYY'. +The iso format is ISO8601, like 'YYYY-MM-DDTHH:mm:ss.sss'. +The ms format is number of milliseconds (9 digits) from the program starup, like 'nnn.nnn.nnn'. +The us format is number of microseconds (12 digits) from the program starup, like 'nnn.nnn.nnn.nnn'. +.TP .B -t --timeout How long to run ttylog, in seconds. .TP diff --git a/ttylog.c b/ttylog.c index baca04d..1383e65 100644 --- a/ttylog.c +++ b/ttylog.c @@ -47,12 +47,24 @@ enum }; +/* Constants for timestamp format. */ +enum +{ + FMT_OLD = 1, /* Old timestamp format, like Mon Oct 20 21:13:53 2025. */ + FMT_ISO = 2, /* ISO8601 timestamp format, YYYY-MM-DDTHH:mm:ss.sss. */ + FMT_MS = 3, /* Relative time in milliseconds from program start. */ + FMT_US = 4, /* Relative time in microseconds from program start. */ +}; + /* Function that prints line in specified output format. Timestamp is optional. Buffer should be at least 4 times the line length. */ void print_line(char* line, int line_len, char* buffer, const char* time_stamp, int fmt); +/* Function to create timestamp according to timestamp format fmt. */ +const char* make_timestamp(int fmt, const struct timespec* start_time); + int main (int argc, char *argv[]) { @@ -72,9 +84,7 @@ main (int argc, char *argv[]) char buffer[4 * sizeof(line)]; char modem_device[512]; struct termios oldtio, newtio; - time_t rawtime; - struct tm *timeinfo; - char *timestr; + const char* timestr; int output_fmt = FMT_ACSII; int line_len_limit = sizeof(line) - 1; const char* baud_str = NULL; @@ -82,6 +92,10 @@ main (int argc, char *argv[]) int stop_bits = 1; /* 1 or 2 stop bits. */ int parity = 'N'; /* No parity (N), Even (E), Odd (O), Mark (M) or Space (S) */ const char* port_mode = "8N1"; + struct timespec startup_timestamp; + + + clock_gettime(CLOCK_MONOTONIC, &startup_timestamp); memset (modem_device, '\0', sizeof(modem_device)); @@ -103,7 +117,7 @@ main (int argc, char *argv[]) fprintf (stderr, " -m, --mode Serial port mode (default: 8N1)\n"); fprintf (stderr, " -d, --device Serial device (eg. /dev/ttyS1)\n"); fprintf (stderr, " -f, --flush Flush output\n"); - fprintf (stderr, " -s, --stamp Prefix each line with datestamp\n"); + fprintf (stderr, " -s, --stamp Prefix each line with datestamp (old, iso, ms, us)\n"); fprintf (stderr, " -t, --timeout How long to run, in seconds.\n"); fprintf (stderr, " -F, --format Set output format to one of a[scii] (default), h[ex], H[EX], r[aw].\n"); fprintf (stderr, " -l, --limit Limit line length.\n"); @@ -130,7 +144,24 @@ main (int argc, char *argv[]) } else if (!strcmp (argv[i], "-s") || !strcmp (argv[i], "--stamp")) { - stamp = 1; + /* Next token is optional. */ + if ((i + 1) >= argc) { stamp = FMT_OLD; } + else if (argv[i + i][0] == '-') { stamp = FMT_OLD; } + else + { + const char* fmt = argv[i + 1]; + i++; + + if (!strcmp(fmt, "old")) { stamp = FMT_OLD; } + else if (!strcmp(fmt, "iso")) { stamp = FMT_ISO; } + else if (!strcmp(fmt, "ms")) { stamp = FMT_MS; } + else if (!strcmp(fmt, "us")) { stamp = FMT_US; } + else + { + fprintf (stderr, "%s: invalid timestamp format '%s'\n", argv[0], fmt); + exit (0); + } + } } else if (!strcmp (argv[i], "-b") || !strcmp (argv[i], "--baud")) { @@ -438,6 +469,7 @@ main (int argc, char *argv[]) { if (!fgets (line, line_len_limit + 1, logfile)) { + line[0] = 0; if (ferror (logfile)) { break; } if (feof (logfile)) { break; } /* Used with files, for testing. */ } @@ -445,21 +477,18 @@ main (int argc, char *argv[]) len = fread (line, 1, line_len_limit, logfile); if (!len) { + line[0] = 0; if (ferror (logfile)) { break; } if (feof (logfile)) { break; } } - line[len - 1] = 0; + else + { + line[len - 1] = 0; + } } - if (stamp) - { - time(&rawtime); - timeinfo = localtime(&rawtime); - timestr = asctime(timeinfo); - timestr[strlen(timestr) - 1] = 0; - } else { - timestr = NULL; - } + if (stamp) { timestr = make_timestamp(stamp, &startup_timestamp); } + else { timestr = NULL; } if(!len){ len = strlen(line); } print_line(line, len, buffer, timestr, output_fmt); @@ -515,3 +544,120 @@ void print_line(char* line, int line_len, char* buffer, const char* time_stamp, } } } + + +/* Function to create timestamp according to timestamp format fmt. */ +const char* make_timestamp(int fmt, const struct timespec* start_time) +{ + char* timestr = NULL; + static char buffer[128]; + + if(fmt == FMT_OLD) + { + time_t rawtime; + struct tm *timeinfo; + time(&rawtime); + timeinfo = localtime(&rawtime); + timestr = asctime(timeinfo); + timestr[strlen(timestr) - 1] = 0; + } + else if(fmt == FMT_ISO) + { + /* YYYY-MM-DDTHH:MM:SS.sss */ + struct timespec ts; + struct tm TM; + unsigned ms; + ts.tv_sec = 0; + ts.tv_nsec = 0; + clock_gettime(CLOCK_REALTIME, &ts); + TM = *localtime(&ts.tv_sec); + ms = ts.tv_nsec / 1000000UL; + snprintf(buffer, sizeof(buffer), "%04d-%02d-%02dT%02d:%02d:%02d.%03d", + TM.tm_year + 1900, TM.tm_mon + 1, TM.tm_mday, + TM.tm_hour, TM.tm_min, TM.tm_sec, ms); + + timestr = buffer; + } + else if(fmt == FMT_MS) + { + /* 32-bit number of milliseconds. */ + struct timespec ts; + unsigned long long ms = 0; + ts.tv_sec = 0; + ts.tv_nsec = 0; + clock_gettime(CLOCK_MONOTONIC, &ts); + + /* Subtract start time from current time. */ + ts.tv_sec -= start_time->tv_sec; + ts.tv_nsec -= start_time->tv_nsec; + if(ts.tv_nsec < 0) + { + ts.tv_sec--; + ts.tv_nsec += 1000000000LL; + } + + /* Convert to milliseconds. */ + ms = ts.tv_nsec / 1000000UL; + ms += ts.tv_sec * 1000U; + ms %= 1000000000ULL; /* 9 decimal digits. */ + snprintf(buffer, sizeof(buffer), "%09llu", ms); + + /* Insert dots after every 3 digits. 000000136 => 000.000.136 */ + /* 012345678 01234567890 */ + buffer[11] = 0; + buffer[10] = buffer[8]; + buffer[9] = buffer[7]; + buffer[8] = buffer[6]; + buffer[7] = '.'; + buffer[6] = buffer[5]; + buffer[5] = buffer[4]; + buffer[4] = buffer[3]; + buffer[3] = '.'; + + timestr = buffer; + } + else if(fmt == FMT_US) + { + /* 64-bit number of microseconds. */ + struct timespec ts; + unsigned long long us = 0; + ts.tv_sec = 0; + ts.tv_nsec = 0; + clock_gettime(CLOCK_MONOTONIC, &ts); + + /* Subtract start time from current time. */ + ts.tv_sec -= start_time->tv_sec; + ts.tv_nsec -= start_time->tv_nsec; + if(ts.tv_nsec < 0) + { + ts.tv_sec--; + ts.tv_nsec += 1000000000LL; + } + + /* Convert to microseconds. */ + us = ts.tv_nsec / 1000UL; + us += ts.tv_sec * 1000000UL; + us %= 1000000000000ULL; /* 12 decimal digits. */ + snprintf(buffer, sizeof(buffer), "%012llu", us); + + /* Insert dots after every 3 digits. 000000000136 => 000.000.000.136 */ + /* 012345678901 012345678901234 */ + buffer[15] = 0; + buffer[14] = buffer[11]; + buffer[13] = buffer[10]; + buffer[12] = buffer[9]; + buffer[11] = '.'; + buffer[10] = buffer[8]; + buffer[9] = buffer[7]; + buffer[8] = buffer[6]; + buffer[7] = '.'; + buffer[6] = buffer[5]; + buffer[5] = buffer[4]; + buffer[4] = buffer[3]; + buffer[3] = '.'; + + timestr = buffer; + } + + return timestr; +} From 58670e972637a8cb22d93f381b47a0fc49bf94c8 Mon Sep 17 00:00:00 2001 From: Mario Ivancic Date: Tue, 21 Oct 2025 22:58:52 +0200 Subject: [PATCH 10/15] Add options --rts and --dtr to set RTS and DTR line state. --- CMakeLists.txt | 6 +-- ttylog.8 | 8 +++- ttylog.c | 112 ++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 97 insertions(+), 29 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f00f086..3454f15 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,9 +35,9 @@ SET(ttylog_executable_HDRS ADD_EXECUTABLE(ttylog ${ttylog_executable_SRCS}) # link against librt: -if(UNIX AND NOT APPLE) - target_link_libraries(ttylog rt) -endif() +#if(UNIX AND NOT APPLE) +# target_link_libraries(ttylog rt) +#endif() # add install targets: INSTALL(TARGETS ttylog DESTINATION sbin) diff --git a/ttylog.8 b/ttylog.8 index 5ebe3c1..2b26a1a 100644 --- a/ttylog.8 +++ b/ttylog.8 @@ -3,7 +3,7 @@ ttylog \- serial device logger .SH SYNOPSIS .B ttylog -[-b|--baud] [-m|--mode] [-d|--device] [-f|--flush] [-s|--stamp] [-t|--timeout] [-F|--format] [-l|--limit] > /path/to/logfile +[-b|--baud] [-m|--mode] [-d|--device] [-f|--flush] [-s|--stamp] [-t|--timeout] [-F|--format] [-l|--limit] [--rts] [--dtr] > /path/to/logfile .PP If you are not using the timeout option, you can stop it running by pressing a ctrl-c when it's going to the screen or doing "kill -HUP nnnn" (where nnnn is @@ -60,6 +60,12 @@ Output format raw is the same as ascii, but fread() is used instead fgets(). .B -l --limit Limit line length. If format is hex or HEX this is actually a byte count limit, not line length limit. +.TP +.B --rts +Set RTS line state to 0 or 1. +.TP +.B --dtr +Set DTR line state to 0 or 1. .SH AUTHOR This manual page was originally written by Tibor Koleszar , for the Debian GNU/Linux system. Modifications and updates written by diff --git a/ttylog.c b/ttylog.c index 1383e65..9d6bad0 100644 --- a/ttylog.c +++ b/ttylog.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -75,10 +76,6 @@ main (int argc, char *argv[]) speed_t baud = 0; int stamp = 0; int flush = 0; - timer_t timerid; - struct sigevent sevp; - sevp.sigev_notify = SIGEV_SIGNAL; - sevp.sigev_signo = SIGINT; int fd; char line[1024]; char buffer[4 * sizeof(line)]; @@ -93,7 +90,10 @@ main (int argc, char *argv[]) int parity = 'N'; /* No parity (N), Even (E), Odd (O), Mark (M) or Space (S) */ const char* port_mode = "8N1"; struct timespec startup_timestamp; - + int rts = -1; + int dtr = -1; + int timeout = 0; + int run_time = 0; clock_gettime(CLOCK_MONOTONIC, &startup_timestamp); @@ -110,7 +110,7 @@ main (int argc, char *argv[]) if (!strcmp (argv[i], "-h") || !strcmp (argv[i], "--help")) { fprintf (stderr, "ttylog version %s\n", TTYLOG_VERSION); - fprintf (stderr, "Usage: ttylog [-b|--baud] [-m|--mode] [-d|--device] [-f|--flush] [-s|--stamp] [-t|--timeout] [-F|--format] [-l|--limit] > /path/to/logfile\n"); + fprintf (stderr, "Usage: ttylog [-b|--baud] [-m|--mode] [-d|--device] [-f|--flush] [-s|--stamp] [-t|--timeout] [-F|--format] [-l|--limit] [--rts] [--dtr] > /path/to/logfile\n"); fprintf (stderr, " -h, --help This help\n"); fprintf (stderr, " -v, --version Version number\n"); fprintf (stderr, " -b, --baud Baud rate\n"); @@ -121,6 +121,8 @@ main (int argc, char *argv[]) fprintf (stderr, " -t, --timeout How long to run, in seconds.\n"); fprintf (stderr, " -F, --format Set output format to one of a[scii] (default), h[ex], H[EX], r[aw].\n"); fprintf (stderr, " -l, --limit Limit line length.\n"); + fprintf (stderr, " --rts Set RTS line state (0 or 1).\n"); + fprintf (stderr, " --dtr Set DTR line state (0 or 1).\n"); fprintf (stderr, "ttylog home page: \n\n"); exit (0); } @@ -250,27 +252,13 @@ main (int argc, char *argv[]) fprintf (stderr, "%s: invalid time span\n", argv[0]); exit(0); } - if (timer_create (CLOCK_REALTIME, &sevp, &timerid) == -1) - { - fprintf (stderr, "%s: unable to create timer: %s\n", argv[0], strerror(errno)); - exit (0); - } - struct itimerspec new_value; - new_value.it_interval.tv_sec = 0; - new_value.it_interval.tv_nsec = 0; - int sec = atoi(argv[i + 1]); - if (!sec) + + timeout = atoi(argv[i + 1]); + if (!timeout) { fprintf (stderr, "%s: invalid time span %s\n", argv[0], argv[i + 1]); exit(0); } - new_value.it_value.tv_sec = atoi(argv[i + 1]); - new_value.it_value.tv_nsec = 0; - if (timer_settime(timerid, 0, &new_value, NULL) == -1) - { - fprintf (stderr, "%s: unable to set timer time: %s\n", argv[0], strerror(errno)); - exit (0); - } i++; } @@ -350,6 +338,40 @@ main (int argc, char *argv[]) exit(0); } } + else if (!strcmp (argv[i], "--rts")) + { + if ((i + 1) >= argc) + { + fprintf (stderr, "%s: RTS line state is not specified\n", argv[0]); + exit(0); + } + + i++; + if(argv[i][0] == '0') { rts = 0; } + else if(argv[i][0] == '1') { rts = 1; } + else + { + fprintf (stderr, "%s: invalid RTS line state '%s'\n", argv[0], argv[i]); + exit(0); + } + } + else if (!strcmp (argv[i], "--dtr")) + { + if ((i + 1) >= argc) + { + fprintf (stderr, "%s: DTR line state is not specified\n", argv[0]); + exit(0); + } + + i++; + if(argv[i][0] == '0') { dtr = 0; } + else if(argv[i][0] == '1') { dtr = 1; } + else + { + fprintf (stderr, "%s: invalid DTR line state '%s'\n", argv[0], argv[i]); + exit(0); + } + } } if (baud_str == NULL) @@ -445,6 +467,30 @@ main (int argc, char *argv[]) tcflush (fd, TCIFLUSH); tcsetattr (fd, TCSANOW, &newtio); + if(rts >= 0) + { + int flags = TIOCM_RTS; + if(rts) { ioctl(fd, TIOCMBIS, &flags); } + else { ioctl(fd, TIOCMBIC, &flags); } + } + + if(dtr >= 0) + { + int flags = TIOCM_DTR; + if(rts) { ioctl(fd, TIOCMBIS, &flags); } + else { ioctl(fd, TIOCMBIC, &flags); } + } + + /* Set low latency flag. Note that not all serial drivers support this feature. */ +#if defined(ASYNC_LOW_LATENCY) + { + struct serial_struct serial; + ioctl(fd, TIOCGSERIAL, &serial); + serial.flags |= ASYNC_LOW_LATENCY; + ioctl(fd, TIOCSSERIAL, &serial); + } +#endif // defined + /* Clear the device */ { int flags = fcntl (fd, F_GETFL, 0); @@ -461,7 +507,18 @@ main (int argc, char *argv[]) { FD_ZERO (&rfds); FD_SET (fd, &rfds); - retval = select (fd + 1, &rfds, NULL, NULL, NULL); + if(timeout) + { + struct timeval tv; + tv.tv_sec = 1; + tv.tv_usec = 0; + retval = select (fd + 1, &rfds, NULL, NULL, &tv); + } + else + { + retval = select (fd + 1, &rfds, NULL, NULL, NULL); + } + if (retval > 0) { size_t len = 0; @@ -495,7 +552,12 @@ main (int argc, char *argv[]) if (flush) { fflush(stdout); } } - else if (retval < 0) { break; } + else if (retval == 0) /* Timeout. */ + { + if(timeout && (run_time >= timeout) ) break; + else if(timeout) { run_time++; } + } + else { break; } /* Error. */ } fclose (logfile); From 4a0c5447a091b34e6ff7e19348dc02e7a94ade3b Mon Sep 17 00:00:00 2001 From: Mario Ivancic Date: Thu, 23 Oct 2025 20:12:10 +0200 Subject: [PATCH 11/15] Fix bug for HEX output mode. --- ttylog.8 | 30 ++++++++++-------- ttylog.c | 95 +++++++++++++++++++++++++++++++++++--------------------- 2 files changed, 76 insertions(+), 49 deletions(-) diff --git a/ttylog.8 b/ttylog.8 index 2b26a1a..9d69ee5 100644 --- a/ttylog.8 +++ b/ttylog.8 @@ -3,7 +3,7 @@ ttylog \- serial device logger .SH SYNOPSIS .B ttylog -[-b|--baud] [-m|--mode] [-d|--device] [-f|--flush] [-s|--stamp] [-t|--timeout] [-F|--format] [-l|--limit] [--rts] [--dtr] > /path/to/logfile +[-b|--baud] [-m|--mode] [-d|--device] [-f|--flush] [-s|--stamp] [-t|--timeout] [-F|--format] [-l|--limit] [--rts] [--dtr] > /path/to/log-file .PP If you are not using the timeout option, you can stop it running by pressing a ctrl-c when it's going to the screen or doing "kill -HUP nnnn" (where nnnn is @@ -26,38 +26,42 @@ Version number of ttylog plus Copyright information Baud rate of the device. Available standard baud rates: 300, 1200, 2400, 4800, 9600, 19200, 38400, 57600 Additional baud rates, available if supported by the system: -28800, 115200, 230400, 460800, 500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000, 2500000, 3000000, 3500000, 4000000. +28800, 115200, 230400, 460800, 500000, 576000, 921600, 1000000, 1152000, +1500000, 2000000, 2500000, 3000000, 3500000, 4000000. .TP -.B -m --mode -Set serial port mode. Default mode is 8N1 (8 data bits, no parity, 1 stop bits). +.B -m, --mode +Set serial port mode. Default mode is 8N1 (8 data bits, no parity, 1 stop bit). Possible options are: 7 or 8 for data bits, 1 or 2 for stop bits. -For parity: N (no parity), E (even parity), O (odd parity), M (mark parity), S (space parity). +For parity: N (no parity), E (even parity), O (odd parity), M (mark parity), +S (space parity). .TP -.B -d --device +.B -d, --device The serial device. For example /dev/ttyS1 .TP -.B -f --flush +.B -f, --flush Output buffers are flushed after every write. .TP .B -s --stamp Prefix each line with timestamp. Timestamp format can be none, old, iso, ms, us. In case of no format, old format is assumed, like 'WDAY MON DD HH:mm:ss YYYY'. The iso format is ISO8601, like 'YYYY-MM-DDTHH:mm:ss.sss'. -The ms format is number of milliseconds (9 digits) from the program starup, like 'nnn.nnn.nnn'. -The us format is number of microseconds (12 digits) from the program starup, like 'nnn.nnn.nnn.nnn'. +The ms format is number of milliseconds (9 digits) from the program startup, +like 'nnn.nnn.nnn'. +The us format is number of microseconds (12 digits) from the program startup, +like 'nnn.nnn.nnn.nnn'. .TP -.B -t --timeout +.B -t, --timeout How long to run ttylog, in seconds. .TP -.B -F --format +.B -F, --format Set output format to one of a[scii] (default), h[ex], H[EX], r[aw]. Output format ascii is the same as in previous versions of ttylog, ttylog expects -EOL characters in the strem. +EOL characters in the stream. Output format hex is for HEX output using lowercase abcdef characters. Output format HEX is for HEX output using uppercase ABCDEF characters. Output format raw is the same as ascii, but fread() is used instead fgets(). .TP -.B -l --limit +.B -l, --limit Limit line length. If format is hex or HEX this is actually a byte count limit, not line length limit. .TP diff --git a/ttylog.c b/ttylog.c index 9d6bad0..b17f94e 100644 --- a/ttylog.c +++ b/ttylog.c @@ -75,7 +75,6 @@ main (int argc, char *argv[]) int i; speed_t baud = 0; int stamp = 0; - int flush = 0; int fd; char line[1024]; char buffer[4 * sizeof(line)]; @@ -110,13 +109,12 @@ main (int argc, char *argv[]) if (!strcmp (argv[i], "-h") || !strcmp (argv[i], "--help")) { fprintf (stderr, "ttylog version %s\n", TTYLOG_VERSION); - fprintf (stderr, "Usage: ttylog [-b|--baud] [-m|--mode] [-d|--device] [-f|--flush] [-s|--stamp] [-t|--timeout] [-F|--format] [-l|--limit] [--rts] [--dtr] > /path/to/logfile\n"); + fprintf (stderr, "Usage: ttylog [-b|--baud] [-m|--mode] [-d|--device] [-s|--stamp] [-t|--timeout] [-F|--format] [-l|--limit] [--rts] [--dtr] > /path/to/logfile\n"); fprintf (stderr, " -h, --help This help\n"); fprintf (stderr, " -v, --version Version number\n"); fprintf (stderr, " -b, --baud Baud rate\n"); fprintf (stderr, " -m, --mode Serial port mode (default: 8N1)\n"); fprintf (stderr, " -d, --device Serial device (eg. /dev/ttyS1)\n"); - fprintf (stderr, " -f, --flush Flush output\n"); fprintf (stderr, " -s, --stamp Prefix each line with datestamp (old, iso, ms, us)\n"); fprintf (stderr, " -t, --timeout How long to run, in seconds.\n"); fprintf (stderr, " -F, --format Set output format to one of a[scii] (default), h[ex], H[EX], r[aw].\n"); @@ -140,10 +138,6 @@ main (int argc, char *argv[]) fprintf (stderr, "There is NO WARRANTY, to the extent permitted by law.\n\n"); exit (0); } - else if (!strcmp (argv[i], "-f") || !strcmp (argv[i], "--flush")) - { - flush = 1; - } else if (!strcmp (argv[i], "-s") || !strcmp (argv[i], "--stamp")) { /* Next token is optional. */ @@ -386,7 +380,7 @@ main (int argc, char *argv[]) exit (0); } - if (!strlen(modem_device)) { + if (!modem_device[0]) { fprintf (stderr, "%s: no device is set. Use %s -h for more information.\n", argv[0], argv[0]); exit (0); } @@ -443,8 +437,13 @@ main (int argc, char *argv[]) /* Ignore framing errors and parity errors. */ newtio.c_iflag |= IGNPAR; - /* Ignore carriage return on input. */ - newtio.c_iflag |= IGNCR; + + if(output_fmt == FMT_ACSII) + { + /* Ignore carriage return on input. */ + newtio.c_iflag |= IGNCR; + } + /* Ignore BREAK condition on input. */ newtio.c_iflag |= IGNBRK; @@ -458,7 +457,7 @@ main (int argc, char *argv[]) /* Set blocking read, no timeouts. */ newtio.c_cc[VTIME] = 0; - newtio.c_cc[VMIN] = 1; + newtio.c_cc[VMIN] = 0; /* Only truly portable method of setting speed. */ cfsetispeed (&newtio, baud); @@ -500,8 +499,7 @@ main (int argc, char *argv[]) } } - if (flush) - setbuf(stdout, NULL); + struct timeval select_timeout; while (1) { @@ -509,10 +507,9 @@ main (int argc, char *argv[]) FD_SET (fd, &rfds); if(timeout) { - struct timeval tv; - tv.tv_sec = 1; - tv.tv_usec = 0; - retval = select (fd + 1, &rfds, NULL, NULL, &tv); + select_timeout.tv_sec = 1; + select_timeout.tv_usec = 0; + retval = select (fd + 1, &rfds, NULL, NULL, &select_timeout); } else { @@ -521,43 +518,66 @@ main (int argc, char *argv[]) if (retval > 0) { - size_t len = 0; + ssize_t len = 0; if(output_fmt == FMT_ACSII) { if (!fgets (line, line_len_limit + 1, logfile)) { line[0] = 0; - if (ferror (logfile)) { break; } - if (feof (logfile)) { break; } /* Used with files, for testing. */ + if (ferror (logfile)) + { + fprintf (stderr, "%s: error reading serial device %s\n", argv[0], modem_device); + break; + } + /* Used with files, for testing. */ + if (!serial_port && feof (logfile)) { break; } + + len = strlen(line); } - } else { - len = fread (line, 1, line_len_limit, logfile); - if (!len) + } + else + { + len = read (fd, line, line_len_limit); + if (len < 0) { + int err = errno; line[0] = 0; - if (ferror (logfile)) { break; } - if (feof (logfile)) { break; } + if (err == EAGAIN || err == EWOULDBLOCK) + { + continue; + } + else + { + fprintf (stderr, "%s: error %d while reading serial device %s\n", argv[0], err, modem_device); + break; + } + } + else if(len > 0) + { + line[len] = 0; } else { - line[len - 1] = 0; + /* EOF */ + break; } } if (stamp) { timestr = make_timestamp(stamp, &startup_timestamp); } else { timestr = NULL; } - if(!len){ len = strlen(line); } print_line(line, len, buffer, timestr, output_fmt); - - if (flush) { fflush(stdout); } } else if (retval == 0) /* Timeout. */ { if(timeout && (run_time >= timeout) ) break; else if(timeout) { run_time++; } } - else { break; } /* Error. */ + else + { + fprintf (stderr, "%s: error in select call\n", argv[0]); + break; + } } fclose (logfile); @@ -582,29 +602,32 @@ void print_line(char* line, int line_len, char* buffer, const char* time_stamp, printf ("[%s] %s\n", time_stamp, line); } else { - fputs (line, stdout); + puts (line); } - } else if(fmt == FMT_HEX_LC || fmt == FMT_HEX_UC) { + } + else if(fmt == FMT_HEX_LC || fmt == FMT_HEX_UC) + { int buff_len = 0; const char* hex_chars = (fmt == FMT_HEX_LC) ? hex_chars_lc : hex_chars_uc; for(int i = 0; i < line_len; i++) { unsigned char d = line[i]; + if (i) { buffer[buff_len++] = ' '; } buffer[buff_len++] = hex_chars[(d >> 4) & 0x0F]; buffer[buff_len++] = hex_chars[d & 0x0F]; - buffer[buff_len++] = ' '; } - buffer[buff_len++] = '\n'; buffer[buff_len] = 0; if (time_stamp) { - printf ("[%s] %s", time_stamp, buffer); + printf ("[%s] %s\n", time_stamp, buffer); } else { - fputs (buffer, stdout); + printf ("%s\n", buffer); } } + + fflush(stdout); } From 477d4f6fd4cab9a2689610982b1ed6b5440311f5 Mon Sep 17 00:00:00 2001 From: Mario Ivancic Date: Thu, 23 Oct 2025 20:27:18 +0200 Subject: [PATCH 12/15] Fix HEX output without timestamp. --- ttylog.c | 128 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 84 insertions(+), 44 deletions(-) diff --git a/ttylog.c b/ttylog.c index b17f94e..ae6cab4 100644 --- a/ttylog.c +++ b/ttylog.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "config.h" @@ -58,9 +59,17 @@ enum }; +typedef struct +{ + char* work_buff; + int line_len_limit; + int line_len; +} print_data_ctx_t; + + /* Function that prints line in specified output format. Timestamp is optional. Buffer should be at least 4 times the line length. */ -void print_line(char* line, int line_len, char* buffer, const char* time_stamp, int fmt); +void print_data(char* raw_data, int raw_data_len, print_data_ctx_t* ctx, const char* time_stamp, int fmt); /* Function to create timestamp according to timestamp format fmt. */ @@ -76,13 +85,12 @@ main (int argc, char *argv[]) speed_t baud = 0; int stamp = 0; int fd; - char line[1024]; - char buffer[4 * sizeof(line)]; + char raw_data[1024]; + char buffer[4 * sizeof(raw_data)]; char modem_device[512]; struct termios oldtio, newtio; const char* timestr; int output_fmt = FMT_ACSII; - int line_len_limit = sizeof(line) - 1; const char* baud_str = NULL; int data_bits = 8; /* 7 or 8 data bits. */ int stop_bits = 1; /* 1 or 2 stop bits. */ @@ -93,6 +101,11 @@ main (int argc, char *argv[]) int dtr = -1; int timeout = 0; int run_time = 0; + print_data_ctx_t print_data_ctx; + + print_data_ctx.work_buff = buffer; + print_data_ctx.line_len_limit = sizeof(raw_data) - 1; + print_data_ctx.line_len = 0; clock_gettime(CLOCK_MONOTONIC, &startup_timestamp); @@ -284,14 +297,13 @@ main (int argc, char *argv[]) exit(0); } - int len = atoi(argv[i + 1]); - if (!len) + print_data_ctx.line_len_limit = atoi(argv[i + 1]); + if (!print_data_ctx.line_len_limit) { fprintf (stderr, "%s: invalid line length limit %s\n", argv[0], argv[i + 1]); exit(0); } - line_len_limit = len; i++; } else if (!strcmp (argv[i], "-m") || !strcmp (argv[i], "--mode")) @@ -494,7 +506,7 @@ main (int argc, char *argv[]) { int flags = fcntl (fd, F_GETFL, 0); fcntl (fd, F_SETFL, flags | O_NONBLOCK); - while (fread (line, 1, sizeof(line), logfile) > 0 ); + while (fread (raw_data, 1, sizeof(raw_data), logfile) > 0 ); fcntl (fd, F_SETFL, flags); } } @@ -521,9 +533,9 @@ main (int argc, char *argv[]) ssize_t len = 0; if(output_fmt == FMT_ACSII) { - if (!fgets (line, line_len_limit + 1, logfile)) + if (!fgets (raw_data, sizeof(raw_data), logfile)) { - line[0] = 0; + raw_data[0] = 0; if (ferror (logfile)) { fprintf (stderr, "%s: error reading serial device %s\n", argv[0], modem_device); @@ -532,16 +544,16 @@ main (int argc, char *argv[]) /* Used with files, for testing. */ if (!serial_port && feof (logfile)) { break; } - len = strlen(line); + len = strlen(raw_data); } } else { - len = read (fd, line, line_len_limit); + len = read (fd, raw_data, sizeof(raw_data) - 1); if (len < 0) { int err = errno; - line[0] = 0; + raw_data[0] = 0; if (err == EAGAIN || err == EWOULDBLOCK) { continue; @@ -554,7 +566,7 @@ main (int argc, char *argv[]) } else if(len > 0) { - line[len] = 0; + raw_data[len] = 0; } else { @@ -566,7 +578,7 @@ main (int argc, char *argv[]) if (stamp) { timestr = make_timestamp(stamp, &startup_timestamp); } else { timestr = NULL; } - print_line(line, len, buffer, timestr, output_fmt); + print_data(raw_data, len, &print_data_ctx, timestr, output_fmt); } else if (retval == 0) /* Timeout. */ { @@ -585,49 +597,77 @@ main (int argc, char *argv[]) return 0; } + /* Function that prints line in specified output format. Timestamp is optional. Buffer should be at least 4 times the line length. */ -void print_line(char* line, int line_len, char* buffer, const char* time_stamp, int fmt) +void print_data(char* raw_data, int raw_data_len, print_data_ctx_t* ctx, const char* time_stamp, int fmt) { static const char* hex_chars_lc = "0123456789abcdef"; static const char* hex_chars_uc = "0123456789ABCDEF"; + int offset = 0; + if(fmt == FMT_ACSII || fmt == FMT_RAW) { - if (time_stamp) + while(raw_data_len) { - /* If timestamps are printed we have to be sure that timestamp is at - the beginning of the line. */ - if(line[line_len - 1] == '\n') { line[line_len - 1] = 0; } + if (time_stamp) + { + if(ctx->line_len != 0) { puts("\n"); } + printf ("[%s] ", time_stamp); + ctx->line_len = 0; + } + + int len = ctx->line_len_limit - ctx->line_len; + if(len > raw_data_len) { len = raw_data_len; } + memcpy(ctx->work_buff, raw_data + offset, len); + offset += len; + ctx->line_len += len; + raw_data_len -= len; + if(ctx->line_len >= ctx->line_len_limit) { ctx->line_len = 0; } - printf ("[%s] %s\n", time_stamp, line); - } else { - puts (line); + // if(ctx->work_buff[len - 1] == '\n') { ctx->work_buff[len - 1] = 0; } + // else { ctx->work_buff[len] = 0; } + ctx->work_buff[len] = 0; + + puts(ctx->work_buff); + fflush(stdout); } } else if(fmt == FMT_HEX_LC || fmt == FMT_HEX_UC) { - int buff_len = 0; const char* hex_chars = (fmt == FMT_HEX_LC) ? hex_chars_lc : hex_chars_uc; - for(int i = 0; i < line_len; i++) - { - unsigned char d = line[i]; - if (i) { buffer[buff_len++] = ' '; } - buffer[buff_len++] = hex_chars[(d >> 4) & 0x0F]; - buffer[buff_len++] = hex_chars[d & 0x0F]; - } + while(raw_data_len) + { + if (time_stamp) + { + if(ctx->line_len != 0) { puts("\n"); } + printf ("[%s] ", time_stamp); + ctx->line_len = 0; + } - buffer[buff_len] = 0; + int len = ctx->line_len_limit - ctx->line_len; + if(len > raw_data_len) { len = raw_data_len; } - if (time_stamp) - { - printf ("[%s] %s\n", time_stamp, buffer); - } else { - printf ("%s\n", buffer); - } - } + int buff_len = 0; + for(int i = 0; i < len; i++) + { + unsigned char d = raw_data[offset + i]; + if (i) { ctx->work_buff[buff_len++] = ' '; } + ctx->work_buff[buff_len++] = hex_chars[(d >> 4) & 0x0F]; + ctx->work_buff[buff_len++] = hex_chars[d & 0x0F]; + } + + ctx->work_buff[buff_len] = 0; + offset += len; + ctx->line_len += len; + raw_data_len -= len; + if(ctx->line_len >= ctx->line_len_limit) { ctx->line_len = 0; } - fflush(stdout); + puts(ctx->work_buff); + fflush(stdout); + } + } } @@ -667,7 +707,7 @@ const char* make_timestamp(int fmt, const struct timespec* start_time) { /* 32-bit number of milliseconds. */ struct timespec ts; - unsigned long long ms = 0; + uint64_t ms = 0; ts.tv_sec = 0; ts.tv_nsec = 0; clock_gettime(CLOCK_MONOTONIC, &ts); @@ -685,7 +725,7 @@ const char* make_timestamp(int fmt, const struct timespec* start_time) ms = ts.tv_nsec / 1000000UL; ms += ts.tv_sec * 1000U; ms %= 1000000000ULL; /* 9 decimal digits. */ - snprintf(buffer, sizeof(buffer), "%09llu", ms); + snprintf(buffer, sizeof(buffer), "%09" PRIu64, ms); /* Insert dots after every 3 digits. 000000136 => 000.000.136 */ /* 012345678 01234567890 */ @@ -705,7 +745,7 @@ const char* make_timestamp(int fmt, const struct timespec* start_time) { /* 64-bit number of microseconds. */ struct timespec ts; - unsigned long long us = 0; + uint64_t us = 0; ts.tv_sec = 0; ts.tv_nsec = 0; clock_gettime(CLOCK_MONOTONIC, &ts); @@ -723,7 +763,7 @@ const char* make_timestamp(int fmt, const struct timespec* start_time) us = ts.tv_nsec / 1000UL; us += ts.tv_sec * 1000000UL; us %= 1000000000000ULL; /* 12 decimal digits. */ - snprintf(buffer, sizeof(buffer), "%012llu", us); + snprintf(buffer, sizeof(buffer), "%012" PRIu64, us); /* Insert dots after every 3 digits. 000000000136 => 000.000.000.136 */ /* 012345678901 012345678901234 */ From 6daa5c56c64ebd1fc845fc016c25ca1e61a1e401 Mon Sep 17 00:00:00 2001 From: Mario Ivancic Date: Mon, 27 Oct 2025 21:22:31 +0100 Subject: [PATCH 13/15] Refactor baud rate parsing code. --- ttylog.c | 129 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 70 insertions(+), 59 deletions(-) diff --git a/ttylog.c b/ttylog.c index ae6cab4..72a8782 100644 --- a/ttylog.c +++ b/ttylog.c @@ -37,7 +37,6 @@ #include "config.h" -#define BAUDN 13 /* Constants for output format. */ enum @@ -75,6 +74,9 @@ void print_data(char* raw_data, int raw_data_len, print_data_ctx_t* ctx, const c /* Function to create timestamp according to timestamp format fmt. */ const char* make_timestamp(int fmt, const struct timespec* start_time); +/* Select baud rate based on user input. */ +int select_baud_rate(const char* baud_str); + int main (int argc, char *argv[]) { @@ -182,64 +184,7 @@ main (int argc, char *argv[]) baud_str = argv[i + 1]; i++; - long long b = strtoll(baud_str, NULL, 10); - switch(b) - { - case 300: baud = B300; break; - case 600: baud = B600; break; - case 1200: baud = B1200; break; - case 2400: baud = B2400; break; - case 4800: baud = B4800; break; - case 9600: baud = B9600; break; - case 19200: baud = B19200; break; -#if defined(B28800) - case 28800: baud = B28800; break; -#endif // defined - case 38400: baud = B38400; break; - case 57600: baud = B57600; break; -#if defined(B115200) - case 115200: baud = B115200; break; -#endif // defined -#if defined(B230400) - case 230400: baud = B230400; break; -#endif // defined -#if defined(B460800) - case 460800: baud = B460800; break; -#endif // defined -#if defined(B500000) - case 500000: baud = B500000; break; -#endif // defined -#if defined(B576000) - case 576000: baud = B576000; break; -#endif // defined -#if defined(B921600) - case 921600: baud = B921600; break; -#endif // defined -#if defined(B1000000) - case 1000000: baud = B1000000; break; -#endif // defined -#if defined(B1152000) - case 1152000: baud = B1152000; break; -#endif // defined -#if defined(B1500000) - case 1500000: baud = B1500000; break; -#endif // defined -#if defined(B2000000) - case 2000000: baud = B2000000; break; -#endif // defined -#if defined(B2500000) - case 2500000: baud = B2500000; break; -#endif // defined -#if defined(B3000000) - case 3000000: baud = B3000000; break; -#endif // defined -#if defined(B3500000) - case 3500000: baud = B3500000; break; -#endif // defined -#if defined(B4000000) - case 4000000: baud = B4000000; break; -#endif // defined - } + baud = select_baud_rate(baud_str); } else if (!strcmp (argv[i], "-d") || !strcmp (argv[i], "--device")) { @@ -786,3 +731,69 @@ const char* make_timestamp(int fmt, const struct timespec* start_time) return timestr; } + + +int select_baud_rate(const char* baud_str) +{ + long long b = strtoll(baud_str, NULL, 10); + int baud = 0; + switch(b) + { + case 300: baud = B300; break; + case 600: baud = B600; break; + case 1200: baud = B1200; break; + case 2400: baud = B2400; break; + case 4800: baud = B4800; break; + case 9600: baud = B9600; break; + case 19200: baud = B19200; break; +#if defined(B28800) + case 28800: baud = B28800; break; +#endif // defined + case 38400: baud = B38400; break; + case 57600: baud = B57600; break; +#if defined(B115200) + case 115200: baud = B115200; break; +#endif // defined +#if defined(B230400) + case 230400: baud = B230400; break; +#endif // defined +#if defined(B460800) + case 460800: baud = B460800; break; +#endif // defined +#if defined(B500000) + case 500000: baud = B500000; break; +#endif // defined +#if defined(B576000) + case 576000: baud = B576000; break; +#endif // defined +#if defined(B921600) + case 921600: baud = B921600; break; +#endif // defined +#if defined(B1000000) + case 1000000: baud = B1000000; break; +#endif // defined +#if defined(B1152000) + case 1152000: baud = B1152000; break; +#endif // defined +#if defined(B1500000) + case 1500000: baud = B1500000; break; +#endif // defined +#if defined(B2000000) + case 2000000: baud = B2000000; break; +#endif // defined +#if defined(B2500000) + case 2500000: baud = B2500000; break; +#endif // defined +#if defined(B3000000) + case 3000000: baud = B3000000; break; +#endif // defined +#if defined(B3500000) + case 3500000: baud = B3500000; break; +#endif // defined +#if defined(B4000000) + case 4000000: baud = B4000000; break; +#endif // defined + } + + return baud; +} From fe781ec150ce7887b1612e97bae48425f2e746bd Mon Sep 17 00:00:00 2001 From: Mario Ivancic Date: Sat, 15 Nov 2025 21:58:26 +0100 Subject: [PATCH 14/15] Fix unneeded new-line characters in the output. --- ttylog.c | 188 +++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 163 insertions(+), 25 deletions(-) diff --git a/ttylog.c b/ttylog.c index 72a8782..58fb556 100644 --- a/ttylog.c +++ b/ttylog.c @@ -37,6 +37,8 @@ #include "config.h" +/* #define DEBUG 1 */ + /* Constants for output format. */ enum @@ -63,12 +65,13 @@ typedef struct char* work_buff; int line_len_limit; int line_len; + int new_line; } print_data_ctx_t; /* Function that prints line in specified output format. Timestamp is optional. Buffer should be at least 4 times the line length. */ -void print_data(char* raw_data, int raw_data_len, print_data_ctx_t* ctx, const char* time_stamp, int fmt); +void print_data(const char* raw_data, int raw_data_len, print_data_ctx_t* ctx, const char* time_stamp, int fmt); /* Function to create timestamp according to timestamp format fmt. */ @@ -77,6 +80,10 @@ const char* make_timestamp(int fmt, const struct timespec* start_time); /* Select baud rate based on user input. */ int select_baud_rate(const char* baud_str); +#ifdef DEBUG +FILE* debug_file; +#endif // DEBUG + int main (int argc, char *argv[]) { @@ -108,11 +115,16 @@ main (int argc, char *argv[]) print_data_ctx.work_buff = buffer; print_data_ctx.line_len_limit = sizeof(raw_data) - 1; print_data_ctx.line_len = 0; + print_data_ctx.new_line = 1; clock_gettime(CLOCK_MONOTONIC, &startup_timestamp); memset (modem_device, '\0', sizeof(modem_device)); +#ifdef DEBUG + debug_file = fopen ("debug-out.txt", "a"); +#endif // DEBUG + if (argc < 2) { fprintf (stderr, "%s: no params. try %s -h\n", argv[0], argv[0]); @@ -157,22 +169,30 @@ main (int argc, char *argv[]) { /* Next token is optional. */ if ((i + 1) >= argc) { stamp = FMT_OLD; } - else if (argv[i + i][0] == '-') { stamp = FMT_OLD; } else { const char* fmt = argv[i + 1]; - i++; - if (!strcmp(fmt, "old")) { stamp = FMT_OLD; } - else if (!strcmp(fmt, "iso")) { stamp = FMT_ISO; } - else if (!strcmp(fmt, "ms")) { stamp = FMT_MS; } - else if (!strcmp(fmt, "us")) { stamp = FMT_US; } + if (fmt[0] == '-') { stamp = FMT_OLD; } else { - fprintf (stderr, "%s: invalid timestamp format '%s'\n", argv[0], fmt); - exit (0); + i++; + + if (!strcmp(fmt, "old")) { stamp = FMT_OLD; } + else if (!strcmp(fmt, "iso")) { stamp = FMT_ISO; } + else if (!strcmp(fmt, "ms")) { stamp = FMT_MS; } + else if (!strcmp(fmt, "us")) { stamp = FMT_US; } + else + { + fprintf (stderr, "%s: invalid timestamp format '%s'\n", argv[0], fmt); + exit (0); + } } } +#ifdef DEBUG + fprintf(debug_file, "Using timestamp format %d\n", stamp); + fflush(debug_file); +#endif // DEBUG } else if (!strcmp (argv[i], "-b") || !strcmp (argv[i], "--baud")) { @@ -185,6 +205,10 @@ main (int argc, char *argv[]) baud_str = argv[i + 1]; i++; baud = select_baud_rate(baud_str); +#ifdef DEBUG + fprintf(debug_file, "Using baudrate of %d bps\n", baud); + fflush(debug_file); +#endif // DEBUG } else if (!strcmp (argv[i], "-d") || !strcmp (argv[i], "--device")) { @@ -196,6 +220,10 @@ main (int argc, char *argv[]) strncpy (modem_device, argv[i + 1], sizeof(modem_device) - 1); i++; +#ifdef DEBUG + fprintf(debug_file, "Using serial port %s\n", modem_device); + fflush(debug_file); +#endif // DEBUG } else if (!strcmp (argv[i], "-t") || !strcmp (argv[i], "--timeout")) { @@ -213,6 +241,10 @@ main (int argc, char *argv[]) } i++; +#ifdef DEBUG + fprintf(debug_file, "Using timeout value of %d s\n", timeout); + fflush(debug_file); +#endif // DEBUG } else if (!strcmp (argv[i], "-F") || !strcmp (argv[i], "--format")) { @@ -233,6 +265,11 @@ main (int argc, char *argv[]) exit(0); } i++; + +#ifdef DEBUG + fprintf(debug_file, "Using output format %d s\n", output_fmt); + fflush(debug_file); +#endif // DEBUG } else if (!strcmp (argv[i], "-l") || !strcmp (argv[i], "--limit")) { @@ -250,6 +287,11 @@ main (int argc, char *argv[]) } i++; + +#ifdef DEBUG + fprintf(debug_file, "Using line length limit of %d bytes\n", print_data_ctx.line_len_limit); + fflush(debug_file); +#endif // DEBUG } else if (!strcmp (argv[i], "-m") || !strcmp (argv[i], "--mode")) { @@ -288,6 +330,11 @@ main (int argc, char *argv[]) fprintf (stderr, "%s: invalid serial port mode %s: invalid stop bits.\n", argv[0], port_mode); exit(0); } + +#ifdef DEBUG + fprintf(debug_file, "Using serial port mode %s (%d data bits, %d stop bits, parity: %c\n", port_mode, data_bits, stop_bits, parity); + fflush(debug_file); +#endif // DEBUG } else if (!strcmp (argv[i], "--rts")) { @@ -305,6 +352,11 @@ main (int argc, char *argv[]) fprintf (stderr, "%s: invalid RTS line state '%s'\n", argv[0], argv[i]); exit(0); } + +#ifdef DEBUG + fprintf(debug_file, "Using RTS value %d\n", rts); + fflush(debug_file); +#endif // DEBUG } else if (!strcmp (argv[i], "--dtr")) { @@ -322,6 +374,11 @@ main (int argc, char *argv[]) fprintf (stderr, "%s: invalid DTR line state '%s'\n", argv[0], argv[i]); exit(0); } + +#ifdef DEBUG + fprintf(debug_file, "Using DTR value %d\n", dtr); + fflush(debug_file); +#endif // DEBUG } } @@ -350,12 +407,22 @@ main (int argc, char *argv[]) } fd = fileno (logfile); +#ifdef DEBUG + fprintf(debug_file, "Opened serial port %s, file descriptor %d\n", modem_device, fd); + fflush(debug_file); +#endif // DEBUG + /* Check are we connected to serial port and if yes, save current serial port settings */ int serial_port = (0 == tcgetattr (fd, &oldtio)); if(serial_port) { memset (&newtio, 0, sizeof (newtio)); /* clear struct for new port settings */ +#ifdef DEBUG + fprintf(debug_file, "Connected to real serial device, not file\n"); + fflush(debug_file); +#endif // DEBUG + /* Enable RTS/CTS (hardware) flow control. */ /* newtio.c_cflag |= CRTSCTS; */ @@ -488,9 +555,8 @@ main (int argc, char *argv[]) } /* Used with files, for testing. */ if (!serial_port && feof (logfile)) { break; } - - len = strlen(raw_data); } + len = strlen(raw_data); } else { @@ -520,10 +586,13 @@ main (int argc, char *argv[]) } } - if (stamp) { timestr = make_timestamp(stamp, &startup_timestamp); } - else { timestr = NULL; } + if(len) + { + if (stamp) { timestr = make_timestamp(stamp, &startup_timestamp); } + else { timestr = NULL; } - print_data(raw_data, len, &print_data_ctx, timestr, output_fmt); + print_data(raw_data, len, &print_data_ctx, timestr, output_fmt); + } } else if (retval == 0) /* Timeout. */ { @@ -545,37 +614,91 @@ main (int argc, char *argv[]) /* Function that prints line in specified output format. Timestamp is optional. Buffer should be at least 4 times the line length. */ -void print_data(char* raw_data, int raw_data_len, print_data_ctx_t* ctx, const char* time_stamp, int fmt) +void print_data(const char* raw_data, int raw_data_len, print_data_ctx_t* ctx, const char* time_stamp, int fmt) { static const char* hex_chars_lc = "0123456789abcdef"; static const char* hex_chars_uc = "0123456789ABCDEF"; int offset = 0; - if(fmt == FMT_ACSII || fmt == FMT_RAW) +#ifdef DEBUG + fprintf(debug_file, "print_data(len=%d, line_len=%d, line_len_limit=%d, new_line=%d)\n", raw_data_len, ctx->line_len, ctx->line_len_limit, ctx->new_line); + fprintf(debug_file, "data: '%s'\n", raw_data); + fflush(debug_file); +#endif // DEBUG + + if(fmt == FMT_ACSII) + { + while(raw_data_len) + { + if (time_stamp) { printf ("[%s] ", time_stamp); } + + int print_nl = 0; + int len = ctx->line_len_limit - ctx->line_len; + if(len > raw_data_len) { len = raw_data_len; } + else { print_nl = 1; } + memcpy(ctx->work_buff, raw_data + offset, len); + offset += len; + ctx->line_len += len; + raw_data_len -= len; + if(ctx->line_len >= ctx->line_len_limit) { ctx->line_len = 0; } + + if(print_nl) + { + ctx->work_buff[len] = '\n'; + ctx->work_buff[len + 1] = 0; + } + else + { + ctx->work_buff[len] = 0; + } + +#ifdef DEBUG + fprintf(debug_file, "workbuff: '%s'\n", ctx->work_buff); + fflush(debug_file); +#endif // DEBUG + + fputs (ctx->work_buff, stdout); + fflush(stdout); + } + } + if(fmt == FMT_RAW) { while(raw_data_len) { if (time_stamp) { - if(ctx->line_len != 0) { puts("\n"); } + if(ctx->line_len != 0) { fputs("\n", stdout); } printf ("[%s] ", time_stamp); ctx->line_len = 0; } + int print_nl = 0; int len = ctx->line_len_limit - ctx->line_len; if(len > raw_data_len) { len = raw_data_len; } + else { print_nl = 1; } memcpy(ctx->work_buff, raw_data + offset, len); offset += len; ctx->line_len += len; raw_data_len -= len; if(ctx->line_len >= ctx->line_len_limit) { ctx->line_len = 0; } - // if(ctx->work_buff[len - 1] == '\n') { ctx->work_buff[len - 1] = 0; } - // else { ctx->work_buff[len] = 0; } - ctx->work_buff[len] = 0; + if(print_nl) + { + ctx->work_buff[len] = '\n'; + ctx->work_buff[len + 1] = 0; + } + else + { + ctx->work_buff[len] = 0; + } + +#ifdef DEBUG + fprintf(debug_file, "workbuff: '%s'\n", ctx->work_buff); + fflush(debug_file); +#endif // DEBUG - puts(ctx->work_buff); + fputs(ctx->work_buff, stdout); fflush(stdout); } } @@ -586,30 +709,45 @@ void print_data(char* raw_data, int raw_data_len, print_data_ctx_t* ctx, const c { if (time_stamp) { - if(ctx->line_len != 0) { puts("\n"); } + if(ctx->line_len != 0) { fputs("\n", stdout); } printf ("[%s] ", time_stamp); ctx->line_len = 0; } + int print_nl = 0; int len = ctx->line_len_limit - ctx->line_len; if(len > raw_data_len) { len = raw_data_len; } + else { print_nl = 1; } int buff_len = 0; for(int i = 0; i < len; i++) { unsigned char d = raw_data[offset + i]; - if (i) { ctx->work_buff[buff_len++] = ' '; } + if (i || ctx->line_len) { ctx->work_buff[buff_len++] = ' '; } ctx->work_buff[buff_len++] = hex_chars[(d >> 4) & 0x0F]; ctx->work_buff[buff_len++] = hex_chars[d & 0x0F]; } - ctx->work_buff[buff_len] = 0; + if(print_nl) + { + ctx->work_buff[buff_len] = '\n'; + ctx->work_buff[buff_len + 1] = 0; + } + else + { + ctx->work_buff[buff_len] = 0; + } offset += len; ctx->line_len += len; raw_data_len -= len; if(ctx->line_len >= ctx->line_len_limit) { ctx->line_len = 0; } - puts(ctx->work_buff); +#ifdef DEBUG + fprintf(debug_file, "workbuff: '%s'\n", ctx->work_buff); + fflush(debug_file); +#endif // DEBUG + + fputs(ctx->work_buff, stdout); fflush(stdout); } } From afc1d90b453b63ad23907d3bbfbf657d9a88aa04 Mon Sep 17 00:00:00 2001 From: Mario Ivancic Date: Sun, 16 Nov 2025 10:50:19 +0100 Subject: [PATCH 15/15] Remove unneeded variables. --- ttylog.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ttylog.c b/ttylog.c index 58fb556..71b8314 100644 --- a/ttylog.c +++ b/ttylog.c @@ -65,7 +65,6 @@ typedef struct char* work_buff; int line_len_limit; int line_len; - int new_line; } print_data_ctx_t; @@ -115,7 +114,6 @@ main (int argc, char *argv[]) print_data_ctx.work_buff = buffer; print_data_ctx.line_len_limit = sizeof(raw_data) - 1; print_data_ctx.line_len = 0; - print_data_ctx.new_line = 1; clock_gettime(CLOCK_MONOTONIC, &startup_timestamp); @@ -622,7 +620,7 @@ void print_data(const char* raw_data, int raw_data_len, print_data_ctx_t* ctx, c int offset = 0; #ifdef DEBUG - fprintf(debug_file, "print_data(len=%d, line_len=%d, line_len_limit=%d, new_line=%d)\n", raw_data_len, ctx->line_len, ctx->line_len_limit, ctx->new_line); + fprintf(debug_file, "print_data(len=%d, line_len=%d, line_len_limit=%d)\n", raw_data_len, ctx->line_len, ctx->line_len_limit); fprintf(debug_file, "data: '%s'\n", raw_data); fflush(debug_file); #endif // DEBUG