Home | History | Annotate | Download | only in net
      1 /* microcom.c - Simple serial console.
      2  *
      3  * Copyright 2017 The Android Open Source Project.
      4 
      5 USE_MICROCOM(NEWTOY(microcom, "<1>1s:X", TOYFLAG_BIN))
      6 
      7 config MICROCOM
      8   bool "microcom"
      9   default y
     10   help
     11     usage: microcom [-s SPEED] [-X] DEVICE
     12 
     13     Simple serial console.
     14 
     15     -s  Set baud rate to SPEED
     16     -X  Ignore ^@ (send break) and ^] (exit).
     17 */
     18 
     19 #define FOR_microcom
     20 #include "toys.h"
     21 
     22 GLOBALS(
     23   char *s;
     24 
     25   int fd;
     26   struct termios original_stdin_state, original_fd_state;
     27 )
     28 
     29 // Puts `fd` into raw mode, setting the baud rate if `speed` != 0,
     30 // and saving the original terminal state.
     31 static void xraw(int fd, const char *name, speed_t speed,
     32                  struct termios *original)
     33 {
     34   struct termios t;
     35 
     36   if (tcgetattr(fd, &t)) perror_exit("tcgetattr %s", name);
     37   *original = t;
     38 
     39   cfmakeraw(&t);
     40   if (speed) cfsetspeed(&t, speed);
     41 
     42   if (tcsetattr(fd, TCSAFLUSH, &t)) perror_exit("tcsetattr %s", name);
     43 }
     44 
     45 static void restore_states(int i)
     46 {
     47   tcsetattr(0, TCSAFLUSH, &TT.original_stdin_state);
     48   tcsetattr(TT.fd, TCSAFLUSH, &TT.original_fd_state);
     49 }
     50 
     51 void microcom_main(void)
     52 {
     53   int speeds[] = {50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400,
     54                   4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800,
     55                   500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000,
     56                   2500000, 3000000, 3500000, 4000000};
     57   struct pollfd fds[2];
     58   int i, speed;
     59 
     60   if (!TT.s) speed = 115200;
     61   else speed = atoi(TT.s);
     62 
     63   // Find speed in table, adjust to constant
     64   for (i = 0; i < ARRAY_LEN(speeds); i++) if (speeds[i] == speed) break;
     65   if (i == ARRAY_LEN(speeds)) error_exit("unknown speed: %s", TT.s);
     66   speed = i+1+4081*(i>15);
     67 
     68   // Open with O_NDELAY, but switch back to blocking for reads.
     69   TT.fd = xopen(*toys.optargs, O_RDWR | O_NOCTTY | O_NDELAY);
     70   if (-1==(i = fcntl(TT.fd, F_GETFL, 0)) || fcntl(TT.fd, F_SETFL, i&~O_NDELAY))
     71     perror_exit_raw(*toys.optargs);
     72 
     73   // Set both input and output to raw mode.
     74   xraw(TT.fd, "fd", speed, &TT.original_fd_state);
     75   xraw(0, "stdin", 0, &TT.original_stdin_state);
     76   // ...and arrange to restore things, however we may exit.
     77   sigatexit(restore_states);
     78 
     79   fds[0].fd = TT.fd;
     80   fds[0].events = POLLIN;
     81   fds[1].fd = 0;
     82   fds[1].events = POLLIN;
     83 
     84   while (poll(fds, 2, -1) > 0) {
     85     char buf[BUFSIZ];
     86 
     87     // Read from connection, write to stdout.
     88     if (fds[0].revents) {
     89       ssize_t n = read(TT.fd, buf, sizeof(buf));
     90       if (n > 0) xwrite(0, buf, n);
     91       else break;
     92     }
     93 
     94     // Read from stdin, write to connection.
     95     if (fds[1].revents) {
     96       if (read(0, buf, 1) != 1) break;
     97       if (!(toys.optflags & FLAG_X)) {
     98         if (!*buf) {
     99           tcsendbreak(TT.fd, 0);
    100           continue;
    101         } else if (*buf == (']'-'@')) break;
    102       }
    103       xwrite(TT.fd, buf, 1);
    104     }
    105   }
    106 }
    107