diff options
| author | hathach <[email protected]> | 2025-09-15 16:45:41 +0700 |
|---|---|---|
| committer | hathach <[email protected]> | 2025-09-15 16:45:41 +0700 |
| commit | 8e34ba9cf6bdcabe2c9eb73ae1aafec38d0ec46d (patch) | |
| tree | 58c2426146aa5d413706a62521ab6e2cb740b170 /test | |
| parent | 802819d271314298ea5a786a37ec6a1e65ef31d6 (diff) | |
| parent | feef534921446e1a3ded54a0c46191fe1709bdb4 (diff) | |
Merge branch 'master' into fork/ennebi/mtp
Diffstat (limited to 'test')
| -rw-r--r-- | test/fuzz/device/net/Makefile | 2 | ||||
| -rw-r--r-- | test/fuzz/make.mk | 6 | ||||
| -rw-r--r-- | test/fuzz/rules.mk | 2 | ||||
| -rw-r--r-- | test/hil/hil_ci_set_matrix.py | 20 | ||||
| -rwxr-xr-x | test/hil/hil_test.py | 164 | ||||
| -rw-r--r-- | test/hil/tinyusb.json | 54 | ||||
| -rw-r--r-- | test/unit-test/test/device/msc/test_msc_device.c | 18 |
7 files changed, 168 insertions, 98 deletions
diff --git a/test/fuzz/device/net/Makefile b/test/fuzz/device/net/Makefile index 4e99604ad..2161ad3f1 100644 --- a/test/fuzz/device/net/Makefile +++ b/test/fuzz/device/net/Makefile @@ -1,5 +1,3 @@ -DEPS_SUBMODULES += lib/lwip - include ../../make.mk # suppress warning caused by lwip diff --git a/test/fuzz/make.mk b/test/fuzz/make.mk index b7b6d6a75..e9aa80bf1 100644 --- a/test/fuzz/make.mk +++ b/test/fuzz/make.mk @@ -124,11 +124,5 @@ endif # Log level is mapped to TUSB DEBUG option ifneq ($(LOG),) - CMAKE_DEFSYM += -DLOG=$(LOG) CFLAGS += -DCFG_TUSB_DEBUG=$(LOG) endif - -# Logger: default is uart, can be set to rtt or swo -ifneq ($(LOGGER),) - CMAKE_DEFSYM += -DLOGGER=$(LOGGER) -endif diff --git a/test/fuzz/rules.mk b/test/fuzz/rules.mk index 24d6cc0d7..b32f8d695 100644 --- a/test/fuzz/rules.mk +++ b/test/fuzz/rules.mk @@ -143,7 +143,7 @@ endif # get depenecies .PHONY: get-deps get-deps: - $(PYTHON) $(TOP)/tools/get_deps.py $(DEPS_SUBMODULES) + $(PYTHON) $(TOP)/tools/get_deps.py $(FAMILY) size: $(BUILD)/$(PROJECT) -@echo '' diff --git a/test/hil/hil_ci_set_matrix.py b/test/hil/hil_ci_set_matrix.py index 67ce2abb8..ecd964d87 100644 --- a/test/hil/hil_ci_set_matrix.py +++ b/test/hil/hil_ci_set_matrix.py @@ -28,14 +28,20 @@ def main(): else: toolchain = 'arm-gcc' - if 'build' in board and 'flags_on' in board['build']: - for f in board['build']['flags_on']: - if f == '': - matrix[toolchain].append(f'-b {name}') - else: - matrix[toolchain].append(f'-b {name} -f1 {f.replace(" ", " -f1 ")}') + build_board = f'-b {name}' + if 'build' in board: + if 'args' in board['build']: + build_board += ' ' + ' '.join(f'-D{a}' for a in board['build']['args']) + if 'flags_on' in board['build']: + for f in board['build']['flags_on']: + if f == '': + matrix[toolchain].append(build_board) + else: + matrix[toolchain].append(f'{build_board} -f1 {f.replace(" ", " -f1 ")}') + else: + matrix[toolchain].append(build_board) else: - matrix[toolchain].append(f'-b {name}') + matrix[toolchain].append(build_board) print(json.dumps(matrix)) diff --git a/test/hil/hil_test.py b/test/hil/hil_test.py index a9f5dc1e1..93cc0a750 100755 --- a/test/hil/hil_test.py +++ b/test/hil/hil_test.py @@ -81,7 +81,7 @@ def get_serial_dev(id, vendor_str, product_str, ifnum): return f'/dev/serial/by-id/usb-{vendor_str}_{product_str}_{id}-if{ifnum:02d}' else: # just use id: mostly for cp210x/ftdi flasher - pattern = f'/dev/serial/by-id/usb-*_{id}-if{ifnum:02d}*' + pattern = f'/dev/serial/by-id/usb-*_{id}-if*' port_list = glob.glob(pattern) return port_list[0] @@ -98,20 +98,18 @@ def get_hid_dev(id, vendor_str, product_str, event): def open_serial_dev(port): timeout = ENUM_TIMEOUT ser = None - while timeout: + while timeout > 0: if os.path.exists(port): try: - # slight delay since kernel may occupy the port briefly - time.sleep(0.5) - timeout = timeout - 0.5 ser = serial.Serial(port, baudrate=115200, timeout=5) break except serial.SerialException: + print(f'serial {port} not reaady {timeout} sec') pass - time.sleep(0.5) - timeout = timeout - 0.5 + time.sleep(0.1) + timeout -= 0.1 - assert timeout, f'Cannot open port f{port}' if os.path.exists(port) else f'Port {port} not existed' + assert timeout > 0, f'Cannot open port f{port}' if os.path.exists(port) else f'Port {port} not existed' return ser @@ -119,7 +117,7 @@ def read_disk_file(uid, lun, fname): # open_fs("fat://{dev}) require 'pip install pyfatfs' dev = get_disk_dev(uid, 'TinyUSB', lun) timeout = ENUM_TIMEOUT - while timeout: + while timeout > 0: if os.path.exists(dev): fat = fs.open_fs(f'fat://{dev}?read_only=true') try: @@ -132,7 +130,7 @@ def read_disk_file(uid, lun, fname): time.sleep(1) timeout -= 1 - assert timeout, f'Storage {dev} not existed' + assert timeout > 0, f'Storage {dev} not existed' return None @@ -202,14 +200,14 @@ def reset_stflash(board): def flash_openocd(board, firmware): flasher = board['flasher'] ret = run_cmd(f'openocd -c "tcl_port disabled" -c "gdb_port disabled" -c "adapter serial {flasher["uid"]}" ' - f'{flasher["args"]} -c init -c halt -c "program {firmware}.elf verify" -c reset -c exit') + f'{flasher["args"]} -c "init; halt; program {firmware}.elf verify; reset; exit"') return ret def reset_openocd(board): flasher = board['flasher'] ret = run_cmd(f'openocd -c "tcl_port disabled" -c "gdb_port disabled" -c "adapter serial {flasher["uid"]}" ' - f'{flasher["args"]} -c "reset exit"') + f'{flasher["args"]} -c "init; reset run; exit"') return ret @@ -304,11 +302,11 @@ def test_dual_host_info_to_device_cdc(board): ser = open_serial_dev(port) # read from cdc, first line should contain vid/pid and serial - data = ser.read(1000) + data = ser.read(10000) ser.close() if len(data) == 0: assert False, 'No data from device' - lines = data.decode('utf-8').splitlines() + lines = data.decode('utf-8', errors='ignore').splitlines() enum_dev_sn = [] for l in lines: @@ -319,6 +317,7 @@ def test_dual_host_info_to_device_cdc(board): if set(declared_devs) != set(enum_dev_sn): failed_msg = f'Expected {declared_devs}, Enumerated {enum_dev_sn}' + print('\n'.join(lines)) assert False, failed_msg return 0 @@ -337,12 +336,12 @@ def test_host_device_info(board): ret = globals()[f'reset_{flasher["name"].lower()}'](board) assert ret.returncode == 0, 'Failed to reset device' - data = ser.read(1000) + data = ser.read(10000) ser.close() if len(data) == 0: assert False, 'No data from device' + lines = data.decode('utf-8', errors='ignore').splitlines() - lines = data.decode('utf-8').splitlines() enum_dev_sn = [] for l in lines: vid_pid_sn = re.search(r'ID ([0-9a-fA-F]+):([0-9a-fA-F]+) SN (\w+)', l) @@ -352,8 +351,8 @@ def test_host_device_info(board): if set(declared_devs) != set(enum_dev_sn): failed_msg = f'Expected {declared_devs}, Enumerated {enum_dev_sn}' + print('\n'.join(lines)) assert False, failed_msg - return 0 @@ -419,7 +418,7 @@ def test_device_dfu(board): # Wait device enum timeout = ENUM_TIMEOUT - while timeout: + while timeout > 0: ret = run_cmd(f'dfu-util -l') stdout = ret.stdout.decode() if f'serial="{uid}"' in stdout and 'Found DFU: [cafe:4000]' in stdout: @@ -427,7 +426,7 @@ def test_device_dfu(board): time.sleep(1) timeout = timeout - 1 - assert timeout, 'Device not available' + assert timeout > 0, 'Device not available' f_dfu0 = f'dfu0_{uid}' f_dfu1 = f'dfu1_{uid}' @@ -460,7 +459,7 @@ def test_device_dfu_runtime(board): # Wait device enum timeout = ENUM_TIMEOUT - while timeout: + while timeout > 0: ret = run_cmd(f'dfu-util -l') stdout = ret.stdout.decode() if f'serial="{uid}"' in stdout and 'Found Runtime: [cafe:4000]' in stdout: @@ -468,7 +467,7 @@ def test_device_dfu_runtime(board): time.sleep(1) timeout = timeout - 1 - assert timeout, 'Device not available' + assert timeout > 0, 'Device not available' def test_device_hid_boot_interface(board): @@ -478,13 +477,13 @@ def test_device_hid_boot_interface(board): mouse2 = get_hid_dev(uid, 'TinyUSB', 'TinyUSB_Device', 'if01-mouse') # Wait device enum timeout = ENUM_TIMEOUT - while timeout: + while timeout > 0: if os.path.exists(kbd) and os.path.exists(mouse1) and os.path.exists(mouse2): break time.sleep(1) timeout = timeout - 1 - assert timeout, 'HID device not available' + assert timeout > 0, 'HID device not available' def test_device_hid_composite_freertos(id): @@ -515,6 +514,64 @@ host_test = [ ] +def test_example(board, f1, example): + """ + Test example firmware + :param board: board dict + :param f1: flags on + :param example: example name + :return: 0 if success/skip, 1 if failed + """ + name = board['name'] + err_count = 0 + + f1_str = "" + if f1 != "": + f1_str = '-f1_' + f1.replace(' ', '_') + + fw_dir = f'{TINYUSB_ROOT}/cmake-build/cmake-build-{name}{f1_str}/{example}' + if not os.path.exists(fw_dir): + fw_dir = f'{TINYUSB_ROOT}/examples/cmake-build-{name}{f1_str}/{example}' + fw_name = f'{fw_dir}/{os.path.basename(example)}' + print(f'{name+f1_str:40} {example:30} ...', end='') + + if not os.path.exists(fw_dir) or not (os.path.exists(f'{fw_name}.elf') or os.path.exists(f'{fw_name}.bin')): + print('Skip (no binary)') + return 0 + + if verbose: + print(f'Flashing {fw_name}.elf') + + # flash firmware. It may fail randomly, retry a few times + max_rety = 3 + start_s = time.time() + for i in range(max_rety): + ret = globals()[f'flash_{board["flasher"]["name"].lower()}'](board, fw_name) + if ret.returncode == 0: + try: + globals()[f'test_{example.replace("/", "_")}'](board) + print(' OK', end='') + break + except Exception as e: + if i == max_rety - 1: + err_count += 1 + print(f'{STATUS_FAILED}: {e}') + else: + print(f'\n Test failed: {e}, retry {i+2}/{max_rety}', end='') + time.sleep(0.5) + else: + print(f'\n Flash failed, retry {i+2}/{max_rety}', end='') + time.sleep(0.5) + + if ret.returncode != 0: + err_count += 1 + print(f' Flash {STATUS_FAILED}', end='') + + print(f' in {time.time() - start_s:.1f}s') + + return err_count + + def test_board(board): name = board['name'] flasher = board['flasher'] @@ -538,56 +595,19 @@ def test_board(board): test_list.remove(skip) print(f'{name:25} {skip:30} ... Skip') - # board_test is added last to disable board's usb - test_list.append('device/board_test') - err_count = 0 flags_on_list = [""] if 'build' in board and 'flags_on' in board['build']: flags_on_list = board['build']['flags_on'] for f1 in flags_on_list: - f1_str = "" - if f1 != "": - f1_str = '-f1_' + f1.replace(' ', '_') for test in test_list: - fw_dir = f'{TINYUSB_ROOT}/cmake-build/cmake-build-{name}{f1_str}/{test}' - if not os.path.exists(fw_dir): - fw_dir = f'{TINYUSB_ROOT}/examples/cmake-build-{name}{f1_str}/{test}' - fw_name = f'{fw_dir}/{os.path.basename(test)}' - print(f'{name+f1_str:40} {test:30} ... ', end='') - - if not os.path.exists(fw_dir) or not (os.path.exists(f'{fw_name}.elf') or os.path.exists(f'{fw_name}.bin')): - print('Skip (no binary)') - continue - - # flash firmware. It may fail randomly, retry a few times - max_rety = 2 - for i in range(max_rety): - ret = globals()[f'flash_{flasher["name"].lower()}'](board, fw_name) - if ret.returncode == 0: - try: - globals()[f'test_{test.replace("/", "_")}'](board) - print('OK') - break - except Exception as e: - if i == max_rety - 1: - err_count += 1 - print(STATUS_FAILED) - print(f' {e}') - else: - print() - print(f' Test failed: {e}, retry {i+1}') - time.sleep(1) - else: - print(f'Flashing failed, retry {i+1}') - time.sleep(1) + err_count += test_example(board, f1, test) - if ret.returncode != 0: - err_count += 1 - print(f'Flash {STATUS_FAILED}') + # flash board_test last to disable board's usb + test_example(board, flags_on_list[0], 'device/board_test') - return err_count + return name, err_count def main(): @@ -601,11 +621,13 @@ def main(): parser = argparse.ArgumentParser() parser.add_argument('config_file', help='Configuration JSON file') parser.add_argument('-b', '--board', action='append', default=[], help='Boards to test, all if not specified') + parser.add_argument('-s', '--skip', action='append', default=[], help='Skip boards from test') parser.add_argument('-v', '--verbose', action='store_true', help='Verbose output') args = parser.parse_args() config_file = args.config_file boards = args.board + skip_boards = args.skip verbose = args.verbose # if config file is not found, try to find it in the same directory as this script @@ -615,12 +637,22 @@ def main(): config = json.load(f) if len(boards) == 0: - config_boards = config['boards'] + config_boards = [e for e in config['boards'] if e['name'] not in skip_boards] else: config_boards = [e for e in config['boards'] if e['name'] in boards] + err_count = 0 with Pool(processes=os.cpu_count()) as pool: - err_count = sum(pool.map(test_board, config_boards)) + mret = pool.map(test_board, config_boards) + err_count = sum(e[1] for e in mret) + # generate skip list for next re-run if failed + skip_fname = f'{config_file}.skip' + if err_count > 0: + skip_boards += [name for name, err in mret if err == 0] + with open(skip_fname, 'w') as f: + f.write(' '.join(f'-s {i}' for i in skip_boards)) + elif os.path.exists(skip_fname): + os.remove(skip_fname) duration = time.time() - duration print() diff --git a/test/hil/tinyusb.json b/test/hil/tinyusb.json index 7393226eb..6afcb2186 100644 --- a/test/hil/tinyusb.json +++ b/test/hil/tinyusb.json @@ -21,16 +21,18 @@ "name": "espressif_s3_devkitm", "uid": "84F703C084E4", "build" : { - "flags_on": ["", "CFG_TUD_DWC2_DMA_ENABLE"] + "flags_on": ["", "CFG_TUD_DWC2_DMA_ENABLE CFG_TUH_DWC2_DMA_ENABLE"] }, "tests": { - "only": ["device/cdc_msc_freertos", "device/hid_composite_freertos"] + "only": ["device/cdc_msc_freertos", "device/hid_composite_freertos", "host/device_info"], + "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2005402"}] }, "flasher": { "name": "esptool", "uid": "3ea619acd1cdeb11a0a0b806e93fd3f1", "args": "-b 1500000" - } + }, + "comment": "Use TS3USB30 mux to test both device and host" }, { "name": "feather_nrf52840_express", @@ -59,8 +61,11 @@ { "name": "metro_m4_express", "uid": "9995AD485337433231202020FF100A34", + "build" : { + "args": ["MAX3421_HOST=1"] + }, "tests": { - "device": true, "host": false, "dual": false, + "device": true, "host": false, "dual": true, "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2002130"}] }, "flasher": { @@ -70,6 +75,19 @@ } }, { + "name": "mimxrt1064_evk", + "uid": "BAE96FB95AFA6DBB8F00005002001200", + "tests": { + "device": true, "host": true, "dual": true, + "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2023299"}] + }, + "flasher": { + "name": "jlink", + "uid": "000725299165", + "args": "-device MIMXRT1064xxx6A" + } + }, + { "name": "lpcxpresso11u37", "uid": "17121919", "tests": { @@ -98,8 +116,11 @@ { "name": "raspberry_pi_pico", "uid": "E6614C311B764A37", + "build" : { + "flags_on": ["CFG_TUH_RPI_PIO_USB"] + }, "tests": { - "device": true, "host": false, "dual": false, + "device": true, "host": true, "dual": true, "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2002470"}] }, "flasher": { @@ -109,10 +130,27 @@ } }, { + "name": "raspberry_pi_pico_w", + "uid": "E6614C311B764A37", + "tests": { + "device": false, "host": true, "dual": false, + "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2023934"}] + }, + "flasher": { + "name": "openocd", + "uid": "E6633861A3819D38", + "args": "-f interface/cmsis-dap.cfg -f target/rp2040.cfg -c \"adapter speed 5000\"" + }, + "comment": "Test native host" + }, + { "name": "raspberry_pi_pico2", "uid": "560AE75E1C7152C9", + "build" : { + "flags_on": ["CFG_TUH_RPI_PIO_USB"] + }, "tests": { - "device": true, "host": false, "dual": false, + "device": true, "host": true, "dual": true, "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "533D004242"}] }, "flasher": { @@ -157,9 +195,9 @@ "device": true, "host": false, "dual": false }, "flasher": { - "name": "stlink", + "name": "openocd", "uid": "004C00343137510F39383538", - "args": "" + "args": "-f interface/stlink.cfg -f target/stm32h7x.cfg" } }, { diff --git a/test/unit-test/test/device/msc/test_msc_device.c b/test/unit-test/test/device/msc/test_msc_device.c index 3ab46b0f9..49843a921 100644 --- a/test/unit-test/test/device/msc/test_msc_device.c +++ b/test/unit-test/test/device/msc/test_msc_device.c @@ -94,19 +94,21 @@ enum uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE]; -// Invoked when received SCSI_CMD_INQUIRY -// Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively -void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) -{ +// Invoked when received SCSI_CMD_INQUIRY, v2 with full inquiry response +// Some inquiry_resp's fields are already filled with default values, application can update them +// Return length of inquiry response, typically sizeof(scsi_inquiry_resp_t) (36 bytes), can be longer if included vendor data. +uint32_t tud_msc_inquiry2_cb(uint8_t lun, scsi_inquiry_resp_t* inquiry_resp, uint32_t bufsize) { (void) lun; - + (void) bufsize; const char vid[] = "TinyUSB"; const char pid[] = "Mass Storage"; const char rev[] = "1.0"; - memcpy(vendor_id , vid, strlen(vid)); - memcpy(product_id , pid, strlen(pid)); - memcpy(product_rev, rev, strlen(rev)); + memcpy(inquiry_resp->vendor_id, vid, strlen(vid)); + memcpy(inquiry_resp->product_id, pid, strlen(pid)); + memcpy(inquiry_resp->product_rev, rev, strlen(rev)); + + return sizeof(scsi_inquiry_resp_t); // 36 bytes } // Invoked when received Test Unit Ready command. |
