10f66f451Sopenharmony_ci/* microcom.c - Simple serial console.
20f66f451Sopenharmony_ci *
30f66f451Sopenharmony_ci * Copyright 2017 The Android Open Source Project.
40f66f451Sopenharmony_ci
50f66f451Sopenharmony_ciUSE_MICROCOM(NEWTOY(microcom, "<1>1s:X", TOYFLAG_USR|TOYFLAG_BIN))
60f66f451Sopenharmony_ci
70f66f451Sopenharmony_ciconfig MICROCOM
80f66f451Sopenharmony_ci  bool "microcom"
90f66f451Sopenharmony_ci  default y
100f66f451Sopenharmony_ci  help
110f66f451Sopenharmony_ci    usage: microcom [-s SPEED] [-X] DEVICE
120f66f451Sopenharmony_ci
130f66f451Sopenharmony_ci    Simple serial console.
140f66f451Sopenharmony_ci
150f66f451Sopenharmony_ci    -s	Set baud rate to SPEED
160f66f451Sopenharmony_ci    -X	Ignore ^@ (send break) and ^] (exit)
170f66f451Sopenharmony_ci*/
180f66f451Sopenharmony_ci
190f66f451Sopenharmony_ci#define FOR_microcom
200f66f451Sopenharmony_ci#include "toys.h"
210f66f451Sopenharmony_ci
220f66f451Sopenharmony_ciGLOBALS(
230f66f451Sopenharmony_ci  char *s;
240f66f451Sopenharmony_ci
250f66f451Sopenharmony_ci  int fd;
260f66f451Sopenharmony_ci  struct termios original_stdin_state, original_fd_state;
270f66f451Sopenharmony_ci)
280f66f451Sopenharmony_ci
290f66f451Sopenharmony_ci// TODO: tty_sigreset outputs ansi escape sequences, how to disable?
300f66f451Sopenharmony_cistatic void restore_states(int i)
310f66f451Sopenharmony_ci{
320f66f451Sopenharmony_ci  tcsetattr(0, TCSAFLUSH, &TT.original_stdin_state);
330f66f451Sopenharmony_ci  tcsetattr(TT.fd, TCSAFLUSH, &TT.original_fd_state);
340f66f451Sopenharmony_ci}
350f66f451Sopenharmony_ci
360f66f451Sopenharmony_civoid microcom_main(void)
370f66f451Sopenharmony_ci{
380f66f451Sopenharmony_ci  struct pollfd fds[2];
390f66f451Sopenharmony_ci  int i, speed;
400f66f451Sopenharmony_ci
410f66f451Sopenharmony_ci  if (!TT.s) speed = 115200;
420f66f451Sopenharmony_ci  else speed = atoi(TT.s);
430f66f451Sopenharmony_ci
440f66f451Sopenharmony_ci  // Open with O_NDELAY, but switch back to blocking for reads.
450f66f451Sopenharmony_ci  TT.fd = xopen(*toys.optargs, O_RDWR | O_NOCTTY | O_NDELAY);
460f66f451Sopenharmony_ci  if (-1==(i = fcntl(TT.fd, F_GETFL, 0)) || fcntl(TT.fd, F_SETFL, i&~O_NDELAY))
470f66f451Sopenharmony_ci    perror_exit_raw(*toys.optargs);
480f66f451Sopenharmony_ci
490f66f451Sopenharmony_ci  // Set both input and output to raw mode.
500f66f451Sopenharmony_ci  xset_terminal(TT.fd, 1, speed, &TT.original_fd_state);
510f66f451Sopenharmony_ci  set_terminal(0, 1, 0, &TT.original_stdin_state);
520f66f451Sopenharmony_ci  // ...and arrange to restore things, however we may exit.
530f66f451Sopenharmony_ci  sigatexit(restore_states);
540f66f451Sopenharmony_ci
550f66f451Sopenharmony_ci  fds[0].fd = TT.fd;
560f66f451Sopenharmony_ci  fds[0].events = POLLIN;
570f66f451Sopenharmony_ci  fds[1].fd = 0;
580f66f451Sopenharmony_ci  fds[1].events = POLLIN;
590f66f451Sopenharmony_ci
600f66f451Sopenharmony_ci  while (poll(fds, 2, -1) > 0) {
610f66f451Sopenharmony_ci    char buf[BUFSIZ];
620f66f451Sopenharmony_ci
630f66f451Sopenharmony_ci    // Read from connection, write to stdout.
640f66f451Sopenharmony_ci    if (fds[0].revents) {
650f66f451Sopenharmony_ci      ssize_t n = read(TT.fd, buf, sizeof(buf));
660f66f451Sopenharmony_ci      if (n > 0) xwrite(0, buf, n);
670f66f451Sopenharmony_ci      else break;
680f66f451Sopenharmony_ci    }
690f66f451Sopenharmony_ci
700f66f451Sopenharmony_ci    // Read from stdin, write to connection.
710f66f451Sopenharmony_ci    if (fds[1].revents) {
720f66f451Sopenharmony_ci      if (read(0, buf, 1) != 1) break;
730f66f451Sopenharmony_ci      if (!(toys.optflags & FLAG_X)) {
740f66f451Sopenharmony_ci        if (!*buf) {
750f66f451Sopenharmony_ci          tcsendbreak(TT.fd, 0);
760f66f451Sopenharmony_ci          continue;
770f66f451Sopenharmony_ci        } else if (*buf == (']'-'@')) break;
780f66f451Sopenharmony_ci      }
790f66f451Sopenharmony_ci      xwrite(TT.fd, buf, 1);
800f66f451Sopenharmony_ci    }
810f66f451Sopenharmony_ci  }
820f66f451Sopenharmony_ci}
83