Skip to content

Commit

Permalink
Fix microcom to set serial device's terminal correctly.
Browse files Browse the repository at this point in the history
Can't use the same set_terminal() logic as ptys because it not displaying
data, it should just accurately copy it.
  • Loading branch information
landley committed Nov 18, 2020
1 parent 0ea0498 commit c251e32
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 7 deletions.
1 change: 1 addition & 0 deletions lib/lib.h
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,7 @@ int terminal_probesize(unsigned *xx, unsigned *yy);
#define KEY_ALT (1<<18)
int scan_key(char *scratch, int timeout_ms);
int scan_key_getsize(char *scratch, int timeout_ms, unsigned *xx, unsigned *yy);
void xsetspeed(struct termios *tio, int speed);
int set_terminal(int fd, int raw, int speed, struct termios *old);
void xset_terminal(int fd, int raw, int speed, struct termios *old);
void tty_esc(char *s);
Expand Down
14 changes: 14 additions & 0 deletions lib/tty.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,20 @@ int terminal_probesize(unsigned *xx, unsigned *yy)
return 0;
}

void xsetspeed(struct termios *tio, int speed)
{
int i, speeds[] = {50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400,
4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800,
500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000,
2500000, 3000000, 3500000, 4000000};

// Find speed in table, adjust to constant
for (i = 0; i < ARRAY_LEN(speeds); i++) if (speeds[i] == speed) break;
if (i == ARRAY_LEN(speeds)) error_exit("unknown speed: %d", speed);
cfsetspeed(tio, i+1+4081*(i>15));
}


// Reset terminal to known state, saving copy of old state if old != NULL.
int set_terminal(int fd, int raw, int speed, struct termios *old)
{
Expand Down
19 changes: 12 additions & 7 deletions toys/net/microcom.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,30 +22,35 @@ config MICROCOM
GLOBALS(
long s;

int fd;
struct termios original_stdin_state, original_fd_state;
int fd, stok;
struct termios old_stdin, old_fd;
)

// TODO: tty_sigreset outputs ansi escape sequences, how to disable?
static void restore_states(int i)
{
tcsetattr(0, TCSAFLUSH, &TT.original_stdin_state);
tcsetattr(TT.fd, TCSAFLUSH, &TT.original_fd_state);
if (TT.stok) tcsetattr(0, TCSAFLUSH, &TT.old_stdin);
tcsetattr(TT.fd, TCSAFLUSH, &TT.old_fd);
}

void microcom_main(void)
{
struct termios tio;
struct pollfd fds[2];
int i;

// Open with O_NDELAY, but switch back to blocking for reads.
TT.fd = xopen(*toys.optargs, O_RDWR | O_NOCTTY | O_NDELAY);
if (-1==(i = fcntl(TT.fd, F_GETFL, 0)) || fcntl(TT.fd, F_SETFL, i&~O_NDELAY))
if (-1==(i = fcntl(TT.fd, F_GETFL, 0)) || fcntl(TT.fd, F_SETFL, i&~O_NDELAY)
|| tcgetattr(TT.fd, &TT.old_fd))
perror_exit_raw(*toys.optargs);

// Set both input and output to raw mode.
xset_terminal(TT.fd, 1, TT.s, &TT.original_fd_state);
set_terminal(0, 1, 0, &TT.original_stdin_state);
memcpy(&tio, &TT.old_fd, sizeof(struct termios));
cfmakeraw(&tio);
xsetspeed(&tio, TT.s);
if (tcsetattr(TT.fd, TCSAFLUSH, &tio)) perror_exit("set speed");
if (!set_terminal(0, 1, 0, &TT.old_stdin)) TT.stok++;
// ...and arrange to restore things, however we may exit.
sigatexit(restore_states);

Expand Down

0 comments on commit c251e32

Please sign in to comment.