mirror of
https://github.com/hathach/tinyusb.git
synced 2026-03-22 07:25:19 +00:00
add hil test for host msc and cdc
This commit is contained in:
@ -151,6 +151,13 @@ openocd -f interface/stlink.cfg -f target/stm32h7x.cfg
|
||||
openocd -f interface/jlink.cfg -f target/stm32h7x.cfg
|
||||
```
|
||||
|
||||
For **rp2040/rp2350** with a CMSIS-DAP probe (e.g. Picoprobe, debugprobe):
|
||||
```bash
|
||||
openocd -f interface/cmsis-dap.cfg -f target/rp2040.cfg -c "adapter speed 5000"
|
||||
# or for rp2350:
|
||||
openocd -f interface/cmsis-dap.cfg -f target/rp2350.cfg -c "adapter speed 5000"
|
||||
```
|
||||
|
||||
For boards that define `OPENOCD_OPTION` in `board.cmake`, use those options directly:
|
||||
```bash
|
||||
openocd $(cat hw/bsp/FAMILY/boards/BOARD/board.cmake | grep OPENOCD_OPTION | ...)
|
||||
|
||||
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018, hathach (tinyusb.org)
|
||||
Copyright (c) 2012-2026, hathach (tinyusb.org)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@ -130,11 +130,16 @@ static bool inquiry_complete_cb(uint8_t dev_addr, const tuh_msc_complete_data_t
|
||||
drive_path[0] += drive_num;
|
||||
|
||||
if (f_mount(&fatfs[drive_num], drive_path, 1) != FR_OK) {
|
||||
puts("mount failed");
|
||||
printf("mount failed\r\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
// change to newly mounted drive
|
||||
f_chdir(drive_path);
|
||||
f_chdrive(drive_path);
|
||||
FRESULT rc = f_chdir("/");
|
||||
if (rc != FR_OK) {
|
||||
printf("chdir failed: %d\r\n", rc);
|
||||
}
|
||||
|
||||
// print the drive label
|
||||
// char label[34];
|
||||
@ -148,7 +153,7 @@ static bool inquiry_complete_cb(uint8_t dev_addr, const tuh_msc_complete_data_t
|
||||
|
||||
//------------- IMPLEMENTATION -------------//
|
||||
void tuh_msc_mount_cb(uint8_t dev_addr) {
|
||||
printf("A MassStorage device is mounted\r\n");
|
||||
printf("A MassStorage device (addr = %u) is mounted\r\n", dev_addr);
|
||||
|
||||
const uint8_t lun = 0;
|
||||
tuh_msc_inquiry(dev_addr, lun, &scsi_resp.inquiry, inquiry_complete_cb, 0);
|
||||
|
||||
@ -1,2 +1,3 @@
|
||||
set(PICO_PLATFORM rp2040)
|
||||
set(PICO_BOARD adafruit_feather_rp2040_usb_host)
|
||||
set(CFG_TUH_RPI_PIO_USB 1)
|
||||
|
||||
@ -2,3 +2,5 @@ set(PICO_PLATFORM rp2350-arm-s)
|
||||
set(PICO_BOARD adafruit_fruit_jam)
|
||||
set(PICO_BOARD_HEADER_DIRS ${CMAKE_CURRENT_LIST_DIR})
|
||||
#set(OPENOCD_SERIAL E6614103E78E8324)
|
||||
|
||||
set(CFG_TUH_RPI_PIO_USB 1)
|
||||
|
||||
@ -2,3 +2,5 @@ set(PICO_PLATFORM rp2350-arm-s)
|
||||
set(PICO_BOARD adafruit_metro_rp2350)
|
||||
set(PICO_BOARD_HEADER_DIRS ${CMAKE_CURRENT_LIST_DIR})
|
||||
#set(OPENOCD_SERIAL E6614103E78E8324)
|
||||
|
||||
set(CFG_TUH_RPI_PIO_USB 1)
|
||||
|
||||
@ -72,6 +72,12 @@ target_compile_definitions(tinyusb_common_base INTERFACE
|
||||
CFG_TUSB_DEBUG=${TINYUSB_DEBUG_LEVEL}
|
||||
)
|
||||
|
||||
if (CFG_TUH_RPI_PIO_USB)
|
||||
target_compile_definitions(tinyusb_common_base INTERFACE
|
||||
CFG_TUH_RPI_PIO_USB=1
|
||||
)
|
||||
endif()
|
||||
|
||||
target_link_libraries(tinyusb_common_base INTERFACE
|
||||
hardware_structs
|
||||
hardware_irq
|
||||
|
||||
@ -80,6 +80,11 @@ flash bank $_FLASHNAME wch_riscv 0x00000000 0 0 0 $_TARGETNAME.0
|
||||
echo "Ready for Remote Connections"
|
||||
"""
|
||||
|
||||
MSC_README_TXT = \
|
||||
b"This is tinyusb's MassStorage Class demo.\r\n\r\n\
|
||||
If you find any bugs or get any questions, feel free to file an\r\n\
|
||||
issue at github.com/hathach/tinyusb"
|
||||
|
||||
# -------------------------------------------------------------
|
||||
# Path
|
||||
# -------------------------------------------------------------
|
||||
@ -360,10 +365,27 @@ def test_dual_host_info_to_device_cdc(board):
|
||||
declared_devs = [f'{d["vid_pid"]}_{d["serial"]}' for d in board['tests']['dev_attached']]
|
||||
port = get_serial_dev(uid, 'TinyUSB', "TinyUSB_Device", 0)
|
||||
ser = open_serial_dev(port)
|
||||
ser.timeout = 0.1
|
||||
|
||||
# read from cdc, first line should contain vid/pid and serial
|
||||
data = ser.read(10000)
|
||||
# read until all expected devices are enumerated
|
||||
data = b''
|
||||
timeout = ENUM_TIMEOUT
|
||||
while timeout > 0:
|
||||
new_data = ser.read(ser.in_waiting or 1)
|
||||
if new_data:
|
||||
data += new_data
|
||||
# check if all devices found
|
||||
enum_dev_sn = []
|
||||
for l in data.decode('utf-8', errors='ignore').splitlines():
|
||||
vid_pid_sn = re.search(r'ID ([0-9a-fA-F]+):([0-9a-fA-F]+) SN (\w+)', l)
|
||||
if vid_pid_sn:
|
||||
enum_dev_sn.append(f'{vid_pid_sn.group(1)}_{vid_pid_sn.group(2)}_{vid_pid_sn.group(3)}')
|
||||
if set(declared_devs).issubset(set(enum_dev_sn)):
|
||||
break
|
||||
time.sleep(0.1)
|
||||
timeout -= 0.1
|
||||
ser.close()
|
||||
|
||||
if len(data) == 0:
|
||||
assert False, 'No data from device'
|
||||
lines = data.decode('utf-8', errors='ignore').splitlines()
|
||||
@ -391,13 +413,31 @@ def test_host_device_info(board):
|
||||
|
||||
port = get_serial_dev(flasher["uid"], None, None, 0)
|
||||
ser = open_serial_dev(port)
|
||||
ser.timeout = 0.1
|
||||
|
||||
# reset device since we can miss the first line
|
||||
ret = globals()[f'reset_{flasher["name"].lower()}'](board)
|
||||
assert ret.returncode == 0, 'Failed to reset device'
|
||||
assert ret.returncode == 0, 'Failed to reset device'
|
||||
|
||||
data = ser.read(10000)
|
||||
# read until all expected devices are enumerated
|
||||
data = b''
|
||||
timeout = ENUM_TIMEOUT
|
||||
while timeout > 0:
|
||||
new_data = ser.read(ser.in_waiting or 1)
|
||||
if new_data:
|
||||
data += new_data
|
||||
# check if all devices found
|
||||
enum_dev_sn = []
|
||||
for l in data.decode('utf-8', errors='ignore').splitlines():
|
||||
vid_pid_sn = re.search(r'ID ([0-9a-fA-F]+):([0-9a-fA-F]+) SN (\w+)', l)
|
||||
if vid_pid_sn:
|
||||
enum_dev_sn.append(f'{vid_pid_sn.group(1)}_{vid_pid_sn.group(2)}_{vid_pid_sn.group(3)}')
|
||||
if set(declared_devs).issubset(set(enum_dev_sn)):
|
||||
break
|
||||
time.sleep(0.1)
|
||||
timeout -= 0.1
|
||||
ser.close()
|
||||
|
||||
if len(data) == 0:
|
||||
assert False, 'No data from device'
|
||||
lines = data.decode('utf-8', errors='ignore').splitlines()
|
||||
@ -416,10 +456,25 @@ def test_host_device_info(board):
|
||||
return 0
|
||||
|
||||
|
||||
def print_msc_info(lines):
|
||||
"""Print MSC inquiry and disk size on a single line"""
|
||||
inquiry = ''
|
||||
disk_size = ''
|
||||
for l in lines:
|
||||
if re.match(r'^[A-Za-z].*\s+rev\s+', l):
|
||||
inquiry = l.strip()
|
||||
if 'Disk Size' in l:
|
||||
disk_size = l.strip()
|
||||
if inquiry or disk_size:
|
||||
print(f'\r\n {inquiry} {disk_size} ', end='')
|
||||
|
||||
|
||||
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:
|
||||
dev_attached = board['tests'].get('dev_attached', [])
|
||||
cdc_devs = [d for d in dev_attached if d.get('is_cdc')]
|
||||
msc_devs = [d for d in dev_attached if d.get('is_msc')]
|
||||
if not cdc_devs and not msc_devs:
|
||||
return
|
||||
|
||||
port = get_serial_dev(flasher["uid"], None, None, 0)
|
||||
@ -430,18 +485,21 @@ def test_host_cdc_msc_hid(board):
|
||||
ret = globals()[f'reset_{flasher["name"].lower()}'](board)
|
||||
assert ret.returncode == 0, 'Failed to reset device'
|
||||
|
||||
# Wait for CDC mounted message
|
||||
# Wait for all expected mount messages
|
||||
data = b''
|
||||
timeout = ENUM_TIMEOUT
|
||||
wait_cdc = len(cdc_devs) > 0
|
||||
wait_msc = len(msc_devs) > 0
|
||||
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:
|
||||
cdc_ok = (not wait_cdc) or (b'CDC Interface is mounted' in data)
|
||||
msc_ok = (not wait_msc) or (b'Disk Size' in data)
|
||||
if cdc_ok and msc_ok:
|
||||
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 = {
|
||||
@ -451,13 +509,29 @@ def test_host_cdc_msc_hid(board):
|
||||
'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='')
|
||||
|
||||
lines = data.decode('utf-8', errors='ignore').splitlines()
|
||||
|
||||
# Verify and print CDC mount
|
||||
if cdc_devs:
|
||||
assert b'CDC Interface is mounted' in data, 'CDC device not mounted on host'
|
||||
dev = cdc_devs[0]
|
||||
chip_name = vid_pid_name.get(dev['vid_pid'], dev['vid_pid'])
|
||||
for l in lines:
|
||||
if 'CDC Interface is mounted' in l:
|
||||
print(f'\r\n {chip_name}: {l} ', end='')
|
||||
|
||||
# Verify and print MSC mount (inquiry + disk size)
|
||||
if msc_devs:
|
||||
assert b'MassStorage device is mounted' in data, 'MSC device not mounted on host'
|
||||
assert b'Disk Size' in data, 'MSC Disk Size not reported'
|
||||
print_msc_info(lines)
|
||||
|
||||
# CDC echo test via flasher serial
|
||||
if not cdc_devs:
|
||||
ser.close()
|
||||
return
|
||||
|
||||
time.sleep(2)
|
||||
ser.reset_input_buffer()
|
||||
|
||||
@ -490,6 +564,65 @@ def test_host_cdc_msc_hid(board):
|
||||
ser.close()
|
||||
|
||||
|
||||
def test_host_msc_file_explorer(board):
|
||||
flasher = board['flasher']
|
||||
msc_devs = [d for d in board['tests'].get('dev_attached', []) if d.get('is_msc')]
|
||||
if not msc_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 MSC mount (Disk Size 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'Disk Size' in data:
|
||||
break
|
||||
time.sleep(0.1)
|
||||
timeout -= 0.1
|
||||
assert b'Disk Size' in data, 'MSC device not mounted'
|
||||
lines = data.decode('utf-8', errors='ignore').splitlines()
|
||||
print_msc_info(lines)
|
||||
|
||||
# Send "cat README.TXT" and read response
|
||||
time.sleep(1)
|
||||
ser.reset_input_buffer()
|
||||
for ch in 'cat README.TXT\r':
|
||||
ser.write(ch.encode())
|
||||
ser.flush()
|
||||
time.sleep(0.002)
|
||||
|
||||
# Read response
|
||||
resp = b''
|
||||
t = 10.0
|
||||
while t > 0:
|
||||
rd = ser.read(max(1, ser.in_waiting))
|
||||
if rd:
|
||||
resp += rd
|
||||
# wait for prompt after command output
|
||||
if b'>' in resp and resp.rstrip().endswith(b'>'):
|
||||
break
|
||||
time.sleep(0.05)
|
||||
t -= 0.05
|
||||
|
||||
# Verify response contains README content
|
||||
resp_text = resp.decode('utf-8', errors='ignore')
|
||||
assert MSC_README_TXT.decode() in resp_text, (f'MSC README.TXT not found in response:\n'
|
||||
f' received: {resp_text}')
|
||||
print('README.TXT matched ', end='')
|
||||
|
||||
ser.close()
|
||||
|
||||
|
||||
# -------------------------------------------------------------
|
||||
# Tests: device
|
||||
# -------------------------------------------------------------
|
||||
@ -565,12 +698,7 @@ def test_device_cdc_msc(board):
|
||||
|
||||
# MSC Block test
|
||||
data = read_disk_file(uid, 0, 'README.TXT')
|
||||
readme = \
|
||||
b"This is tinyusb's MassStorage Class demo.\r\n\r\n\
|
||||
If you find any bugs or get any questions, feel free to file an\r\n\
|
||||
issue at github.com/hathach/tinyusb"
|
||||
|
||||
assert data == readme, f'MSC wrong data in README.TXT\n expected: {readme.decode()}\n received: {data.decode()}'
|
||||
assert data == MSC_README_TXT, f'MSC wrong data in README.TXT\n expected: {MSC_README_TXT.decode()}\n received: {data.decode()}'
|
||||
|
||||
|
||||
def test_device_cdc_msc_freertos(board):
|
||||
@ -838,6 +966,7 @@ dual_tests = [
|
||||
|
||||
host_test = [
|
||||
'host/cdc_msc_hid',
|
||||
'host/msc_file_explorer',
|
||||
'host/device_info',
|
||||
]
|
||||
|
||||
|
||||
@ -175,6 +175,25 @@
|
||||
"args": "-f interface/cmsis-dap.cfg -f target/rp2350.cfg -c \"adapter speed 5000\""
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "adafruit_fruit_jam",
|
||||
"uid": "2B0DC7A45781189E",
|
||||
"tests": {
|
||||
"device": false,
|
||||
"host": true,
|
||||
"dual": true,
|
||||
"dev_attached": [
|
||||
{"vid_pid": "0403_6001", "serial": "0", "is_cdc": true},
|
||||
{"vid_pid": "058f_6387", "serial": "A8BEE062633D", "is_msc": true,
|
||||
"msc_disk_size": 3730, "msc_inquiry": "Generic Flash Disk rev 8.07"}
|
||||
]
|
||||
},
|
||||
"flasher": {
|
||||
"name": "openocd",
|
||||
"uid": "E6614103E78E8324",
|
||||
"args": "-f interface/cmsis-dap.cfg -f target/rp2350.cfg -c \"adapter speed 5000\""
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "stm32f072disco",
|
||||
"uid": "3A001A001357364230353532",
|
||||
|
||||
Reference in New Issue
Block a user