mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-10-28 00:53:45 +08:00
a82935f326
Integrate onroad views, configurable widgets, local settings, steering-profile contracts, Bluetooth and Android Auto with their device and runtime services. Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com> Co-authored-by: Daniel Koepping <elkoled@gmail.com> Co-authored-by: Danny <dannyirwin31@yahoo.com> Co-authored-by: DimitriChrysafis <Dimitri.chrysafis@gmail.com> Co-authored-by: Dom <168790843+firestar5683@users.noreply.github.com> Co-authored-by: Harald Schäfer <harald.the.engineer@gmail.com> Co-authored-by: Prabhaav Pillai <prabhaav@msu.edu> Co-authored-by: Shane Smiskol <shane@smiskol.com> Co-authored-by: dirwin31 <83434411+dirwin31@users.noreply.github.com> Co-authored-by: firestarsdog <229254897+firestarsdog@users.noreply.github.com> Co-authored-by: stef <19478336+stefpi@users.noreply.github.com> Co-authored-by: whoisdomi <dcantu83@gmail.com> Co-authored-by: Intelli <contact@intelli.software> Co-authored-by: pharmacomaniac <blittle65@gmail.com> Co-authored-by: prabhaavp <prabhaav@msu.edu>
96 lines
4.2 KiB
Python
96 lines
4.2 KiB
Python
"""One read-only model snapshot adapter for native UI and authenticated Galaxy."""
|
|
|
|
from collections.abc import Callable
|
|
from pathlib import Path
|
|
import time
|
|
from typing import Any
|
|
|
|
from openpilot.cereal.services import SERVICE_LIST
|
|
from openpilot.starpilot.models.catalog import model_entries
|
|
from openpilot.starpilot.models.receipt import process_start_ticks, read_receipt
|
|
from openpilot.starpilot.models.status import ModelLoad, ModelOutput, ModelProcess, ModelStatus, project_status
|
|
|
|
|
|
MODEL_SERVICES = ("managerState", "modelV2", "drivingModelData")
|
|
|
|
|
|
def _stamp(sm: Any, service: str, now_mono_ns: int) -> tuple[int, bool]:
|
|
try:
|
|
stamp = sm.logMonoTime[service]
|
|
valid = (type(stamp) is int and 0 < stamp <= now_mono_ns and bool(sm.valid[service]) and
|
|
bool(sm.alive[service]) and now_mono_ns - stamp <= int(2e9 / SERVICE_LIST[service].frequency))
|
|
return stamp if type(stamp) is int else 0, valid
|
|
except (AttributeError, KeyError, TypeError, ValueError, ZeroDivisionError):
|
|
return 0, False
|
|
|
|
|
|
def _process(sm: Any, now_mono_ns: int, start_ticks: Callable[[int], int]) -> ModelProcess | None:
|
|
if not _stamp(sm, "managerState", now_mono_ns)[1]:
|
|
return None
|
|
try:
|
|
processes = [state for state in sm["managerState"].processes if state.name == "modeld"]
|
|
if len(processes) != 1:
|
|
return None
|
|
state = processes[0]
|
|
pid = int(state.pid)
|
|
if not state.running or pid <= 0:
|
|
return None
|
|
return ModelProcess(pid, start_ticks(pid), True)
|
|
except (AttributeError, KeyError, TypeError, ValueError, OSError):
|
|
return None
|
|
|
|
|
|
def _output(sm: Any, params: Any, now_mono_ns: int) -> ModelOutput | None:
|
|
model_stamp, model_valid = _stamp(sm, "modelV2", now_mono_ns)
|
|
driving_stamp, driving_valid = _stamp(sm, "drivingModelData", now_mono_ns)
|
|
if model_stamp == 0 and driving_stamp == 0:
|
|
return None
|
|
try:
|
|
raw_chestnut = params.get("ChestnutActive")
|
|
chestnut = (raw_chestnut if type(raw_chestnut) is bool else
|
|
None if raw_chestnut not in (None, b"0", b"1") else raw_chestnut == b"1")
|
|
big = bool(sm["modelV2"].big) if model_stamp else False
|
|
return ModelOutput(model_stamp, model_valid, driving_stamp, driving_valid, big, chestnut)
|
|
except (AttributeError, KeyError, TypeError, ValueError, OSError):
|
|
return None
|
|
|
|
|
|
def snapshot(sm: Any, params: Any, now_mono_ns: int, *, requested_id: str | None = None,
|
|
receipt_file: Path | None = None, start_ticks: Callable[[int], int] = process_start_ticks,
|
|
read_load: Callable[[Path | None], ModelLoad | None] = read_receipt) -> ModelStatus:
|
|
"""Sample one manager process and two live model outputs; never infer a load from Params."""
|
|
process = _process(sm, now_mono_ns, start_ticks)
|
|
output = _output(sm, params, now_mono_ns) if process is not None else None
|
|
load = read_load(receipt_file) if process is not None else None
|
|
return project_status(requested_id, process, load, output, now_mono_ns)
|
|
|
|
|
|
class ModelStatusSource:
|
|
"""Independent optional subscriber; it does not affect UI/global service health."""
|
|
|
|
def __init__(self, params: Any, sm: Any | None = None, clock: Callable[[], int] = time.monotonic_ns):
|
|
if sm is None:
|
|
from openpilot.cereal import messaging
|
|
sm = messaging.SubMaster(list(MODEL_SERVICES))
|
|
self.sm = sm
|
|
self.params = params
|
|
self.clock = clock
|
|
|
|
def snapshot(self) -> ModelStatus:
|
|
self.sm.update(0)
|
|
from openpilot.selfdrive.modeld.helpers import chestnut_present
|
|
from openpilot.starpilot.models.manager import requested_runtime_id
|
|
return snapshot(self.sm, self.params, self.clock(), requested_id=requested_runtime_id(chestnut_present()))
|
|
|
|
def json(self) -> dict[str, object]:
|
|
status = self.snapshot()
|
|
return {"schemaVersion": 1, "catalog": [{"id": entry.model_id, "name": entry.name,
|
|
"selectable": entry.selectable} for entry in model_entries().values()],
|
|
"requestedId": status.requested_id, "loadedId": status.loaded_id,
|
|
"variant": status.variant.value if status.variant is not None else None,
|
|
"health": status.health.value, "fallbackReason": status.fallback_reason,
|
|
"artifactSha256": status.artifact_sha256, "pendingNextStart": status.pending_next_start}
|
|
|
|
def close(self) -> None:
|
|
self.sm = None
|