From 2e4c3f43ee96fcac5b03366458e343cc69df4c7c Mon Sep 17 00:00:00 2001 From: firestar5683 <168790843+firestar5683@users.noreply.github.com> Date: Fri, 24 Apr 2026 22:51:49 -0500 Subject: [PATCH] Fallback mode HDA2 Revert "Fallback mode HDA2" This reverts commit 81b2b3584227bd1aa62089770245e50e131e0a3b. Fallback mode hda2 --- opendbc_repo/opendbc/car/hyundai/interface.py | 50 ++++++++++++++--- .../opendbc/car/hyundai/tests/test_hyundai.py | 56 +++++++++++++++++++ 2 files changed, 99 insertions(+), 7 deletions(-) diff --git a/opendbc_repo/opendbc/car/hyundai/interface.py b/opendbc_repo/opendbc/car/hyundai/interface.py index 65c5b72a1..67a687483 100644 --- a/opendbc_repo/opendbc/car/hyundai/interface.py +++ b/opendbc_repo/opendbc/car/hyundai/interface.py @@ -20,6 +20,8 @@ ENABLE_BUTTONS = (ButtonType.accelCruise, ButtonType.decelCruise, ButtonType.can # Track when ECU disable happened - used to permanently suppress CAN errors from disabled ECU ECU_DISABLE_TIMESTAMP = 0.0 +READY_ONLY_MSGS = {0x255, 0x2e5, 0x3a0, 0x3b0, 0x3b1, 0x3b5, 0x3f0, 0x3f5} +READY_MSG_THRESHOLD = 3 class CarInterface(CarInterfaceBase): @@ -204,25 +206,37 @@ class CarInterface(CarInterfaceBase): if CP.flags & HyundaiFlags.CANFD_LKA_STEERING.value: addr, bus = 0x730, CanBus(CP).ECAN - # Try ECU disable. If it succeeds (IGN-ON mode), enable longitudinal. - # If it fails (READY mode returns NRC 0x22, or timeout), strip LONG safety flag - # so panda forwards stock SCC messages normally (lateral-only mode). - ecu_log(f"=== ECU DISABLE attempt: addr=0x{addr:x}, bus={bus} ===") - ecu_disabled = disable_ecu(can_recv, can_send, bus=bus, addr=addr, com_cont_req=communication_control) - if CP.carFingerprint == CAR.HYUNDAI_IONIQ_6: + ecu_log(f"=== Checking for READY mode: addr=0x{addr:x}, bus={bus} ===") + ready_detected = CarInterface._ready_mode_detected(can_recv, bus) + + if ready_detected: + params.put_bool("EcuDisableFailed", True) + CP.safetyConfigs[-1].safetyParam &= ~HyundaiSafetyFlags.LONG.value + ecu_log(f"=== READY mode detected - safetyParam stripped to {CP.safetyConfigs[-1].safetyParam}, lateral-only mode ===") + ecu_disabled = False + else: + # Try ECU disable. If it succeeds (IGN-ON mode), enable longitudinal. + # If it fails (READY mode returns NRC 0x22, or timeout), strip LONG safety flag + # so panda forwards stock SCC messages normally (lateral-only mode). + ecu_log(f"=== ECU DISABLE attempt: addr=0x{addr:x}, bus={bus} ===") + ecu_disabled = disable_ecu(can_recv, can_send, bus=bus, addr=addr, com_cont_req=communication_control) + # Ioniq 6: track success/failure to auto-switch between openpilot long and stock ACC if ecu_disabled: ECU_DISABLE_TIMESTAMP = time.monotonic() params.put_bool("EcuDisableFailed", False) params.put_bool("ExperimentalMode", True) ecu_log("=== ECU DISABLE SUCCESS - Longitudinal + Experimental ENABLED ===") - else: + elif not ready_detected: params.put_bool("EcuDisableFailed", True) CP.safetyConfigs[-1].safetyParam &= ~HyundaiSafetyFlags.LONG.value ecu_log(f"=== ECU DISABLE FAILED - safetyParam stripped to {CP.safetyConfigs[-1].safetyParam}, lateral-only mode ===") else: # Other cars: just log, don't change safety params or params store + # Try ECU disable. If it succeeds (IGN-ON mode), enable longitudinal. + ecu_log(f"=== ECU DISABLE attempt: addr=0x{addr:x}, bus={bus} ===") + ecu_disabled = disable_ecu(can_recv, can_send, bus=bus, addr=addr, com_cont_req=communication_control) if ecu_disabled: ecu_log("=== ECU DISABLE SUCCESS ===") else: @@ -237,6 +251,28 @@ class CarInterface(CarInterfaceBase): communication_control = bytes([uds.SERVICE_TYPE.COMMUNICATION_CONTROL, 0x80 | uds.CONTROL_TYPE.ENABLE_RX_ENABLE_TX, uds.MESSAGE_TYPE.NORMAL]) CarInterface.init(CP, can_recv, can_send, communication_control) + @staticmethod + def _ready_mode_detected(can_recv, bus, timeout_s=1.0): + ready_msgs_seen = set() + all_msgs_seen = set() + start_time = time.monotonic() + + while time.monotonic() - start_time < timeout_s: + for can_packets in can_recv(wait_for_one=True): + for packet in can_packets: + if packet.src == bus: + all_msgs_seen.add(packet.address) + if packet.address in READY_ONLY_MSGS: + ready_msgs_seen.add(packet.address) + + if len(ready_msgs_seen) >= READY_MSG_THRESHOLD: + break + + elapsed = time.monotonic() - start_time + ready_detected = len(ready_msgs_seen) >= READY_MSG_THRESHOLD + ecu_log(f"=== READY scan: ready_msgs={[hex(m) for m in ready_msgs_seen]}, total_bus_msgs={len(all_msgs_seen)}, elapsed={elapsed:.2f}s ===") + return ready_detected + def update(self, can_packets, starpilot_toggles): ret, fp_ret = super().update(can_packets, starpilot_toggles) diff --git a/opendbc_repo/opendbc/car/hyundai/tests/test_hyundai.py b/opendbc_repo/opendbc/car/hyundai/tests/test_hyundai.py index ff2e6e2f5..9aa6673b8 100644 --- a/opendbc_repo/opendbc/car/hyundai/tests/test_hyundai.py +++ b/opendbc_repo/opendbc/car/hyundai/tests/test_hyundai.py @@ -1,3 +1,4 @@ +import sys from hypothesis import settings, given, strategies as st from types import SimpleNamespace @@ -7,6 +8,7 @@ from opendbc.can import CANPacker from opendbc.car import Bus, ButtonType, gen_empty_fingerprint from opendbc.car.structs import CarParams from opendbc.car.fw_versions import build_fw_dict, match_fw_to_car +import opendbc.car.hyundai.interface as hyundai_interface from opendbc.car.hyundai.carstate import CarState from opendbc.car.hyundai.interface import CarInterface from opendbc.car.hyundai import hyundaicanfd @@ -277,6 +279,60 @@ class TestHyundaiFingerprint: assert all(parser.can_valid for parser in can_parsers.values()) + def test_ioniq_6_ready_mode_skips_ecu_disable(self, monkeypatch): + class FakeParams: + def __init__(self): + self.bools = {} + + def put_bool(self, key, value): + self.bools[key] = value + + class Packet: + def __init__(self, src, address): + self.src = src + self.address = address + + toggles = get_test_toggles() + fingerprint = gen_empty_fingerprint() + cam_can = CanBus(None, fingerprint).CAM + fingerprint[cam_can][0x50] = 8 + fingerprint[cam_can][0x110] = 8 + CP = CarInterface.get_params(CAR.HYUNDAI_IONIQ_6, fingerprint, [], True, False, False, toggles) + assert CP.openpilotLongitudinalControl + assert CP.safetyConfigs[-1].safetyParam & HyundaiSafetyFlags.LONG + + fake_params = FakeParams() + monkeypatch.setitem(sys.modules, "openpilot.common.params", SimpleNamespace(Params=lambda: fake_params)) + + calls = {"disable_ecu": 0} + + def fake_disable_ecu(*args, **kwargs): + calls["disable_ecu"] += 1 + return True + + time_state = {"value": -0.25} + def fake_monotonic(): + time_state["value"] += 0.25 + return time_state["value"] + + monkeypatch.setattr(hyundai_interface, "disable_ecu", fake_disable_ecu) + monkeypatch.setattr(hyundai_interface.time, "monotonic", fake_monotonic) + + ready_msgs = [ + Packet(CanBus(CP).ECAN, 0x255), + Packet(CanBus(CP).ECAN, 0x2e5), + Packet(CanBus(CP).ECAN, 0x3a0), + ] + + def fake_can_recv(wait_for_one=True): + return [ready_msgs] + + CarInterface.init(CP, fake_can_recv, lambda *args, **kwargs: None) + + assert calls["disable_ecu"] == 0 + assert fake_params.bools["EcuDisableFailed"] is True + assert not (CP.safetyConfigs[-1].safetyParam & HyundaiSafetyFlags.LONG) + def test_blacklisted_parts(self, subtests): # Asserts no ECUs known to be shared across platforms exist in the database. # Tucson having Santa Cruz camera and EPS for example