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; } } }
/*********************************************************************** * * Function: cmd_aboot * * Purpose: Sets autoboot source * * Processing: * See function. * * Parameters: None * * Outputs: None * * Returns: Always returns TRUE * * Notes: None * **********************************************************************/ BOOL_32 cmd_aboot(void) { UNS_8 *curp; UNS_32 addr; BOOL_32 processed = TRUE, ready = FALSE; INT_32 nexidx; ABOOT_SETUP_T abs; abs.fname [0] = '\0'; if (parse_get_entry_count() >= 3) { /* Get source */ curp = get_parsed_entry(1); nexidx = 2; if (str_cmp(curp, "term") == 0) { /* Clear break */ term_break(); abs.abootsrc = SRC_TERM; } else if (str_cmp(curp, "blk") == 0) { abs.abootsrc = SRC_BLKDEV; /* Get filename */ curp = get_parsed_entry(2); memcpy(abs.fname, curp, str_size(curp)); abs.fname[str_size(curp)] = '\0'; nexidx = 3; } else if (str_cmp(curp, "flash") == 0) { abs.abootsrc = SRC_NAND; } else if (str_cmp(curp, "none") == 0) { abs.abootsrc = SRC_NONE; } else { term_dat_out_crlf(invalsrc_msg); processed = FALSE; } /* Get file type */ curp = get_parsed_entry(nexidx); abs.flt = FLT_NONE; if (str_cmp(curp, "elf") == 0) { abs.flt = FLT_ELF; } else if (str_cmp(curp, "raw") == 0) { abs.flt = FLT_RAW; } else if (str_cmp(curp, "bin") == 0) { abs.flt = FLT_BIN; } else if (str_cmp(curp, "srec") == 0) { abs.flt = FLT_SREC; } else { abs.flt = FLT_NONE; term_dat_out(unkft_msg); term_dat_out_crlf(curp); processed = FALSE; } /* Next index */ nexidx++; /* Handle each file type */ if (processed == TRUE) { switch (abs.flt) { case FLT_RAW: /* Get load address */ curp = get_parsed_entry(nexidx); ready = str_hex_to_val(curp, &addr); if (ready == TRUE) { abs.loadaddr = addr; abs.startaddr = addr; } else { term_dat_out_crlf(rawna_msg); } /* Start address */ nexidx++; curp = get_parsed_entry(nexidx); if (curp != NULL) { ready &= str_hex_to_val(curp, &addr); if (ready == TRUE) { abs.startaddr = addr; } } break; case FLT_BIN: ready = FALSE; /* TBD not supported yet */ processed = TRUE; break; case FLT_SREC: ready = TRUE; processed = TRUE; break; case FLT_ELF: ready = FALSE; /* TBD not supported yet */ processed = TRUE; break; default: break; } } } if (ready == TRUE) { syscfg.aboot = abs; cfg_save(&syscfg); term_dat_out_crlf(bsgood_msg); } else { term_dat_out_crlf(bsbad_msg); } return TRUE; }
/*********************************************************************** * * Function: cmd_load * * Purpose: Load command * * Processing: * For the load command, start parsing subcommand elements and * route to the specific handler. * * Parameters: None * * Outputs: None * * Returns: Always returns TRUE * * Notes: None * **********************************************************************/ BOOL_32 cmd_load(void) { UNS_8 *curp; UNS_32 addr; BOOL_32 processed = TRUE, loaded = FALSE; FILE_DATA_T fdata; SRC_LOAD_T src = SRC_TERM; INT_32 nexidx; UNS_8 *fname; if (parse_get_entry_count() >= 3) { /* Get source */ curp = get_parsed_entry(1); nexidx = 2; if (str_cmp(curp, "term") == 0) { /* Clear break */ term_break(); src = SRC_TERM; } else if (str_cmp(curp, "blk") == 0) { src = SRC_BLKDEV; nexidx = 3; } else if (str_cmp(curp, "flash") == 0) { src = SRC_NAND; } else { term_dat_out_crlf(invalsrc_msg); processed = FALSE; } /* Get file type */ curp = get_parsed_entry(nexidx); fdata.flt = FLT_NONE; if (str_cmp(curp, "elf") == 0) { fdata.flt = FLT_ELF; } else if (str_cmp(curp, "raw") == 0) { fdata.flt = FLT_RAW; } else if (str_cmp(curp, "bin") == 0) { fdata.flt = FLT_BIN; } else if (str_cmp(curp, "srec") == 0) { fdata.flt = FLT_SREC; } else { fdata.flt = FLT_NONE; term_dat_out(unkft_msg); term_dat_out_crlf(curp); processed = FALSE; } /* Next index */ nexidx++; /* Handle each file type */ if (processed == TRUE) { /* Get filename */ fname = get_parsed_entry(2); switch (fdata.flt) { case FLT_RAW: /* Get load address */ curp = get_parsed_entry(nexidx); loaded = str_hex_to_val(curp, &addr); if (loaded == TRUE) { fdata.loadaddr = addr; fdata.startaddr = (PFV) addr; } else { term_dat_out_crlf(rawna_msg); } /* Start address */ nexidx++; curp = get_parsed_entry(nexidx); if (curp != NULL) { loaded &= str_hex_to_val(curp, &addr); if (loaded == TRUE) { fdata.startaddr = (PFV) addr; } } if (loaded == TRUE) { loaded = raw_load(&fdata, fdata.loadaddr, fname, src); } processed = TRUE; break; case FLT_BIN: processed = TRUE; /* TBD not supported yet */ break; case FLT_SREC: loaded = srec_parse(&fdata, src, fname); break; case FLT_ELF: processed = TRUE; /* TBD not supported yet */ break; default: break; } } } if (loaded == TRUE) { term_dat_out_crlf(floaded_msg); sysinfo.lfile.loadaddr = fdata.loadaddr; sysinfo.lfile.flt = fdata.flt; sysinfo.lfile.num_bytes = fdata.num_bytes; sysinfo.lfile.startaddr = fdata.startaddr; sysinfo.lfile.contiguous = fdata.contiguous; sysinfo.lfile.loaded = TRUE; } else { term_dat_out_crlf(notloaded_msg); sysinfo.lfile.loadaddr = 0xFFFFFFFF; sysinfo.lfile.flt = FLT_NONE; sysinfo.lfile.num_bytes = 0; sysinfo.lfile.startaddr = (PFV) 0xFFFFFFFF; processed = FALSE; } return TRUE; }
/*********************************************************************** * * Function: raw_load * * Purpose: Load a raw file from a source to memory * * Processing: * See function. * * Parameters: * fdata : Pointer to file data to fill * addr : Address to load data * filename : Filename (sd cards only) * src : Data source * * Outputs: None * * Returns: TRUE if the file was loaded, otherwise FALSE * * Notes: None * **********************************************************************/ BOOL_32 raw_load(FILE_DATA_T *fdata, UNS_32 addr, UNS_8 *filename, SRC_LOAD_T src) { UNS_32 rb, bytes = 0; UNS_8 ch, *ptr8 = (UNS_8 *) addr; BOOL_32 readloop, loaded = FALSE; if (src == SRC_TERM) { term_dat_out_crlf(rawdl_msg); /* Read data from terminal until a break is encountered */ while (term_break() == FALSE) { if (term_dat_in(&ch, 1) > 0) { bytes++; *ptr8 = ch; ptr8++; } } fdata->num_bytes = bytes; fdata->contiguous = TRUE; loaded = TRUE; } else if (src == SRC_NAND) { /* Move image in NAND to memory */ term_dat_out_crlf(rawnanddlns_msg); } else if (src == SRC_BLKDEV) { /* Initialize FAT interface first */ if (fat_init() == FALSE) { term_dat_out(blkdeverr_msg); } /* Try to open file */ else if (fat_file_open(filename) == FALSE) { term_dat_out_crlf(nofilmsg); } else { fdata->num_bytes = 0; readloop = TRUE; while (readloop == TRUE) { rb = fat_file_read(ptr8, 8); fdata->num_bytes += rb; ptr8 += 8; if (rb != 8) { readloop = FALSE; } } fdata->contiguous = TRUE; loaded = TRUE; } fat_deinit(); } return loaded; }
/*********************************************************************** * * Function: readline * * Purpose: Read line with line feed * * Processing: * See function. * * Parameters: * data : Pointer to line data to fill * src : Data source * * Outputs: None * * Returns: TRUE if the line was loaded, otherwise FALSE * * Notes: None * **********************************************************************/ static BOOL_32 readline(UNS_8 *data, SRC_LOAD_T src) { UNS_32 rb; int lastidx, idx; BOOL_32 linedone = FALSE, linegood = FALSE; lastidx = idx = 0; while (linedone == FALSE) { switch (src) { case SRC_TERM: /* Has a break occurred? */ if (term_break() == TRUE) { /* Exit now */ linedone = TRUE; } else if (term_dat_in((data + idx), 1) > 0) { idx++; } break; case SRC_NAND: /* Get a byte from the FLASH */ /* Get a byte from the SD/MMC card */ rb = stream_flash_read(&data [idx], 1); if (rb == 0) { linedone = TRUE; } idx++; break; case SRC_BLKDEV: /* Get a byte from the SD/MMC card */ rb = fat_file_read(&data [idx], 1); if (rb == 0) { linedone = TRUE; } idx++; break; case SRC_NONE: default: return FALSE; } if (lastidx != idx) { if (data [lastidx] == '\r') { linedone = TRUE; linegood = TRUE; data [lastidx] = '\0'; } lastidx = idx; } } data [idx] = '\0'; str_upper_to_lower(data); return linegood; }
/* 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; }