From 443c35228d29378511b832bc1d8975daff7dca2f Mon Sep 17 00:00:00 2001 From: firestar5683 <168790843+firestar5683@users.noreply.github.com> Date: Thu, 27 Aug 2026 21:22:39 -0500 Subject: [PATCH] iPod stuck on replay f --- scripts/launch_onroad_desktop.sh | 13 ++++ tools/agnos/patch_system_reset_image.py | 9 ++- tools/agnos/test_patch_system_reset_image.py | 20 +++++- tools/agnos/validate_agnos_runtime.sh | 4 +- tools/replay/onroad_config.py | 69 +++++++++++++++++++- tools/replay/tests/test_onroad_config.py | 18 +++++ 6 files changed, 129 insertions(+), 4 deletions(-) diff --git a/scripts/launch_onroad_desktop.sh b/scripts/launch_onroad_desktop.sh index 3440c67e9..3e5249781 100755 --- a/scripts/launch_onroad_desktop.sh +++ b/scripts/launch_onroad_desktop.sh @@ -79,6 +79,7 @@ CEM_PID="" ALERT_PID="" CSC_PID="" GALAXY_PID="" +GPU_SYNC_PID="" GALAXY_PORT="" GALAXY_URL="" ONROAD_TEMP_PREFIX="" @@ -262,6 +263,9 @@ cleanup() { if [[ -n "${GALAXY_PID}" ]]; then kill "${GALAXY_PID}" >/dev/null 2>&1 || true fi + if [[ -n "${GPU_SYNC_PID}" ]]; then + kill "${GPU_SYNC_PID}" >/dev/null 2>&1 || true + fi for pid in "${UI_PIDS[@]-}"; do if [[ -n "${pid}" ]]; then @@ -286,6 +290,9 @@ cleanup() { if [[ -n "${GALAXY_PID}" ]]; then wait "${GALAXY_PID}" >/dev/null 2>&1 || true fi + if [[ -n "${GPU_SYNC_PID}" ]]; then + wait "${GPU_SYNC_PID}" >/dev/null 2>&1 || true + fi if [[ -n "${ONROAD_TEMP_PREFIX:-}" && "${ONROAD_TEMP_PREFIX}" == desktop-onroad-* ]]; then echo "Cleaning up temporary prefix environment (${ONROAD_TEMP_PREFIX})..." @@ -468,6 +475,11 @@ launch_replay() { fi } +launch_gpu_param_sync() { + "${ROOT_DIR}/.venv/bin/python3" "${ROOT_DIR}/tools/replay/onroad_config.py" sync-gpu & + GPU_SYNC_PID=$! +} + launch_nav_demo() { echo "Starting fake nav demo publisher..." "${ROOT_DIR}/.venv/bin/python3" "${ROOT_DIR}/tools/replay/fake_nav_demo.py" & @@ -687,6 +699,7 @@ fi echo "Starting replay: ${REPLAY_ARGS[*]}" launch_replay +launch_gpu_param_sync if [[ "${NAV_DEMO}" == "1" && "${OFFROAD_DEMO}" != "1" ]]; then launch_nav_demo diff --git a/tools/agnos/patch_system_reset_image.py b/tools/agnos/patch_system_reset_image.py index 1bd27251c..f4f358947 100755 --- a/tools/agnos/patch_system_reset_image.py +++ b/tools/agnos/patch_system_reset_image.py @@ -261,6 +261,12 @@ def install_bundled_installer(owner: str, branch: str, installer_url: str) -> No 'CONNECTIVITY_URL = "https://openpilot.comma.ai"\nOPENPILOT_URL = "file:///usr/comma/installer"' + bundled_installer_helper, ) + source = replace_exactly( + source, + 'USER_AGENT = f"AGNOSSetup-{HARDWARE.get_os_version()}"', + 'USER_AGENT = f"AGNOSSetup-{\'.\'.join(HARDWARE.get_os_version().split(\'.\')[:2])}"', + ) + source = replace_exactly( source, ''' # autocomplete incomplete URLs @@ -273,7 +279,7 @@ def install_bundled_installer(owner: str, branch: str, installer_url: str) -> No # installer.comma.ai binary targets Wayland and cannot run in this AGNOS. self.installer_url = ("https://installer.comma.ai/firestar5683/StarPilot" if url == OPENPILOT_URL else url) self.bundled_installer_target = (("firestar5683", "StarPilot") if url == OPENPILOT_URL else None) - match = re.fullmatch(r"(?:https://installer\\.comma\\.ai/)?([A-Za-z0-9_.-]+)/([A-Za-z0-9_.-]+)", url) + match = re.fullmatch(r"(?:https://installer\\.comma\\.ai/)?([A-Za-z0-9_-]+)/([A-Za-z0-9_.-]+)", url) if match: self.bundled_installer_target = match.groups() self.installer_url = f"https://installer.comma.ai/{'/'.join(self.bundled_installer_target)}" @@ -444,6 +450,7 @@ def validate_factory_install_payloads(setup: Path, installer: Path) -> None: if "CONNECTIVITY_URL = \"https://openpilot.comma.ai\"" not in source: raise RuntimeError(f"Connectivity check changed unexpectedly in {member}") for expected in ( + 'USER_AGENT = f"AGNOSSetup-{\'.\'.join(HARDWARE.get_os_version().split(\'.\')[:2])}"', "patch_bundled_installer(tmpfile, *self.bundled_installer_target)", "install_bundled_installer(*bundled_target, self.installer_url)", 'self.bundled_installer_target = (("firestar5683", "StarPilot") if url == OPENPILOT_URL else None)', diff --git a/tools/agnos/test_patch_system_reset_image.py b/tools/agnos/test_patch_system_reset_image.py index edec1d23c..fece34b6d 100644 --- a/tools/agnos/test_patch_system_reset_image.py +++ b/tools/agnos/test_patch_system_reset_image.py @@ -1,6 +1,7 @@ import importlib.util import json import os +import re import zipfile from pathlib import Path @@ -120,7 +121,8 @@ def _setup_source(member: str) -> str: 'error_msg = "Ensure the entered URL is valid, and the device\'s internet connection is good."\n' ' self.download_failed(self.download_url, error_msg)' ) - return f'''OPENPILOT_URL = "https://openpilot.comma.ai" + return f'''USER_AGENT = f"AGNOSSetup-{{HARDWARE.get_os_version()}}" +OPENPILOT_URL = "https://openpilot.comma.ai" {connectivity} {labels} def download(self, url: str): @@ -178,6 +180,9 @@ def test_patch_setup_zipapp_preserves_prefix_and_custom_flow(tmp_path): assert 'ButtonRadio("StarPilot"' in tici assert "urllib.request.urlopen(CONNECTIVITY_URL" in tici for setup_source in (mici, tici): + assert 'USER_AGENT = f"AGNOSSetup-{\'.\'.join(HARDWARE.get_os_version().split(\'.\')[:2])}"' in setup_source + assert 're.fullmatch(r"(?:https://installer\\.comma\\.ai/)?([A-Za-z0-9_-]+)/([A-Za-z0-9_.-]+)", url)' in setup_source + assert "install.sunnypilot.ai/release-mici" in setup_source assert "patch_bundled_installer(tmpfile, *self.bundled_installer_target)" in setup_source assert "install_bundled_installer(*bundled_target, self.installer_url)" in setup_source assert 'self.bundled_installer_target = (("firestar5683", "StarPilot") if url == OPENPILOT_URL else None)' in setup_source @@ -188,6 +193,19 @@ def test_patch_setup_zipapp_preserves_prefix_and_custom_flow(tmp_path): assert "self.download_url == OPENPILOT_URL" in setup_source assert 'url = f"https://installer.comma.ai/{url}"' not in setup_source + shorthand_pattern = r"(?:https://installer\.comma\.ai/)?([A-Za-z0-9_-]+)/([A-Za-z0-9_.-]+)" + assert re.fullmatch(shorthand_pattern, "sunnypilot/release-mici").groups() == ("sunnypilot", "release-mici") + assert re.fullmatch(shorthand_pattern, "https://installer.comma.ai/sunnypilot/release-mici").groups() == ( + "sunnypilot", "release-mici", + ) + for installer_url in ( + "install.sunnypilot.ai/release-mici", + "https://install.sunnypilot.ai/release-mici", + "staging.sunnypilot.ai", + "dev.sunnypilot.ai", + ): + assert re.fullmatch(shorthand_pattern, installer_url) is None + def test_patch_installer_binary_keeps_elf_layout_and_targets_starpilot(tmp_path): source = tmp_path / "installer" diff --git a/tools/agnos/validate_agnos_runtime.sh b/tools/agnos/validate_agnos_runtime.sh index 992db70c2..60f4cf648 100755 --- a/tools/agnos/validate_agnos_runtime.sh +++ b/tools/agnos/validate_agnos_runtime.sh @@ -42,6 +42,8 @@ with zipfile.ZipFile("/usr/comma/setup") as setup: source = setup.read(member).decode("utf-8") assert 'OPENPILOT_URL = "file:///usr/comma/installer"' in source, member assert 'CONNECTIVITY_URL = "https://openpilot.comma.ai"' in source, member + assert 'USER_AGENT = f"AGNOSSetup-{\'.\'.join(HARDWARE.get_os_version().split(\'.\')[:2])}"' in source, member + assert 're.fullmatch(r"(?:https://installer\\.comma\\.ai/)?([A-Za-z0-9_-]+)/([A-Za-z0-9_.-]+)", url)' in source, member assert "StarPilot" in source, member assert "install_bundled_installer(*bundled_target, self.installer_url)" in source, member assert 'self.bundled_installer_target = (("firestar5683", "StarPilot") if url == OPENPILOT_URL else None)' in source, member @@ -80,7 +82,7 @@ c548c10b875b8841637017503ac73b1d466a36926df59fc5382221c021738d90 /usr/local/lib 41b0a5e7807506779f2163d23d5120949efaeeaf96fb9b69758551c9af7c7c1a /usr/local/lib/libswresample.so.3.5.100 370d154aaf7e1e9ee433c069348ae885036a9d8cc4c8babfbfae12c8d5b3f2e8 /usr/comma/installer 934f74ab4b2ac06048418c2857be3a041e192ec03c09979987691c23c91353bd /usr/comma/setup_keys -6565acac9eb8167931f6ad50c62254b64f037d21a7944456bd8ec328c7f4af0b /usr/comma/setup +d3f66148cb25ce381f5abf33cd9e0a2eb5e7fa20b137eeb1bf226d05534fc32f /usr/comma/setup bcba2b336cf0ca852786f8a58bbce407e0e9fe952c26fc5d903f6d9a34b44b4f /usr/comma/comma.sh HASHES diff --git a/tools/replay/onroad_config.py b/tools/replay/onroad_config.py index 27615a357..9f215c545 100644 --- a/tools/replay/onroad_config.py +++ b/tools/replay/onroad_config.py @@ -55,6 +55,47 @@ class ReplayArgs: auto_source: bool = False +@dataclass +class ReplayGpuState: + """Reconstruct modeld's transient GPU Params from replayed messages.""" + present: bool = False + compiled: bool = False + loading: bool = False + active: bool = False + failed: bool = False + + def update(self, *, present: bool | None = None, event_names: Sequence[str] = (), model_updated: bool = False) -> tuple[bool, bool, bool, bool]: + loading_event = "bigModelLoading" in event_names + failed_event = "bigModelFailed" in event_names + + if present is not None: + self.present = present + if not present: + self.compiled = False + self.loading = False + self.active = False + self.failed = False + + if loading_event or failed_event: + self.present = True + self.compiled = True + + if loading_event: + self.loading = True + self.active = False + self.failed = False + elif failed_event: + self.loading = False + self.active = False + self.failed = True + elif model_updated and self.present and self.compiled and not self.failed: + self.compiled = True + self.loading = False + self.active = True + + return self.present, self.compiled, self.loading, self.active + + def _truthy_env(name: str) -> bool: return os.getenv(name, "").lower() in {"1", "true", "yes", "on"} @@ -291,10 +332,34 @@ def _cmd_seed(args: Sequence[str]) -> int: return 0 +def _cmd_sync_gpu() -> int: + from cereal import messaging + + params = Params() + sm = messaging.SubMaster(["deviceState", "onroadEvents", "modelV2"]) + state = ReplayGpuState() + last_values: tuple[bool, bool, bool, bool] | None = None + + while True: + sm.update(1000) + if not any(sm.updated.values()): + continue + + present = bool(sm["deviceState"].chestnutPresent) if sm.updated["deviceState"] else None + event_names = tuple(str(event.name) for event in sm["onroadEvents"]) if sm.updated["onroadEvents"] else () + values = state.update(present=present, event_names=event_names, model_updated=sm.updated["modelV2"]) + if values == last_values: + continue + + for key, value in zip(("UsbGpuPresent", "UsbGpuCompiled", "UsbGpuLoading", "UsbGpuActive"), values, strict=True): + params.put_bool(key, value) + last_values = values + + def main(argv: Sequence[str] | None = None) -> int: argv = list(sys.argv[1:] if argv is None else argv) if not argv or argv[0] in {"-h", "--help"}: - print("Usage: onroad_config.py (select-ui|seed) ", file=sys.stderr) + print("Usage: onroad_config.py (select-ui|seed|sync-gpu) ", file=sys.stderr) return 2 command = argv[0] @@ -306,6 +371,8 @@ def main(argv: Sequence[str] | None = None) -> int: return _cmd_select_ui(args) if command == "seed": return _cmd_seed(args) + if command == "sync-gpu": + return _cmd_sync_gpu() print(f"Unknown command: {command}", file=sys.stderr) return 2 diff --git a/tools/replay/tests/test_onroad_config.py b/tools/replay/tests/test_onroad_config.py index ad5eb60eb..d77cdb2f6 100644 --- a/tools/replay/tests/test_onroad_config.py +++ b/tools/replay/tests/test_onroad_config.py @@ -81,6 +81,24 @@ def test_select_ui_uses_c3_for_all_big_routes(): assert onroad_config.select_ui_target(None) == "c3" +def test_replay_gpu_state_reconstructs_loading_failure_and_restart(): + state = onroad_config.ReplayGpuState() + + assert state.update(present=True) == (True, False, False, False) + assert state.update(event_names=("selfdriveInitializing", "bigModelLoading")) == (True, True, True, False) + assert state.update(event_names=("bigModelFailed",), model_updated=True) == (True, True, False, False) + assert state.update(model_updated=True) == (True, True, False, False) + assert state.update(event_names=("bigModelLoading",)) == (True, True, True, False) + assert state.update(model_updated=True) == (True, True, False, True) + + +def test_replay_gpu_state_detects_active_later_segment(): + state = onroad_config.ReplayGpuState() + + assert state.update(present=True, model_updated=True) == (True, True, False, True) + assert state.update(present=False) == (False, False, False, False) + + def test_seed_onroad_params_uses_logged_disabled_bool_and_desktop_overrides(monkeypatch): monkeypatch.setenv("SP_ONROAD_NAV_DEMO", "1") params = FakeParams()