mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-11-08 13:33:42 +08:00
58427d61d9
Select qualified speed-limit sources, preserve acceptance and override decisions, and publish distinct control and display coordinates. Carry accepted and pending source identity with each displayed decision. Co-authored-by: firestarsdog <229254897+firestarsdog@users.noreply.github.com>
59 lines
3.3 KiB
Python
59 lines
3.3 KiB
Python
"""Versioned accepted-limit persistence with explicit identity applicability."""
|
|
|
|
import json
|
|
import math
|
|
|
|
from openpilot.cereal import custom
|
|
from openpilot.starpilot.schema_cache import schema_fingerprint
|
|
from openpilot.starpilot.speed_limits import acceptance as acc
|
|
|
|
FORMAT = "starpilot-slc-accepted"
|
|
VERSION = 1
|
|
|
|
|
|
def encode(accepted: acc.AcceptedLimit, saved_wall_ns: int) -> str:
|
|
if not isinstance(accepted, acc.AcceptedLimit) or type(saved_wall_ns) is not int or saved_wall_ns <= 0:
|
|
raise ValueError("invalid accepted history")
|
|
candidate = accepted.candidate
|
|
identity = candidate.observation_identity
|
|
if not acc.observation_is_valid(acc.Observation(acc.ObservationKind.VALID, candidate), session_id=accepted.session_id):
|
|
raise ValueError("invalid accepted candidate")
|
|
return json.dumps({"format": FORMAT, "version": VERSION, "source_schema": schema_fingerprint(custom.SlcDashboardObservation.schema),
|
|
"saved_wall_ns": saved_wall_ns, "source": candidate.source, "speed_mps": candidate.speed_mps,
|
|
"identity_kind": identity.kind.value, "identity_value": identity.value,
|
|
"origin_session": accepted.session_id}, sort_keys=True, separators=(",", ":"))
|
|
|
|
|
|
def decode(raw: str | bytes | dict | None, *, session_id: str, current: acc.Observation,
|
|
now_wall_ns: int, max_age_ns: int) -> acc.AcceptedLimit | None:
|
|
"""Only durable geographic identity can be carried into a new drive.
|
|
|
|
The caller sets an applicability age from its source contract. Dashboard TSR
|
|
producer episodes are drive-local and cannot be restored across a new session.
|
|
"""
|
|
if raw is None or type(session_id) is not str or not session_id or type(now_wall_ns) is not int or type(max_age_ns) is not int:
|
|
return None
|
|
if max_age_ns < 0 or now_wall_ns <= 0:
|
|
return None
|
|
try:
|
|
value = raw if isinstance(raw, dict) else json.loads(raw)
|
|
if (type(value) is not dict or set(value) != {"format", "version", "source_schema", "saved_wall_ns", "source",
|
|
"speed_mps", "identity_kind", "identity_value", "origin_session"} or
|
|
value["format"] != FORMAT or type(value["version"]) is not int or value["version"] != VERSION or
|
|
value["source_schema"] != schema_fingerprint(custom.SlcDashboardObservation.schema) or
|
|
type(value["saved_wall_ns"]) is not int or value["saved_wall_ns"] > now_wall_ns or
|
|
now_wall_ns - value["saved_wall_ns"] > max_age_ns or
|
|
value["identity_kind"] != acc.IdentityKind.GEOGRAPHIC.value or
|
|
not isinstance(value["identity_value"], str) or not value["identity_value"] or
|
|
not isinstance(value["origin_session"], str) or not value["origin_session"] or
|
|
type(value["speed_mps"]) not in (int, float) or not math.isfinite(value["speed_mps"])):
|
|
return None
|
|
candidate = acc.Candidate(value["source"], acc.ObservationIdentity(acc.IdentityKind.GEOGRAPHIC, value["identity_value"]),
|
|
float(value["speed_mps"]))
|
|
if (not acc.observation_is_valid(acc.Observation(acc.ObservationKind.VALID, candidate), session_id=session_id) or
|
|
current != acc.Observation(acc.ObservationKind.VALID, candidate)):
|
|
return None
|
|
return acc.AcceptedLimit(candidate, session_id, 0)
|
|
except (TypeError, ValueError, OverflowError):
|
|
return None
|