mirror of
https://github.com/infiniteCable2/openpilot.git
synced 2026-08-05 16:26:10 +08:00
speedup test_pandad.py (#38009)
* speedup slowest * less setup * rm som reset logging * simpliy a lil more * lil more * down to 36s * sleeeeeeep * finishing touches * oopsie * ty fix --------- Co-authored-by: Comma Device <device@comma.ai>
This commit is contained in:
@@ -103,8 +103,6 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> 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"}},
|
||||
|
||||
+32
-80
@@ -14,21 +14,11 @@ from openpilot.common.swaglog import cloudlog
|
||||
|
||||
|
||||
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 main() -> None:
|
||||
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
|
||||
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])
|
||||
|
||||
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()
|
||||
# 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__":
|
||||
|
||||
Binary file not shown.
@@ -15,12 +15,6 @@ HERE = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
@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 @@ class TestPandad:
|
||||
|
||||
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 @@ class TestPandad:
|
||||
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 @@ class TestPandad:
|
||||
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 @@ class TestPandad:
|
||||
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()
|
||||
|
||||
@@ -414,7 +414,7 @@ class Tici(HardwareBase):
|
||||
|
||||
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 @@ class Tici(HardwareBase):
|
||||
|
||||
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):
|
||||
|
||||
Reference in New Issue
Block a user