int flash_xmodem_recv(FILE * f, uint32_t offs) { union { union { struct xmodem_rcv rx; struct xmodem_snd sx; }; } xmodem; struct comm_dev comm; struct file * raw; uint8_t buf[128]; int ret; int cnt; raw = ftty_lowlevel(f); comm.arg = raw->data; comm.op.send = (int (*)(void *, const void *, unsigned int))raw->op->write; comm.op.recv = (int (*)(void *, void *, unsigned int, unsigned int))raw->op->read; DCC_LOG(LOG_TRACE, "................................."); xmodem_rcv_init(&xmodem.rx, &comm, XMODEM_RCV_CRC); cnt = 0; do { if ((ret = xmodem_rcv_loop(&xmodem.rx, buf, 128)) < 0) { DCC_LOG1(LOG_ERROR, "ret=%d", ret); return ret; } stm32_flash_write(offs, buf, ret); cnt += ret; offs += ret; } while (ret > 0); return cnt; }
char * history_readline(struct cmd_history * ht, FILE * f, char * buf, int max) { int mode; int pos; int val; int len; int ctrl; int c; int i; char * s; if (isfatty(f)) { f = ftty_lowlevel(f); } mode = 0; pos = 0; val = 0; ctrl = 0; len = 0; /* reserve space for NULL termination */ max--; for (;;) { if ((c = fgetc(f)) == EOF) { DCC_LOG(LOG_INFO, "EOF"); return NULL; } DCC_LOG1(LOG_MSG, "[%02x]", c); switch (mode) { case MODE_ESC: switch (c) { case '[': mode = MODE_ESC_VAL1; val = 0; ctrl = 0; break; case 'O': mode = MODE_ESC_O; break; default: DCC_LOG1(LOG_INFO, "ESC:'%c'", c); mode = 0; }; continue; case MODE_ESC_VAL1: case MODE_ESC_VAL2: switch (c) { case '0'...'9': val = val * 10 + c - '0'; continue; case 'A': /* cursor up */ DCC_LOG2(LOG_MSG, "up %d, %d", ctrl, val); c = IN_CURSOR_UP + ctrl; break; case 'B': /* cursor down */ DCC_LOG2(LOG_MSG, "down %d, %d", ctrl, val); c = IN_CURSOR_DOWN + ctrl; break; case 'C': /* cursor right */ DCC_LOG2(LOG_MSG, "right %d, %d", ctrl, val); c = IN_CURSOR_RIGHT + ctrl; break; case 'D': /* cursor left */ DCC_LOG2(LOG_MSG, "left %d, %d", ctrl, val); c = IN_CURSOR_LEFT + ctrl; break; case '~': switch (val) { case 1: DCC_LOG1(LOG_MSG, "home %d", ctrl); c = IN_HOME + ctrl; break; case 2: DCC_LOG1(LOG_MSG, "insert %d", ctrl); c = IN_INSERT + ctrl; break; case 3: /* delete */ DCC_LOG1(LOG_MSG, "delete %d", ctrl); c = IN_DELETE + ctrl; break; case 4: /* end */ DCC_LOG(LOG_MSG, "end"); c = IN_END + ctrl; break; case 5: DCC_LOG1(LOG_MSG, "pg up %d", ctrl); c = IN_PAGE_UP + ctrl; break; case 6: DCC_LOG1(LOG_MSG, "pg down %d", ctrl); c = IN_PAGE_DOWN + ctrl; break; default: DCC_LOG1(LOG_INFO, "seq %d", val); mode = 0; continue; } break; case ';': mode = MODE_ESC_VAL2; ctrl = IN_CTRL; val = 0; continue; default: DCC_LOG1(LOG_MSG, "VAL:'%c'", c); mode = 0; continue; }; mode = 0; break; case MODE_ESC_O: switch (c) { case 'F': /* end */ DCC_LOG(LOG_MSG, "end"); c = IN_END; break; case 'H': /* home */ DCC_LOG(LOG_MSG, "home"); c = IN_HOME; break; default: DCC_LOG1(LOG_INFO, "ESC O:'%c'", c); mode = 0; continue; } mode = 0; break; } switch (c) { case IN_ESC: DCC_LOG(LOG_MSG, "ESC"); mode = MODE_ESC; continue; case IN_CURSOR_UP: if (ht->pos == ht->head) { buf[len] = '\0'; /* save current line on history's head */ strcpy(ht->buf + ht->pos * ht->len, buf); } if ((s = history_prev(ht)) == NULL) continue; goto set_buf; case IN_CURSOR_DOWN: if ((s = history_next(ht)) == NULL) continue; goto set_buf; case IN_CURSOR_RIGHT: if (pos < len) fputc(buf[pos++], f); else fputs(OUT_BEL, f); continue; case IN_CURSOR_LEFT: if (pos > 0) { fputs(OUT_CURSOR_LEFT, f); pos--; } else { fputs(OUT_BEL, f); } continue; case IN_CTRL_CURSOR_RIGHT: while (pos < len) { fputc(buf[pos++], f); if ((buf[pos - 1] != ' ') && (buf[pos] == ' ')) break; } continue; case IN_CTRL_CURSOR_LEFT: if (pos > 0) { do { fputs(OUT_CURSOR_LEFT, f); pos--; if ((buf[pos - 1] == ' ') && (buf[pos] != ' ')) break; } while (pos > 0); } continue; case IN_PAGE_UP: continue; case IN_PAGE_DOWN: continue; case IN_INSERT: continue; case IN_HOME: while (pos > 0) { fputs(OUT_CURSOR_LEFT, f); pos--; } continue; case IN_END: while (pos < len) { fputc(buf[pos++], f); } continue; case IN_TN_BS: DCC_LOG(LOG_MSG, "IN_TN_BS"); case IN_BS: if (pos == 0) { fputs(OUT_BEL, f); continue; } if (len == pos) { pos--; len--; fputs(OUT_BS, f); continue; } fputs(OUT_CURSOR_LEFT, f); pos--; /* fall back */ case IN_DELETE: if (len == pos) { continue; } len--; for (i = pos; i < len; i++) { buf[i] = buf[i + 1]; } buf[len] = '\0'; fputs(&buf[pos], f); fputc(' ', f); for (i = len + 1; i > pos; i--) fputs(OUT_CURSOR_LEFT, f); continue; case IN_EOL: buf[len] = '\0'; fputs("\r\n", f); return buf; case IN_SKIP: fputs(OUT_SKIP, f); return NULL; } if (len == max) { fputs(OUT_BEL, f); continue; } if (len == pos) { fputc(c, f); buf[pos] = c; pos++; len++; continue; } for (i = len; i > pos; i--) { buf[i] = buf[i - 1]; } len++; buf[pos] = c; buf[len] = '\0'; fputs(&buf[pos], f); pos++; for (i = len; i > pos; i--) fputs(OUT_CURSOR_LEFT, f); continue; set_buf: for (i = pos; i > 0; i--) fputs(OUT_CURSOR_LEFT, f); strcpy(buf, s); fputs(s, f); pos = strlen(s); if (pos < len) { for (i = pos; i < len; i++) fputc(' ', f); for (i = pos; i < len; i++) fputs(OUT_CURSOR_LEFT, f); } len = pos; } }