Files
firestar5683 ec8d7eb98b Contracts
Define persistent settings, typed schema fields and storage migrations before feature owners consume them. Keep calibration and parameter readers aligned with the shared data contracts.

Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com>
Co-authored-by: Danny <dannyirwin31@yahoo.com>
Co-authored-by: Harald Schäfer <harald.the.engineer@gmail.com>
Co-authored-by: Prabhaav Pillai <prabhaav@msu.edu>
Co-authored-by: dirwin31 <83434411+dirwin31@users.noreply.github.com>
Co-authored-by: firestarsdog <229254897+firestarsdog@users.noreply.github.com>

Co-authored-by: haraschax <6804392+haraschax@users.noreply.github.com>

Co-authored-by: Dom <168790843+firestar5683@users.noreply.github.com>
Co-authored-by: prabhaavp <prabhaav@msu.edu>
2026-10-14 19:56:17 -05:00

69 lines
2.8 KiB
Python

"""Pure fresh offroad evidence shared by local saved-setting action owners.
Python deviceState stamps MONOTONIC; C++ pandad stamps BOOTTIME on Linux.
"""
from dataclasses import dataclass
import os
DEVICE_TTL_NS = 1_500_000_000 # 2 Hz publisher, allowing one missed frame.
PANDA_TTL_NS = 300_000_000 # 10 Hz publisher, allowing one missed frame.
RESUME_SKEW_NS = 5_000_000
def host_parked(environ=os.environ) -> bool:
"""./dev galaxy, ./c3 and ./c4 have no car or drive-state publishers; they are always parked.
Only those launchers set SP_HOST_PARKED. Route replay (./onroad) keeps its recorded drive state.
"""
prefix = environ.get("OPENPILOT_PREFIX", "")
return (environ.get("SP_HOST_PARKED") == "1" and environ.get("SP_HOST_RUNTIME") == "1" and
bool(prefix) and prefix == environ.get("SP_HOST_PREFIX"))
@dataclass(frozen=True)
class ParkedEvidence:
manager_offroad: bool
device_seen: bool
device_alive: bool
device_valid: bool
device_started: bool
device_stamp_mono_ns: int
device_recv_mono_ns: int
device_boot_minus_mono_at_recv_ns: int | None
device_after_mono_ns: int # Collector must set a startup/resume barrier before receiving evidence.
panda_seen: bool
panda_alive: bool
panda_valid: bool
panda_stamp_boot_ns: int
panda_recv_mono_ns: int
panda_ignition: tuple[bool, ...]
def fresh_offroad(evidence: ParkedEvidence, *, now_mono_ns: int, now_boot_ns: int) -> bool:
"""Confirm effective offroad mode, including Force Offroad with ignition on."""
e = evidence
if (not e.manager_offroad or not all((e.device_seen, e.device_alive, e.device_valid,
e.panda_seen, e.panda_alive, e.panda_valid)) or
e.device_started or e.device_boot_minus_mono_at_recv_ns is None or
not e.panda_ignition or
min(e.device_stamp_mono_ns, e.panda_stamp_boot_ns, e.device_recv_mono_ns, e.panda_recv_mono_ns) <= 0 or
e.device_stamp_mono_ns <= e.device_after_mono_ns):
return False
device_mono_age = now_mono_ns - e.device_stamp_mono_ns
device_boot_age = now_boot_ns - (e.device_stamp_mono_ns + e.device_boot_minus_mono_at_recv_ns)
panda_boot_age = now_boot_ns - e.panda_stamp_boot_ns
device_receipt_age = now_mono_ns - e.device_recv_mono_ns
panda_receipt_age = now_mono_ns - e.panda_recv_mono_ns
return (0 <= device_mono_age <= DEVICE_TTL_NS and
-RESUME_SKEW_NS <= device_boot_age <= DEVICE_TTL_NS and
0 <= panda_boot_age <= PANDA_TTL_NS and
0 <= device_receipt_age <= DEVICE_TTL_NS and
0 <= panda_receipt_age <= PANDA_TTL_NS)
def fresh_parked(evidence: ParkedEvidence, *, now_mono_ns: int, now_boot_ns: int) -> bool:
"""Confirm fresh offroad mode with ignition off for operations that require it."""
return not any(evidence.panda_ignition) and fresh_offroad(evidence, now_mono_ns=now_mono_ns, now_boot_ns=now_boot_ns)