Files
StarPilot/openpilot/starpilot/ui/ford_cluster_feature.py
T
alan-polk 8da0c9d916 Ford: remove the interim BluePilot port; AOL on the stock profiles
StarPilot's angle-only bluepilot_lateral adaptation and the BluePilot-derived curvature strategies (Mach-E,
classic, Explorer, generic CAN FD, new-port curvature, manual-turn latch, curvature preview, pinion
measurement) are removed, with their extended safety profiles 16/32/64 and the interim angle word 128. Ford
lateral is upstream's stock curvature path until the BluePilot lateral library is mounted.

StarPilot's own Ford features stay, re-keyed from the extended words to the stock ones:
- AOL: classic 32 -> 0, Mach-E 18 and the CAN FD trucks 66 -> 2 (+1 with openpilot long); the CAN FD
  retained-display rules apply to word 2. Edge/Mondeo/Transit and the manual bit (256) are unchanged.
- release CAN FD long: word 3 (was 19/67); 19 and 67 are now retired and denied.
- stock cruise switch, CAN FD camera-lead radar handling, hands-free cluster: keyed on the Ford family.
- classic stock ACC (0) keeps the no-ACCDATA TX list the extended classic profile had.

Bits 9-14 of the Ford param are reserved for the BluePilot lateral library's startup bits
(safety/modes/ford_param.h); AOL and pandad mask them out of the profile word.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 22:49:32 -05:00

49 lines
2.6 KiB
Python

"""Ford hands-free cluster display preference shared by Galaxy and the native feature presentation."""
from openpilot.starpilot.saved_document import commit_exact
from openpilot.starpilot.ui.feature_settings_state import FeatureRow
class FordClusterFeature:
"""Shared native/Galaxy saved display preference for Ford CAN-FD profiles."""
def __init__(self, owner):
self.owner = owner
def capability(self):
from openpilot.starpilot.car.ford.cluster_preferences import qualified
cp = self.owner.vehicle_params()
try:
if cp is None or not qualified(cp):
return None
return (str(cp.carFingerprint), int(cp.flags), int(cp.alternativeExperience), bool(cp.openpilotLongitudinalControl),
tuple((str(c.safetyModel), int(c.safetyParam)) for c in cp.safetyConfigs))
except (AttributeError, TypeError, ValueError, OverflowError):
return None
def rows(self, parked):
from openpilot.starpilot.car.ford.cluster_preferences import KEY, CHOICES, read_choice
capability = self.capability()
if capability is None:
return ()
value, raw, readable, valid = read_choice(self.owner.params)
return (FeatureRow(KEY, "Ford hands-free cluster display", CHOICES[value] if valid else "Invalid saved choice", raw,
choices=tuple(CHOICES.values()), available=parked and self.owner.authority("parked_preferences") and readable,
capability=capability, repair_value="" if valid else CHOICES[0], default_value=CHOICES[0],
reason="Changes the active cluster icon only; driver attention requirements remain unchanged."),)
def apply(self, request):
from openpilot.starpilot.car.ford.cluster_preferences import KEY, CHOICES, read_choice
value = next((code for code, label in CHOICES.items() if label == request.value), None)
if (request.key != KEY or value is None or request.related_source is not None or request.display_unit or request.direction):
return False
def authorized():
capability = self.capability()
_, raw, readable, valid = read_choice(self.owner.params)
return (self.owner.authority("parked_preferences") and bool(request.vehicle_fingerprint) and
self.owner.vehicle_fingerprint() == request.vehicle_fingerprint and capability is not None and
capability == request.capability and readable and raw == request.expected and (valid or value == 0))
result = commit_exact(self.owner.params, key=KEY, max_bytes=8, raw=str(value).encode(), expected=request.expected,
authorized=authorized, temp_prefix=".ford-cluster-")
return result.committed and result.verified