diff options
author | Elliott Hughes <enh@google.com> | 2017-01-14 13:12:13 -0800 |
---|---|---|
committer | Rob Landley <rob@landley.net> | 2017-01-14 16:53:10 -0600 |
commit | 12fcf08b5c96238530148d7d9975642b2299e39a (patch) | |
tree | 10d2bfd0dbca618a5820810aefc341b5929fd02f | |
parent | ae7ea62eea205d2816e09070b034a588dbaaaa6a (diff) | |
download | toybox-12fcf08b5c96238530148d7d9975642b2299e39a.tar.gz |
Add "microcom" to pending.
Our device bringup folks wanted a simple serial console, both on the
host and on the device. This is certainly enough to replace what I've
been using personally on the host.
I'd never heard of "microcom" until I asked the internets what busybox
users use, so I don't care what we call this or what the options are
called. (But would like to decide before it gets ossified in a million
factory test scripts and the like!)
The tool that this replaces for me defaulted to /dev/ttyUSB0, but since
I don't know whether that default would be useful for most other people
too, I left that out. Command-line history will solve my transition
problem.
-rw-r--r-- | toys/pending/microcom.c | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/toys/pending/microcom.c b/toys/pending/microcom.c new file mode 100644 index 00000000..d41a9a21 --- /dev/null +++ b/toys/pending/microcom.c @@ -0,0 +1,104 @@ +/* microcom.c - Simple serial console. + * + * Copyright 2017 The Android Open Source Project. + +USE_MICROCOM(NEWTOY(microcom, "<1>1s:X", TOYFLAG_BIN)) + +config MICROCOM + bool "microcom" + default n + help + usage: microcom [-s SPEED] [-X] + + Simple serial console. + + -s Set baud rate to SPEED + -X Ignore ^@ (send break) and ^X (exit). +*/ + +#define FOR_microcom +#include "toys.h" + +GLOBALS( + char *speed; + + int fd; + struct termios original_stdin_state, original_fd_state; +) + +// Puts `fd` into raw mode, setting the baud rate if `speed` != 0, +// and saving the original terminal state. +static void xraw(int fd, const char *name, speed_t speed, + struct termios *original) +{ + struct termios t; + + if (tcgetattr(fd, &t)) perror_exit("tcgetattr %s", name); + *original = t; + + cfmakeraw(&t); + if (speed && cfsetspeed(&t, speed)) perror_exit("cfsetspeed"); + + if (tcsetattr(fd, TCSAFLUSH, &t)) perror_exit("tcsetattr %s", name); +} + +static void restore_states(int i) +{ + tcsetattr(0, TCSAFLUSH, &TT.original_stdin_state); + tcsetattr(TT.fd, TCSAFLUSH, &TT.original_fd_state); +} + +void microcom_main(void) +{ + speed_t speed = B115200; + struct pollfd fds[2]; + int flags; + + // TODO: move this into lib and support all known baud rates? + if (TT.speed) { + switch (atolx(TT.speed)) { + case 9600: speed = B9600; break; + case 19200: speed = B19200; break; + case 38400: speed = B38400; break; + case 115200: speed = B115200; break; + default: error_exit("unknown speed: %s", TT.speed); + } + } + + // Open with O_NDELAY, but switch back to blocking for reads. + TT.fd = xopen(*toys.optargs, O_RDWR | O_NOCTTY | O_NDELAY); + flags = fcntl(TT.fd, F_GETFL, 0); + if (flags == -1) perror_exit("fcntl F_GETFL"); + if (fcntl(TT.fd, F_SETFL, flags & ~O_NDELAY)) perror_exit("fcntl F_SETFL"); + + // Set both input and output to raw mode. + xraw(TT.fd, "fd", speed, &TT.original_fd_state); + xraw(0, "stdin", 0, &TT.original_stdin_state); + // ...and arrange to restore things, however we may exit. + sigatexit(restore_states); + + fds[0].fd = TT.fd; + fds[0].events = POLLIN; + fds[1].fd = 0; + fds[1].events = POLLIN; + + while (poll(fds, 2, -1) > 0) { + char buf[BUFSIZ]; + + // Read from connection, write to stdout. + if (fds[0].revents) { + ssize_t n = read(TT.fd, buf, sizeof(buf)); + if (n > 0) xwrite(0, buf, n); + else break; + } + + // Read from stdin, write to connection. + if (fds[1].revents) { + if (read(0, buf, 1) == 1) { + if (buf[0] == 0) tcsendbreak(TT.fd, 0); + else if (buf[0] == ('X'-'@')) break; + else xwrite(TT.fd, buf, 1); + } else break; + } + } +} |