summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhathach <[email protected]>2026-04-02 23:30:06 +0700
committerhathach <[email protected]>2026-04-03 10:45:13 +0700
commit134e14849b1864ce3454950a50d2c79d93a96cd8 (patch)
treea4c7f1d6eac8e5483c40789c895bc4ea3a71f5d6
parentb3d34cdf8962186d326dadf50421bb85f488c80a (diff)
fix hil host cdc echo test with imxrt and other fast mcu
-rw-r--r--examples/CMakeLists.txt6
-rw-r--r--examples/host/cdc_msc_hid/src/cdc_app.c76
-rw-r--r--examples/host/cdc_msc_hid/src/tusb_config.h5
-rw-r--r--examples/host/cdc_msc_hid_freertos/src/cdc_app.c4
-rw-r--r--examples/host/msc_file_explorer/src/main.c33
-rw-r--r--hw/bsp/board.c19
-rw-r--r--hw/bsp/board_api.h6
-rw-r--r--hw/bsp/espressif/boards/family.c4
-rw-r--r--hw/bsp/imxrt/family.c13
-rw-r--r--hw/bsp/rp2040/family.c4
-rwxr-xr-xtest/hil/hil_test.py7
11 files changed, 87 insertions, 90 deletions
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index b458c9ce3..7669290a8 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -26,9 +26,3 @@ add_custom_target(tinyusb_metrics
COMMENT "Generating average code size metrics"
VERBATIM
)
-
-#add_custom_command(TARGET tinyusb_metrics POST_BUILD
-# COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/../tools/metrics.py compare ${TOP}/cmake-build/cmake-build-${BOARD}/metrics.json ${CMAKE_BINARY_DIR}/metrics.json
-# COMMENT "Generating average code size metrics"
-# VERBATIM
-# )
diff --git a/examples/host/cdc_msc_hid/src/cdc_app.c b/examples/host/cdc_msc_hid/src/cdc_app.c
index 4c2c5e807..c897bdd06 100644
--- a/examples/host/cdc_msc_hid/src/cdc_app.c
+++ b/examples/host/cdc_msc_hid/src/cdc_app.c
@@ -28,11 +28,13 @@
#include "bsp/board_api.h"
#include "app.h"
-static size_t get_console_inputs(uint8_t* buf, size_t bufsize) {
+static size_t console_read(uint8_t *buf, size_t bufsize) {
size_t count = 0;
while (count < bufsize) {
- int ch = board_getchar();
- if (ch <= 0) { break; }
+ const int ch = board_getchar();
+ if (ch < 0) {
+ break;
+ }
buf[count] = (uint8_t) ch;
count++;
}
@@ -40,46 +42,54 @@ static size_t get_console_inputs(uint8_t* buf, size_t bufsize) {
return count;
}
+static size_t console_write(const uint8_t *buf, size_t bufsize) {
+ size_t count = 0;
+ while (count < bufsize) {
+ if (board_putchar((int)buf[count]) < 0) {
+ break;
+ }
+ count++;
+ }
+ return count;
+}
+
+// forward from console to usbh
+static void console_to_usbh(uint8_t idx) {
+ uint8_t buf[64];
+ size_t count = console_read(buf, sizeof(buf));
+ if (count > 0) {
+ tuh_cdc_write(idx, buf, count);
+ }
+}
+
void cdc_app_task(void) {
- uint8_t buf[64 + 1]; // +1 for extra null character
- uint32_t const bufsize = sizeof(buf) - 1;
+ const uint8_t idx = 0;
+
+ // Bidirectional forwarding: console <-> host cdc interfaces
+ if (!tuh_cdc_mounted(idx)) {
+ return;
+ }
- uint32_t count = get_console_inputs(buf, bufsize);
- buf[count] = 0;
+ // usbh -> uart
+ uint8_t buf[64];
+ uint32_t count = tuh_cdc_read(idx, buf, sizeof(buf));
+ uint32_t wr = 0;
- // loop over all mounted interfaces
- for (uint8_t idx = 0; idx < CFG_TUH_CDC; idx++) {
- if (tuh_cdc_mounted(idx)) {
- // console --> cdc interfaces
- if (count > 0) {
- tuh_cdc_write(idx, buf, count);
- tuh_cdc_write_flush(idx);
- }
+ do {
+ // uart write is slow, while waiting forward uart -> usbh else uart rx can be overflow
+ if (count) {
+ wr += console_write(buf + wr, count);
}
- }
+ console_to_usbh(idx);
+ } while (wr < count);
+
+ tuh_cdc_write_flush(idx);
}
//--------------------------------------------------------------------+
// TinyUSB callbacks
//--------------------------------------------------------------------+
-// Invoked when received new data
-void tuh_cdc_rx_cb(uint8_t idx) {
- uint8_t buf[64 + 1]; // +1 for extra null character
- uint32_t const bufsize = sizeof(buf) - 1;
-
- // forward cdc interfaces -> console
- const uint32_t count = tuh_cdc_read(idx, buf, bufsize);
- if (count) {
- buf[count] = 0;
- printf("%s", (char*) buf);
-
- #ifndef __ICCARM__ // TODO IAR doesn't support stream control ?
- fflush(stdout);// flush right away, else nanolib will wait for newline
- #endif
- }
-}
-
// Invoked when a device with CDC interface is mounted
// idx is index of cdc interface in the internal pool.
void tuh_cdc_mount_cb(uint8_t idx) {
diff --git a/examples/host/cdc_msc_hid/src/tusb_config.h b/examples/host/cdc_msc_hid/src/tusb_config.h
index 75de3511c..26fcdd1cb 100644
--- a/examples/host/cdc_msc_hid/src/tusb_config.h
+++ b/examples/host/cdc_msc_hid/src/tusb_config.h
@@ -102,8 +102,11 @@
// Size of buffer to hold descriptors and other data used for enumeration
#define CFG_TUH_ENUMERATION_BUFSIZE 256
+// Increase task event queue to handle rapid bulk transfer completions
+#define CFG_TUH_TASK_QUEUE_SZ 64
+
#define CFG_TUH_HUB 1 // number of supported hubs
-#define CFG_TUH_CDC 2 // number of supported CDC devices. also activates CDC ACM
+#define CFG_TUH_CDC 1 // number of supported CDC devices. also activates CDC ACM
#define CFG_TUH_CDC_FTDI 1 // FTDI Serial. FTDI is not part of CDC class, only to re-use CDC driver API
#define CFG_TUH_CDC_CP210X 1 // CP210x Serial. CP210X is not part of CDC class, only to re-use CDC driver API
#define CFG_TUH_CDC_CH34X 1 // CH340 or CH341 Serial. CH34X is not part of CDC class, only to re-use CDC driver API
diff --git a/examples/host/cdc_msc_hid_freertos/src/cdc_app.c b/examples/host/cdc_msc_hid_freertos/src/cdc_app.c
index 0e0105980..30baacaac 100644
--- a/examples/host/cdc_msc_hid_freertos/src/cdc_app.c
+++ b/examples/host/cdc_msc_hid_freertos/src/cdc_app.c
@@ -53,7 +53,7 @@ void cdc_app_init(void) {
}
// helper
-static size_t get_console_inputs(uint8_t *buf, size_t bufsize) {
+static size_t console_read(uint8_t *buf, size_t bufsize) {
size_t count = 0;
while (count < bufsize) {
int ch = board_getchar();
@@ -75,7 +75,7 @@ static void cdc_app_task(void* param) {
uint32_t const bufsize = sizeof(buf) - 1;
while (1) {
- uint32_t count = get_console_inputs(buf, bufsize);
+ uint32_t count = console_read(buf, bufsize);
buf[count] = 0;
if (count) {
diff --git a/examples/host/msc_file_explorer/src/main.c b/examples/host/msc_file_explorer/src/main.c
index f6bf9a60a..07515e626 100644
--- a/examples/host/msc_file_explorer/src/main.c
+++ b/examples/host/msc_file_explorer/src/main.c
@@ -23,39 +23,6 @@
*
*/
-/* Example to show how to navigate mass storage device with built-in command line.
- * Type help for list of supported commands and syntax (mostly linux commands)
-
- > help
- * help
- Print list of commands
- * cat
- Usage: cat [FILE]...
- Concatenate FILE(s) to standard output..
- * cd
- Usage: cd [DIR]...
- Change the current directory to DIR.
- * cp
- Usage: cp SOURCE DEST
- Copy SOURCE to DEST.
- * ls
- Usage: ls [DIR]...
- List information about the FILEs (the current directory by default).
- * pwd
- Usage: pwd
- Print the name of the current working directory.
- * mkdir
- Usage: mkdir DIR...
- Create the DIRECTORY(ies), if they do not already exist..
- * mv
- Usage: mv SOURCE DEST...
- Rename SOURCE to DEST.
- * rm
- Usage: rm [FILE]...
- Remove (unlink) the FILE(s).
- */
-
-#include <stdlib.h>
#include <string.h>
#include "bsp/board_api.h"
diff --git a/hw/bsp/board.c b/hw/bsp/board.c
index 71c209950..1c159189c 100644
--- a/hw/bsp/board.c
+++ b/hw/bsp/board.c
@@ -97,9 +97,17 @@ int sys_read (int fhdl, char *buf, size_t count) {
#else
// Default logging with on-board UART
+// Retry to ensure printf/log output is not lost when board_uart_write is non-blocking
int sys_write (int fhdl, const char *buf, size_t count) {
(void) fhdl;
- return board_uart_write(buf, (int) count);
+ int written = 0;
+ while ((size_t)written < count) {
+ int wr = board_uart_write(buf + written, (int)(count - (size_t)written));
+ if (wr > 0) {
+ written += wr;
+ }
+ }
+ return written;
}
int sys_read (int fhdl, char *buf, size_t count) {
@@ -157,10 +165,13 @@ int board_getchar(void) {
return (sys_read(0, &c, 1) > 0) ? (int) c : (-1);
}
-void board_putchar(int c) {
- (void) sys_write(0, (const char*)&c, 1);
+int board_putchar(int c) {
+ if (board_uart_write((const char *)&c, 1)) {
+ return c;
+ } else {
+ return -1;
+ }
}
-
//--------------------------------------------------------------------
// FreeRTOS hooks
//--------------------------------------------------------------------
diff --git a/hw/bsp/board_api.h b/hw/bsp/board_api.h
index 4487871eb..73c06078a 100644
--- a/hw/bsp/board_api.h
+++ b/hw/bsp/board_api.h
@@ -92,10 +92,10 @@ uint32_t board_button_read(void);
// Get board unique ID for USB serial number. Return number of bytes. Note max_len is typically 16
size_t board_get_unique_id(uint8_t id[], size_t max_len);
-// Get characters from UART. Return number of read bytes
+// Get characters from UART (non-blocking). Return number of read bytes.
int board_uart_read(uint8_t *buf, int len);
-// Send characters to UART. Return number of sent bytes
+// Send characters to UART (non-blocking). Return number of sent bytes
int board_uart_write(void const *buf, int len);
//--------------------------------------------------------------------+
@@ -153,7 +153,7 @@ static inline void board_delay(uint32_t ms) {
// stdio getchar() is blocking, this is non-blocking version
int board_getchar(void);
-void board_putchar(int c);
+int board_putchar(int c);
#ifdef __cplusplus
}
diff --git a/hw/bsp/espressif/boards/family.c b/hw/bsp/espressif/boards/family.c
index 04d8a4001..48b1253b6 100644
--- a/hw/bsp/espressif/boards/family.c
+++ b/hw/bsp/espressif/boards/family.c
@@ -162,8 +162,8 @@ int board_getchar(void) {
return getchar();
}
-void board_putchar(int c) {
- putchar(c);
+int board_putchar(int c) {
+ return putchar(c);
}
void board_init_after_tusb(void) {
diff --git a/hw/bsp/imxrt/family.c b/hw/bsp/imxrt/family.c
index c1ee34b1a..9f3297e9a 100644
--- a/hw/bsp/imxrt/family.c
+++ b/hw/bsp/imxrt/family.c
@@ -229,8 +229,17 @@ int board_uart_read(uint8_t *buf, int len) {
}
int board_uart_write(void const *buf, int len) {
- LPUART_WriteBlocking(UART_PORT, (uint8_t const *) buf, len);
- return len;
+ const uint8_t *p = (const uint8_t *)buf;
+ int count = 0;
+ while (count < len) {
+ if (LPUART_GetStatusFlags(UART_PORT) & kLPUART_TxDataRegEmptyFlag) {
+ LPUART_WriteByte(UART_PORT, p[count]);
+ count++;
+ } else {
+ break;
+ }
+ }
+ return count;
}
#if CFG_TUSB_OS == OPT_OS_NONE
diff --git a/hw/bsp/rp2040/family.c b/hw/bsp/rp2040/family.c
index c64025036..c952de03b 100644
--- a/hw/bsp/rp2040/family.c
+++ b/hw/bsp/rp2040/family.c
@@ -288,8 +288,8 @@ int board_getchar(void) {
return getchar_timeout_us(0);
}
-void board_putchar(int c) {
- stdio_putchar(c);
+int board_putchar(int c) {
+ return stdio_putchar(c);
}
void board_init_after_tusb(void) {
diff --git a/test/hil/hil_test.py b/test/hil/hil_test.py
index cf3cff1a3..40779d1a4 100755
--- a/test/hil/hil_test.py
+++ b/test/hil/hil_test.py
@@ -564,7 +564,7 @@ def test_host_cdc_msc_hid(board):
ser.flush()
# wait until this chunk is echoed back
echo = b''
- t_end = time.monotonic() + 5.0
+ t_end = time.monotonic() + 1.0
while time.monotonic() < t_end and len(echo) < chunk_size:
rd = ser.read(chunk_size - len(echo))
if rd:
@@ -1189,7 +1189,7 @@ def test_example(board, f1, example):
print(f'Flashing {fw_name}.elf')
# flash firmware. It may fail randomly, retry a few times
- max_rety = 3
+ max_rety = max_retry
start_s = time.time()
for i in range(max_rety):
ret = globals()[f'flash_{board["flasher"]["name"].lower()}'](board, fw_name)
@@ -1269,6 +1269,7 @@ def main():
global verbose
global test_only
global build_dir
+ global max_retry
duration = time.time()
@@ -1278,6 +1279,7 @@ def main():
parser.add_argument('-s', '--skip', action='append', default=[], help='Skip boards from test')
parser.add_argument('-t', '--test-only', action='append', default=[], help='Tests to run, all if not specified')
parser.add_argument('-B', '--build', default='cmake-build', help='Build folder name (default: cmake-build)')
+ parser.add_argument('-r', '--retry', type=int, default=3, help='Retry count for failed tests (default: 3)')
parser.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
args = parser.parse_args()
@@ -1287,6 +1289,7 @@ def main():
verbose = args.verbose
test_only = args.test_only
build_dir = args.build
+ max_retry = args.retry
# if config file is not found, try to find it in the same directory as this script
if not os.path.exists(config_file):