Files
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

87 lines
2.8 KiB
Python

"""Supplied Device panel data and request-only input for the large UI."""
from collections.abc import Callable
from dataclasses import dataclass
from enum import StrEnum
from openpilot.starpilot.galaxy.access import AccessStatus
class DeviceRequest(StrEnum):
# Open the pairing/management entry; this never pairs or unpairs a device.
OPEN_GALAXY = "open_galaxy"
PREVIEW_DRIVER_CAMERA = "preview_driver_camera"
RESET_DRIVER_MONITORING = "reset_driver_monitoring"
RESET_CALIBRATION = "reset_calibration"
@dataclass(frozen=True)
class DeviceAction:
request: DeviceRequest
@dataclass(frozen=True)
class DeviceState:
dongle_id: str = "N/A"
serial: str = "N/A"
galaxy_paired: bool | None = False
galaxy_configured: bool | None = None
galaxy_status: AccessStatus = AccessStatus.UNCONFIGURED
galaxy_local_only: bool = False
offroad: bool = True
available_actions: frozenset[DeviceRequest] = frozenset(DeviceRequest)
BUTTON_ROWS = (
(DeviceRequest.OPEN_GALAXY, 2),
(DeviceRequest.PREVIEW_DRIVER_CAMERA, 3),
(DeviceRequest.RESET_DRIVER_MONITORING, 4),
(DeviceRequest.RESET_CALIBRATION, 5),
)
def button_rect(request: DeviceRequest) -> tuple[int, int, int, int]:
index = dict(BUTTON_ROWS)[request]
return 1860, 50 + index * 171 + 35, 250, 100
def request_enabled(request: DeviceRequest, state: DeviceState) -> bool:
return request in state.available_actions and state.offroad
class DeviceInput:
"""Single pointer hit testing for the captured viewport; no device operation."""
def __init__(self, emit: Callable[[DeviceAction], None]):
self.emit = emit
self._pressed: tuple[float, float, DeviceRequest, AccessStatus | None] | None = None
@staticmethod
def _target(x: float, y: float, state: DeviceState) -> DeviceRequest | None:
if not (550 <= x < 2110 and 50 <= y < 1030):
return None
for request, _ in BUTTON_ROWS:
rx, ry, width, height = button_rect(request)
if rx <= x < rx + width and ry <= y < ry + height and request_enabled(request, state):
return request
return None
def press(self, x: float, y: float, state: DeviceState) -> None:
target = self._target(x, y, state)
self._pressed = (x, y, target, state.galaxy_status if target == DeviceRequest.OPEN_GALAXY else None) if target is not None else None
def move(self, x: float, y: float, state: DeviceState) -> None:
if self._pressed is not None:
_, _, target, status = self._pressed
if (self._target(x, y, state) != target or
(target == DeviceRequest.OPEN_GALAXY and state.galaxy_status != status)):
self.cancel()
def release(self, x: float, y: float, state: DeviceState) -> None:
self.move(x, y, state)
if self._pressed is not None:
self.emit(DeviceAction(self._pressed[2]))
self.cancel()
def cancel(self) -> None:
self._pressed = None