Skip to content

Commit 740762c

Browse files
committed
feat(usb_serial_jtag): Update vfs read to be POSIX compliant
The function now returns with available data in blocking mode instead of waiting for the requested size to be available before returning.
1 parent 139df47 commit 740762c

File tree

4 files changed

+82
-34
lines changed

4 files changed

+82
-34
lines changed

components/esp_driver_usb_serial_jtag/include/driver/usb_serial_jtag_select.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11

22
/*
3-
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
3+
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
44
*
55
* SPDX-License-Identifier: Apache-2.0
66
*/
@@ -27,6 +27,13 @@ typedef void (*usj_select_notif_callback_t)(usj_select_notif_t usb_serial_jtag_s
2727
*/
2828
void usb_serial_jtag_set_select_notif_callback(usj_select_notif_callback_t usb_serial_jtag_select_notif_callback);
2929

30+
/**
31+
* @brief Return the number of bytes available for reading
32+
*
33+
* @return the number of bytes available for reading in the buffer
34+
*/
35+
size_t usb_serial_jtag_get_read_bytes_available(void);
36+
3037
/**
3138
* @brief Return the readiness status of the driver for read operation
3239
*

components/esp_driver_usb_serial_jtag/src/usb_serial_jtag.c

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -366,12 +366,23 @@ void usb_serial_jtag_set_select_notif_callback(usj_select_notif_callback_t usj_s
366366
}
367367
}
368368

369-
bool usb_serial_jtag_read_ready(void)
369+
size_t usb_serial_jtag_get_read_bytes_available(void)
370370
{
371371
// sign the the driver is read ready is that data is waiting in the RX ringbuffer
372-
UBaseType_t items_waiting = 0;
373-
vRingbufferGetInfo(p_usb_serial_jtag_obj->rx_ring_buf, NULL, NULL, NULL, NULL, &items_waiting);
374-
return items_waiting != 0;
372+
UBaseType_t bytes_available = 0;
373+
if (usb_serial_jtag_is_driver_installed()) {
374+
vRingbufferGetInfo(p_usb_serial_jtag_obj->rx_ring_buf, NULL, NULL, NULL, NULL, &bytes_available);
375+
if (bytes_available <= 0) {
376+
return 0;
377+
}
378+
}
379+
380+
return (size_t)bytes_available;
381+
}
382+
383+
bool usb_serial_jtag_read_ready(void)
384+
{
385+
return usb_serial_jtag_get_read_bytes_available() != 0;
375386
}
376387

377388
bool usb_serial_jtag_write_ready(void)

components/esp_driver_usb_serial_jtag/src/usb_serial_jtag_vfs.c

Lines changed: 57 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -229,36 +229,66 @@ static ssize_t usb_serial_jtag_read(int fd, void* data, size_t size)
229229
assert(fd == USJ_LOCAL_FD);
230230
char *data_c = (char *) data;
231231
size_t received = 0;
232+
size_t available_size = 0;
233+
int c = NONE; // store the read char
232234
_lock_acquire_recursive(&s_ctx.read_lock);
233235

234-
while (received < size) {
235-
int c = usb_serial_jtag_read_char(fd);
236-
if (c == '\r') {
237-
if (s_ctx.rx_mode == ESP_LINE_ENDINGS_CR) {
238-
c = '\n';
239-
} else if (s_ctx.rx_mode == ESP_LINE_ENDINGS_CRLF) {
240-
/* look ahead */
241-
int c2 = usb_serial_jtag_read_char(fd);
242-
if (c2 == NONE) {
243-
/* could not look ahead, put the current character back */
244-
usb_serial_jtag_return_char(fd, c);
245-
break;
246-
}
247-
if (c2 == '\n') {
248-
/* this was \r\n sequence. discard \r, return \n */
236+
// if blocking read, wait for data to be available
237+
if (!s_ctx.non_blocking) {
238+
c = usb_serial_jtag_read_char(fd);
239+
}
240+
241+
// find the actual fetch size
242+
available_size += usb_serial_jtag_get_read_bytes_available();
243+
if (c != NONE) {
244+
available_size++;
245+
}
246+
if (s_ctx.peek_char != NONE) {
247+
available_size++;
248+
}
249+
size_t fetch_size = MIN(available_size, size);
250+
251+
if (fetch_size > 0) {
252+
do {
253+
if (c == NONE) { // for non-O_NONBLOCK mode, there is already a pre-fetched char
254+
c = usb_serial_jtag_read_char(fd);
255+
}
256+
assert(c != NONE);
257+
258+
if (c == '\r') {
259+
if (s_ctx.rx_mode == ESP_LINE_ENDINGS_CR) {
249260
c = '\n';
250-
} else {
251-
/* \r followed by something else. put the second char back,
252-
* it will be processed on next iteration. return \r now.
253-
*/
254-
usb_serial_jtag_return_char(fd, c2);
261+
} else if (s_ctx.rx_mode == ESP_LINE_ENDINGS_CRLF) {
262+
/* look ahead */
263+
int c2 = usb_serial_jtag_read_char(fd);
264+
fetch_size--;
265+
if (c2 == NONE) {
266+
/* could not look ahead, put the current character back */
267+
usb_serial_jtag_return_char(fd, c);
268+
c = NONE;
269+
break;
270+
}
271+
if (c2 == '\n') {
272+
/* this was \r\n sequence. discard \r, return \n */
273+
c = '\n';
274+
} else {
275+
/* \r followed by something else. put the second char back,
276+
* it will be processed on next iteration. return \r now.
277+
*/
278+
usb_serial_jtag_return_char(fd, c2);
279+
fetch_size++;
280+
}
255281
}
256282
}
257-
} else if (c == NONE) {
258-
break;
259-
}
260-
data_c[received] = (char) c;
261-
++received;
283+
284+
data_c[received] = (char) c;
285+
++received;
286+
c = NONE;
287+
} while (received < fetch_size);
288+
}
289+
290+
if (c != NONE) { // fetched, but not used
291+
usb_serial_jtag_return_char(fd, c);
262292
}
263293
_lock_release_recursive(&s_ctx.read_lock);
264294
if (received > 0) {
@@ -454,7 +484,7 @@ static esp_err_t usb_serial_jtag_start_select(int nfds, fd_set *readfds, fd_set
454484
bool trigger_select = false;
455485

456486
// check if the select should return instantly if the bus is read ready
457-
if (FD_ISSET(USJ_LOCAL_FD, &args->readfds_orig) && usb_serial_jtag_read_ready()) {
487+
if (FD_ISSET(USJ_LOCAL_FD, &args->readfds_orig) && (usb_serial_jtag_get_read_bytes_available() > 0)) {
458488
// signal immediately when data is buffered
459489
FD_SET(USJ_LOCAL_FD, readfds);
460490
trigger_select = true;

components/esp_driver_usb_serial_jtag/test_apps/usb_serial_jtag_vfs/pytest_usb_serial_jtag_vfs.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ def test_usj_vfs_select(dut: Dut, test_message: list) -> None:
3434
)
3535
@pytest.mark.parametrize('test_message', ['!(@*#&(!*@&#((SDasdkjhad\nce'])
3636
@idf_parametrize('target', ['esp32s3', 'esp32c3', 'esp32c6', 'esp32h2'], indirect=['target'])
37-
def test_usj_vfs_read(dut: Dut, test_message: list) -> None:
37+
def test_usj_vfs_read_return(dut: Dut, test_message: list) -> None:
3838
dut.expect_exact('Press ENTER to see the list of tests')
3939
dut.write('"read does not return on new line character"')
4040
dut.expect_exact('ready to receive', timeout=2)
@@ -52,7 +52,7 @@ def test_usj_vfs_read(dut: Dut, test_message: list) -> None:
5252
)
5353
@pytest.mark.parametrize('test_message', ['testdata'])
5454
@idf_parametrize('target', ['esp32s3', 'esp32c3', 'esp32c6', 'esp32h2'], indirect=['target'])
55-
def test_usj_vfs_read(dut: Dut, test_message: list) -> None:
55+
def test_usj_vfs_read_blocking(dut: Dut, test_message: list) -> None:
5656
dut.expect_exact('Press ENTER to see the list of tests')
5757
dut.write('"blocking read returns with available data"')
5858
dut.expect_exact('ready to receive', timeout=2)

0 commit comments

Comments
 (0)