void loop(void) { enum { ST_COMMAND, ST_TRANSPARENT } state; int dtr_up; fd_set rdset, wrset; int newbaud, newflow, newparity, newbits; char *newflow_str, *newparity_str; char fname[128]; int r, n; unsigned char c; tty_q.len = 0; state = ST_TRANSPARENT; dtr_up = 0; for (;;) { FD_ZERO(&rdset); FD_ZERO(&wrset); FD_SET(STI, &rdset); FD_SET(tty_fd, &rdset); if ( tty_q.len ) FD_SET(tty_fd, &wrset); if (select(FD_SETSIZE, &rdset, &wrset, NULL, NULL) < 0) fatal("select failed: %d : %s", errno, strerror(errno)); if ( FD_ISSET(STI, &rdset) ) { /* read from terminal */ do { n = read(STI, &c, 1); } while (n < 0 && errno == EINTR); if (n == 0) fatal("stdin closed"); else if (n < 0) fatal("read from stdin failed: %s", strerror(errno)); switch (state) { case ST_COMMAND: if ( c == opts.escape ) { state = ST_TRANSPARENT; /* pass the escape character down */ if (tty_q.len <= TTY_Q_SZ) tty_q.buff[tty_q.len++] = c; else fd_printf(STO, "\x07"); break; } state = ST_TRANSPARENT; switch (c) { case KEY_EXIT: return; case KEY_QUIT: term_set_hupcl(tty_fd, 0); term_flush(tty_fd); term_apply(tty_fd); term_erase(tty_fd); return; case KEY_STATUS: fd_printf(STO, "\r\n"); fd_printf(STO, "*** baud: %d\r\n", opts.baud); fd_printf(STO, "*** flow: %s\r\n", opts.flow_str); fd_printf(STO, "*** parity: %s\r\n", opts.parity_str); fd_printf(STO, "*** databits: %d\r\n", opts.databits); fd_printf(STO, "*** dtr: %s\r\n", dtr_up ? "up" : "down"); break; case KEY_PULSE: fd_printf(STO, "\r\n*** pulse DTR ***\r\n"); if ( term_pulse_dtr(tty_fd) < 0 ) fd_printf(STO, "*** FAILED\r\n"); break; case KEY_TOGGLE: if ( dtr_up ) r = term_lower_dtr(tty_fd); else r = term_raise_dtr(tty_fd); if ( r >= 0 ) dtr_up = ! dtr_up; fd_printf(STO, "\r\n*** DTR: %s ***\r\n", dtr_up ? "up" : "down"); break; case KEY_BAUD_UP: newbaud = baud_up(opts.baud); term_set_baudrate(tty_fd, newbaud); tty_q.len = 0; term_flush(tty_fd); if ( term_apply(tty_fd) >= 0 ) opts.baud = newbaud; fd_printf(STO, "\r\n*** baud: %d ***\r\n", opts.baud); break; case KEY_BAUD_DN: newbaud = baud_down(opts.baud); term_set_baudrate(tty_fd, newbaud); tty_q.len = 0; term_flush(tty_fd); if ( term_apply(tty_fd) >= 0 ) opts.baud = newbaud; fd_printf(STO, "\r\n*** baud: %d ***\r\n", opts.baud); break; case KEY_FLOW: newflow = flow_next(opts.flow, &newflow_str); term_set_flowcntrl(tty_fd, newflow); tty_q.len = 0; term_flush(tty_fd); if ( term_apply(tty_fd) >= 0 ) { opts.flow = newflow; opts.flow_str = newflow_str; } fd_printf(STO, "\r\n*** flow: %s ***\r\n", opts.flow_str); break; case KEY_PARITY: newparity = parity_next(opts.parity, &newparity_str); term_set_parity(tty_fd, newparity); tty_q.len = 0; term_flush(tty_fd); if ( term_apply(tty_fd) >= 0 ) { opts.parity = newparity; opts.parity_str = newparity_str; } fd_printf(STO, "\r\n*** parity: %s ***\r\n", opts.parity_str); break; case KEY_BITS: newbits = bits_next(opts.databits); term_set_databits(tty_fd, newbits); tty_q.len = 0; term_flush(tty_fd); if ( term_apply(tty_fd) >= 0 ) opts.databits = newbits; fd_printf(STO, "\r\n*** databits: %d ***\r\n", opts.databits); break; case KEY_SEND: fd_printf(STO, "\r\n*** file: "); r = fd_readline(STI, STO, fname, sizeof(fname)); fd_printf(STO, "\r\n"); if ( r < -1 && errno == EINTR ) break; if ( r <= -1 ) fatal("cannot read filename: %s", strerror(errno)); run_cmd(tty_fd, opts.send_cmd, fname, NULL); break; case KEY_RECEIVE: fd_printf(STO, "*** file: "); r = fd_readline(STI, STO, fname, sizeof(fname)); fd_printf(STO, "\r\n"); if ( r < -1 && errno == EINTR ) break; if ( r <= -1 ) fatal("cannot read filename: %s", strerror(errno)); if ( fname[0] ) run_cmd(tty_fd, opts.send_cmd, fname, NULL); else run_cmd(tty_fd, opts.receive_cmd, NULL); break; case KEY_BREAK: term_break(tty_fd); fd_printf(STO, "\r\n*** break sent ***\r\n"); break; default: break; } break; case ST_TRANSPARENT: if ( c == opts.escape ) { state = ST_COMMAND; } else { if (tty_q.len <= TTY_Q_SZ) tty_q.buff[tty_q.len++] = c; else fd_printf(STO, "\x07"); } break; default: assert(0); break; } } if ( FD_ISSET(tty_fd, &rdset) ) { /* read from port */ do { n = read(tty_fd, &c, 1); } while (n < 0 && errno == EINTR); if (n == 0) fatal("term closed"); else if ( n < 0 ) fatal("read from term failed: %s", strerror(errno)); do { n = write(STO, &c, 1); } while ( errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR ); if ( n <= 0 ) fatal("write to stdout failed: %s", strerror(errno)); } if ( FD_ISSET(tty_fd, &wrset) ) { /* write to port */ do { n = write(tty_fd, tty_q.buff, tty_q.len); } while ( n < 0 && errno == EINTR ); if ( n <= 0 ) fatal("write to term failed: %s", strerror(errno)); memcpy(tty_q.buff, tty_q.buff + n, tty_q.len - n); tty_q.len -= n; } } }
/* Process command key. Returns non-zero if command results in picocom exit, zero otherwise. */ int do_command (unsigned char c) { static int dtr_up = 0; int newbaud, newflow, newparity, newbits, newstopbits; const char *xfr_cmd; char *fname; int r; switch (c) { case KEY_EXIT: return 1; case KEY_QUIT: term_set_hupcl(tty_fd, 0); term_flush(tty_fd); term_apply(tty_fd, 1); term_erase(tty_fd); return 1; case KEY_STATUS: show_status(dtr_up); break; case KEY_HELP: case KEY_KEYS: show_keys(); break; case KEY_PULSE: fd_printf(STO, "\r\n*** pulse DTR ***\r\n"); if ( term_pulse_dtr(tty_fd) < 0 ) fd_printf(STO, "*** FAILED\r\n"); break; case KEY_TOGGLE: if ( dtr_up ) r = term_lower_dtr(tty_fd); else r = term_raise_dtr(tty_fd); if ( r >= 0 ) dtr_up = ! dtr_up; fd_printf(STO, "\r\n*** DTR: %s ***\r\n", dtr_up ? "up" : "down"); break; case KEY_BAUD: case KEY_BAUD_UP: case KEY_BAUD_DN: if ( c== KEY_BAUD) { newbaud = read_baud(); if ( newbaud < 0 ) { fd_printf(STO, "*** cannot read baudrate ***\r\n"); break; } opts.baud = newbaud; } else if (c == KEY_BAUD_UP) { opts.baud = baud_up(opts.baud); } else { opts.baud = baud_down(opts.baud); } term_set_baudrate(tty_fd, opts.baud); tty_q.len = 0; term_flush(tty_fd); term_apply(tty_fd, 1); newbaud = term_get_baudrate(tty_fd, NULL); if ( opts.baud != newbaud ) { fd_printf(STO, "\r\n*** baud: %d (%d) ***\r\n", opts.baud, newbaud); } else { fd_printf(STO, "\r\n*** baud: %d ***\r\n", opts.baud); } set_tty_write_sz(newbaud); break; case KEY_FLOW: opts.flow = flow_next(opts.flow); term_set_flowcntrl(tty_fd, opts.flow); tty_q.len = 0; term_flush(tty_fd); term_apply(tty_fd, 1); newflow = term_get_flowcntrl(tty_fd); if ( opts.flow != newflow ) { fd_printf(STO, "\r\n*** flow: %s (%s) ***\r\n", flow_str[opts.flow], flow_str[newflow]); } else { fd_printf(STO, "\r\n*** flow: %s ***\r\n", flow_str[opts.flow]); } break; case KEY_PARITY: opts.parity = parity_next(opts.parity); term_set_parity(tty_fd, opts.parity); tty_q.len = 0; term_flush(tty_fd); term_apply(tty_fd, 1); newparity = term_get_parity(tty_fd); if (opts.parity != newparity ) { fd_printf(STO, "\r\n*** parity: %s (%s) ***\r\n", parity_str[opts.parity], parity_str[newparity]); } else { fd_printf(STO, "\r\n*** parity: %s ***\r\n", parity_str[opts.parity]); } break; case KEY_BITS: opts.databits = bits_next(opts.databits); term_set_databits(tty_fd, opts.databits); tty_q.len = 0; term_flush(tty_fd); term_apply(tty_fd, 1); newbits = term_get_databits(tty_fd); if (opts.databits != newbits ) { fd_printf(STO, "\r\n*** databits: %d (%d) ***\r\n", opts.databits, newbits); } else { fd_printf(STO, "\r\n*** databits: %d ***\r\n", opts.databits); } break; case KEY_STOP: opts.stopbits = stopbits_next(opts.stopbits); term_set_stopbits(tty_fd, opts.stopbits); tty_q.len = 0; term_flush(tty_fd); term_apply(tty_fd, 1); newstopbits = term_get_stopbits(tty_fd); if (opts.stopbits != newstopbits ) { fd_printf(STO, "\r\n*** stopbits: %d (%d) ***\r\n", opts.stopbits, newstopbits); } else { fd_printf(STO, "\r\n*** stopbits: %d ***\r\n", opts.stopbits); } break; case KEY_LECHO: opts.lecho = ! opts.lecho; fd_printf(STO, "\r\n*** local echo: %s ***\r\n", opts.lecho ? "yes" : "no"); break; case KEY_SEND: case KEY_RECEIVE: xfr_cmd = (c == KEY_SEND) ? opts.send_cmd : opts.receive_cmd; if ( xfr_cmd[0] == '\0' ) { fd_printf(STO, "\r\n*** command disabled ***\r\n"); break; } fname = read_filename(); if (fname == NULL) { fd_printf(STO, "*** cannot read filename ***\r\n"); break; } run_cmd(tty_fd, xfr_cmd, fname); free(fname); break; case KEY_BREAK: term_break(tty_fd); fd_printf(STO, "\r\n*** break sent ***\r\n"); break; default: break; } return 0; }