Skip to content

Commit 7b72c32

Browse files
committed
Merge branch 'feat/usb-serial-jtag-select' into 'master'
feat(usb_serial_jtag): Add select functionality to the driver Closes IDF-7415 and IDFGH-8509 See merge request espressif/esp-idf!30919
2 parents 370a735 + 83d00b1 commit 7b72c32

File tree

15 files changed

+522
-1
lines changed

15 files changed

+522
-1
lines changed

components/esp_driver_usb_serial_jtag/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ endif()
1818
idf_component_register(SRCS ${srcs}
1919
INCLUDE_DIRS ${include}
2020
PRIV_REQUIRES "${priv_requires}"
21+
LDFRAGMENTS "linker.lf"
2122
)
2223

2324
if(CONFIG_VFS_SUPPORT_IO AND CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG_ENABLED)

components/esp_driver_usb_serial_jtag/include/driver/usb_serial_jtag.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,13 @@ esp_err_t usb_serial_jtag_driver_uninstall(void);
105105
*/
106106
bool usb_serial_jtag_is_connected(void);
107107

108+
/**
109+
* @brief Get information whether the USB serial JTAG driver is installed or not
110+
*
111+
* @return True if driver is installed and False if driver not installed
112+
*/
113+
bool usb_serial_jtag_is_driver_installed(void);
114+
108115
#ifdef __cplusplus
109116
}
110117
#endif
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
2+
/*
3+
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
4+
*
5+
* SPDX-License-Identifier: Apache-2.0
6+
*/
7+
8+
#pragma once
9+
10+
#ifdef __cplusplus
11+
extern "C" {
12+
#endif
13+
14+
#include "driver/usb_serial_jtag.h"
15+
16+
typedef enum {
17+
USJ_SELECT_READ_NOTIF,
18+
USJ_SELECT_WRITE_NOTIF,
19+
USJ_SELECT_ERROR_NOTIF,
20+
} usj_select_notif_t;
21+
22+
typedef void (*usj_select_notif_callback_t)(usj_select_notif_t usb_serial_jtag_select_notif, BaseType_t *task_woken);
23+
24+
/**
25+
* @brief Set notification callback function for select() events
26+
* @param usb_serial_jtag_select_notif_callback callback function
27+
*/
28+
void usb_serial_jtag_set_select_notif_callback(usj_select_notif_callback_t usb_serial_jtag_select_notif_callback);
29+
30+
/**
31+
* @brief Return the readiness status of the driver for read operation
32+
*
33+
* @return true if driver read ready, false if not
34+
*/
35+
bool usb_serial_jtag_read_ready(void);
36+
37+
/**
38+
* @brief Return the readiness status of the driver for write operation
39+
*
40+
* @return true if driver is write ready, false if not
41+
*/
42+
bool usb_serial_jtag_write_ready(void);
43+
44+
#ifdef __cplusplus
45+
}
46+
#endif
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[mapping:usb_serial_jtag_vfs]
2+
archive: libesp_driver_usb_serial_jtag.a
3+
entries:
4+
if VFS_SELECT_IN_RAM = y:
5+
usb_serial_jtag_vfs: select_notif_callback_isr (noflash)

components/esp_driver_usb_serial_jtag/src/usb_serial_jtag.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "freertos/ringbuf.h"
1515
#include "esp_intr_alloc.h"
1616
#include "driver/usb_serial_jtag.h"
17+
#include "driver/usb_serial_jtag_select.h"
1718
#include "soc/periph_defs.h"
1819
#include "soc/soc_caps.h"
1920
#include "esp_check.h"
@@ -49,6 +50,8 @@ typedef struct {
4950
//Synchronization stuff, only used for flush for now
5051
SemaphoreHandle_t tx_mux;
5152
SemaphoreHandle_t tx_idle_sem;
53+
54+
usj_select_notif_callback_t usj_select_notif_callback; /*!< Notification about select() events */
5255
} usb_serial_jtag_obj_t;
5356

