]> git.sur5r.net Git - tio/blobdiff - src/tty.c
New upstream version 1.34
[tio] / src / tty.c
index 8de680b2b160651a831f9d6dd291a0fcbf379552..64098b476b43e5561cb73c3c453a6810ce8f2600 100644 (file)
--- a/src/tty.c
+++ b/src/tty.c
@@ -1,7 +1,7 @@
 /*
- * tio - a simple TTY terminal I/O application
+ * tio - a simple TTY terminal I/O tool
  *
- * Copyright (c) 2014-2017  Martin Lund
+ * Copyright (c) 2014-2022  Martin Lund
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
 #include <sys/stat.h>
 #include <sys/param.h>
 #include <sys/file.h>
+#include <sys/ioctl.h>
 #include <fcntl.h>
 #include <termios.h>
 #include <stdbool.h>
 #include <errno.h>
 #include <time.h>
+#include <dirent.h>
 #include "config.h"
-#include "tio/tty.h"
-#include "tio/print.h"
-#include "tio/options.h"
-#include "tio/time.h"
-#include "tio/log.h"
-#include "tio/error.h"
+#include "tty.h"
+#include "print.h"
+#include "options.h"
+#include "misc.h"
+#include "log.h"
+#include "error.h"
 
 #ifdef HAVE_TERMIOS2
 extern int setspeed2(int fd, int baudrate);
 #endif
 
+#ifdef __APPLE__
+#define PATH_SERIAL_DEVICES "/dev/"
+#else
+#define PATH_SERIAL_DEVICES "/dev/serial/by-id/"
+#endif
+
 static struct termios tio, tio_old, stdout_new, stdout_old, stdin_new, stdin_old;
 static unsigned long rx_total = 0, tx_total = 0;
 static bool connected = false;
-static bool tainted = false;
 static bool print_mode = NORMAL;
 static bool standard_baudrate = true;
 static void (*print)(char c);
@@ -60,27 +67,37 @@ static bool map_o_cr_nl = false;
 static bool map_o_nl_crnl = false;
 static bool map_o_del_bs = false;
 
-#define tio_printf(format, args...) \
-{ \
-    if (tainted) putchar('\n'); \
-    color_printf("[tio %s] " format, current_time(), ## args); \
-    tainted = false; \
-}
 
-static void print_hex(char c)
+static void toggle_line(const char *line_name, int mask)
 {
-    printf("%02x ", (unsigned char) c);
-}
+    int state;
 
-static void print_normal(char c)
-{
-    putchar(c);
+    if (ioctl(fd, TIOCMGET, &state) < 0)
+    {
+        error_printf("Could not get line state: %s", strerror(errno));
+    }
+    else
+    {
+        if (state & mask)
+        {
+            state &= ~mask;
+            tio_printf("set %s to LOW", line_name);
+        }
+        else
+        {
+            state |= mask;
+            tio_printf("set %s to HIGH", line_name);
+        }
+        if (ioctl(fd, TIOCMSET, &state) < 0)
+            error_printf("Could not set line state: %s", strerror(errno));
+    }
 }
 
 void handle_command_sequence(char input_char, char previous_char, char *output_char, bool *forward)
 {
     char unused_char;
     bool unused_bool;
+    int state;
 
     /* Ignore unused arguments */
     if (output_char == NULL)
