diff --git a/Jenkinsfile b/Jenkinsfile index b91dc9a9..11cedd5d 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -30,22 +30,6 @@ pipeline { } } } - stage('CANFD tests') { - steps { - lock(resource: "pedal", inversePrecedence: true, quantity: 1) { - timeout(time: 10, unit: 'MINUTES') { - script { - sh "docker run --rm --privileged \ - --volume /dev/bus/usb:/dev/bus/usb \ - --volume /var/run/dbus:/var/run/dbus \ - --net host \ - ${env.DOCKER_IMAGE_TAG} \ - bash -c 'cd /tmp/panda && ./board/build_all.sh && JUNGLE=058010800f51363038363036 H7_PANDAS_EXCLUDE=\"080021000c51303136383232\" ./tests/canfd/test_canfd.py'" - } - } - } - } - } stage('HITL tests') { steps { lock(resource: "pandas", inversePrecedence: true, quantity: 1) { @@ -62,5 +46,21 @@ pipeline { } } } + stage('CANFD tests') { + steps { + lock(resource: "pedal", inversePrecedence: true, quantity: 1) { + timeout(time: 10, unit: 'MINUTES') { + script { + sh "docker run --rm --privileged \ + --volume /dev/bus/usb:/dev/bus/usb \ + --volume /var/run/dbus:/var/run/dbus \ + --net host \ + ${env.DOCKER_IMAGE_TAG} \ + bash -c 'cd /tmp/panda && ./board/build_all.sh && JUNGLE=058010800f51363038363036 H7_PANDAS_EXCLUDE=\"080021000c51303136383232\" ./tests/canfd/test_canfd.py'" + } + } + } + } + } } } diff --git a/python/__init__.py b/python/__init__.py index 4f47bdfb..cee39f4d 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -206,8 +206,10 @@ class Panda: def __init__(self, serial: Optional[str] = None, claim: bool = True): self._serial = serial self._handle = None + self._bcd_device = None + + # connect and set mcu type self.connect(claim) - self._mcu_type = self.get_mcu_type() def close(self): self._handle.close() @@ -238,6 +240,12 @@ class Panda: if claim: self._handle.claimInterface(0) # self._handle.setInterfaceAltSetting(0, 0) # Issue in USB stack + + # bcdDevice wasn't always set to the hw type, ignore if it's the old constant + bcd = device.getbcdDevice() + if bcd is not None and bcd != 0x2300: + self._bcd_device = bytearray([bcd >> 8, ]) + break except Exception as e: print("exception", e) @@ -245,7 +253,9 @@ class Panda: if not wait or self._handle is not None: break context = usb1.USBContext() # New context needed so new devices show up - assert(self._handle is not None) + + assert self._handle is not None + self._mcu_type = self.get_mcu_type() self.health_version, self.can_version = self.get_packets_versions() print("connected") @@ -264,8 +274,10 @@ class Panda: self.reconnect() def reconnect(self): - self.close() - time.sleep(1.0) + if self._handle is not None: + self.close() + time.sleep(1.0) + success = False # wait up to 15 seconds for i in range(0, 15): @@ -436,7 +448,14 @@ class Panda: return bytes(part_1 + part_2) def get_type(self): - return self._handle.controlRead(Panda.REQUEST_IN, 0xc1, 0, 0, 0x40) + ret = self._handle.controlRead(Panda.REQUEST_IN, 0xc1, 0, 0, 0x40) + + # bootstub doesn't implement this call, so fallback to bcdDevice + invalid_type = self.bootstub and (ret is None or len(ret) != 1) + if invalid_type and self._bcd_device is not None: + ret = self._bcd_device + + return ret # Returns tuple with health packet version and CAN packet/USB packet version def get_packets_versions(self): diff --git a/tests/automated/1_program.py b/tests/automated/1_program.py index 2f4cefab..f610fa31 100644 --- a/tests/automated/1_program.py +++ b/tests/automated/1_program.py @@ -1,9 +1,11 @@ +import time from nose.tools import assert_equal from panda import Panda, DEFAULT_FW_FN, DEFAULT_H7_FW_FN, MCU_TYPE_H7 from .helpers import test_all_pandas, panda_connect_and_init def check_signature(p): + assert not p.bootstub, "Flashed firmware not booting. Stuck in bootstub." fn = DEFAULT_H7_FW_FN if p.get_mcu_type() == MCU_TYPE_H7 else DEFAULT_FW_FN firmware_sig = Panda.get_signature_from_firmware(fn) panda_sig = p.get_signature() @@ -18,5 +20,23 @@ def test_a_recover(p): @test_all_pandas @panda_connect_and_init(full_reset=False) def test_b_flash(p): + # test flash from bootstub + serial = p._serial + assert serial != None + p.reset(enter_bootstub=True) + p.close() + time.sleep(2) + + np = Panda(serial) + assert np.bootstub + assert np._serial == serial + np.flash() + np.close() + + p.reconnect() + p.reset() + check_signature(p) + + # test flash from app p.flash() check_signature(p) diff --git a/tests/automated/2_health.py b/tests/automated/2_health.py index 22de6da3..5442d3a2 100644 --- a/tests/automated/2_health.py +++ b/tests/automated/2_health.py @@ -1,7 +1,10 @@ import time + +from panda import Panda from panda_jungle import PandaJungle # pylint: disable=import-error from .helpers import panda_jungle, test_all_pandas, test_all_gen2_pandas, panda_connect_and_init + @test_all_pandas @panda_connect_and_init def test_ignition(p): @@ -38,3 +41,23 @@ def test_voltage(p): voltage = p.health()['voltage'] assert ((voltage > 10000) and (voltage < 14000)) time.sleep(0.1) + +@test_all_pandas +@panda_connect_and_init +def test_hw_type(p): + """ + hw type should be same in bootstub as application + """ + + hw_type = p.get_type() + mcu_type = p.get_mcu_type() + assert mcu_type is not None + + p.reset(enter_bootstub=True, reconnect=True) + p.close() + time.sleep(3) + pp = Panda(p.get_usb_serial()) + assert pp.bootstub + assert pp.get_type() == hw_type, "Bootstub and app hw type mismatch" + assert pp.get_mcu_type() == mcu_type, "Bootstub and app MCU type mismatch" + pp.close() diff --git a/tests/automated/helpers.py b/tests/automated/helpers.py index c2892d66..7bcc08fd 100644 --- a/tests/automated/helpers.py +++ b/tests/automated/helpers.py @@ -204,11 +204,15 @@ def panda_connect_and_init(fn=None, full_reset=True): # Check if the pandas did not throw any faults while running test for panda in pandas: - panda.reconnect() - assert panda.health()['fault_status'] == 0 + if not panda.bootstub: + panda.reconnect() + assert panda.health()['fault_status'] == 0 finally: for p in pandas: - p.close() + try: + p.close() + except Exception: + pass return wrapper def clear_can_buffers(panda):