mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-11-08 05:23:41 +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>
200 lines
6.6 KiB
Python
200 lines
6.6 KiB
Python
"""Strict saved visibility choices shared by settings and onroad presentation."""
|
|
|
|
from dataclasses import dataclass
|
|
from enum import IntEnum
|
|
import math
|
|
import os
|
|
import stat
|
|
from typing import Any
|
|
|
|
from openpilot.common.constants import CV
|
|
from openpilot.starpilot.saved_source import read_saved
|
|
|
|
|
|
class CameraViewChoice(IntEnum):
|
|
AUTO = 0
|
|
DRIVER = 1
|
|
STANDARD = 2
|
|
WIDE = 3
|
|
NONE = 4
|
|
|
|
|
|
CAMERA_LABELS = ("Auto", "Driver", "Standard", "Wide", "None")
|
|
|
|
|
|
class LeadInfoMode(IntEnum):
|
|
OFF = 0
|
|
DISTANCE = 1
|
|
SPEED = 2
|
|
|
|
|
|
LEAD_INFO_LABELS = ("Off", "Distance", "Speed")
|
|
|
|
|
|
def format_lead_info(lead, mode: int, metric: bool | None) -> str:
|
|
"""The lead's distance or speed for the text above the lead marker; empty when there is nothing to show."""
|
|
if lead is None or not lead.present or mode not in (LeadInfoMode.DISTANCE, LeadInfoMode.SPEED) or metric is None:
|
|
return ""
|
|
try:
|
|
value = float(lead.dRel if mode == LeadInfoMode.DISTANCE else lead.vLead)
|
|
except (AttributeError, TypeError, ValueError, OverflowError):
|
|
return ""
|
|
if not math.isfinite(value):
|
|
return ""
|
|
value = max(value, 0.0)
|
|
if mode == LeadInfoMode.DISTANCE:
|
|
return f"{round(value if metric else value * 3.28084)} {'m' if metric else 'ft'}"
|
|
return f"{round(value * (CV.MS_TO_KPH if metric else CV.MS_TO_MPH))} {'km/h' if metric else 'mph'}"
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class SavedCameraView:
|
|
raw: bytes | None
|
|
value: CameraViewChoice | None
|
|
readable: bool
|
|
|
|
|
|
def read_camera_view(params: Any) -> SavedCameraView:
|
|
try:
|
|
raw, readable = read_saved(params, "CameraView", 8)
|
|
except (AttributeError, OSError, TypeError, ValueError):
|
|
return SavedCameraView(None, None, False)
|
|
if not readable:
|
|
return SavedCameraView(raw, None, False)
|
|
if raw is None:
|
|
return SavedCameraView(None, CameraViewChoice.STANDARD, True)
|
|
try:
|
|
if raw not in (b"0", b"1", b"2", b"3", b"4"):
|
|
raise ValueError("Invalid camera choice")
|
|
return SavedCameraView(raw, CameraViewChoice(int(raw)), True)
|
|
except (TypeError, ValueError):
|
|
return SavedCameraView(raw, None, True)
|
|
|
|
|
|
DEFAULTS = {
|
|
"DeveloperSidebar": False,
|
|
"HideSpeed": False,
|
|
"HideMaxSpeed": False,
|
|
"HideSteeringWheel": False,
|
|
"HideDMIcon": False,
|
|
"HidePersonalityAlerts": False,
|
|
"ShowBrakeStatus": False,
|
|
"PedalsOnUI": False,
|
|
"DriverCamera": False,
|
|
"StoppedTimer": False,
|
|
"StockConfidenceBallWidget": False,
|
|
"EnableTorqueBarWidget": True,
|
|
"RainbowPath": False,
|
|
"HideLeadMarker": True,
|
|
"LeadInfo": False,
|
|
"BlindSpotMetrics": True,
|
|
"SignalMetrics": False,
|
|
"ShowSpeedLimits": True,
|
|
"UseVienna": False,
|
|
}
|
|
MAX_RAW_BYTES = 16
|
|
# Superseded by the onroad customization document; read only to retire them.
|
|
RETIRED_DISPLAY_KEYS = ("HideSpeed", "HideMaxSpeed", "HideSteeringWheel", "HideDMIcon", "EnableTorqueBarWidget",
|
|
"StoppedTimer", "RainbowPath")
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class SavedVisibility:
|
|
raw: bytes | None
|
|
value: bool | None
|
|
readable: bool = True
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class SavedLeadInfo:
|
|
flag: SavedVisibility
|
|
mode_raw: bytes | None
|
|
mode: LeadInfoMode | None
|
|
readable: bool
|
|
|
|
|
|
def read_lead_info(params: Any) -> SavedLeadInfo:
|
|
flag = read_visibility(params, "LeadInfo")
|
|
try:
|
|
raw, readable = read_saved(params, "LeadInfoMode", 16)
|
|
except (AttributeError, OSError, TypeError, ValueError):
|
|
raw, readable = None, False
|
|
if not flag.readable or not readable:
|
|
return SavedLeadInfo(flag, raw, None, False)
|
|
if flag.value is None or raw not in (None, b"0", b"1", b"2"):
|
|
return SavedLeadInfo(flag, raw, None, True)
|
|
if not flag.value:
|
|
mode = LeadInfoMode.OFF
|
|
elif raw in (None, b"0", b"2"):
|
|
mode = LeadInfoMode.SPEED
|
|
else:
|
|
mode = LeadInfoMode.DISTANCE
|
|
return SavedLeadInfo(flag, raw, mode, True)
|
|
|
|
|
|
def read_visibility(params: Any, key: str) -> SavedVisibility:
|
|
if key not in DEFAULTS:
|
|
raise KeyError(key)
|
|
try:
|
|
path = params.get_param_path(key)
|
|
descriptor = os.open(path, os.O_RDONLY | os.O_NONBLOCK | os.O_NOFOLLOW)
|
|
except FileNotFoundError:
|
|
return SavedVisibility(None, DEFAULTS[key])
|
|
except (AttributeError, OSError, TypeError, ValueError):
|
|
return SavedVisibility(None, None, False)
|
|
try:
|
|
if not stat.S_ISREG(os.fstat(descriptor).st_mode):
|
|
return SavedVisibility(None, None, False)
|
|
raw = os.read(descriptor, MAX_RAW_BYTES + 1)
|
|
except OSError:
|
|
return SavedVisibility(None, None, False)
|
|
finally:
|
|
os.close(descriptor)
|
|
if len(raw) > MAX_RAW_BYTES:
|
|
return SavedVisibility(raw, None, False)
|
|
return SavedVisibility(raw, False if raw == b"0" else True if raw == b"1" else None)
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class OnroadAppearance:
|
|
show_developer_sidebar: bool = False
|
|
show_blindspot_border: bool = True
|
|
show_signal_border: bool = False
|
|
show_speed_limit_sign: bool = True
|
|
use_vienna_sign: bool = False
|
|
show_stock_confidence_ball: bool = False
|
|
show_lead_indicator: bool = False
|
|
lead_info_mode: LeadInfoMode = LeadInfoMode.OFF
|
|
lead_info_metric: bool | None = False
|
|
camera_view: CameraViewChoice = CameraViewChoice.STANDARD
|
|
driver_camera_on_reverse: bool = False
|
|
hide_personality_alerts: bool = False
|
|
wheel_pedal_feedback: bool = False
|
|
|
|
|
|
def onroad_appearance(params: Any) -> OnroadAppearance:
|
|
"""Bad saved bytes keep the visible baseline; no view writes during refresh."""
|
|
values = {key: read_visibility(params, key).value for key in DEFAULTS}
|
|
saved_lead_info = read_lead_info(params)
|
|
camera_view = read_camera_view(params).value
|
|
try:
|
|
metric_raw, metric_readable = read_saved(params, "IsMetric", 8)
|
|
except (AttributeError, OSError, TypeError, ValueError):
|
|
metric_raw, metric_readable = None, False
|
|
metric = False if metric_readable and metric_raw in (None, b"0") else True if metric_readable and metric_raw == b"1" else None
|
|
return OnroadAppearance(
|
|
show_developer_sidebar=values["DeveloperSidebar"] is True,
|
|
hide_personality_alerts=values["HidePersonalityAlerts"] is True,
|
|
wheel_pedal_feedback=values["ShowBrakeStatus"] is True or values["PedalsOnUI"] is True,
|
|
show_blindspot_border=values["BlindSpotMetrics"] is True,
|
|
show_signal_border=values["SignalMetrics"] is True,
|
|
show_speed_limit_sign=values["ShowSpeedLimits"] is True,
|
|
use_vienna_sign=values["UseVienna"] is True,
|
|
show_stock_confidence_ball=values["StockConfidenceBallWidget"] is True,
|
|
show_lead_indicator=values["HideLeadMarker"] is False,
|
|
lead_info_mode=saved_lead_info.mode if values["HideLeadMarker"] is False and saved_lead_info.mode is not None else LeadInfoMode.OFF,
|
|
lead_info_metric=metric,
|
|
camera_view=camera_view if camera_view is not None else CameraViewChoice.STANDARD,
|
|
driver_camera_on_reverse=values["DriverCamera"] is True,
|
|
)
|