Skip to content

Commit

Permalink
[Console] add ability to unblock
Browse files Browse the repository at this point in the history
  • Loading branch information
chipweinberger committed Oct 15, 2022
1 parent ac315ad commit 85950d0
Show file tree
Hide file tree
Showing 9 changed files with 153 additions and 36 deletions.
14 changes: 12 additions & 2 deletions components/console/esp_console_repl.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ typedef enum {
CONSOLE_REPL_STATE_DEINIT,
CONSOLE_REPL_STATE_INIT,
CONSOLE_REPL_STATE_START,
CONSOLE_REPL_STATE_TASK_ENDED,
} repl_state_t;

typedef struct {
Expand Down Expand Up @@ -162,8 +163,8 @@ esp_err_t esp_console_new_repl_usb_serial_jtag(const esp_console_dev_usb_serial_
goto _exit;
}

/* Tell vfs to use usb-serial-jtag driver */
esp_vfs_usb_serial_jtag_use_driver();
/* Tell vfs to use usb-serial-jtag driver for reads */
esp_vfs_usb_serial_jtag_use_driver_for_rx();

// setup history
ret = esp_console_setup_history(repl_config->history_save_path, repl_config->max_history_len, &usb_serial_jtag_repl->repl_com);
Expand Down Expand Up @@ -455,6 +456,13 @@ static esp_err_t esp_console_repl_usb_serial_jtag_delete(esp_console_repl_t *rep
goto _exit;
}
repl_com->state = CONSOLE_REPL_STATE_DEINIT;

// wait for repl thread to stop
while (repl_com->state != CONSOLE_REPL_STATE_TASK_ENDED) {
usb_serial_jtag_unblock_reads();
vTaskDelay(20 / portTICK_PERIOD_MS);
}

esp_console_deinit();
esp_vfs_usb_serial_jtag_use_nonblocking();
usb_serial_jtag_driver_uninstall();
Expand Down Expand Up @@ -535,6 +543,8 @@ static void esp_console_repl_task(void *args)
/* linenoise allocates line buffer on the heap, so need to free it */
linenoiseFree(line);
}

repl_com->state = CONSOLE_REPL_STATE_TASK_ENDED;
ESP_LOGD(TAG, "The End");
vTaskDelete(NULL);
}
63 changes: 41 additions & 22 deletions components/console/linenoise/linenoise.c
Original file line number Diff line number Diff line change
Expand Up @@ -221,8 +221,8 @@ static void flushWrite(void) {
}

