diff --git a/README.md b/README.md index 7e74cab..da56837 100644 --- a/README.md +++ b/README.md @@ -110,14 +110,24 @@ The help prompt lists the available commands. Commands (lead with ctrl-b): c: print available quick commands 0-9: load the given quick command (0 is 10) - p, 0-9: select a different quick commands page (0 is 10) + p: select a different quick commands page i: view info/stats x: start XModem upload with 128B payloads X: start XModem upload with 1024B payloads + H: enter/exit hex buffer mode h: view this help q: quit Bytenuts ``` +### Hex Buffer Mode +When the `ctrl+b H` command has been issued for the first time, you will enter hex buffer mode. In this mode, the input buffer is interpreted as a hex string and will be converted to its byte equivalent before it gets sent to the target. Example inputs: + +- `746573740d0a` gets sent as `test\r\n` +- `d0a` gets sent as `\r\n` as it assumed the trailing `0` has been omitted +- `74657374xd0a` gets sent as `test` since the `xd` byte contains an invalid hex character + +Hex buffer mode can be turned off with a second `ctrl+b H`. + ## Quick Commands You can provide multiple pages of quick commands you can easily load in with `ctrl+b [0-9]` in the files `~/.config/bytenuts/commands`. Bytenuts will load pages starting from `commands1` until a `commands` no longer exists. The commands should be newline separated. When a command is loaded, the entire contents of the line is loaded into the input buffer. diff --git a/src/cheerios.c b/src/cheerios.c index a38f3d5..05212e7 100644 --- a/src/cheerios.c +++ b/src/cheerios.c @@ -143,25 +143,10 @@ cheerios_stop() } int -cheerios_input(const char *line) +cheerios_input(const char *buf, size_t len) { - size_t line_len = strlen(line); - pthread_mutex_lock(&cheerios.lock); - - if (cheerios.config->echo) { - char *line_parsed = calloc(1, line_len + 5 + 1); - sprintf(line_parsed, ">> %s\r\n", line); - insert_buf(&cheerios.lines, line_parsed, strlen(line_parsed)); - free(line_parsed); - } - - write(cheerios.ser_fd, line, strlen(line)); - if (cheerios.config->no_crlf) - write(cheerios.ser_fd, "\n", 1); - else - write(cheerios.ser_fd, "\r\n", 2); - + write(cheerios.ser_fd, buf, len); pthread_mutex_unlock(&cheerios.lock); return 0; } diff --git a/src/cheerios.h b/src/cheerios.h index 08b3a5b..e83dee2 100644 --- a/src/cheerios.h +++ b/src/cheerios.h @@ -62,9 +62,8 @@ int cheerios_gofwd(int lines); /* stop the thread and release memory */ int cheerios_stop(); -/* send over a line of user input to the output - * do not terminate with a newline! */ -int cheerios_input(const char *line); +/* send over a line of user input to the output */ +int cheerios_input(const char *buf, size_t len); /* output a line only to the terminal for info/prompt purposes * do not terminate with a newline! */ diff --git a/src/ingest.c b/src/ingest.c index 1c80214..1c491f5 100644 --- a/src/ingest.c +++ b/src/ingest.c @@ -378,6 +378,7 @@ ingest_thread(void *arg) " i: view info/stats\r\n" " x: start XModem upload with 128B payloads\r\n" " X: start XModem upload with 1024B payloads\r\n" + " H: enter/exit hex buffer mode\r\n" " h: view this help\r\n" " q: quit Bytenuts\r\n", ingest.config->escape @@ -429,9 +430,21 @@ mode_normal(int ch) return 0; switch (ch) { - case '\n': /* send inputs */ - if (cheerios_input(ingest.inbuf)) { - break; + case '\n': { /* send inputs */ + size_t inlen = strlen(ingest.inbuf); + const char *ending; + + if (ingest.config->no_crlf) + ending = "\n"; + else + ending = "\r\n"; + + cheerios_input(ingest.inbuf, inlen); + cheerios_input(ending, strlen(ending)); + if (ingest.config->echo) { + cheerios_insert(">> ", 3); + cheerios_insert(ingest.inbuf, inlen); + cheerios_insert("\r\n", 2); } /* store in history */ @@ -453,6 +466,7 @@ mode_normal(int ch) ingest_refresh(); break; + } case KEY_UP: /* load in history */ if (ingest.history_pos == 0) { /* top of history */ break; @@ -617,17 +631,46 @@ mode_hex(int ch) case '\n': { /* send inputs */ char hexbuf[sizeof(ingest.inbuf)/2]; size_t inbuflen = strlen(ingest.inbuf); + size_t hexlen = 0; + /* assume leading 0 on odd length buffers */ + if (inbuflen % 2 != 0) { + memmove(&ingest.inbuf[1], ingest.inbuf, inbuflen); + ingest.inbuf[0] = '0'; + inbuflen++; + } for (int i = 0; i < inbuflen; i += 2) { char tmp = ingest.inbuf[i+2]; + char *inval; + long ch; + ingest.inbuf[i+2] = '\0'; - hexbuf[i/2] = strtol(&ingest.inbuf[i], NULL, 16); - // cheerios_print("HEX 0x%02X (%c)\r\n", hexbuf[i/2], hexbuf[i/2]); + ch = strtol(&ingest.inbuf[i], &inval, 16); ingest.inbuf[i+2] = tmp; + + /* strtol could not parse a character */ + if (inval != &ingest.inbuf[i+2]) + break; + + hexbuf[i/2] = ch; + hexlen++; } - if (cheerios_insert(hexbuf, inbuflen/2)) { - break; + cheerios_input(hexbuf, hexlen); + if (ingest.config->echo) { + cheerios_insert(">> (hex)\r\n", 10); + for (int i = 0; i < hexlen; i++) { + if ( + i > 0 && + i != hexlen-1 && + i % 16 == 0 + ) { + cheerios_insert("\r\n", 2); + } + cheerios_insert(&ingest.inbuf[i*2], 2); + cheerios_insert(" ", 1); + } + cheerios_insert("\r\n", 2); } /* store in history */