forked from test34/can_wizard
console: fix a bug preventing us from starting a CLI on non-default UART
This commit is contained in:
parent
d74c0675f5
commit
13794c4c11
1 changed files with 84 additions and 24 deletions
|
@ -205,47 +205,107 @@ static void flushWrite(void) {
|
||||||
/* Use the ESC [6n escape sequence to query the horizontal cursor position
|
/* Use the ESC [6n escape sequence to query the horizontal cursor position
|
||||||
* and return it. On error -1 is returned, on success the position of the
|
* and return it. On error -1 is returned, on success the position of the
|
||||||
* cursor. */
|
* cursor. */
|
||||||
static int getCursorPosition() {
|
static int getCursorPosition(void) {
|
||||||
char buf[32];
|
char buf[LINENOISE_COMMAND_MAX_LEN] = { 0 };
|
||||||
int cols, rows;
|
int cols = 0;
|
||||||
unsigned int i = 0;
|
int rows = 0;
|
||||||
|
int i = 0;
|
||||||
|
const int out_fd = fileno(stdout);
|
||||||
|
const int in_fd = fileno(stdin);
|
||||||
|
/* The following ANSI escape sequence is used to get from the TTY the
|
||||||
|
* cursor position. */
|
||||||
|
const char get_cursor_cmd[] = "\x1b[6n";
|
||||||
|
|
||||||
/* Report cursor location */
|
/* Send the command to the TTY on the other end of the UART.
|
||||||
fprintf(stdout, "\x1b[6n");
|
* Let's use unistd's write function. Thus, data sent through it are raw
|
||||||
|
* reducing the overhead compared to using fputs, fprintf, etc... */
|
||||||
|
write(out_fd, get_cursor_cmd, sizeof(get_cursor_cmd));
|
||||||
|
|
||||||
|
/* For USB CDC, it is required to flush the output. */
|
||||||
flushWrite();
|
flushWrite();
|
||||||
/* Read the response: ESC [ rows ; cols R */
|
|
||||||
|
/* The other end will send its response which format is ESC [ rows ; cols R
|
||||||
|
* We don't know exactly how many bytes we have to read, thus, perform a
|
||||||
|
* read for each byte.
|
||||||
|
* Stop right before the last character of the buffer, to be able to NULL
|
||||||
|
* terminate it. */
|
||||||
while (i < sizeof(buf)-1) {
|
while (i < sizeof(buf)-1) {
|
||||||
if (fread(buf+i, 1, 1, stdin) != 1) break;
|
/* Keep using unistd's functions. Here, using `read` instead of `fgets`
|
||||||
if (buf[i] == 'R') break;
|
* or `fgets` guarantees us that we we can read a byte regardless on
|
||||||
|
* whether the sender sent end of line character(s) (CR, CRLF, LF). */
|
||||||
|
if (read(in_fd, buf + i, 1) != 1 || buf[i] == 'R') {
|
||||||
|
/* If we couldn't read a byte from STDIN or if 'R' was received,
|
||||||
|
* the transmission is finished. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For some reasons, it is possible that we receive new line character
|
||||||
|
* after querying the cursor position on some UART. Let's ignore them,
|
||||||
|
* this will not affect the rest of the program. */
|
||||||
|
if (buf[i] != '\n') {
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NULL-terminate the buffer, this is required by `sscanf`. */
|
||||||
buf[i] = '\0';
|
buf[i] = '\0';
|
||||||
/* Parse it. */
|
|
||||||
if (buf[0] != ESC || buf[1] != '[') return -1;
|
/* Parse the received data to get the position of the cursor. */
|
||||||
if (sscanf(buf+2,"%d;%d",&rows,&cols) != 2) return -1;
|
if (buf[0] != ESC || buf[1] != '[' || sscanf(buf+2,"%d;%d",&rows,&cols) != 2) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
return cols;
|
return cols;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Try to get the number of columns in the current terminal, or assume 80
|
/* Try to get the number of columns in the current terminal, or assume 80
|
||||||
* if it fails. */
|
* if it fails. */
|
||||||
static int getColumns() {
|
static int getColumns(void) {
|
||||||
int start, cols;
|
int start = 0;
|
||||||
|
int cols = 0;
|
||||||
|
int written = 0;
|
||||||
|
char seq[LINENOISE_COMMAND_MAX_LEN] = { 0 };
|
||||||
|
const int fd = fileno(stdout);
|
||||||
|
|
||||||
|
/* The following ANSI escape sequence is used to tell the TTY to move
|
||||||
|
* the cursor to the most-right position. */
|
||||||
|
const char move_cursor_right[] = "\x1b[999C";
|
||||||
|
const size_t cmd_len = sizeof(move_cursor_right);
|
||||||
|
|
||||||
|
/* This one is used to set the cursor position. */
|
||||||
|
const char set_cursor_pos[] = "\x1b[%dD";
|
||||||
|
|
||||||
/* Get the initial position so we can restore it later. */
|
/* Get the initial position so we can restore it later. */
|
||||||
start = getCursorPosition();
|
start = getCursorPosition();
|
||||||
if (start == -1) goto failed;
|
if (start == -1) {
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
/* Go to right margin and get position. */
|
/* Send the command to go to right margin. Use `write` function instead of
|
||||||
if (fwrite("\x1b[999C", 1, 6, stdout) != 6) goto failed;
|
* `fwrite` for the same reasons explained in `getCursorPosition()` */
|
||||||
|
if (write(fd, move_cursor_right, cmd_len) != cmd_len) {
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
flushWrite();
|
flushWrite();
|
||||||
cols = getCursorPosition();
|
|
||||||
if (cols == -1) goto failed;
|
|
||||||
|
|
||||||
/* Restore position. */
|
/* After sending this command, we can get the new position of the cursor,
|
||||||
|
* we'd get the size, in columns, of the opened TTY. */
|
||||||
|
cols = getCursorPosition();
|
||||||
|
if (cols == -1) {
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Restore the position of the cursor back. */
|
||||||
if (cols > start) {
|
if (cols > start) {
|
||||||
char seq[32];
|
/* Generate the move cursor command. */
|
||||||
snprintf(seq,32,"\x1b[%dD",cols-start);
|
written = snprintf(seq, LINENOISE_COMMAND_MAX_LEN, set_cursor_pos, cols-start);
|
||||||
if (fwrite(seq, 1, strlen(seq), stdout) == -1) {
|
|
||||||
|
/* If `written` is equal or bigger than LINENOISE_COMMAND_MAX_LEN, it
|
||||||
|
* means that the output has been truncated because the size provided
|
||||||
|
* is too small. */
|
||||||
|
assert (written < LINENOISE_COMMAND_MAX_LEN);
|
||||||
|
|
||||||
|
/* Send the command with `write`, which is not buffered. */
|
||||||
|
if (write(fd, seq, written) == -1) {
|
||||||
/* Can't recover... */
|
/* Can't recover... */
|
||||||
}
|
}
|
||||||
flushWrite();
|
flushWrite();
|
||||||
|
|
Loading…
Reference in a new issue