mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-10-29 09:33:48 +08:00
Match Dom hands-free cluster scope across Ford CAN-FD
This commit is contained in:
@@ -77,6 +77,7 @@ class CarController(CarControllerBase):
|
||||
self.mache_extended_announced = False
|
||||
self.mache_ui_active = False
|
||||
self.hands_free_cluster_input = None
|
||||
self.cluster_extended_announced = False
|
||||
self.generic_canfd = generic_canfd_qualified(CP)
|
||||
self.classic_lateral = GenericCanfdLateralController(CP) if self.generic_canfd else create_classic_controller(CP)
|
||||
self.new_port_curvature = create_new_port_curvature(CP)
|
||||
@@ -329,6 +330,10 @@ class CarController(CarControllerBase):
|
||||
self.accel = accel
|
||||
self.gas = gas
|
||||
|
||||
# Track the actual outgoing LKA announcement for every CAN-FD display owner.
|
||||
if any(address == 0x3CA for address, _, _ in can_sends):
|
||||
self.cluster_extended_announced = True
|
||||
|
||||
### ui ###
|
||||
# AOL safety forwards stock UI until an active lateral replacement owns it.
|
||||
# Avoid competing cluster messages while stock remains the display owner.
|
||||
@@ -347,7 +352,7 @@ class CarController(CarControllerBase):
|
||||
|
||||
if (self.frame % CarControllerParams.ACC_UI_STEP) == 0 or send_ui:
|
||||
show_distance_bars = self.frame - self.distance_bar_frame < 400
|
||||
hands_free_cluster = bool(self.mache_lateral is not None and self.mache_extended_announced and
|
||||
hands_free_cluster = bool(self.cluster_extended_announced and
|
||||
self.hands_free_cluster_input is not None and self.hands_free_cluster_input.enabled)
|
||||
can_sends.append(fordcan.create_acc_ui_msg(self.packer, self.CAN, self.CP, main_on, ui_enabled,
|
||||
fcw_alert, CS.out.cruiseState.standstill, show_distance_bars,
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
"""Dom CAN-FD cluster scope through actual factory, setting UI and controller."""
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
|
||||
import pytest
|
||||
|
||||
from opendbc.can import CANParser
|
||||
from opendbc.car import structs
|
||||
from opendbc.car.ford.tests.test_mache_ui_owner import setup, UI
|
||||
from opendbc.car.ford.values import CAR, FordFlags
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.common.prefix import OpenpilotPrefix
|
||||
from openpilot.starpilot.car.ford.cluster_preferences import KEY, qualified
|
||||
from openpilot.starpilot.controller_extensions import configure_controller
|
||||
from openpilot.starpilot.ui.feature_settings_owner import FeatureSettingsOwner
|
||||
from openpilot.starpilot.ui.feature_settings_state import row_change
|
||||
|
||||
DOM_CANFD = (
|
||||
CAR.FORD_MUSTANG_MACH_E_MK1, CAR.FORD_ESCAPE_MK4_5, CAR.FORD_EXPEDITION_MK4,
|
||||
CAR.FORD_F_150_MK14, CAR.FORD_F_150_LIGHTNING_MK1, CAR.FORD_RANGER_MK2, CAR.FORD_MONDEO_MK5,
|
||||
)
|
||||
|
||||
|
||||
def test_scope_covers_every_dom_canfd_profile():
|
||||
assert set(DOM_CANFD) == {car for car in CAR if car.config.flags & FordFlags.CANFD and not car.config.flags & FordFlags.LKA_STEERING}
|
||||
|
||||
|
||||
@pytest.mark.parametrize('identity', DOM_CANFD)
|
||||
@pytest.mark.parametrize('aol', [False, True])
|
||||
@pytest.mark.parametrize('enabled', [False, True])
|
||||
def test_all_dom_profiles_have_shared_setting_and_correct_active_status(identity, aol, enabled):
|
||||
with OpenpilotPrefix():
|
||||
saved = Params()
|
||||
controller, state = setup(aol=aol, identity=identity)
|
||||
assert qualified(controller.CP)
|
||||
owner = FeatureSettingsOwner(saved, lambda group: True, vehicle_params=lambda: controller.CP,
|
||||
vehicle_fingerprint=lambda: str(identity))
|
||||
row = next(r for r in owner.snapshot('torque', parked=True, system_long=True, lateral_context=True, metric=False).rows if r.key == KEY)
|
||||
assert row.available and row.value == 'Off'
|
||||
if enabled:
|
||||
assert owner.apply(row_change(row, 1))
|
||||
configure_controller(SimpleNamespace(CP=controller.CP, CC=controller), saved)
|
||||
assert controller.hands_free_cluster_input.enabled == enabled
|
||||
command = structs.CarControl()
|
||||
for _ in range(10):
|
||||
_, frames = controller.update(command.as_reader(), state, controller.frame * 10_000_000)
|
||||
if identity == CAR.FORD_MUSTANG_MACH_E_MK1 and aol:
|
||||
assert not UI.intersection(address for address, _, _ in frames)
|
||||
command.latActive = True
|
||||
parser = CANParser('ford_lincoln_base_pt', [('ACCDATA_3', 5)], 0)
|
||||
statuses = []
|
||||
for _ in range(110):
|
||||
_, frames = controller.update(command.as_reader(), state, controller.frame * 10_000_000)
|
||||
for frame in frames:
|
||||
if frame[0] == 0x18A:
|
||||
parser.update([(controller.frame * 10_000_000, [frame])])
|
||||
statuses.append(parser.vl['ACCDATA_3']['Tja_D_Stat'])
|
||||
assert statuses and set(statuses) == {7 if enabled else 2}
|
||||
assert controller.cluster_extended_announced
|
||||
|
||||
|
||||
@pytest.mark.parametrize('identity', [car for car in CAR if car not in DOM_CANFD])
|
||||
def test_non_canfd_fords_do_not_show_cluster_setting(identity):
|
||||
with OpenpilotPrefix():
|
||||
saved = Params()
|
||||
controller, _ = setup(identity=identity)
|
||||
assert not qualified(controller.CP)
|
||||
configure_controller(SimpleNamespace(CP=controller.CP, CC=controller), saved)
|
||||
assert controller.hands_free_cluster_input is None
|
||||
owner = FeatureSettingsOwner(saved, lambda group: True, vehicle_params=lambda: controller.CP,
|
||||
vehicle_fingerprint=lambda: str(identity))
|
||||
assert KEY not in {r.key for r in owner.snapshot('torque', parked=True, system_long=True, lateral_context=True, metric=False).rows}
|
||||
|
||||
|
||||
def test_invalid_profile_does_not_enable_display_preference():
|
||||
with OpenpilotPrefix():
|
||||
saved = Params()
|
||||
Path(saved.get_param_path(KEY)).write_bytes(b'1')
|
||||
controller, _ = setup()
|
||||
controller.CP.safetyConfigs[0].safetyParam = 0
|
||||
assert not qualified(controller.CP)
|
||||
configure_controller(SimpleNamespace(CP=controller.CP, CC=controller), saved)
|
||||
assert controller.hands_free_cluster_input is None
|
||||
@@ -12,7 +12,7 @@ from opendbc.car.ford.tests.test_mache_ui_owner import setup, UI
|
||||
from opendbc.car.ford.values import CAR
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.common.prefix import OpenpilotPrefix
|
||||
from openpilot.starpilot.car.ford.cluster_preferences import KEY, MachEClusterPreference, read_choice
|
||||
from openpilot.starpilot.car.ford.cluster_preferences import KEY, FordClusterPreference, read_choice
|
||||
from openpilot.starpilot.controller_extensions import configure_controller
|
||||
from openpilot.starpilot.ui.feature_settings_owner import FeatureSettingsOwner
|
||||
from openpilot.starpilot.ui.feature_settings_state import row_change
|
||||
@@ -33,7 +33,7 @@ def test_saved_opt_in_through_actual_controller_configuration_and_warning_priori
|
||||
saved = Params()
|
||||
owner, state = setup()
|
||||
configure_controller(SimpleNamespace(CP=owner.CP, CC=owner), saved)
|
||||
assert isinstance(owner.hands_free_cluster_input, MachEClusterPreference)
|
||||
assert isinstance(owner.hands_free_cluster_input, FordClusterPreference)
|
||||
assert not owner.hands_free_cluster_input.enabled
|
||||
parser = CANParser('ford_lincoln_base_pt', [('ACCDATA_3', 5)], 0)
|
||||
command = structs.CarControl(latActive=True)
|
||||
|
||||
@@ -5,13 +5,24 @@ KEY = "FordHandsFreeCluster"
|
||||
CHOICES = {0: "Off", 1: "On"}
|
||||
|
||||
|
||||
def qualified(cp):
|
||||
"""Dom's CAN-FD/non-LKA scope, constrained to existing admitted owners."""
|
||||
from opendbc.car.ford.values import FordFlags
|
||||
from opendbc.car.ford.mache_lateral import qualified as mache
|
||||
from opendbc.car.ford.generic_canfd_lateral import qualified as generic
|
||||
from opendbc.car.ford.new_port_curvature import qualified as new_port
|
||||
from opendbc.bluepilot_lateral.hosts.starpilot import qualified as angle
|
||||
return bool(cp.brand == "ford" and cp.flags & FordFlags.CANFD and not cp.flags & FordFlags.LKA_STEERING and
|
||||
(mache(cp) or generic(cp) or new_port(cp) or angle(cp)))
|
||||
|
||||
|
||||
def read_choice(params):
|
||||
raw, readable = read_saved(params, KEY, 8)
|
||||
valid = readable and raw in (None, b"0", b"1")
|
||||
return int(valid and raw == b"1"), raw, readable, valid
|
||||
|
||||
|
||||
class MachEClusterPreference:
|
||||
class FordClusterPreference:
|
||||
def __init__(self, params):
|
||||
self.params = params
|
||||
self.enabled = bool(read_choice(params)[0])
|
||||
|
||||
@@ -139,9 +139,9 @@ class ResumePlanInputs:
|
||||
def configure_controller(CI, params):
|
||||
cp = CI.CP
|
||||
controller = CI.CC
|
||||
if controller is not None and getattr(controller, "mache_lateral", None) is not None:
|
||||
from openpilot.starpilot.car.ford.cluster_preferences import MachEClusterPreference
|
||||
controller.hands_free_cluster_input = MachEClusterPreference(params)
|
||||
from openpilot.starpilot.car.ford.cluster_preferences import FordClusterPreference, qualified as cluster_qualified
|
||||
if controller is not None and cluster_qualified(cp):
|
||||
controller.hands_free_cluster_input = FordClusterPreference(params)
|
||||
if controller is not None and cp.brand == 'gm':
|
||||
from opendbc.car.gm.values import (is_bolt_euv_longitudinal, is_volt_longitudinal,
|
||||
camera_acc_pedal_profile, volt_cc_pedal_profile)
|
||||
|
||||
@@ -62,12 +62,12 @@ class FordLateralFeature:
|
||||
|
||||
|
||||
class FordClusterFeature:
|
||||
"""Shared native/Galaxy saved display preference for the Mach-E."""
|
||||
"""Shared native/Galaxy saved display preference for Ford CAN-FD profiles."""
|
||||
def __init__(self, owner):
|
||||
self.owner = owner
|
||||
|
||||
def capability(self):
|
||||
from opendbc.car.ford.mache_lateral import qualified
|
||||
from openpilot.starpilot.car.ford.cluster_preferences import qualified
|
||||
cp = self.owner.vehicle_params()
|
||||
try:
|
||||
if cp is None or not qualified(cp):
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
{"protected_inventory_sha256": "accbfb22312328a90cb22906acefde416d9eb24121e049a21d5283529531ed68", "schema_version": 1}
|
||||
{"protected_inventory_sha256": "4026fd67ff54d43b1eda7fd9b8a732fbf8bcbc9cf820498a83ce2521715935ef", "schema_version": 1}
|
||||
|
||||
Reference in New Issue
Block a user