Merge pull request #2355 from hathach/update-hil-rp2040
Update hil test for rp2040 on self-hosted PI4
This commit is contained in:
48
.github/workflows/cmake_arm.yml
vendored
48
.github/workflows/cmake_arm.yml
vendored
@@ -105,15 +105,14 @@ jobs:
|
|||||||
|
|
||||||
# ---------------------------------------
|
# ---------------------------------------
|
||||||
# Hardware in the loop (HIL)
|
# Hardware in the loop (HIL)
|
||||||
# Current self-hosted instance is running on an RPI4 with
|
# Current self-hosted instance is running on an RPI4.
|
||||||
# - pico + pico-probe connected via USB
|
# For attached hardware checkout hil_pi4.json
|
||||||
# - pico-probe is /dev/ttyACM0
|
|
||||||
# ---------------------------------------
|
# ---------------------------------------
|
||||||
hw-rp2040-test:
|
hw-rp2040-test:
|
||||||
# run only with hathach's commit due to limited resource on RPI4
|
# run only with hathach's commit due to limited resource on RPI4
|
||||||
if: github.repository_owner == 'hathach'
|
if: github.repository_owner == 'hathach'
|
||||||
needs: build-arm
|
needs: build-arm
|
||||||
runs-on: [self-hosted, Linux, ARM64, rp2040]
|
runs-on: [self-hosted, rp2040, hardware-in-the-loop]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Clean workspace
|
- name: Clean workspace
|
||||||
@@ -122,43 +121,16 @@ jobs:
|
|||||||
rm -rf "${{ github.workspace }}"
|
rm -rf "${{ github.workspace }}"
|
||||||
mkdir -p "${{ github.workspace }}"
|
mkdir -p "${{ github.workspace }}"
|
||||||
|
|
||||||
|
- name: Checkout test/hil
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
sparse-checkout: test/hil
|
||||||
|
|
||||||
- name: Download rp2040 Artifacts
|
- name: Download rp2040 Artifacts
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: rp2040
|
name: rp2040
|
||||||
|
|
||||||
- name: Create flash.sh
|
- name: Test on actual hardware (hardware in the loop)
|
||||||
run: |
|
run: |
|
||||||
echo > flash.sh 'cmdout=$(openocd -f "interface/cmsis-dap.cfg" -f "target/rp2040.cfg" -c "adapter speed 5000" -c "program $1 reset exit")'
|
python3 test/hil/hil_test.py hil_pi4.json
|
||||||
echo >> flash.sh 'if (( $? )) ; then echo $cmdout ; fi'
|
|
||||||
chmod +x flash.sh
|
|
||||||
|
|
||||||
- name: Test cdc_dual_ports
|
|
||||||
run: |
|
|
||||||
./flash.sh cdc_dual_ports.elf
|
|
||||||
while (! ([ -e /dev/ttyACM1 ] && [ -e /dev/ttyACM2 ])) && [ $SECONDS -le 10 ]; do :; done
|
|
||||||
test -e /dev/ttyACM1 && echo "ttyACM1 exists"
|
|
||||||
test -e /dev/ttyACM2 && echo "ttyACM2 exists"
|
|
||||||
|
|
||||||
- name: Test cdc_msc
|
|
||||||
run: |
|
|
||||||
./flash.sh cdc_msc.elf
|
|
||||||
readme='/media/pi/TinyUSB MSC/README.TXT'
|
|
||||||
while (! ([ -e /dev/ttyACM1 ] && [ -f "$readme" ])) && [ $SECONDS -le 10 ]; do :; done
|
|
||||||
test -e /dev/ttyACM1 && echo "ttyACM1 exists"
|
|
||||||
test -f "$readme" && echo "$readme exists"
|
|
||||||
cat "$readme"
|
|
||||||
|
|
||||||
- name: Test dfu
|
|
||||||
run: |
|
|
||||||
./flash.sh dfu.elf
|
|
||||||
while (! (dfu-util -l | grep "Found DFU")) && [ $SECONDS -le 10 ]; do :; done
|
|
||||||
dfu-util -d cafe -a 0 -U dfu0
|
|
||||||
dfu-util -d cafe -a 1 -U dfu1
|
|
||||||
grep "TinyUSB DFU! - Partition 0" dfu0
|
|
||||||
grep "TinyUSB DFU! - Partition 1" dfu1
|
|
||||||
|
|
||||||
- name: Test dfu_runtime
|
|
||||||
run: |
|
|
||||||
./flash.sh dfu_runtime.elf
|
|
||||||
while (! (dfu-util -l | grep "Found Runtime")) && [ $SECONDS -le 10 ]; do :; done
|
|
||||||
|
@@ -395,6 +395,22 @@ function(family_flash_stlink TARGET)
|
|||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
|
|
||||||
|
# Add flash openocd target
|
||||||
|
function(family_flash_openocd TARGET CLI_OPTIONS)
|
||||||
|
if (NOT DEFINED OPENOCD)
|
||||||
|
set(OPENOCD openocd)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
separate_arguments(CLI_OPTIONS_LIST UNIX_COMMAND ${CLI_OPTIONS})
|
||||||
|
|
||||||
|
# note skip verify since it has issue with rp2040
|
||||||
|
add_custom_target(${TARGET}-openocd
|
||||||
|
DEPENDS ${TARGET}
|
||||||
|
COMMAND ${OPENOCD} ${CLI_OPTIONS_LIST} -c "program $<TARGET_FILE:${TARGET}> reset exit"
|
||||||
|
VERBATIM
|
||||||
|
)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
# Add flash pycod target
|
# Add flash pycod target
|
||||||
function(family_flash_pyocd TARGET)
|
function(family_flash_pyocd TARGET)
|
||||||
if (NOT DEFINED PYOC)
|
if (NOT DEFINED PYOC)
|
||||||
|
@@ -12,6 +12,7 @@ include(${CMAKE_CURRENT_LIST_DIR}/pico_sdk_import.cmake)
|
|||||||
# include basic family CMake functionality
|
# include basic family CMake functionality
|
||||||
set(FAMILY_MCUS RP2040)
|
set(FAMILY_MCUS RP2040)
|
||||||
set(JLINK_DEVICE rp2040_m0_0)
|
set(JLINK_DEVICE rp2040_m0_0)
|
||||||
|
set(OPENOCD_OPTION "-f interface/cmsis-dap.cfg -f target/rp2040.cfg -c \"adapter speed 5000\"")
|
||||||
|
|
||||||
include(${CMAKE_CURRENT_LIST_DIR}/boards/${BOARD}/board.cmake)
|
include(${CMAKE_CURRENT_LIST_DIR}/boards/${BOARD}/board.cmake)
|
||||||
|
|
||||||
@@ -158,6 +159,7 @@ function(family_configure_target TARGET RTOS)
|
|||||||
pico_enable_stdio_uart(${TARGET} 1)
|
pico_enable_stdio_uart(${TARGET} 1)
|
||||||
target_link_libraries(${TARGET} PUBLIC pico_stdlib pico_bootsel_via_double_reset tinyusb_board${RTOS_SUFFIX} tinyusb_additions)
|
target_link_libraries(${TARGET} PUBLIC pico_stdlib pico_bootsel_via_double_reset tinyusb_board${RTOS_SUFFIX} tinyusb_additions)
|
||||||
|
|
||||||
|
family_flash_openocd(${TARGET} ${OPENOCD_OPTION})
|
||||||
family_flash_jlink(${TARGET})
|
family_flash_jlink(${TARGET})
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
|
11
test/hil/hil_pi4.json
Normal file
11
test/hil/hil_pi4.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"boards": [
|
||||||
|
{
|
||||||
|
"name": "raspberry_pi_pico",
|
||||||
|
"uid": "E6614C311B764A37",
|
||||||
|
"debugger": "openocd",
|
||||||
|
"debugger_sn": "E6614103E72C1D2F",
|
||||||
|
"debugger_args": "-f interface/cmsis-dap.cfg -f target/rp2040.cfg -c \"adapter speed 5000\""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@@ -32,21 +32,66 @@ import serial
|
|||||||
import subprocess
|
import subprocess
|
||||||
import json
|
import json
|
||||||
|
|
||||||
|
ENUM_TIMEOUT = 10
|
||||||
|
|
||||||
def get_serial_dev(id, product, ifnum):
|
|
||||||
|
def get_serial_dev(id, vendor_str, product_str, ifnum):
|
||||||
# get usb serial by id
|
# get usb serial by id
|
||||||
return f'/dev/serial/by-id/usb-TinyUSB_{product}_{id}-if{ifnum:02d}'
|
return f'/dev/serial/by-id/usb-{vendor_str}_{product_str}_{id}-if{ifnum:02d}'
|
||||||
|
|
||||||
|
|
||||||
def get_disk_dev(id, lun):
|
# Currently not used, left as reference
|
||||||
|
def get_disk_dev(id, vendor_str, lun):
|
||||||
# get usb disk by id
|
# get usb disk by id
|
||||||
return f'/dev/disk/by-id/usb-TinyUSB_Mass_Storage_{id}-0:{lun}'
|
return f'/dev/disk/by-id/usb-{vendor_str}_Mass_Storage_{id}-0:{lun}'
|
||||||
|
|
||||||
|
|
||||||
def get_hid_dev(id, product, event):
|
def get_hid_dev(id, vendor_str, product_str, event):
|
||||||
return f'/dev/input/by-id/usb-TinyUSB_{product}_{id}-{event}'
|
return f'/dev/input/by-id/usb-{vendor_str}_{product_str}_{id}-{event}'
|
||||||
|
|
||||||
|
|
||||||
|
def open_serial_dev(port):
|
||||||
|
timeout = ENUM_TIMEOUT
|
||||||
|
ser = None
|
||||||
|
while timeout:
|
||||||
|
if os.path.exists(port):
|
||||||
|
try:
|
||||||
|
# slight delay since kernel may occupy the port briefly
|
||||||
|
time.sleep(0.2)
|
||||||
|
ser = serial.Serial(port, timeout=1)
|
||||||
|
break
|
||||||
|
except serial.SerialException:
|
||||||
|
pass
|
||||||
|
time.sleep(0.8)
|
||||||
|
timeout = timeout - 1
|
||||||
|
assert timeout, 'Device not available or Cannot open port'
|
||||||
|
return ser
|
||||||
|
|
||||||
|
|
||||||
|
def read_disk_file(id, fname):
|
||||||
|
# on different self-hosted, the mount point is different
|
||||||
|
file_list = [
|
||||||
|
f'/media/blkUSB_{id[-8:]}.02/{fname}',
|
||||||
|
f'/media/{os.getenv("USER")}/TinyUSB MSC/{fname}'
|
||||||
|
]
|
||||||
|
timeout = ENUM_TIMEOUT
|
||||||
|
while timeout:
|
||||||
|
for file in file_list:
|
||||||
|
if os.path.isfile(file):
|
||||||
|
with open(file, 'rb') as f:
|
||||||
|
data = f.read()
|
||||||
|
return data
|
||||||
|
|
||||||
|
time.sleep(1)
|
||||||
|
timeout = timeout - 1
|
||||||
|
|
||||||
|
assert timeout, 'Device not available'
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
# -------------------------------------------------------------
|
||||||
|
# Flash with debugger
|
||||||
|
# -------------------------------------------------------------
|
||||||
def flash_jlink(sn, dev, firmware):
|
def flash_jlink(sn, dev, firmware):
|
||||||
script = ['halt', 'r', f'loadfile {firmware}', 'r', 'go', 'exit']
|
script = ['halt', 'r', f'loadfile {firmware}', 'r', 'go', 'exit']
|
||||||
f = open('flash.jlink', 'w')
|
f = open('flash.jlink', 'w')
|
||||||
@@ -59,31 +104,29 @@ def flash_jlink(sn, dev, firmware):
|
|||||||
assert ret.returncode == 0, 'Flash failed\n' + stdout
|
assert ret.returncode == 0, 'Flash failed\n' + stdout
|
||||||
|
|
||||||
|
|
||||||
|
def flash_openocd(sn, args, firmware):
|
||||||
|
ret = subprocess.run(f'openocd {args} -c "program {firmware} reset exit"',
|
||||||
|
shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||||
|
stdout = ret.stdout.decode()
|
||||||
|
assert ret.returncode == 0, 'Flash failed\n' + stdout
|
||||||
|
|
||||||
|
|
||||||
|
# -------------------------------------------------------------
|
||||||
|
# Tests
|
||||||
|
# -------------------------------------------------------------
|
||||||
def test_board_test(id):
|
def test_board_test(id):
|
||||||
# Dummy test
|
# Dummy test
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def test_cdc_dual_ports(id):
|
def test_cdc_dual_ports(id):
|
||||||
port1 = get_serial_dev(id, "TinyUSB_Device", 0)
|
port1 = get_serial_dev(id, 'TinyUSB', "TinyUSB_Device", 0)
|
||||||
port2 = get_serial_dev(id, "TinyUSB_Device", 2)
|
port2 = get_serial_dev(id, 'TinyUSB', "TinyUSB_Device", 2)
|
||||||
|
|
||||||
# Wait device enum
|
ser1 = open_serial_dev(port1)
|
||||||
timeout = 10
|
ser2 = open_serial_dev(port2)
|
||||||
while timeout:
|
|
||||||
if os.path.exists(port1) and os.path.exists(port2):
|
|
||||||
break
|
|
||||||
time.sleep(1)
|
|
||||||
timeout = timeout - 1
|
|
||||||
|
|
||||||
assert timeout, 'Device not available'
|
|
||||||
|
|
||||||
# Echo test
|
# Echo test
|
||||||
ser1 = serial.Serial(port1)
|
|
||||||
ser2 = serial.Serial(port2)
|
|
||||||
|
|
||||||
ser1.timeout = 1
|
|
||||||
ser2.timeout = 1
|
|
||||||
|
|
||||||
str1 = b"test_no1"
|
str1 = b"test_no1"
|
||||||
ser1.write(str1)
|
ser1.write(str1)
|
||||||
ser1.flush()
|
ser1.flush()
|
||||||
@@ -98,32 +141,17 @@ def test_cdc_dual_ports(id):
|
|||||||
|
|
||||||
|
|
||||||
def test_cdc_msc(id):
|
def test_cdc_msc(id):
|
||||||
port = get_serial_dev(id, "TinyUSB_Device", 0)
|
|
||||||
file = f'/media/blkUSB_{id[-8:]}.02/README.TXT'
|
|
||||||
# Wait device enum
|
|
||||||
timeout = 10
|
|
||||||
while timeout:
|
|
||||||
if os.path.exists(port) and os.path.isfile(file):
|
|
||||||
break
|
|
||||||
time.sleep(1)
|
|
||||||
timeout = timeout - 1
|
|
||||||
|
|
||||||
assert timeout, 'Device not available'
|
|
||||||
|
|
||||||
# Echo test
|
# Echo test
|
||||||
ser1 = serial.Serial(port)
|
port = get_serial_dev(id, 'TinyUSB', "TinyUSB_Device", 0)
|
||||||
|
ser = open_serial_dev(port)
|
||||||
ser1.timeout = 1
|
|
||||||
|
|
||||||
str = b"test_str"
|
str = b"test_str"
|
||||||
ser1.write(str)
|
ser.write(str)
|
||||||
ser1.flush()
|
ser.flush()
|
||||||
assert ser1.read(100) == str, 'CDC wrong data'
|
assert ser.read(100) == str, 'CDC wrong data'
|
||||||
|
|
||||||
# Block test
|
# Block test
|
||||||
f = open(file, 'rb')
|
data = read_disk_file(id, 'README.TXT')
|
||||||
data = f.read()
|
|
||||||
|
|
||||||
readme = \
|
readme = \
|
||||||
b"This is tinyusb's MassStorage Class demo.\r\n\r\n\
|
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\
|
If you find any bugs or get any questions, feel free to file an\r\n\
|
||||||
@@ -131,9 +159,10 @@ issue at github.com/hathach/tinyusb"
|
|||||||
|
|
||||||
assert data == readme, 'MSC wrong data'
|
assert data == readme, 'MSC wrong data'
|
||||||
|
|
||||||
|
|
||||||
def test_dfu(id):
|
def test_dfu(id):
|
||||||
# Wait device enum
|
# Wait device enum
|
||||||
timeout = 10
|
timeout = ENUM_TIMEOUT
|
||||||
while timeout:
|
while timeout:
|
||||||
ret = subprocess.run(f'dfu-util -l',
|
ret = subprocess.run(f'dfu-util -l',
|
||||||
shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||||
@@ -172,7 +201,7 @@ def test_dfu(id):
|
|||||||
|
|
||||||
def test_dfu_runtime(id):
|
def test_dfu_runtime(id):
|
||||||
# Wait device enum
|
# Wait device enum
|
||||||
timeout = 10
|
timeout = ENUM_TIMEOUT
|
||||||
while timeout:
|
while timeout:
|
||||||
ret = subprocess.run(f'dfu-util -l',
|
ret = subprocess.run(f'dfu-util -l',
|
||||||
shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||||
@@ -186,11 +215,11 @@ def test_dfu_runtime(id):
|
|||||||
|
|
||||||
|
|
||||||
def test_hid_boot_interface(id):
|
def test_hid_boot_interface(id):
|
||||||
kbd = get_hid_dev(id, 'TinyUSB_Device', 'event-kbd')
|
kbd = get_hid_dev(id, 'TinyUSB', 'TinyUSB_Device', 'event-kbd')
|
||||||
mouse1 = get_hid_dev(id, 'TinyUSB_Device', 'if01-event-mouse')
|
mouse1 = get_hid_dev(id, 'TinyUSB', 'TinyUSB_Device', 'if01-event-mouse')
|
||||||
mouse2 = get_hid_dev(id, 'TinyUSB_Device', 'if01-mouse')
|
mouse2 = get_hid_dev(id, 'TinyUSB', 'TinyUSB_Device', 'if01-mouse')
|
||||||
# Wait device enum
|
# Wait device enum
|
||||||
timeout = 10
|
timeout = ENUM_TIMEOUT
|
||||||
while timeout:
|
while timeout:
|
||||||
if os.path.exists(kbd) and os.path.exists(mouse1) and os.path.exists(mouse2):
|
if os.path.exists(kbd) and os.path.exists(mouse1) and os.path.exists(mouse2):
|
||||||
break
|
break
|
||||||
@@ -211,11 +240,13 @@ if __name__ == '__main__':
|
|||||||
|
|
||||||
# all possible tests, board_test is last to disable board's usb
|
# all possible tests, board_test is last to disable board's usb
|
||||||
all_tests = [
|
all_tests = [
|
||||||
'cdc_dual_ports', 'cdc_msc', 'dfu', 'dfu_runtime', 'hid_boot_interface', 'board_test'
|
'cdc_dual_ports', 'cdc_msc', 'dfu', 'dfu_runtime', 'hid_boot_interface',
|
||||||
|
'board_test'
|
||||||
]
|
]
|
||||||
|
|
||||||
for board in config['boards']:
|
for board in config['boards']:
|
||||||
print(f'Testing board:{board["name"]}')
|
print(f'Testing board:{board["name"]}')
|
||||||
|
debugger = board['debugger'].lower()
|
||||||
|
|
||||||
# default to all tests
|
# default to all tests
|
||||||
if 'tests' in board:
|
if 'tests' in board:
|
||||||
@@ -230,18 +261,27 @@ if __name__ == '__main__':
|
|||||||
test_list.remove(skip)
|
test_list.remove(skip)
|
||||||
|
|
||||||
for test in test_list:
|
for test in test_list:
|
||||||
mk_elf = f'examples/device/{test}/_build/{board["name"]}/{test}.elf'
|
# cmake, make, download from artifacts
|
||||||
cmake_elf = f'cmake-build/cmake-build-{board["name"]}/device/{test}/{test}.elf'
|
elf_list = [
|
||||||
if os.path.isfile(cmake_elf):
|
f'cmake-build/cmake-build-{board["name"]}/device/{test}/{test}.elf',
|
||||||
elf = cmake_elf
|
f'examples/device/{test}/_build/{board["name"]}/{test}.elf',
|
||||||
elif os.path.isfile(mk_elf):
|
f'{test}.elf'
|
||||||
elf = mk_elf
|
]
|
||||||
else:
|
|
||||||
|
elf = None
|
||||||
|
for e in elf_list:
|
||||||
|
if os.path.isfile(e):
|
||||||
|
elf = e
|
||||||
|
break
|
||||||
|
|
||||||
|
if elf is None:
|
||||||
print(f'Cannot find firmware file for {test}')
|
print(f'Cannot find firmware file for {test}')
|
||||||
sys.exit(-1)
|
sys.exit(-1)
|
||||||
|
|
||||||
if board['debugger'].lower() == 'jlink':
|
if debugger == 'jlink':
|
||||||
flash_jlink(board['debugger_sn'], board['cpu'], elf)
|
flash_jlink(board['debugger_sn'], board['cpu'], elf)
|
||||||
|
elif debugger == 'openocd':
|
||||||
|
flash_openocd(board['debugger_sn'], board['debugger_args'], elf)
|
||||||
else:
|
else:
|
||||||
# ToDo
|
# ToDo
|
||||||
pass
|
pass
|
||||||
|
@@ -11,3 +11,4 @@ attch
|
|||||||
endianess
|
endianess
|
||||||
pris
|
pris
|
||||||
busses
|
busses
|
||||||
|
ser
|
||||||
|
Reference in New Issue
Block a user