5457
static usb_serial_jtag_obj_t *p_usb_serial_jtag_obj = NULL;
@@ -103,6 +106,12 @@ static void usb_serial_jtag_isr_handler_default(void *arg)
103106
// Return the buffer if we got it from the ring buffer.
104107
if (queued_buf != p_usb_serial_jtag_obj->tx_stash_buf) {
105108
vRingbufferReturnItemFromISR(p_usb_serial_jtag_obj->tx_ring_buf, queued_buf, &xTaskWoken);
109+
110+
// We just moved items out of the TX ring buffer, the driver is considered write ready, since
111+
// the TX ring buffer is assured to be not full.
112+
if (p_usb_serial_jtag_obj->usj_select_notif_callback) {
113+
p_usb_serial_jtag_obj->usj_select_notif_callback(USJ_SELECT_WRITE_NOTIF, &xTaskWoken);
114+
}
106115
}
107116
} else {
108117
// No data to send.
@@ -139,6 +148,10 @@ static void usb_serial_jtag_isr_handler_default(void *arg)
139148
uint8_t buf[USB_SER_JTAG_RX_MAX_SIZE];
140149
uint32_t rx_fifo_len = usb_serial_jtag_ll_read_rxfifo(buf, USB_SER_JTAG_RX_MAX_SIZE);
141150
xRingbufferSendFromISR(p_usb_serial_jtag_obj->rx_ring_buf, buf, rx_fifo_len, &xTaskWoken);
151+
152+
if (p_usb_serial_jtag_obj->usj_select_notif_callback) {
153+
p_usb_serial_jtag_obj->usj_select_notif_callback(USJ_SELECT_READ_NOTIF, &xTaskWoken);
154+
}
142155
}
143156

144157
if (xTaskWoken == pdTRUE) {
@@ -341,3 +354,29 @@ esp_err_t usb_serial_jtag_driver_uninstall(void)
341354
p_usb_serial_jtag_obj = NULL;
342355
return ESP_OK;
343356
}
357+
358+
bool usb_serial_jtag_is_driver_installed(void)
359+
{
360+
return (p_usb_serial_jtag_obj != NULL);
361+
}
362+
363+
void usb_serial_jtag_set_select_notif_callback(usj_select_notif_callback_t usj_select_notif_callback)
364+
{
365+
if (usb_serial_jtag_is_driver_installed()) {
366+
p_usb_serial_jtag_obj->usj_select_notif_callback = usj_select_notif_callback;
367+
}
368+
}
369+
370+
bool usb_serial_jtag_read_ready(void)
371+
{
372+
// sign the the driver is read ready is that data is waiting in the RX ringbuffer
373+
UBaseType_t items_waiting = 0;
374+
vRingbufferGetInfo(p_usb_serial_jtag_obj->rx_ring_buf, NULL, NULL, NULL, NULL, &items_waiting);
375+
return items_waiting != 0;
376+
}
377+
378+
bool usb_serial_jtag_write_ready(void)
379+
{
380+
// sign that the driver is write ready is that the TX ring buffer is not full
381+
return (xRingbufferGetCurFreeSize(p_usb_serial_jtag_obj->tx_ring_buf) > 0);
382+
}

components/esp_driver_usb_serial_jtag/src/usb_serial_jtag_vfs.c

Lines changed: 194 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,14 @@
2323
#include "sdkconfig.h"
2424
#include "soc/soc_caps.h"
2525
#include "hal/usb_serial_jtag_ll.h"
26+
#include "driver/usb_serial_jtag_select.h"
2627
#include "driver/usb_serial_jtag_vfs.h"
2728
#include "driver/usb_serial_jtag.h"
2829
#include "esp_private/startup_internal.h"
30+
#include "esp_heap_caps.h"
31+
32+
// local file descriptor value for the USJ
33+
#define USJ_LOCAL_FD 0
2934

3035
// Token signifying that no character is available
3136
#define NONE -1
@@ -46,6 +51,12 @@
4651
# define DEFAULT_RX_MODE ESP_LINE_ENDINGS_LF
4752
#endif
4853

54+
#if CONFIG_VFS_SELECT_IN_RAM
55+
#define USJ_VFS_MALLOC_FLAGS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
56+
#else
57+
#define USJ_VFS_MALLOC_FLAGS MALLOC_CAP_DEFAULT
58+
#endif
59+
4960
// write bytes function type
5061
typedef void (*tx_func_t)(int, int);
5162
// read bytes function type
@@ -108,10 +119,30 @@ static usb_serial_jtag_vfs_context_t s_ctx = {
108119
.fsync_func = usb_serial_jtag_wait_tx_done_no_driver
109120
};
110121

122+
#ifdef CONFIG_VFS_SUPPORT_SELECT
123+
124+
typedef struct {
125+
esp_vfs_select_sem_t select_sem;
126+
fd_set *readfds;
127+
fd_set *writefds;
128+
fd_set *errorfds;
129+
fd_set readfds_orig;
130+
fd_set writefds_orig;
131+
fd_set errorfds_orig;
132+
} usb_serial_jtag_select_args_t;
133+
134+
static usb_serial_jtag_select_args_t **s_registered_selects = NULL;
135+
static int s_registered_select_num = 0;
136+
static portMUX_TYPE s_registered_select_lock = portMUX_INITIALIZER_UNLOCKED;
137+
138+
static esp_err_t usb_serial_jtag_end_select(void *end_select_args);
139+
140+
#endif // CONFIG_VFS_SUPPORT_SELECT
141+
111142
static int usb_serial_jtag_open(const char * path, int flags, int mode)
112143
{
113144
s_ctx.non_blocking = ((flags & O_NONBLOCK) == O_NONBLOCK);
114-
return 0;
145+
return USJ_LOCAL_FD;
115146
}
116147

