From a3b2b4217630eea3f514ee042ee399e9ee397b8a Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 17 Mar 2026 14:58:45 +0700 Subject: [PATCH] add hil host cdc test --- AGENTS.md | 1 - hw/bsp/stm32h7/boards/stm32h743eval/board.h | 20 ++++-- hw/bsp/stm32h7/family.c | 20 +++++- test/hil/hil_test.py | 75 +++++++++++++++++++++ test/hil/tinyusb.json | 16 ++--- 5 files changed, 117 insertions(+), 15 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 4e510b01e..d491f94f1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -27,7 +27,6 @@ information that does not match the info here. ## Build Examples Choose ONE of these approaches: - **Option 1: Individual Example with CMake and Ninja (RECOMMENDED)** ```bash diff --git a/hw/bsp/stm32h7/boards/stm32h743eval/board.h b/hw/bsp/stm32h7/boards/stm32h743eval/board.h index d2f61a5ce..3914d7aac 100644 --- a/hw/bsp/stm32h7/boards/stm32h743eval/board.h +++ b/hw/bsp/stm32h7/boards/stm32h743eval/board.h @@ -205,13 +205,25 @@ static int32_t board_i2c_deinit(void) { } static int32_t i2c_readreg(uint16_t DevAddr, uint16_t Reg, uint8_t *pData, uint16_t Length) { - TU_ASSERT (HAL_OK == HAL_I2C_Mem_Read(&i2c_handle, DevAddr, Reg, I2C_MEMADD_SIZE_8BIT, pData, Length, 10000)); - return 0; + for (int retry = 0; retry < 3; retry++) { + if (HAL_OK == HAL_I2C_Mem_Read(&i2c_handle, DevAddr, Reg, I2C_MEMADD_SIZE_8BIT, pData, Length, 10000)) { + return 0; + } + HAL_Delay(10); + } + TU_ASSERT(0); + return -1; } static int32_t i2c_writereg(uint16_t DevAddr, uint16_t Reg, uint8_t *pData, uint16_t Length) { - TU_ASSERT(HAL_OK == HAL_I2C_Mem_Write(&i2c_handle, DevAddr, Reg, I2C_MEMADD_SIZE_8BIT, pData, Length, 10000)); - return 0; + for (int retry = 0; retry < 3; retry++) { + if (HAL_OK == HAL_I2C_Mem_Write(&i2c_handle, DevAddr, Reg, I2C_MEMADD_SIZE_8BIT, pData, Length, 10000)) { + return 0; + } + HAL_Delay(10); + } + TU_ASSERT(0); + return -1; } static int32_t i2c_get_tick(void) { diff --git a/hw/bsp/stm32h7/family.c b/hw/bsp/stm32h7/family.c index c94c2e755..a95674217 100644 --- a/hw/bsp/stm32h7/family.c +++ b/hw/bsp/stm32h7/family.c @@ -275,9 +275,25 @@ size_t board_get_unique_id(uint8_t id[], size_t max_len) { } int board_uart_read(uint8_t *buf, int len) { - (void) buf; - (void) len; +#ifdef UART_DEV + int count = 0; + // clear overrun error if any + if (__HAL_UART_GET_FLAG(&UartHandle, UART_FLAG_ORE)) { + __HAL_UART_CLEAR_FLAG(&UartHandle, UART_CLEAR_OREF); + } + for (int i = 0; i < len; i++) { + if (__HAL_UART_GET_FLAG(&UartHandle, UART_FLAG_RXNE)) { + buf[i] = (uint8_t) UartHandle.Instance->RDR; + count++; + } else { + break; + } + } + return count; +#else + (void) buf; (void) len; return 0; +#endif } int board_uart_write(void const *buf, int len) { diff --git a/test/hil/hil_test.py b/test/hil/hil_test.py index 7cffd2da8..65585d929 100755 --- a/test/hil/hil_test.py +++ b/test/hil/hil_test.py @@ -416,6 +416,80 @@ def test_host_device_info(board): return 0 +def test_host_cdc_msc_hid(board): + flasher = board['flasher'] + cdc_devs = [d for d in board['tests'].get('dev_attached', []) if d.get('is_cdc')] + if not cdc_devs: + return + + port = get_serial_dev(flasher["uid"], None, None, 0) + ser = open_serial_dev(port) + ser.timeout = 0.1 + + # reset device to catch mount messages + ret = globals()[f'reset_{flasher["name"].lower()}'](board) + assert ret.returncode == 0, 'Failed to reset device' + + # Wait for CDC mounted message + data = b'' + timeout = ENUM_TIMEOUT + while timeout > 0: + new_data = ser.read(ser.in_waiting or 1) + if new_data: + data += new_data + if b'CDC Interface is mounted' in data: + break + time.sleep(0.1) + timeout -= 0.1 + assert b'CDC Interface is mounted' in data, 'CDC device not mounted on host' + + # Lookup serial chip name from vid_pid + vid_pid_name = { + '0403_6001': 'FTDI', '0403_6010': 'FTDI', '0403_6011': 'FTDI', '0403_6014': 'FTDI', + '10c4_ea60': 'CP210x', '10c4_ea70': 'CP210x', + '067b_2303': 'PL2303', '067b_23a3': 'PL2303', + '1a86_7523': 'CH340', '1a86_7522': 'CH340', + '1a86_55d3': 'CH9102', '1a86_55d4': 'CH9102', + } + dev = cdc_devs[0] + chip_name = vid_pid_name.get(dev['vid_pid'], dev['vid_pid']) + for l in data.decode('utf-8', errors='ignore').splitlines(): + if 'CDC Interface is mounted' in l: + print(f'\r\n {chip_name}: {l} ', end='') + + # CDC echo test via flasher serial + time.sleep(2) + ser.reset_input_buffer() + + def rand_ascii(length): + return "".join(random.choices(string.ascii_letters + string.digits, k=length)).encode("ascii") + + sizes = [8, 32, 64, 128] + for size in sizes: + test_data = rand_ascii(size) + ser.reset_input_buffer() + + # Write byte-by-byte with delay to avoid UART overrun + for b in test_data: + ser.write(bytes([b])) + ser.flush() + time.sleep(0.001) + + # Read echo back with timeout + echo = b'' + t = 5.0 + while t > 0 and len(echo) < size: + rd = ser.read(max(1, ser.in_waiting)) + if rd: + echo += rd + time.sleep(0.05) + t -= 0.05 + assert echo == test_data, (f'CDC echo wrong data ({size} bytes):\n' + f' expected: {test_data}\n received: {echo}') + + ser.close() + + # ------------------------------------------------------------- # Tests: device # ------------------------------------------------------------- @@ -763,6 +837,7 @@ dual_tests = [ ] host_test = [ + 'host/cdc_msc_hid', 'host/device_info', ] diff --git a/test/hil/tinyusb.json b/test/hil/tinyusb.json index e8449ba74..eaf60c6ce 100644 --- a/test/hil/tinyusb.json +++ b/test/hil/tinyusb.json @@ -8,7 +8,7 @@ }, "tests": { "only": ["device/cdc_msc_freertos", "device/hid_composite_freertos", "host/device_info"], - "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2002427"}] + "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2002427", "is_cdc": true}] }, "flasher": { "name": "esptool", @@ -26,7 +26,7 @@ }, "tests": { "only": ["device/cdc_msc_freertos", "device/hid_composite_freertos", "host/device_info"], - "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2005402"}] + "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2005402", "is_cdc": true}] }, "flasher": { "name": "esptool", @@ -67,7 +67,7 @@ }, "tests": { "device": true, "host": false, "dual": true, - "dev_attached": [{"vid_pid": "067b_2303", "serial": "0"}], + "dev_attached": [{"vid_pid": "067b_2303", "serial": "0", "is_cdc": true}], "comment": "pl23x" }, "flasher": { @@ -93,7 +93,7 @@ "uid": "BAE96FB95AFA6DBB8F00005002001200", "tests": { "device": true, "host": true, "dual": true, - "dev_attached": [{"vid_pid": "10c4_ea60", "serial": "0001"}], + "dev_attached": [{"vid_pid": "10c4_ea60", "serial": "0001", "is_cdc": true}], "comment": "cp2102" }, "flasher": { @@ -136,7 +136,7 @@ }, "tests": { "device": true, "host": true, "dual": true, - "dev_attached": [{"vid_pid": "1a86_7523", "serial": "0"}], + "dev_attached": [{"vid_pid": "1a86_7523", "serial": "0", "is_cdc": true}], "comment": "ch34x" }, "flasher": { @@ -150,7 +150,7 @@ "uid": "E6614C311B764A37", "tests": { "device": false, "host": true, "dual": false, - "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2023934"}] + "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2023934", "is_cdc": true}] }, "flasher": { "name": "openocd", @@ -167,7 +167,7 @@ }, "tests": { "device": true, "host": true, "dual": true, - "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "533D004242"}] + "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "533D004242", "is_cdc": true}] }, "flasher": { "name": "openocd", @@ -193,7 +193,7 @@ }, "tests": { "device": true, "host": true, "dual": false, - "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2003414"}] + "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2003414", "is_cdc": true}] }, "flasher": { "name": "jlink",