Files
StarPilot/openpilot/starpilot/galaxy/device_state.py
T
firestar5683 a82935f326 User interfaces and Android Auto
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>
2026-10-14 20:02:39 -05:00

77 lines
3.1 KiB
Python

"""Lightweight vehicle status for Galaxy's header; never grants control authority."""
import threading
import time
from openpilot.starpilot.parked_evidence import RESUME_SKEW_NS, host_parked
TTL_NS = 3_000_000_000
class DeviceStateSource:
def __init__(self, messages=None, *, mono=time.monotonic_ns,
boot=lambda: time.clock_gettime_ns(getattr(time, 'CLOCK_BOOTTIME', time.CLOCK_MONOTONIC))):
self.messages, self.mono, self.boot = messages, mono, boot
self.lock = threading.Lock()
self.floor = getattr(messages, "after_mono_ns", mono())
self.offset = None
self.device_offset = None
self.closed = False
def sample(self):
unknown = {'state': None, 'maxAgeMs': 0}
with self.lock:
if self.closed:
return unknown
if host_parked():
return {'state': 'parked', 'maxAgeMs': TTL_NS // 1_000_000}
try:
if self.messages is None:
from openpilot.cereal import messaging
self.messages = messaging.SubMaster(['deviceState', 'pandaStates'])
snapshot = getattr(self.messages, 'snapshot', None)
if callable(snapshot):
sm = snapshot()
if sm is None:
return unknown
self.floor = max(self.floor, sm.after_mono_ns)
self.device_offset = sm.device_offset_ns
else:
sm = self.messages
sm.update(0)
before, boot, now = self.mono(), self.boot(), self.mono()
if not 0 <= now - before <= RESUME_SKEW_NS:
return unknown
offset = boot - (before + now) // 2
if self.offset is not None and abs(offset - self.offset) > RESUME_SKEW_NS:
self.floor, self.device_offset = now, None
self.offset = offset
if sm.updated['deviceState'] and int(sm.logMonoTime['deviceState']) > self.floor:
self.device_offset = offset
if self.device_offset is None or not all(sm.seen[key] and sm.valid[key] for key in ('deviceState', 'pandaStates')):
return unknown
stamp = int(sm.logMonoTime['deviceState'])
if stamp <= self.floor:
return unknown
ages = (now - stamp, boot - (stamp + self.device_offset), boot - int(sm.logMonoTime['pandaStates']),
now - int(sm.recv_time['deviceState'] * 1e9), now - int(sm.recv_time['pandaStates'] * 1e9))
if not all(0 <= age < TTL_NS for age in ages) or not len(sm['pandaStates']):
return unknown
state = ('driving' if sm['deviceState'].started else
'standby' if any(p.ignitionLine or p.ignitionCan for p in sm['pandaStates']) else 'parked')
return {'state': state, 'maxAgeMs': (TTL_NS - max(ages)) // 1_000_000}
except (OSError, RuntimeError, AttributeError, TypeError, ValueError, OverflowError):
return unknown
def close(self):
with self.lock:
self.closed = True
if self.messages is not None:
for socket in getattr(self.messages, 'sock', {}).values():
close = getattr(socket, 'close', None)
if close is not None:
close()
self.messages = None
self.floor, self.offset, self.device_offset = self.mono(), None, None