diff --git a/common/params_keys.h b/common/params_keys.h index b81a373d0876ef..64d77177846542 100644 --- a/common/params_keys.h +++ b/common/params_keys.h @@ -103,8 +103,6 @@ inline static std::unordered_map keys = { {"OnroadCycleRequested", {CLEAR_ON_MANAGER_START, BOOL}}, {"OpenpilotEnabledToggle", {PERSISTENT, BOOL, "1"}}, {"PandaHeartbeatLost", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}}, - {"PandaSomResetTriggered", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}}, - {"PandaSignatures", {CLEAR_ON_MANAGER_START, BYTES}}, {"PrimeType", {PERSISTENT, INT}}, {"RecordAudio", {PERSISTENT, BOOL}}, {"RecordAudioFeedback", {PERSISTENT, BOOL, "0"}}, diff --git a/selfdrive/pandad/pandad.py b/selfdrive/pandad/pandad.py index df2b4f7ee895a6..fcae0d8b3779a8 100755 --- a/selfdrive/pandad/pandad.py +++ b/selfdrive/pandad/pandad.py @@ -14,21 +14,11 @@ def get_expected_signature() -> bytes: - try: - fn = os.path.join(FW_PATH, McuType.H7.config.app_fn) - return Panda.get_signature_from_firmware(fn) - except Exception: - cloudlog.exception("Error computing expected signature") - return b"" - -def flash_panda(panda_serial: str) -> Panda: - try: - panda = Panda(panda_serial) - except PandaProtocolMismatch: - cloudlog.warning("detected protocol mismatch, reflashing panda") - HARDWARE.recover_internal_panda() - raise + fn = os.path.join(FW_PATH, McuType.H7.config.app_fn) + return Panda.get_signature_from_firmware(fn) +def flash_panda(panda_serial: str): + panda = Panda(panda_serial) fw_signature = get_expected_signature() internal_panda = panda.is_internal() @@ -58,7 +48,7 @@ def flash_panda(panda_serial: str) -> Panda: cloudlog.info("Version mismatch after flashing, exiting") raise AssertionError - return panda + panda.close() def main() -> None: @@ -74,89 +64,51 @@ def signal_handler(signum, frame): do_exit = False signal.signal(signal.SIGINT, signal_handler) - count = 0 - first_run = True - params = Params() - no_internal_panda_count = 0 + # check health for lost heartbeat + try: + for s in Panda.list(): + with Panda(s) as p: + health = p.health() + if p.is_internal() and health["heartbeat_lost"]: + Params().put_bool("PandaHeartbeatLost", True) + cloudlog.event("heartbeat lost", deviceState=health) + except Exception: + cloudlog.exception("pandad.uncaught_exception") + count = 0 while not do_exit: try: - count += 1 cloudlog.event("pandad.flash_and_connect", count=count) - params.remove("PandaSignatures") - - # Handle missing internal panda - if no_internal_panda_count > 0: - if no_internal_panda_count == 3: - cloudlog.info("No pandas found, putting internal panda into DFU") - HARDWARE.recover_internal_panda() - else: - cloudlog.info("No pandas found, resetting internal panda") - HARDWARE.reset_internal_panda() - time.sleep(3) # wait to come back up + if (count % 2) == 0: + HARDWARE.reset_internal_panda() + else: + HARDWARE.recover_internal_panda() + count += 1 # Flash all Pandas in DFU mode - dfu_serials = PandaDFU.list() - if len(dfu_serials) > 0: - for serial in dfu_serials: - cloudlog.info(f"Panda in DFU mode found, flashing recovery {serial}") - PandaDFU(serial).recover() + for serial in PandaDFU.list(): + cloudlog.info(f"Panda in DFU mode found, flashing recovery {serial}") + PandaDFU(serial).recover() time.sleep(1) panda_serials = Panda.list() - if len(panda_serials) == 0: - no_internal_panda_count += 1 - continue - - cloudlog.info(f"{len(panda_serials)} panda(s) found, connecting - {panda_serials}") - - # Flash the first panda - panda_serial = panda_serials[0] - panda = flash_panda(panda_serial) - - # Ensure internal panda is present if expected - if HARDWARE.has_internal_panda() and not panda.is_internal(): - cloudlog.error("Internal panda is missing, trying again") - no_internal_panda_count += 1 - continue - no_internal_panda_count = 0 - - # log panda fw version - params.put("PandaSignatures", panda.get_signature()) - - # check health for lost heartbeat - health = panda.health() - if health["heartbeat_lost"]: - params.put_bool("PandaHeartbeatLost", True) - cloudlog.event("heartbeat lost", deviceState=health, serial=panda.get_usb_serial()) - if health["som_reset_triggered"]: - params.put_bool("PandaSomResetTriggered", True) - cloudlog.event("panda.som_reset_triggered", health=health, serial=panda.get_usb_serial()) - - if first_run: - # reset panda to ensure we're in a good state - cloudlog.info(f"Resetting panda {panda.get_usb_serial()}") - panda.reset(reconnect=True) - - panda.close() + if len(panda_serials): + assert len(panda_serials) == 1 + cloudlog.info(f"{len(panda_serials)} panda found, connecting - {panda_serials}") + flash_panda(panda_serials[0]) + + # run real pandad + os.environ['MANAGER_DAEMON'] = 'pandad' + process = subprocess.Popen(["./pandad"], cwd=os.path.join(BASEDIR, "selfdrive/pandad")) + process.wait() # TODO: wrap all panda exceptions in a base panda exception except (usb1.USBErrorNoDevice, usb1.USBErrorPipe): # a panda was disconnected while setting everything up. let's try again cloudlog.exception("Panda USB exception while setting up") - continue except PandaProtocolMismatch: cloudlog.exception("pandad.protocol_mismatch") - continue except Exception: cloudlog.exception("pandad.uncaught_exception") - continue - - first_run = False - - # run pandad with all connected serials as arguments - os.environ['MANAGER_DAEMON'] = 'pandad' - process = subprocess.Popen(["./pandad", panda_serial], cwd=os.path.join(BASEDIR, "selfdrive/pandad")) - process.wait() if __name__ == "__main__": diff --git a/selfdrive/pandad/tests/bootstub.panda_h7_spiv0.bin b/selfdrive/pandad/tests/bootstub.panda_h7_spiv0.bin deleted file mode 100755 index 5cf2fa45196484..00000000000000 Binary files a/selfdrive/pandad/tests/bootstub.panda_h7_spiv0.bin and /dev/null differ diff --git a/selfdrive/pandad/tests/test_pandad.py b/selfdrive/pandad/tests/test_pandad.py index 6a5840d4875b36..9dacd3f5a88d40 100644 --- a/selfdrive/pandad/tests/test_pandad.py +++ b/selfdrive/pandad/tests/test_pandad.py @@ -15,12 +15,6 @@ @pytest.mark.tici class TestPandad: - - def setup_method(self): - # ensure panda is up - if len(Panda.list()) == 0: - self._run_test(60) - def teardown_method(self): managed_processes['pandad'].stop() @@ -30,7 +24,7 @@ def _run_test(self, timeout=30) -> float: managed_processes['pandad'].start() while (time.monotonic() - st) < timeout: - sm.update(100) + sm.update(10) if len(sm['pandaStates']) and sm['pandaStates'][0].pandaType != log.PandaState.PandaType.unknown: break dt = time.monotonic() - st @@ -45,10 +39,6 @@ def _go_to_dfu(self): HARDWARE.recover_internal_panda() assert Panda.wait_for_dfu(None, 10) - def _assert_no_panda(self): - assert not Panda.wait_for_dfu(None, 3) - assert not Panda.wait_for_panda(None, 3) - def _flash_bootstub(self, fn): self._go_to_dfu() pd = PandaDFU(None) @@ -56,12 +46,11 @@ def _flash_bootstub(self, fn): fn = os.path.join(HERE, pd.get_mcu_type().config.bootstub_fn) with open(fn, "rb") as f: pd.program_bootstub(f.read()) - pd.reset() HARDWARE.reset_internal_panda() def test_in_dfu(self): HARDWARE.recover_internal_panda() - self._run_test(60) + self._run_test() def test_in_bootstub(self): with Panda() as p: @@ -69,30 +58,24 @@ def test_in_bootstub(self): assert p.bootstub self._run_test() - def test_internal_panda_reset(self): + def test_in_reset(self): gpio_init(GPIO.STM_RST_N, True) gpio_set(GPIO.STM_RST_N, 1) - time.sleep(0.5) - assert all(not Panda(s).is_internal() for s in Panda.list()) + assert not Panda.list() self._run_test() - assert any(Panda(s).is_internal() for s in Panda.list()) - - def test_old_spi_protocol(self): - # flash firmware with old SPI protocol - self._flash_bootstub(os.path.join(HERE, "bootstub.panda_h7_spiv0.bin")) - self._run_test(45) - def test_release_to_devel_bootstub(self): + st = time.monotonic() self._flash_bootstub(None) - self._run_test(45) + print("flash done", time.monotonic() - st) + self._run_test() def test_recover_from_bad_bootstub(self): self._go_to_dfu() with PandaDFU(None) as pd: - pd.program_bootstub(b"\x00"*1024) - pd.reset() + pd._handle.program(pd.get_mcu_type().config.bootstub_address, b"\x00"*100) HARDWARE.reset_internal_panda() - self._assert_no_panda() + assert not Panda.list() + assert not PandaDFU.list() - self._run_test(60) + self._run_test() diff --git a/system/hardware/tici/hardware.py b/system/hardware/tici/hardware.py index dcdeb8ac47b831..120ca77107992e 100644 --- a/system/hardware/tici/hardware.py +++ b/system/hardware/tici/hardware.py @@ -414,7 +414,7 @@ def reset_internal_panda(self): gpio_set(GPIO.STM_RST_N, 1) gpio_set(GPIO.STM_BOOT0, 0) - time.sleep(1) + time.sleep(0.01) gpio_set(GPIO.STM_RST_N, 0) def recover_internal_panda(self): @@ -423,9 +423,9 @@ def recover_internal_panda(self): gpio_set(GPIO.STM_RST_N, 1) gpio_set(GPIO.STM_BOOT0, 1) - time.sleep(0.5) + time.sleep(0.01) gpio_set(GPIO.STM_RST_N, 0) - time.sleep(0.5) + time.sleep(0.01) gpio_set(GPIO.STM_BOOT0, 0) def booted(self):