117148
static void usb_serial_jtag_tx_char_no_driver(int fd, int c)
@@ -300,6 +331,164 @@ static int usb_serial_jtag_fsync(int fd)
300331
}
301332
}
302333

334+
#ifdef CONFIG_VFS_SUPPORT_SELECT
335+
336+
static void select_notif_callback_isr(usj_select_notif_t usj_select_notif, BaseType_t *task_woken)
337+
{
338+
portENTER_CRITICAL_ISR(&s_registered_select_lock);
339+
for (int i = 0; i < s_registered_select_num; ++i) {
340+
usb_serial_jtag_select_args_t *args = s_registered_selects[i];
341+
if (args) {
342+
switch (usj_select_notif) {
343+
case USJ_SELECT_READ_NOTIF:
344+
if (FD_ISSET(USJ_LOCAL_FD, &args->readfds_orig)) {
345+
FD_SET(USJ_LOCAL_FD, args->readfds);
346+
esp_vfs_select_triggered_isr(args->select_sem, task_woken);
347+
}
348+
break;
349+
case USJ_SELECT_WRITE_NOTIF:
350+
if (FD_ISSET(USJ_LOCAL_FD, &args->writefds_orig)) {
351+
FD_SET(USJ_LOCAL_FD, args->writefds);
352+
esp_vfs_select_triggered_isr(args->select_sem, task_woken);
353+
}
354+
break;
355+
case USJ_SELECT_ERROR_NOTIF:
356+
if (FD_ISSET(USJ_LOCAL_FD, &args->errorfds_orig)) {
357+
FD_SET(USJ_LOCAL_FD, args->errorfds);
358+
esp_vfs_select_triggered_isr(args->select_sem, task_woken);
359+
}
360+
break;
361+
}
362+
}
363+
}
364+
portEXIT_CRITICAL_ISR(&s_registered_select_lock);
365+
}
366+
367+
static esp_err_t register_select(usb_serial_jtag_select_args_t *args)
368+
{
369+
esp_err_t ret = ESP_ERR_INVALID_ARG;
370+
371+
if (args) {
372+
portENTER_CRITICAL(&s_registered_select_lock);
373+
const int new_size = s_registered_select_num + 1;
374+
usb_serial_jtag_select_args_t **new_selects;
375+
if ((new_selects = heap_caps_realloc(s_registered_selects, new_size * sizeof(usb_serial_jtag_select_args_t *), USJ_VFS_MALLOC_FLAGS)) == NULL) {
376+
ret = ESP_ERR_NO_MEM;
377+
} else {
378+
/* on first select registration register the callback */
379+
if (s_registered_select_num == 0) {
380+
usb_serial_jtag_set_select_notif_callback(select_notif_callback_isr);
381+
}
382+
383+
s_registered_selects = new_selects;
384+
s_registered_selects[s_registered_select_num] = args;
385+
s_registered_select_num = new_size;
386+
ret = ESP_OK;
387+
}
388+
portEXIT_CRITICAL(&s_registered_select_lock);
389+
}
390+
391+
return ret;
392+
}
393+
394+
static esp_err_t unregister_select(usb_serial_jtag_select_args_t *args)
395+
{
396+
esp_err_t ret = ESP_OK;
397+
if (args) {
398+
ret = ESP_ERR_INVALID_STATE;
399+
portENTER_CRITICAL(&s_registered_select_lock);
400+
for (int i = 0; i < s_registered_select_num; ++i) {
401+
if (s_registered_selects[i] == args) {
402+
const int new_size = s_registered_select_num - 1;
403+
// The item is removed by overwriting it with the last item. The subsequent rellocation will drop the
404+
// last item.
405+
s_registered_selects[i] = s_registered_selects[new_size];
406+
s_registered_selects = heap_caps_realloc(s_registered_selects, new_size * sizeof(usb_serial_jtag_select_args_t *), USJ_VFS_MALLOC_FLAGS);
407+
// Shrinking a buffer with realloc is guaranteed to succeed.
408+
s_registered_select_num = new_size;
409+
410+
/* when the last select is unregistered, also unregister the callback */
411+
if (s_registered_select_num == 0) {
412+
usb_serial_jtag_set_select_notif_callback(NULL);
413+
}
414+
415+
ret = ESP_OK;
416+
break;
417+
}
418+
}
419+
portEXIT_CRITICAL(&s_registered_select_lock);
420+
}
421+
return ret;
422+
}
423+
424+
static esp_err_t usb_serial_jtag_start_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
425+
esp_vfs_select_sem_t select_sem, void **end_select_args)
426+
{
427+
(void)nfds; /* Since there is only 1 usb serial jtag port, this parameter is useless */
428+
*end_select_args = NULL;
429+
if (!usb_serial_jtag_is_driver_installed()) {
430+
return ESP_ERR_INVALID_STATE;
431+
}
432+
433+
usb_serial_jtag_select_args_t *args = heap_caps_malloc(sizeof(usb_serial_jtag_select_args_t), USJ_VFS_MALLOC_FLAGS);
434+
435+
if (args == NULL) {
436+
return ESP_ERR_NO_MEM;
437+
}
438+
args->select_sem = select_sem;
439+
args->readfds = readfds;
440+
args->writefds = writefds;
441+
args->errorfds = exceptfds;
442+
args->readfds_orig = *readfds; // store the original values because they will be set to zero
443+
args->writefds_orig = *writefds;
444+
args->errorfds_orig = *exceptfds;
445+
FD_ZERO(readfds);
446+
FD_ZERO(writefds);
447+
FD_ZERO(exceptfds);
448+
449+
esp_err_t ret = register_select(args);
450+
if (ret != ESP_OK) {
451+
free(args);
452+
return ret;
453+
}
454+
455+
bool trigger_select = false;
456+
457+
// check if the select should return instantly if the bus is read ready
458+
if (FD_ISSET(USJ_LOCAL_FD, &args->readfds_orig) && usb_serial_jtag_read_ready()) {
459+
// signal immediately when data is buffered
460+
FD_SET(USJ_LOCAL_FD, readfds);
461+
trigger_select = true;
462+
}
463+
464+
// check if the select should return instantly if the bus is write ready
465+
if (FD_ISSET(USJ_LOCAL_FD, &args->writefds_orig) && usb_serial_jtag_write_ready()) {
466+
// signal immediately when data can be written
467+
FD_SET(USJ_LOCAL_FD, writefds);
468+
trigger_select = true;
469+
}
470+
471+
if (trigger_select) {
472+
esp_vfs_select_triggered(args->select_sem);
473+
}
474+
475+
*end_select_args = args;
476+
return ESP_OK;
477+
}
478+
479+
static esp_err_t usb_serial_jtag_end_select(void *end_select_args)
480+
{
481+
usb_serial_jtag_select_args_t *args = end_select_args;
482+
esp_err_t ret = unregister_select(args);
483+
if (args) {
484+
free(args);
485+
}
486+
487+
return ret;
488+
}
489+
490+
#endif // CONFIG_VFS_SUPPORT_SELECT
491+
303492
#ifdef CONFIG_VFS_SUPPORT_TERMIOS
304493
static int usb_serial_jtag_tcsetattr(int fd, int optional_actions, const struct termios *p)
305494
{
@@ -391,6 +580,10 @@ static const esp_vfs_t usj_vfs = {
391580
.read = &usb_serial_jtag_read,
392581
.fcntl = &usb_serial_jtag_fcntl,
393582
.fsync = &usb_serial_jtag_fsync,
583+
#ifdef CONFIG_VFS_SUPPORT_SELECT
584+
.start_select = &usb_serial_jtag_start_select,
585+
.end_select = &usb_serial_jtag_end_select,
586+
#endif // CONFIG_VFS_SUPPORT_SELECT
394587
#ifdef CONFIG_VFS_SUPPORT_TERMIOS
395588
.tcsetattr = &usb_serial_jtag_tcsetattr,
396589
.tcgetattr = &usb_serial_jtag_tcgetattr,

components/esp_driver_usb_serial_jtag/test_apps/.build-test-rules.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,14 @@ components/esp_driver_usb_serial_jtag/test_apps/usb_serial_jtag:
1111
- vfs
1212
- esp_driver_gpio
1313
- esp_driver_usb_serial_jtag
14+
15+
components/esp_driver_usb_serial_jtag/test_apps/usb_serial_jtag_vfs:
16+
disable:
17+
- if: SOC_USB_SERIAL_JTAG_SUPPORTED != 1
18+
disable_test:
19+
- if: IDF_TARGET in ["esp32p4", "esp32c5", "esp32c61"]
20+
temporary: true
21+
reason: No runners.
22+
depends_components:
23+
- vfs
24+
- esp_driver_usb_serial_jtag

0 commit comments

Comments
 (0)