mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-11-12 07:23:45 +08:00
Restore Ioniq 6 Alpha Long compatibility across camera and external Panda layouts
This commit is contained in:
@@ -52,7 +52,6 @@ def _base_word(cp, *, experiences=(0,)):
|
||||
return None
|
||||
if (
|
||||
cp.brand != 'hyundai'
|
||||
or factory == CAR.HYUNDAI_IONIQ_6
|
||||
or not factory.config.flags & HyundaiFlags.CANFD
|
||||
or factory.config.flags & (HyundaiFlags.CANFD_ANGLE_STEERING | HyundaiFlags.NON_SCC)
|
||||
or cp.passive
|
||||
@@ -85,6 +84,8 @@ def _base_word(cp, *, experiences=(0,)):
|
||||
word |= 0x0400
|
||||
if factory in CARNIVAL_CARS and alt_buttons:
|
||||
word |= 0x2000
|
||||
if factory == CAR.HYUNDAI_IONIQ_6 and word != 0x09:
|
||||
return None
|
||||
return word if word | STOCK_AOL_MARKER in STOCK_AOL_WORDS else None
|
||||
|
||||
|
||||
@@ -100,7 +101,7 @@ CARNIVAL_LONG_AOL_WORD = 0x28B4
|
||||
LONG_AOL_WORDS = frozenset((CARNIVAL_LONG_AOL_WORD, 0x080D, 0x0815, 0x0895, 0x2815, 0x2895)) | SPORTAGE_LONG_AOL_WORDS
|
||||
LONG_EV_CARS = frozenset((CAR.HYUNDAI_IONIQ_5, CAR.HYUNDAI_KONA_EV_2ND_GEN))
|
||||
INDEPENDENT_LONG_BUTTON_CARS = LONG_EV_CARS | {
|
||||
CAR.GENESIS_GV70_ELECTRIFIED_1ST_GEN, CAR.GENESIS_GV60_EV_1ST_GEN, CAR.KIA_SPORTAGE_5TH_GEN, CAR.KIA_CARNIVAL_2025,
|
||||
CAR.HYUNDAI_IONIQ_6, CAR.GENESIS_GV70_ELECTRIFIED_1ST_GEN, CAR.GENESIS_GV60_EV_1ST_GEN, CAR.KIA_SPORTAGE_5TH_GEN, CAR.KIA_CARNIVAL_2025,
|
||||
}
|
||||
|
||||
|
||||
@@ -115,7 +116,7 @@ def qualified_long(cp, *, marked_only=False):
|
||||
if not eligible(cp):
|
||||
return False
|
||||
word = _base_word(cp, experiences=(0, 32))
|
||||
if cp.carFingerprint == CAR.GENESIS_GV60_EV_1ST_GEN:
|
||||
if cp.carFingerprint in (CAR.GENESIS_GV60_EV_1ST_GEN, CAR.HYUNDAI_IONIQ_6):
|
||||
if word != 0x09:
|
||||
return False
|
||||
elif cp.carFingerprint == CAR.KIA_SPORTAGE_5TH_GEN:
|
||||
|
||||
@@ -138,7 +138,8 @@ class CarController(CarControllerBase):
|
||||
self.last_ccnc_now_ns = 0
|
||||
self.ccnc_baselined = False
|
||||
self.ioniq6_longitudinal = (Ioniq6LongitudinalPolicy()
|
||||
if CP.carFingerprint == CAR.HYUNDAI_IONIQ_6 and CP.openpilotLongitudinalControl else None)
|
||||
if CP.carFingerprint == CAR.HYUNDAI_IONIQ_6 and CP.openpilotLongitudinalControl and
|
||||
int(CP.safetyConfigs[-1].safetyParam) in (0x8015, 0x8095, 0x8815, 0x8895) else None)
|
||||
self.pe_longitudinal = PELongitudinalPolicy() if pe_long_qualified(CP) else None
|
||||
self.pe_startup = None
|
||||
self.ev9_longitudinal = EV9LongitudinalPolicy() if ev9_long_qualified(CP) else None
|
||||
|
||||
@@ -685,17 +685,19 @@ class CarState(CarStateBase):
|
||||
if CP.flags & HyundaiFlags.CANFD_LKA_STEER_MSG:
|
||||
cam_msgs.append(("CAM_0x362" if CP.flags & HyundaiFlags.CANFD_LKA_STEER_MSG_ALT else "CAM_0x2a4", 20))
|
||||
elif CP.carFingerprint == CAR.HYUNDAI_IONIQ_6 and CP.openpilotLongitudinalControl:
|
||||
# The acknowledged ADAS takeover removes stock SCC from E-CAN. Require
|
||||
# every independent native input and the matching camera source instead.
|
||||
# Both topologies require genuine chassis inputs; only HDA-II uses
|
||||
# the camera template after acknowledged ADAS takeover.
|
||||
msgs.extend((("ACCELERATOR", 100), ("TCS", 50), ("WHEEL_SPEEDS", 100), ("MDPS", 100)))
|
||||
msgs.extend((("CRUISE_BUTTONS_ALT", math.nan), ("DOORS_SEATBELTS", math.nan),
|
||||
("STEERING_SENSORS", math.nan), ("BLINKERS", math.nan)))
|
||||
cam_msgs.append(("CAM_0x362" if CP.flags & HyundaiFlags.CANFD_LKA_STEER_MSG_ALT else "CAM_0x2a4", 20))
|
||||
if CP.flags & HyundaiFlags.CANFD_LKA_STEER_MSG:
|
||||
cam_msgs.append(("CAM_0x362" if CP.flags & HyundaiFlags.CANFD_LKA_STEER_MSG_ALT else "CAM_0x2a4", 20))
|
||||
elif CP.carFingerprint == CAR.HYUNDAI_IONIQ_6 and not CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS:
|
||||
# Stock standard-button Ioniq 6 reads alternate DISTANCE_UNIT too, but
|
||||
# that frame may be absent. Subscribe before the lazy lookup makes it
|
||||
# required; existing native and CarState safety inputs remain required.
|
||||
msgs.append(("CRUISE_BUTTONS_ALT", math.nan))
|
||||
if not any(name == "CRUISE_BUTTONS_ALT" for name, _ in msgs):
|
||||
msgs.append(("CRUISE_BUTTONS_ALT", math.nan))
|
||||
from opendbc.car.hyundai.ev6_startup import eligible as ev6_eligible
|
||||
from opendbc.car.hyundai.gv70_startup import eligible as gv70_eligible
|
||||
if ev6_eligible(CP) or gv70_eligible(CP):
|
||||
|
||||
@@ -142,6 +142,9 @@ class CarInterface(CarInterfaceBase):
|
||||
CAN = CanBus(None, fingerprint, lka_steering)
|
||||
|
||||
ret.alphaLongitudinalAvailable = not (ret.flags & HyundaiFlags.CANFD_NO_RADAR_DISABLE)
|
||||
if (candidate == CAR.HYUNDAI_IONIQ_6 and not lka_steering and
|
||||
fingerprint[CAN.CAM].get(0x1A0) == 32 and fingerprint[CAN.ECAN].get(0x1CF) == 8):
|
||||
ret.alphaLongitudinalAvailable = True
|
||||
if ret.flags & HyundaiFlags.CANFD_ANGLE_STEERING:
|
||||
# These manual angle profiles retain stock SCC in both builds.
|
||||
ret.alphaLongitudinalAvailable = False
|
||||
|
||||
@@ -0,0 +1,187 @@
|
||||
from tempfile import TemporaryDirectory
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from opendbc.car import Bus, gen_empty_fingerprint, structs
|
||||
from opendbc.car.hyundai.interface import CarInterface
|
||||
from opendbc.car.hyundai.carcontroller import CarController
|
||||
from opendbc.car.hyundai.canfd_stock_aol import qualified, qualified_long
|
||||
from opendbc.car.hyundai.hyundaicanfd import CanBus
|
||||
from opendbc.car.hyundai.tests.test_ioniq6_handoff import ioniq6_profiles
|
||||
from opendbc.car.hyundai.values import CAR, DBC
|
||||
from opendbc.can import CANPacker
|
||||
from opendbc.safety.tests.libsafety import libsafety_py
|
||||
from opendbc.safety.tests import test_hyundai_gv60_hda1_long_aol as native_fixture
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.starpilot.car.hyundai.aol import policy_for, native_accepts_cp
|
||||
from openpilot.selfdrive.ui.layouts.settings import toggles
|
||||
|
||||
|
||||
def camera_params(offset=0, alpha=False):
|
||||
fp = gen_empty_fingerprint()
|
||||
fp[offset].update({0x1CF: 8, 0x35: 32, 0x175: 24, 0xA0: 24, 0xEA: 24, 0x1BA: 24, 0x1E5: 16})
|
||||
fp[offset + 2].update({0x12A: 16, 0x1A0: 32})
|
||||
fp[offset + 1].update({0x110: 32, 0x100: 24})
|
||||
return CarInterface.get_params(CAR.HYUNDAI_IONIQ_6, fp, [], alpha, False, False)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('offset', (0, 4))
|
||||
def test_camera_scc_factory_offers_long_without_hda2_takeover(offset):
|
||||
stock = camera_params(offset)
|
||||
cp = camera_params(offset, True)
|
||||
assert stock.alphaLongitudinalAvailable, 'HDA1_ALPHA_CAPABILITY_MISSING'
|
||||
assert not stock.openpilotLongitudinalControl and stock.pcmCruise
|
||||
assert cp.alphaLongitudinalAvailable and cp.openpilotLongitudinalControl and not cp.pcmCruise
|
||||
assert cp.steerControlType == structs.CarParams.SteerControlType.torque
|
||||
assert cp.safetyConfigs[-1].safetyParam == 0x0D
|
||||
assert CanBus(cp).ECAN == offset
|
||||
assert CarController(DBC[cp.carFingerprint], cp).ioniq6_longitudinal is None
|
||||
with patch('opendbc.car.hyundai.interface.disable_ecu') as disable:
|
||||
CarInterface.init(cp, Mock(), Mock())
|
||||
disable.assert_not_called()
|
||||
for value in (stock, cp):
|
||||
policy = policy_for(value)
|
||||
assert policy.runtime_supported and policy.explicit_latch
|
||||
value.safetyConfigs[-1].safetyParam |= policy.safety_param_addition
|
||||
value.alternativeExperience |= policy.alternative_experience_addition
|
||||
word = 0x80D if value.openpilotLongitudinalControl else 0x809
|
||||
assert value.safetyConfigs[-1].safetyParam == word
|
||||
assert native_accepts_cp(value, int(structs.CarParams.SafetyModel.hyundaiCanfd), word)
|
||||
assert not native_accepts_cp(value, int(structs.CarParams.SafetyModel.hyundai), word)
|
||||
assert not native_accepts_cp(value, int(structs.CarParams.SafetyModel.hyundaiCanfd), word ^ 16)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('offset', (0, 4))
|
||||
def test_external_hda2_settings_explain_opt_in_without_claiming_stock_acc_authority(offset):
|
||||
_, stock, _ = ioniq6_profiles(bus_offset=offset, alternate=True)
|
||||
with TemporaryDirectory() as root:
|
||||
params = Params(root)
|
||||
params.put_bool('ExperimentalMode', True, block=True)
|
||||
class Toggle:
|
||||
def __init__(self):
|
||||
self.action_item = self
|
||||
self.description = ''
|
||||
def set_enabled(self, enabled):
|
||||
self.enabled = enabled
|
||||
def set_description(self, description):
|
||||
self.description = description
|
||||
def set_state(self, state):
|
||||
self.state = state
|
||||
panel = toggles.TogglesLayout.__new__(toggles.TogglesLayout)
|
||||
panel._params = params
|
||||
panel._is_release = False
|
||||
panel._initial_cruise_speed = Mock()
|
||||
panel._long_personality_setting = SimpleNamespace(action_item=Toggle())
|
||||
panel._toggles = {'ExperimentalMode': Toggle(), 'IsRhdDetected': Toggle()}
|
||||
panel._toggle_defs = {}
|
||||
panel._locked_toggles = set()
|
||||
panel._update_experimental_mode_icon = Mock()
|
||||
panel._slc_offsets = SimpleNamespace(_raw=lambda key: None)
|
||||
panel._localization = SimpleNamespace(snapshot=lambda: SimpleNamespace(rows=(None, SimpleNamespace(source=None, available=True))))
|
||||
ui = SimpleNamespace(CP=stock, has_longitudinal_control=False, update_params=lambda: None)
|
||||
with patch.object(toggles, 'ui_state', ui):
|
||||
panel._update_toggles()
|
||||
assert 'Enable the openpilot longitudinal control (alpha)' in panel._toggles['ExperimentalMode'].description
|
||||
assert not panel._toggles['ExperimentalMode'].enabled
|
||||
assert params.get_bool('ExperimentalMode')
|
||||
|
||||
|
||||
@pytest.mark.parametrize('offset', (0, 4))
|
||||
def test_camera_long_actual_controller_packets_use_existing_native_contract(offset):
|
||||
cp = camera_params(offset, True)
|
||||
assert cp.openpilotLongitudinalControl
|
||||
cp.safetyConfigs[-1].safetyParam |= 0x800
|
||||
cp.alternativeExperience = 32
|
||||
ci = CarInterface(cp)
|
||||
packer = CANPacker(DBC[cp.carFingerprint][Bus.pt])
|
||||
bus = CanBus(cp)
|
||||
frames = [packer.make_can_msg(name, bus.ECAN, values) for name, values in (
|
||||
('ACCELERATOR', {'GEAR': 5}), ('TCS', {'ACCEnable': 0}), ('WHEEL_SPEEDS', {}), ('MDPS', {}),
|
||||
('CRUISE_BUTTONS', {'COUNTER': 1}), ('DOORS_SEATBELTS', {'DRIVER_SEATBELT': 1}), ('STEERING_SENSORS', {}))]
|
||||
ci.update([(1_000_000_000, frames)])
|
||||
case = native_fixture.TestGv60Hda1LongAol(methodName='runTest')
|
||||
case.setUp()
|
||||
try:
|
||||
case.mode(0x80D)
|
||||
if case.release:
|
||||
assert not case.safety.safety_config_valid()
|
||||
return
|
||||
case.healthy(0x80D, omit='CRUISE_BUTTONS')
|
||||
case.safety.set_aol_test_heartbeat(True)
|
||||
case.safety.aol_set_host_request(3)
|
||||
for tick, counter, button in ((0, 13, 0), (1, 14, 2), (2, 0, 0)):
|
||||
case.safety.set_timer(1_000_000 + tick * 20_000)
|
||||
assert case.safety.safety_rx_hook(case.packet(packer.make_can_msg('CRUISE_BUTTONS', 0, {'COUNTER': counter, 'CRUISE_BUTTONS': button})))
|
||||
case.safety.aol_set_host_request(3)
|
||||
assert case.safety.aol_get_permission_mask() == 3
|
||||
cc = structs.CarControl(enabled=True, latActive=True, longActive=True)
|
||||
cc.actuators.torque = .01
|
||||
cc.actuators.accel = .1
|
||||
cc.actuators.longControlState = structs.CarControl.Actuators.LongControlState.pid
|
||||
controller = CarController(DBC[cp.carFingerprint], cp)
|
||||
assert controller.ioniq6_longitudinal is None
|
||||
_, sent = controller.update(cc.as_reader(), ci.CS, 1_000_000_000)
|
||||
assert any(frame[0] == 0x1A0 for frame in sent)
|
||||
assert not any(frame[0] == 0x730 for frame in sent)
|
||||
for frame in sent:
|
||||
assert frame[2] in (offset, offset + 1, offset + 2)
|
||||
packet = libsafety_py.make_CANPacket(frame[0], frame[2] - offset, frame[1])
|
||||
assert case.safety.safety_tx_hook(packet), (hex(frame[0]), frame[2])
|
||||
finally:
|
||||
case.tearDown()
|
||||
|
||||
|
||||
@pytest.mark.parametrize('mutation', ('aux_word', 'wrong_model', 'angle', 'lka', 'passive'))
|
||||
def test_camera_admission_never_borrows_other_topologies(mutation):
|
||||
cp = camera_params(4, True)
|
||||
cp.safetyConfigs[-1].safetyParam |= 0x800
|
||||
cp.alternativeExperience = 32
|
||||
if mutation == 'aux_word':
|
||||
cp.safetyConfigs[0].safetyParam = 1
|
||||
elif mutation == 'wrong_model':
|
||||
cp.safetyConfigs[-1].safetyModel = structs.CarParams.SafetyModel.hyundai
|
||||
elif mutation == 'angle':
|
||||
cp.steerControlType = structs.CarParams.SteerControlType.angle
|
||||
elif mutation == 'lka':
|
||||
cp.flags |= 1
|
||||
else:
|
||||
cp.passive = True
|
||||
assert not qualified(cp) and not qualified_long(cp)
|
||||
assert not policy_for(cp).runtime_supported
|
||||
|
||||
|
||||
@pytest.mark.parametrize('offset', (0, 4))
|
||||
def test_galaxy_exposes_external_stock_alpha_request_and_preserves_choice(offset):
|
||||
from openpilot.starpilot.ui.feature_settings_owner import FeatureSettingsOwner
|
||||
_, stock, _ = ioniq6_profiles(bus_offset=offset, alternate=True)
|
||||
with TemporaryDirectory() as root:
|
||||
params = Params(root)
|
||||
params.put_bool('IsReleaseBranch', False, block=True)
|
||||
params.put_bool('AlphaLongitudinalEnabled', True, block=True)
|
||||
stock.radarUnavailable = True
|
||||
owner = FeatureSettingsOwner(params, lambda scope: True,
|
||||
vehicle_params=lambda: stock, vehicle_fingerprint=lambda: str(stock.carFingerprint), galaxy=lambda: True)
|
||||
assert owner._alpha_long_capability() is not None
|
||||
rows = owner._alpha_long_rows(True)
|
||||
assert len(rows) == 1 and rows[0].key == 'AlphaLongitudinalEnabled'
|
||||
assert params.get_bool('AlphaLongitudinalEnabled')
|
||||
stock.passive = True
|
||||
assert owner._alpha_long_capability() is None
|
||||
assert params.get_bool('AlphaLongitudinalEnabled')
|
||||
|
||||
|
||||
@pytest.mark.parametrize('offset', (0, 4))
|
||||
def test_cached_radar_discovery_can_save_request_but_cannot_grant_long_or_aol(offset):
|
||||
from opendbc.car.hyundai.ioniq6_handoff import build_ioniq6_hda2_long_candidate
|
||||
from openpilot.starpilot.car.hyundai.aol import ioniq6_alpha_long_available, ioniq6_settings_capable
|
||||
fingerprint, stock, _ = ioniq6_profiles(bus_offset=offset, alternate=True)
|
||||
stock.radarUnavailable = True
|
||||
assert ioniq6_alpha_long_available(stock), 'CACHED_EXTERNAL_RADAR_BLOCKS_ALPHA_REQUEST'
|
||||
assert not ioniq6_settings_capable(stock)
|
||||
assert not policy_for(stock).runtime_supported
|
||||
assert build_ioniq6_hda2_long_candidate(stock, fingerprint) is None
|
||||
assert not stock.openpilotLongitudinalControl and stock.pcmCruise
|
||||
stock.safetyConfigs[-1].safetyParam ^= 16
|
||||
assert not ioniq6_alpha_long_available(stock)
|
||||
@@ -1,7 +1,7 @@
|
||||
from collections.abc import Callable
|
||||
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.starpilot.car.hyundai.aol import ioniq6_settings_capable
|
||||
from openpilot.starpilot.car.hyundai.aol import ioniq6_alpha_long_available
|
||||
from openpilot.starpilot.car.ford.longitudinal_preferences import release_long_available as ford_release_long_available
|
||||
from opendbc.car.volkswagen.meb_modes import MEB_CARS, settings_capable as meb_settings_capable
|
||||
from openpilot.starpilot.car.volkswagen.preferences import stock_long_requested
|
||||
@@ -144,7 +144,7 @@ class DeveloperLayout(Widget):
|
||||
# CP gating
|
||||
if ui_state.CP is not None:
|
||||
alpha_avail = (meb_settings_capable(ui_state.CP) if ui_state.CP.brand == 'volkswagen' and ui_state.CP.carFingerprint in MEB_CARS
|
||||
else ui_state.CP.alphaLongitudinalAvailable or ioniq6_settings_capable(ui_state.CP))
|
||||
else ui_state.CP.alphaLongitudinalAvailable or ioniq6_alpha_long_available(ui_state.CP))
|
||||
if not alpha_avail or (self._is_release and not (meb_settings_capable(ui_state.CP) or ford_release_long_available(ui_state.CP))):
|
||||
self._alpha_long_toggle.set_visible(False)
|
||||
else:
|
||||
@@ -216,7 +216,7 @@ class DeveloperLayout(Widget):
|
||||
if result == DialogResult.CONFIRM:
|
||||
if (not ui_state.is_offroad() or ui_state.CP is None or
|
||||
not (meb_settings_capable(ui_state.CP) if ui_state.CP.brand == 'volkswagen' and ui_state.CP.carFingerprint in MEB_CARS
|
||||
else ui_state.CP.alphaLongitudinalAvailable or ioniq6_settings_capable(ui_state.CP)) or
|
||||
else ui_state.CP.alphaLongitudinalAvailable or ioniq6_alpha_long_available(ui_state.CP)) or
|
||||
self._is_release and not (meb_settings_capable(ui_state.CP) or ford_release_long_available(ui_state.CP))):
|
||||
self._alpha_long_toggle.action_item.set_state(False)
|
||||
return
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
from openpilot.starpilot.car.hyundai.aol import ioniq6_alpha_long_available
|
||||
from openpilot.starpilot.car.ford.longitudinal_preferences import release_long_available as ford_release_long_available
|
||||
from openpilot.cereal import log
|
||||
from openpilot.common.params import Params, UnknownKeyName
|
||||
@@ -196,7 +197,7 @@ class TogglesLayout(Widget):
|
||||
unavailable = tr("Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control.")
|
||||
|
||||
long_desc = unavailable + " " + tr("openpilot longitudinal control may come in a future update.")
|
||||
if ui_state.CP.alphaLongitudinalAvailable:
|
||||
if ui_state.CP.alphaLongitudinalAvailable or ioniq6_alpha_long_available(ui_state.CP):
|
||||
if self._is_release and not ford_release_long_available(ui_state.CP):
|
||||
long_desc = unavailable + " " + tr("An alpha version of openpilot longitudinal control can be tested, along with " +
|
||||
"Experimental mode, on non-release branches.")
|
||||
|
||||
@@ -7,7 +7,7 @@ from openpilot.selfdrive.ui.mici.widgets.dialog import BigDialog, BigInputDialog
|
||||
from openpilot.system.ui.lib.application import gui_app
|
||||
from openpilot.selfdrive.ui.layouts.settings.common import restart_needed_callback
|
||||
from openpilot.selfdrive.ui.ui_state import ui_state
|
||||
from openpilot.starpilot.car.hyundai.aol import ioniq6_settings_capable
|
||||
from openpilot.starpilot.car.hyundai.aol import ioniq6_alpha_long_available
|
||||
from openpilot.starpilot.car.ford.longitudinal_preferences import release_long_available as ford_release_long_available
|
||||
from opendbc.car.volkswagen.meb_modes import MEB_CARS, settings_capable as meb_settings_capable
|
||||
from openpilot.starpilot.car.volkswagen.preferences import stock_long_requested
|
||||
@@ -177,7 +177,7 @@ class DeveloperLayoutMici(NavScroller):
|
||||
# CP gating
|
||||
if ui_state.CP is not None:
|
||||
alpha_avail = (meb_settings_capable(ui_state.CP) if ui_state.CP.brand == 'volkswagen' and ui_state.CP.carFingerprint in MEB_CARS
|
||||
else ui_state.CP.alphaLongitudinalAvailable or ioniq6_settings_capable(ui_state.CP))
|
||||
else ui_state.CP.alphaLongitudinalAvailable or ioniq6_alpha_long_available(ui_state.CP))
|
||||
if not alpha_avail or (ui_state.is_release and not (meb_settings_capable(ui_state.CP) or ford_release_long_available(ui_state.CP))):
|
||||
self._alpha_long_toggle.set_visible(False)
|
||||
else:
|
||||
@@ -201,7 +201,7 @@ class DeveloperLayoutMici(NavScroller):
|
||||
def do_toggle(_state: bool):
|
||||
if (not ui_state.is_offroad() or (_state and (ui_state.CP is None or
|
||||
not (meb_settings_capable(ui_state.CP) if ui_state.CP.brand == 'volkswagen' and ui_state.CP.carFingerprint in MEB_CARS
|
||||
else ui_state.CP.alphaLongitudinalAvailable or ioniq6_settings_capable(ui_state.CP)) or
|
||||
else ui_state.CP.alphaLongitudinalAvailable or ioniq6_alpha_long_available(ui_state.CP)) or
|
||||
ui_state.is_release and not (meb_settings_capable(ui_state.CP) or ford_release_long_available(ui_state.CP))))):
|
||||
self._update_toggles()
|
||||
return
|
||||
|
||||
@@ -45,11 +45,11 @@ _REQUIRED_FLAGS = int(HyundaiFlags.CANFD | HyundaiFlags.EV | HyundaiFlags.CANFD_
|
||||
_FORBIDDEN_FLAGS = int(HyundaiFlags.CANFD_ALT_BUTTONS | HyundaiFlags.CANFD_ANGLE_STEERING | HyundaiFlags.CANFD_CAMERA_SCC)
|
||||
|
||||
|
||||
def _ioniq6_hda2_base(CP) -> bool:
|
||||
def _ioniq6_hda2_base(CP, *, require_radar=True) -> bool:
|
||||
if (
|
||||
str(CP.carFingerprint) != str(HyundaiCAR.HYUNDAI_IONIQ_6)
|
||||
or CP.brand != 'hyundai'
|
||||
or CP.radarUnavailable
|
||||
or (require_radar and CP.radarUnavailable)
|
||||
or CP.notCar
|
||||
or CP.passive
|
||||
or CP.dashcamOnly
|
||||
@@ -61,8 +61,8 @@ def _ioniq6_hda2_base(CP) -> bool:
|
||||
return flags & _REQUIRED_FLAGS == _REQUIRED_FLAGS and not flags & _FORBIDDEN_FLAGS
|
||||
|
||||
|
||||
def _stock_ioniq6(CP, *, marked_only=False) -> bool:
|
||||
if not _ioniq6_hda2_base(CP) or CP.openpilotLongitudinalControl or not CP.pcmCruise:
|
||||
def _stock_ioniq6(CP, *, marked_only=False, require_radar=True) -> bool:
|
||||
if not _ioniq6_hda2_base(CP, require_radar=require_radar) or CP.openpilotLongitudinalControl or not CP.pcmCruise:
|
||||
return False
|
||||
stock = 0x91 if int(CP.flags) & int(HyundaiFlags.CANFD_LKA_STEER_MSG_ALT) else 0x11
|
||||
raw = int(CP.safetyConfigs[config_index(CP)].safetyParam)
|
||||
@@ -98,6 +98,12 @@ def ioniq6_settings_capable(CP) -> bool:
|
||||
return _stock_ioniq6(CP) or (IONIQ6_LONG_PREARM_ENABLED and ioniq6_long_eligible(CP))
|
||||
|
||||
|
||||
def ioniq6_alpha_long_available(CP) -> bool:
|
||||
# Cached radar discovery may predate the external-bus repair. This saves only
|
||||
# an opt-in; the takeover still requires fresh physical radar and ECU evidence.
|
||||
return _stock_ioniq6(CP, require_radar=False) or (IONIQ6_LONG_PREARM_ENABLED and ioniq6_long_eligible(CP))
|
||||
|
||||
|
||||
def qualified_ccnc_long_aol(CP, *, marked_only=False):
|
||||
return qualified_ev9_long_aol(CP, marked_only=marked_only) or qualified_pe_long_aol(CP, marked_only=marked_only)
|
||||
|
||||
@@ -232,9 +238,9 @@ def native_profile_supported(model: int, param: int) -> bool:
|
||||
|
||||
|
||||
def native_accepts_cp(CP, model: int, param: int) -> bool:
|
||||
# Ioniq 6 has its own exact contract; no generic Hyundai owner accepts it.
|
||||
# HDA-II retains its dedicated namespace; camera SCC uses the shared exact word.
|
||||
# Revalidate the complete contract on every call, without caching live authority.
|
||||
if CP.carFingerprint == HyundaiCAR.HYUNDAI_IONIQ_6:
|
||||
if CP.carFingerprint == HyundaiCAR.HYUNDAI_IONIQ_6 and not CP.flags & HyundaiFlags.CANFD_CAMERA_SCC:
|
||||
return qualified_ioniq6(CP)
|
||||
if qualified_ccnc_long_aol(CP, marked_only=True):
|
||||
return model == int(car.CarParams.SafetyModel.hyundaiCanfd) and param == CP.safetyConfigs[0].safetyParam
|
||||
|
||||
@@ -205,12 +205,12 @@ class FeatureSettingsOwner:
|
||||
release, readable = read_saved(self.params, 'IsReleaseBranch', 8)
|
||||
try:
|
||||
from opendbc.car.values import PLATFORMS
|
||||
from openpilot.starpilot.car.hyundai.aol import ioniq6_settings_capable
|
||||
from openpilot.starpilot.car.hyundai.aol import ioniq6_alpha_long_available
|
||||
from openpilot.starpilot.car.ford.longitudinal_preferences import release_long_available as ford_release_long_available
|
||||
platform = PLATFORMS.get(str(cp.carFingerprint))
|
||||
if (not self._galaxy() or platform is None or platform.__class__.__module__.split('.')[-2] != str(cp.brand) or
|
||||
not readable or release not in (None, b'0', b'1') or cp.notCar or cp.passive or cp.dashcamOnly or
|
||||
not (cp.alphaLongitudinalAvailable or ioniq6_settings_capable(cp)) or
|
||||
not (cp.alphaLongitudinalAvailable or ioniq6_alpha_long_available(cp)) or
|
||||
(release == b'1' and not ford_release_long_available(cp))):
|
||||
return None
|
||||
return (str(cp.carFingerprint), str(cp.brand), int(cp.flags), int(cp.alternativeExperience),
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
{"protected_inventory_sha256": "634cdb0998641b505e1f24b4fb715965c778b355de58ecfb7cf292b5616941e2", "schema_version": 1}
|
||||
{"protected_inventory_sha256": "b93d12cdd85e78c16f978b68bd56777fab78fa2a3a94beb99a7ed0a2a635466f", "schema_version": 1}
|
||||
|
||||
Reference in New Issue
Block a user