/* 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
* cursor. */
* and return it. On read error -1 is returned, On cursor error, -2 is returned.
* On success the position of the cursor. */
static int getCursorPosition(void) {
char buf[LINENOISE_COMMAND_MAX_LEN] = { 0 };
int cols = 0;
Expand All @@ -248,10 +248,14 @@ static int getCursorPosition(void) {
* Stop right before the last character of the buffer, to be able to NULL
* terminate it. */
while (i < sizeof(buf)-1) {

int nread = read(in_fd, buf + i, 1);
if (nread == -1 && errno == EWOULDBLOCK) {return -1;} // read error

/* Keep using unistd's functions. Here, using `read` instead of `fgets`
* 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 (nread != 1 || buf[i] == 'R') {
/* If we couldn't read a byte from STDIN or if 'R' was received,
* the transmission is finished. */
break;
Expand All @@ -270,7 +274,8 @@ static int getCursorPosition(void) {

/* Parse the received data to get the position of the cursor. */
if (buf[0] != ESC || buf[1] != '[' || sscanf(buf+2,"%d;%d",&rows,&cols) != 2) {
return -1;
// cursor error
return -2;
}
return cols;
}
Expand All @@ -294,9 +299,8 @@ static int getColumns(void) {

/* Get the initial position so we can restore it later. */
start = getCursorPosition();
if (start == -1) {
goto failed;
}
if (start == -1 && errno == EWOULDBLOCK) {return -1;}
if (start == -2) {goto failed;}

/* Send the command to go to right margin. Use `write` function instead of
* `fwrite` for the same reasons explained in `getCursorPosition()` */
Expand All @@ -308,9 +312,8 @@ static int getColumns(void) {
/* 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;
}
if (cols == -1 && errno == EWOULDBLOCK) {return -1;}
if (cols == -2) {goto failed;}

/* Restore the position of the cursor back. */
if (cols > start) {
Expand Down Expand Up @@ -819,6 +822,9 @@ static int linenoiseEdit(char *buf, size_t buflen, const char *prompt)
int out_fd = fileno(stdout);
int in_fd = fileno(stdin);

int cols = getColumns();
if (cols == -1 && errno == EWOULDBLOCK) {return -1;}

/* Populate the linenoise state that we pass to functions implementing
* specific editing functionalities. */
l.buf = buf;
Expand All @@ -827,9 +833,9 @@ static int linenoiseEdit(char *buf, size_t buflen, const char *prompt)
l.plen = strlen(prompt);
l.oldpos = l.pos = 0;
l.len = 0;
l.cols = getColumns();
l.maxrows = 0;
l.history_index = 0;
l.cols = cols;

/* Buffer starts empty. */
l.buf[0] = '\0';
Expand All @@ -840,16 +846,21 @@ static int linenoiseEdit(char *buf, size_t buflen, const char *prompt)
linenoiseHistoryAdd("");

int pos1 = getCursorPosition();
if (pos1 == -1 && errno == EWOULDBLOCK){return -1;}

if (write(out_fd, prompt,l.plen) == -1) {
return -1;
}
flushWrite();

int pos2 = getCursorPosition();
if (pos2 == -1 && errno == EWOULDBLOCK){return -1;}

if (pos1 >= 0 && pos2 >= 0) {
l.plen = pos2 - pos1;
}
while(1) {
char c;
int c;
int nread;
char seq[3];

Expand All @@ -864,7 +875,8 @@ static int linenoiseEdit(char *buf, size_t buflen, const char *prompt)
*/
t1 = getMillis();
nread = read(in_fd, &c, 1);
if (nread <= 0) return l.len;
if (nread == -1 && errno == EWOULDBLOCK) {return -1;}
if (nread <= 0){return l.len;}

if ( (getMillis() - t1) < LINENOISE_PASTE_KEY_DELAY && c != ENTER) {
/* Pasting data, insert characters without formatting.
Expand Down Expand Up @@ -940,19 +952,19 @@ static int linenoiseEdit(char *buf, size_t buflen, const char *prompt)
case CTRL_N: /* ctrl-n */
linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT);
break;
case ESC: /* escape sequence */
case ESC:{ /* escape sequence */
/* Read the next two bytes representing the escape sequence. */
if (read(in_fd, seq, 2) < 2) {
break;
}
int n = read(in_fd, seq, 2);
if (n == -1 && errno == EWOULDBLOCK) {return -1;}
if (n < 2) {break;}

/* ESC [ sequences. */
if (seq[0] == '[') {
if (seq[1] >= '0' && seq[1] <= '9') {
/* Extended escape, read additional byte. */
if (read(in_fd, seq+2, 1) == -1) {
break;
}
int n = read(in_fd, seq+2, 1);
if (n == -1 && errno == EWOULDBLOCK) {return -1;}
if (n == -1) {break;}
if (seq[2] == '~') {
switch(seq[1]) {
case '3': /* Delete key. */
Expand Down Expand Up @@ -996,6 +1008,7 @@ static int linenoiseEdit(char *buf, size_t buflen, const char *prompt)
}
}
break;
}
default:
if (linenoiseEditInsert(&l,c)) return -1;
break;
Expand Down Expand Up @@ -1054,6 +1067,8 @@ int linenoiseProbe(void) {
timeout_ms -= retry_ms;
char c;
int cb = read(stdin_fileno, &c, 1);
// Note! Due to the fcntl call above, this is read in non-blocking mode!
// So, nread == -1 && errno == EWOULDBLOCK are expected here!
if (cb < 0) {
continue;
}
Expand Down Expand Up @@ -1084,8 +1099,10 @@ static int linenoiseRaw(char *buf, size_t buflen, const char *prompt) {
}

count = linenoiseEdit(buf, buflen, prompt);
fputc('\n', stdout);
flushWrite();
if (count != -1){
fputc('\n', stdout);
flushWrite();
}
return count;
}

Expand All @@ -1095,6 +1112,8 @@ static int linenoiseDumb(char* buf, size_t buflen, const char* prompt) {
size_t count = 0;
while (count < buflen) {
int c = fgetc(stdin);
if (c == -1 && errno == EWOULDBLOCK) {return -1;}

if (c == '\n') {
break;
} else if (c >= 0x1c && c <= 0x1f){
Expand Down
9 changes: 9 additions & 0 deletions components/driver/include/driver/usb_serial_jtag.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,15 @@ typedef struct {
*/
esp_err_t usb_serial_jtag_driver_install(usb_serial_jtag_driver_config_t *usb_serial_jtag_config);

/**
* @brief Unblock usb_serial_jtag_read_bytes() from any read that it is currently waiting on.
*
* @return
* - ESP_OK Success
* - ESP_INVALID_STATE If the Usb Serial JTAG driver has not been installed
*/
esp_err_t usb_serial_jtag_unblock_reads();

/**
* @brief USB_SERIAL_JTAG read bytes from USB_SERIAL_JTAG buffer
*
Expand Down
10 changes: 10 additions & 0 deletions components/driver/usb_serial_jtag.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,16 @@ esp_err_t usb_serial_jtag_driver_install(usb_serial_jtag_driver_config_t *usb_se
return err;
}

esp_err_t usb_serial_jtag_unblock_reads()
{
if (p_usb_serial_jtag_obj->rx_ring_buf == NULL) {
return ESP_ERR_INVALID_STATE;
}

vRingbufferUnblockRx(p_usb_serial_jtag_obj->rx_ring_buf);
return ESP_OK;
}

int usb_serial_jtag_read_bytes(void* buf, uint32_t length, TickType_t ticks_to_wait)
{
uint8_t *data = NULL;
Expand Down
10 changes: 10 additions & 0 deletions components/esp_ringbuf/include/freertos/ringbuf.h
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,16 @@ void vRingbufferGetInfo(RingbufHandle_t xRingbuffer,
UBaseType_t *uxAcquire,
UBaseType_t *uxItemsWaiting);

/**
* @brief Unblock any read function that is currently waiting. example: xRingbufferReceiveUpTo()
*
* All read functions take a xTicksToWait argument, which can be set up to
* to infinity. This function will unblock any threads currently waiting.
*
* @param[in] xRingbuffer The ring buffer who's rx will be unblocked.
*/
void vRingbufferUnblockRx(RingbufHandle_t xRingbuffer);

/**
* @brief Debugging function to print the internal pointers in the ring buffer
*
Expand Down
26 changes: 25 additions & 1 deletion components/esp_ringbuf/ringbuf.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#define rbBYTE_BUFFER_FLAG ( ( UBaseType_t ) 2 ) //The ring buffer is a byte buffer
#define rbBUFFER_FULL_FLAG ( ( UBaseType_t ) 4 ) //The ring buffer is currently full (write pointer == free pointer)
#define rbBUFFER_STATIC_FLAG ( ( UBaseType_t ) 8 ) //The ring buffer is statically allocated
#define rbBUFFER_UNBLOCK_RX_FLAG ( ( UBaseType_t ) 16) //A request has been made to unblock any pending reads

//Item flags
#define rbITEM_FREE_FLAG ( ( UBaseType_t ) 1 ) //Item has been retrieved and returned by application, free to overwrite
Expand Down Expand Up @@ -759,6 +760,8 @@ static size_t prvGetCurMaxSizeByteBuf(Ringbuffer_t *pxRingbuffer)
return xFreeSize;
}



static BaseType_t prvReceiveGeneric(Ringbuffer_t *pxRingbuffer,
void **pvItem1,
void **pvItem2,
Expand All @@ -772,12 +775,19 @@ static BaseType_t prvReceiveGeneric(Ringbuffer_t *pxRingbuffer,
TickType_t xTicksEnd = xTaskGetTickCount() + xTicksToWait;
TickType_t xTicksRemaining = xTicksToWait;
while (xTicksRemaining <= xTicksToWait) { //xTicksToWait will underflow once xTaskGetTickCount() > ticks_end
//Block until more free space becomes available or timeout
//Block until some bytes become available or timeout
if (xSemaphoreTake(rbGET_RX_SEM_HANDLE(pxRingbuffer), xTicksRemaining) != pdTRUE) {
xReturn = pdFALSE; //Timed out attempting to get semaphore
break;
}

// has a request been made to unblock?
if (pxRingbuffer->uxRingbufferFlags & rbBUFFER_UNBLOCK_RX_FLAG) {
pxRingbuffer->uxRingbufferFlags &= ~rbBUFFER_UNBLOCK_RX_FLAG; // clear flag
xReturn = pdFALSE;
break;
}

//Semaphore obtained, check if item can be retrieved
portENTER_CRITICAL(&pxRingbuffer->mux);
if (prvCheckItemAvail(pxRingbuffer) == pdTRUE) {
Expand Down Expand Up @@ -1421,6 +1431,18 @@ void vRingbufferGetInfo(RingbufHandle_t xRingbuffer,
portEXIT_CRITICAL(&pxRingbuffer->mux);
}

void vRingbufferUnblockRx(RingbufHandle_t xRingbuffer)
{
Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer;
configASSERT(pxRingbuffer);

// is the semaphore taken?
if (uxSemaphoreGetCount(rbGET_RX_SEM_HANDLE(pxRingbuffer)) == 0) {
pxRingbuffer->uxRingbufferFlags |= rbBUFFER_UNBLOCK_RX_FLAG;
xSemaphoreGive(rbGET_RX_SEM_HANDLE(pxRingbuffer));
}
}

void xRingbufferPrintInfo(RingbufHandle_t xRingbuffer)
{
Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer;
Expand All @@ -1432,3 +1454,5 @@ void xRingbufferPrintInfo(RingbufHandle_t xRingbuffer)
pxRingbuffer->pucWrite - pxRingbuffer->pucHead,
pxRingbuffer->pucAcquire - pxRingbuffer->pucHead);
}


25 changes: 24 additions & 1 deletion components/vfs/include/esp_vfs_dev.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,33 @@ void esp_vfs_dev_uart_use_driver(int uart_num);
/**
* @brief set VFS to use USB-SERIAL-JTAG driver for reading and writing
* @note application must configure USB-SERIAL-JTAG driver before calling these functions
* With these functions, read and write are blocking and interrupt-driven.
* With this functions, read and write are blocking and interrupt-driven.
*
* @warning If there is no terminal *consuming* the bytes we are sending,
* sending data will block indefinitely, until a terminal attaches and consumes them.
* (i.e. printf & ESP_LOGI will block, pausing the application when the tx buffer becomes full)
*/
void esp_vfs_usb_serial_jtag_use_driver(void);

/**
* @brief set VFS to use USB-SERIAL-JTAG driver for writing.
* @note application must configure USB-SERIAL-JTAG driver before calling these functions
* With this functions, read is blocking and interrupt-driven.
*/
void esp_vfs_usb_serial_jtag_use_driver_for_rx(void);

/**
* @brief set VFS to use USB-SERIAL-JTAG driver for reading
* @note application must configure USB-SERIAL-JTAG driver before calling these functions
* With these functions, write is blocking and interrupt-driven.
*
* @warning If there is no terminal *consuming* the bytes we are sending,
* sending data will block indefinitely, until a terminal attaches and consumes them.
* (i.e. printf & ESP_LOGI will block, pausing the application when the tx buffer becomes full)
*/
void esp_vfs_usb_serial_jtag_use_driver_for_tx(void);


/**
* @brief set VFS to use simple functions for reading and writing UART
* Read is non-blocking, write is busy waiting until TX FIFO has enough space.
Expand Down
14 changes: 14 additions & 0 deletions components/vfs/vfs_usb_serial_jtag.c
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,20 @@ void esp_vfs_usb_serial_jtag_use_nonblocking(void)
_lock_release_recursive(&s_ctx.read_lock);
}

void esp_vfs_usb_serial_jtag_use_driver_for_rx(void)
{
_lock_acquire_recursive(&s_ctx.read_lock);
s_ctx.rx_func = usbjtag_rx_char_via_driver;
_lock_release_recursive(&s_ctx.read_lock);
}

void esp_vfs_usb_serial_jtag_use_driver_for_tx(void)
{
_lock_acquire_recursive(&s_ctx.write_lock);
s_ctx.tx_func = usbjtag_tx_char_via_driver;
_lock_release_recursive(&s_ctx.write_lock);
}

void esp_vfs_usb_serial_jtag_use_driver(void)
{
_lock_acquire_recursive(&s_ctx.read_lock);
Expand Down
Loading

0 comments on commit 85950d0

Please sign in to comment.