Files
2026-10-22 12:51:07 -05:00

106 lines
5.1 KiB
Python

import hashlib
from openpilot.starpilot.aol.vehicle import policy_for
from openpilot.starpilot.conditional_mode.manual import ioniq6_media_eligible
from openpilot.starpilot.feature_capabilities import lateral_supported
from openpilot.starpilot.controllers.wheel_actions import ACTIONS, DEFAULTS, KEYS, PADDLE_KEY, button_reported, eligible, paddle_bookmark_available
from openpilot.starpilot.saved_document import commit_exact
from openpilot.starpilot.saved_source import read_saved
from openpilot.starpilot.ui.feature_settings_state import FeatureRow
PREFIX = "wheel:"
LABELS = ("LKAS press", "Main cruise press", "Distance short press", "Distance long press", "Distance very long press",
"Cancel short press", "Cancel long press", "Cancel very long press", "MODE press", "MODE long press",
"MODE very long press", "Star button", "Star long press", "Star very long press", "Left paddle press")
class WheelFeature:
def __init__(self, owner):
self.owner = owner
def capability(self):
cp = self.owner.vehicle_params()
if not eligible(cp):
return None
reader = cp.as_reader() if hasattr(cp, "as_reader") else cp
base = (cp.carFingerprint, hashlib.sha256(reader.as_builder().to_bytes()).hexdigest())
if self.owner.configuration_vehicle():
return base + (self.owner.longitudinal_available(), "configuration")
return base + (True,) if self.owner.configuration_longitudinal() else base
def choices(self, key):
cp = self.owner.vehicle_params()
if self.capability() is None:
return ()
if key == PADDLE_KEY:
return ("Off", "Bookmark") if paddle_bookmark_available(self.owner.params, cp) else ()
policy = policy_for(cp)
media = ioniq6_media_eligible(cp)
if self.owner.configuration_vehicle():
from openpilot.starpilot.car.hyundai.settings import configuration_wheel_policy, configuration_media_supported
policy = configuration_wheel_policy(cp) or policy
media = configuration_media_supported(cp) or media
if not button_reported(cp, key):
return ()
if key == "LKASButtonControl" and not (policy.lkas_button_supported or policy.auxiliary_lkas_supported):
return ()
if key in KEYS[:2] and policy.fixed_cruise_buttons and not (
key == "LKASButtonControl" and policy.auxiliary_lkas_supported):
return ()
if key in KEYS[5:8] and cp.brand == 'gm':
from opendbc.car.gm.cancel_remap import supported
if supported(cp) and read_saved(self.owner.params, 'RemapCancelToDistance', 8) != (b'1', True):
return ()
if key in KEYS[8:] and not media:
return ()
codes = {0, 8, 11, 12, 13}
if self.owner.longitudinal_available():
codes.update((1, 2, 5, 10, 14))
codes.add(6)
if lateral_supported(cp):
codes.add(7)
if not policy.fixed_cruise_buttons and policy.settings_supported:
if key in KEYS[:5] or not policy.explicit_latch:
codes.update((3, 4, 9))
elif policy.distance_pause_only and key in KEYS[2:5]:
codes.update((3, 4))
if key == "MainCruiseButtonControl":
codes &= {0, 9}
if self.owner.longitudinal_available():
codes.add(10)
return tuple(label for label, code in ACTIONS.items() if code in codes)
def rows(self):
capability = self.capability()
if capability is None:
return []
rows = []
for key, label in zip(KEYS, LABELS, strict=True):
choices = self.choices(key)
if not choices:
continue
raw, readable = read_saved(self.owner.params, key, 8)
number = DEFAULTS.get(key, 0) if raw is None else int(raw) if raw in tuple(str(i).encode() for i in range(15)) else -1
selected = next((name for name, code in ACTIONS.items() if code == number), None)
default = next(label for label, code in ACTIONS.items() if code == DEFAULTS.get(key, 0))
rows.append(FeatureRow(PREFIX + key, label, selected or "Invalid saved action", raw, choices,
default_value=default if default in choices else None,
available=readable and self.owner.authority("preferences"),
reason=("Bookmark on release. Available while Left Paddle Longitudinal Pause is Off." if key == PADDLE_KEY else
"Axis pause and AOL assignments apply after restarting. Other actions can apply this drive. " +
"Long actions fire while held."),
capability=capability, repair_value="Off" if selected is None else ""))
return rows
def apply(self, request):
key = request.key.removeprefix(PREFIX)
if key not in KEYS or request.value not in self.choices(key) or request.capability != self.capability():
return False
capability = request.capability
def authorized():
return (self.owner.authority("preferences") and capability == self.capability() and
request.value in self.choices(key))
return commit_exact(self.owner.params, key=key, max_bytes=8, raw=str(ACTIONS[request.value]).encode(),
expected=request.expected, authorized=authorized, temp_prefix=".tmp_wheel_").committed