@@ -102,13 +119,39 @@ void handle_command_sequence(char input_char, char previous_char, char *output_c
                 tio_printf(" ctrl-t ?   List available key commands");
                 tio_printf(" ctrl-t b   Send break");
                 tio_printf(" ctrl-t c   Show configuration");
+                tio_printf(" ctrl-t d   Toggle DTR line");
                 tio_printf(" ctrl-t e   Toggle local echo mode");
                 tio_printf(" ctrl-t h   Toggle hexadecimal mode");
                 tio_printf(" ctrl-t l   Clear screen");
+                tio_printf(" ctrl-t L   Show lines state");
                 tio_printf(" ctrl-t q   Quit");
+                tio_printf(" ctrl-t r   Toggle RTS line");
                 tio_printf(" ctrl-t s   Show statistics");
                 tio_printf(" ctrl-t t   Send ctrl-t key code");
-                tio_printf(" ctrl-t T   Toggle timestamps");
+                tio_printf(" ctrl-t T   Toggle line timestamp mode");
+                tio_printf(" ctrl-t v   Show version");
+                break;
+
+            case KEY_SHIFT_L:
+                if (ioctl(fd, TIOCMGET, &state) < 0)
+                {
+                    error_printf("Could not get line state: %s", strerror(errno));
+                    break;
+                }
+                tio_printf("Lines state:");
+                tio_printf(" DTR: %s", (state & TIOCM_DTR) ? "HIGH" : "LOW");
+                tio_printf(" RTS: %s", (state & TIOCM_RTS) ? "HIGH" : "LOW");
+                tio_printf(" CTS: %s", (state & TIOCM_CTS) ? "HIGH" : "LOW");
+                tio_printf(" DSR: %s", (state & TIOCM_DSR) ? "HIGH" : "LOW");
+                tio_printf(" DCD: %s", (state & TIOCM_CD) ? "HIGH" : "LOW");
+                tio_printf(" RI : %s", (state & TIOCM_RI) ? "HIGH" : "LOW");
+                break;
+            case KEY_D:
+                toggle_line("DTR", TIOCM_DTR);
+                break;
+
+            case KEY_R:
+                toggle_line("RTS", TIOCM_RTS);
                 break;
 
             case KEY_B:
@@ -123,9 +166,10 @@ void handle_command_sequence(char input_char, char previous_char, char *output_c
                 tio_printf(" Flow: %s", option.flow);
                 tio_printf(" Stopbits: %d", option.stopbits);
                 tio_printf(" Parity: %s", option.parity);
-                tio_printf(" Local Echo: %s", option.local_echo ? "yes":"no");
-                tio_printf(" Timestamps: %s", option.timestamp ? "yes" : "no");
+                tio_printf(" Local echo: %s", option.local_echo ? "enabled" : "disabled");
+                tio_printf(" Timestamps: %s", option.timestamp ? "enabled" : "disabled");
                 tio_printf(" Output delay: %d", option.output_delay);
+                tio_printf(" Auto connect: %s", option.no_autoconnect ? "disabled" : "enabled");
                 if (option.map[0] != 0)
                     tio_printf(" Map flags: %s", option.map);
                 if (option.log)
@@ -165,7 +209,8 @@ void handle_command_sequence(char input_char, char previous_char, char *output_c
             case KEY_S:
                 /* Show tx/rx statistics upon ctrl-t s sequence */
                 tio_printf("Statistics:");
-                tio_printf(" Sent %lu bytes, received %lu bytes", tx_total, rx_total);
+                tio_printf(" Sent %lu bytes", tx_total);
+                tio_printf(" Received %lu bytes", rx_total);
                 break;
 
             case KEY_T:
@@ -178,6 +223,10 @@ void handle_command_sequence(char input_char, char previous_char, char *output_c
                 option.timestamp = !option.timestamp;
                 break;
 
+            case KEY_V:
+                tio_printf("tio v%s", VERSION);
+                break;
+
             default:
                 /* Ignore unknown ctrl-t escaped keys */
                 break;
@@ -229,6 +278,10 @@ void stdout_configure(void)
 {
     int status;
 
+    /* Disable line buffering in stdout. This is necessary if we
+     * want things like local echo to work correctly. */
+    setbuf(stdout, NULL);
+
     /* Save current stdout settings */
     if (tcgetattr(STDOUT_FILENO, &stdout_old) < 0)
     {
@@ -255,10 +308,6 @@ void stdout_configure(void)
         exit(EXIT_FAILURE);
     }
 
-    /* Print launch hints */
-    tio_printf("tio v%s", VERSION);
-    tio_printf("Press ctrl-t q to quit");
-
     /* At start use normal print function */
     print = print_normal;
 
@@ -293,9 +342,9 @@ void tty_configure(void)
          * Only switch cases for baud rates detected supported by the host
          * system are inserted.
          *
-         * To see which baud rates are being probed see configure.ac
+         * To see which baud rates are being probed see meson.build
          */
-        AUTOCONF_BAUDRATE_CASES
+        BAUDRATE_CASES
 
         default:
 #ifdef HAVE_TERMIOS2
@@ -318,7 +367,7 @@ void tty_configure(void)
         }
 
         // Set output speed
-        cfsetospeed(&tio, baudrate);
+        status = cfsetospeed(&tio, baudrate);
         if (status == -1)
         {
             error_printf("Could not configure output speed (%s)", strerror(errno));
@@ -455,6 +504,7 @@ void tty_wait_for_device(void)
     struct timeval tv;
     static char input_char, previous_char = 0;
     static bool first = true;
+    static int last_errno = 0;
 
     /* Loop until device pops up */
     while (true)
@@ -501,8 +551,17 @@ void tty_wait_for_device(void)
         }
 
         /* Test for accessible device file */
-        if (access(option.tty_device, R_OK) == 0)
+        status = access(option.tty_device, R_OK);
+        if (status == 0) {
+            last_errno = 0;
             return;
+        }
+        else if (last_errno != errno)
+        {
+            warning_printf("Could not open tty device (%s)", strerror(errno));
+            tio_printf("Waiting for tty device..");
+            last_errno = errno;
+        }
     }
 }
 
@@ -530,6 +589,7 @@ static void optional_local_echo(char c)
     if (!option.local_echo)
         return;
     print(c);
+    fflush(stdout);
     if (option.log)
         log_write(c);
 }
@@ -542,7 +602,8 @@ int tty_connect(void)
     static char previous_char = 0;
     static bool first = true;
     int    status;
-    time_t next_timestamp = 0;
+    bool next_timestamp = false;
+    char*  now = NULL;
 
     /* Open tty device */
 #ifdef __APPLE__
@@ -577,10 +638,10 @@ int tty_connect(void)
     /* Print connect status */
     tio_printf("Connected");
     connected = true;
-    tainted = false;
+    print_tainted = false;
 
     if (option.timestamp)
-        next_timestamp = time(NULL);
+        next_timestamp = true;
 
     /* Save current port settings */
     if (tcgetattr(fd, &tio_old) < 0)
@@ -636,8 +697,23 @@ int tty_connect(void)
                     /* Print timestamp on new line, if desired. */
                     if (next_timestamp && input_char != '\n' && input_char != '\r')
                     {
-                        fprintf(stdout, ANSI_COLOR_GRAY "[%s] " ANSI_COLOR_RESET, current_time());
-                        next_timestamp = 0;
+                        now = current_time();
+                        if (now)
+                        {
+                            ansi_printf_raw("[%s] ", now);
+                            if (option.log)
+                            {
+                                log_write('[');
+                                while (*now != '\0')
+                                {
+                                    log_write(*now);
+                                    ++now;
+                                }
+                                log_write(']');
+                                log_write(' ');
+                            }
+                            next_timestamp = false;
+                        }
                     }
 
                     /* Map input character */
@@ -646,7 +722,7 @@ int tty_connect(void)
                         print('\r');
                         print('\n');
                         if (option.timestamp)
-                            next_timestamp = time(NULL);
+                            next_timestamp = true;
                     } else
                     {
                         /* Print received tty character to stdout */
@@ -658,10 +734,10 @@ int tty_connect(void)
                     if (option.log)
                         log_write(input_char);
 
-                    tainted = true;
+                    print_tainted = true;
 
                     if (input_char == '\n' && option.timestamp)
-                        next_timestamp = time(NULL);
+                        next_timestamp = true;
                 } else
                 {
                     /* Error reading - device is likely unplugged */
@@ -698,30 +774,32 @@ int tty_connect(void)
                         output_char = '\n';
 
                     /* Map newline character */
-                    if ((output_char == '\n') && (map_o_nl_crnl)) {
-                        char r = '\r';
+                    if ((output_char == '\n' || output_char == '\r') && (map_o_nl_crnl)) {
+                        const char *crlf = "\r\n";
 
-                        optional_local_echo(r);
-                        status = write(fd, &r, 1);
+                        optional_local_echo(crlf[0]);
+                        optional_local_echo(crlf[1]);
+                        status = write(fd, crlf, 2);
                         if (status < 0)
                             warning_printf("Could not write to tty device");
 
-                        tx_total++;
+                        tx_total += 2;
                         delay(option.output_delay);
-                    }
-
-                    /* Send output to tty device */
-                    optional_local_echo(output_char);
-                    status = write(fd, &output_char, 1);
-                    if (status < 0)
-                        warning_printf("Could not write to tty device");
-                    fsync(fd);
+                    } else
+                    {
+                        /* Send output to tty device */
+                        optional_local_echo(output_char);
+                        status = write(fd, &output_char, 1);
+                        if (status < 0)
+                            warning_printf("Could not write to tty device");
+                        fsync(fd);
 
-                    /* Update transmit statistics */
-                    tx_total++;
+                        /* Update transmit statistics */
+                        tx_total++;
 
-                    /* Insert output delay */
-                    delay(option.output_delay);
+                        /* Insert output delay */
+                        delay(option.output_delay);
+                    }
                 }
 
                 /* Save previous key */
@@ -747,3 +825,24 @@ error_read:
 error_open:
     return TIO_ERROR;
 }
+
+void list_serial_devices(void)
+{
+    DIR *d = opendir(PATH_SERIAL_DEVICES);
+    if (d)
+    {
+        struct dirent *dir;
+        while ((dir = readdir(d)) != NULL)
+        {
+            if ((strcmp(dir->d_name, ".")) && (strcmp(dir->d_name, "..")))
+            {
+#ifdef __APPLE__
+#define TTY_DEVICES_PREFIX "tty."
+                if (!strncmp(dir->d_name, TTY_DEVICES_PREFIX, sizeof(TTY_DEVICES_PREFIX) - 1))
+#endif
+                printf("%s%s\n", PATH_SERIAL_DEVICES, dir->d_name);
+            }
+        }
+        closedir(d);
+    }
+}