From 43bed1aa47647debf397562d3d77f26947be2abb Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 30 Sep 2023 23:19:06 -0700 Subject: [PATCH] jungle HITL tests setup (#1665) * setup new zoo * run * fix --------- Co-authored-by: Bruce Wayne --- Jenkinsfile | 8 +++--- python/constants.py | 6 ++-- python/usb.py | 13 +++++---- tests/ci_reset_hw.py | 56 ------------------------------------- tests/hitl/reset_jungles.py | 39 ++++++++++++++++++++++++++ tests/libs/resetter.py | 14 +++++++--- 6 files changed, 64 insertions(+), 72 deletions(-) delete mode 100755 tests/ci_reset_hw.py create mode 100755 tests/hitl/reset_jungles.py diff --git a/Jenkinsfile b/Jenkinsfile index 87f588a5..da378b6a 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -99,7 +99,6 @@ pipeline { } } - /* stage ('Acquire resource locks') { options { lock(resource: "pandas") @@ -115,15 +114,16 @@ pipeline { } } } - stage('prep') { + stage('jungle tests') { steps { script { retry (3) { - docker_run("reset hardware", 3, "python ./tests/ci_reset_hw.py") + docker_run("reset hardware", 3, "python ./tests/hitl/reset_jungles.py") } } } } + /* stage('pedal tests') { steps { script { @@ -146,9 +146,9 @@ pipeline { } } } + */ } } - */ } } } diff --git a/python/constants.py b/python/constants.py index 68ce4a51..8078da3e 100644 --- a/python/constants.py +++ b/python/constants.py @@ -11,6 +11,7 @@ class McuConfig(NamedTuple): mcu: str mcu_idcode: int sector_sizes: List[int] + sector_count: int # total sector count, used for MCU identification in DFU mode uid_address: int block_size: int serial_number_address: int @@ -32,13 +33,14 @@ Fx = ( 0x8000000, "bootstub.panda.bin", ) -F2Config = McuConfig("STM32F2", 0x411, [0x4000 for _ in range(4)] + [0x10000] + [0x20000 for _ in range(7)], *Fx) -F4Config = McuConfig("STM32F4", 0x463, [0x4000 for _ in range(4)] + [0x10000] + [0x20000 for _ in range(11)], *Fx) +F2Config = McuConfig("STM32F2", 0x411, [0x4000 for _ in range(4)] + [0x10000] + [0x20000 for _ in range(7)], 12, *Fx) +F4Config = McuConfig("STM32F4", 0x463, [0x4000 for _ in range(4)] + [0x10000] + [0x20000 for _ in range(11)], 16, *Fx) H7Config = McuConfig( "STM32H7", 0x483, [0x20000 for _ in range(7)], + 8, 0x1FF1E800, 0x400, # there is an 8th sector, but we use that for the provisioning chunk, so don't program over that! diff --git a/python/usb.py b/python/usb.py index 0ea0020b..0a012896 100644 --- a/python/usb.py +++ b/python/usb.py @@ -34,13 +34,14 @@ class STBootloaderUSBHandle(BaseSTBootloaderHandle): def __init__(self, libusb_device, libusb_handle): self._libusb_handle = libusb_handle - # lsusb -v | grep Flash + # example from F4: lsusb -v | grep Flash # iInterface 4 @Internal Flash /0x08000000/04*016Kg,01*064Kg,011*128Kg - out = libusb_handle.controlRead(0x80, 0x06, 0x0300 | 4, 0, 255) - flash_desc = bytes(out[2:]).decode('utf-16le') - sector_count = sum([int(s.split('*')[0]) for s in flash_desc.split('/')[-1].split(',')]) - - mcu_by_sector_count = {len(m.config.sector_sizes): m for m in McuType} + for i in range(20): + desc = libusb_handle.getStringDescriptor(i, 0) + if desc is not None and desc.startswith("@Internal Flash"): + sector_count = sum([int(s.split('*')[0]) for s in desc.split('/')[-1].split(',')]) + break + mcu_by_sector_count = {m.config.sector_count: m for m in McuType} assert sector_count in mcu_by_sector_count, f"Unkown MCU: {sector_count=}" self._mcu_type = mcu_by_sector_count[sector_count] diff --git a/tests/ci_reset_hw.py b/tests/ci_reset_hw.py deleted file mode 100755 index 2cdd3f1f..00000000 --- a/tests/ci_reset_hw.py +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env python3 -import concurrent.futures - -from panda import Panda, PandaDFU, PandaJungle -from panda.tests.libs.resetter import Resetter - -# all jungles used in the HITL tests -JUNGLES = [ - "058010800f51363038363036", - "23002d000851393038373731" -] - - -# Reset + flash all CI hardware to get it into a consistent state -# * ports 1-2 are jungles -# * port 3 is for the USB hubs -if __name__ == "__main__": - r = Resetter() - - r.enable_boot(True) - r.cycle_power(delay=7, ports=[1, 2, 3]) - r.enable_boot(False) - - pandas = PandaDFU.list() - print("DFU pandas:", pandas) - assert len(pandas) == 7 - - with concurrent.futures.ProcessPoolExecutor(max_workers=len(pandas)) as exc: - def recover(serial): - PandaDFU(serial).recover() - list(exc.map(recover, pandas, timeout=20)) - - r.cycle_power(delay=7, ports=[1, 2]) - - pandas = Panda.list() - print(pandas) - assert len(pandas) >= 7 - - with concurrent.futures.ProcessPoolExecutor(max_workers=len(pandas)) as exc: - def flash(serial): - with Panda(serial) as pf: - if pf.bootstub: - pf.flash() - list(exc.map(flash, pandas, timeout=20)) - - print("flashing jungle") - # flash jungles - pjs = PandaJungle.list() - assert set(pjs) == set(JUNGLES), f"Got different jungles than expected:\ngot {set(pjs)}\nexpected {set(JUNGLES)}" - for s in pjs: - with PandaJungle(serial=s) as pj: - print(f"- flashing {s}") - pj.flash() - - r.cycle_power(delay=0, ports=[1, 2]) - r.close() diff --git a/tests/hitl/reset_jungles.py b/tests/hitl/reset_jungles.py new file mode 100755 index 00000000..e9733279 --- /dev/null +++ b/tests/hitl/reset_jungles.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 +import concurrent.futures + +from panda import PandaJungle, PandaJungleDFU, McuType +from panda.tests.libs.resetter import Resetter + +def recover(s): + with PandaJungleDFU(s) as pd: + pd.recover() + +def flash(s): + with PandaJungle(s) as p: + p.flash() + return p.get_mcu_type() + +# Reset + flash all CI hardware to get it into a consistent state +# * port 1: jungles-under-test +# * port 2: USB hubs +# * port 3: HITL pandas and their jungles +if __name__ == "__main__": + with Resetter() as r: + # everything off + for i in range(1, 4): + r.enable_power(i, 0) + r.cycle_power(ports=[1, 2], dfu=True) + + dfu_serials = PandaJungleDFU.list() + assert len(dfu_serials) == 2 + + with concurrent.futures.ProcessPoolExecutor(max_workers=len(dfu_serials)) as exc: + list(exc.map(recover, dfu_serials, timeout=30)) + + # power cycle for H7 bootloader bug + r.cycle_power(ports=[1, 2]) + + serials = PandaJungle.list() + assert len(serials) == len(dfu_serials) + mcu_types = list(exc.map(flash, serials, timeout=20)) + assert set(mcu_types) == {McuType.F4, McuType.H7} diff --git a/tests/libs/resetter.py b/tests/libs/resetter.py index 720ae9c2..3868bde6 100644 --- a/tests/libs/resetter.py +++ b/tests/libs/resetter.py @@ -7,6 +7,12 @@ class Resetter(): self._handle = None self.connect() + def __enter__(self): + return self + + def __exit__(self, *args): + self.close() + def close(self): self._handle.close() self._context.close() @@ -36,16 +42,16 @@ class Resetter(): def enable_boot(self, enabled): self._handle.controlWrite((usb1.ENDPOINT_OUT | usb1.TYPE_VENDOR | usb1.RECIPIENT_DEVICE), 0xff, 0, enabled, b'') - def cycle_power(self, delay=5, ports=None): + def cycle_power(self, delay=5, dfu=False, ports=None): if ports is None: ports = [1, 2, 3] + self.enable_boot(dfu) for port in ports: self.enable_power(port, False) - - time.sleep(1) + time.sleep(0.5) for port in ports: self.enable_power(port, True) - time.sleep(delay) + self.enable_boot(False)