diff --git a/opendbc_repo/opendbc/car/honda/stock_aol.py b/opendbc_repo/opendbc/car/honda/stock_aol.py index 2757c6ccbd..fbdded8ff2 100644 --- a/opendbc_repo/opendbc/car/honda/stock_aol.py +++ b/opendbc_repo/opendbc/car/honda/stock_aol.py @@ -40,7 +40,7 @@ def qualified(cp, *, marked_only=False): identity = next((candidate for candidate in CLASSIC_BOSCH | NIDEC | RADARLESS if candidate == cp.carFingerprint), None) if identity is None: return False - detected = int(HondaFlags.BOSCH_EXT_HUD | HondaFlags.BOSCH_ALT_BRAKE | HondaFlags.HAS_BSM | HondaFlags.EPS_MODIFIED) + detected = int(HondaFlags.BOSCH_EXT_HUD | HondaFlags.BOSCH_ALT_BRAKE | HondaFlags.HAS_BSM | HondaFlags.EPS_MODIFIED | HondaFlags.HYBRID) if int(cp.flags) & ~(int(identity.config.flags) | detected): return False flags = HondaFlags(cp.flags) diff --git a/opendbc_repo/opendbc/car/honda/tests/test_stock_aol.py b/opendbc_repo/opendbc/car/honda/tests/test_stock_aol.py index 9cee633d7d..a601d1ec6e 100644 --- a/opendbc_repo/opendbc/car/honda/tests/test_stock_aol.py +++ b/opendbc_repo/opendbc/car/honda/tests/test_stock_aol.py @@ -3,7 +3,7 @@ import pytest from opendbc.car import gen_empty_fingerprint, structs from opendbc.car.honda.interface import CarInterface from opendbc.car.honda.stock_aol import CLASSIC_BOSCH, NIDEC, RADARLESS, qualified, temporary_restriction -from opendbc.car.honda.values import CAR +from opendbc.car.honda.values import CAR, HondaFlags from openpilot.starpilot.aol.intent import AolSettings, AOL_TOGGLE from openpilot.starpilot.car.honda.aol import policy_for, create_intent, native_accepts_cp @@ -12,18 +12,22 @@ AUTO_188 = frozenset((CAR.ACURA_RDX, CAR.HONDA_CRV_SA, CAR.HONDA_ACCORD_9G)) IDENTITIES = tuple(sorted(CLASSIC_BOSCH | NIDEC | RADARLESS, key=str)) -def final_cp(identity, alpha=False, release=False): +def final_cp(identity, alpha=False, release=False, *, hybrid=False): fingerprint = gen_empty_fingerprint() pt = 1 if identity in CLASSIC_BOSCH else 0 address, length = (0x188, 6) if identity in AUTO_188 else (0x1A3, 8) fingerprint[pt][address] = length + if hybrid: + fingerprint[pt][0x184] = 8 return CarInterface.get_params(identity, fingerprint, [], alpha, release, False) @pytest.mark.parametrize("identity", IDENTITIES) @pytest.mark.parametrize("alpha,release", ((False, False), (True, False), (True, True))) -def test_actual_factory_admission_and_marker(identity, alpha, release): - cp = final_cp(identity, alpha, release) +@pytest.mark.parametrize("hybrid", (False, True)) +def test_actual_factory_admission_and_marker(identity, alpha, release, hybrid): + cp = final_cp(identity, alpha, release, hybrid=hybrid) + assert bool(cp.flags & HondaFlags.HYBRID) == hybrid expected = not (identity in CLASSIC_BOSCH and cp.openpilotLongitudinalControl) assert qualified(cp) == expected if not expected: @@ -49,20 +53,21 @@ def test_actual_factory_admission_and_marker(identity, alpha, release): @pytest.mark.parametrize("identity", IDENTITIES) -def test_manual_unknown_namespace_and_extra_panda_denied(identity): - cp = final_cp(identity) +@pytest.mark.parametrize("hybrid", (False, True)) +def test_manual_unknown_namespace_and_extra_panda_denied(identity, hybrid): + cp = final_cp(identity, hybrid=hybrid) cp.fingerprintSource = structs.CarParams.FingerprintSource.fixed assert not qualified(cp) - cp = final_cp(identity) + cp = final_cp(identity, hybrid=hybrid) cp.transmissionType = structs.CarParams.TransmissionType.manual assert not qualified(cp) - cp = final_cp(identity) + cp = final_cp(identity, hybrid=hybrid) cp.flags |= 1 << 31 assert not qualified(cp) - cp = final_cp(identity) + cp = final_cp(identity, hybrid=hybrid) cp.safetyConfigs[0].safetyParam |= 0x4000 assert not qualified(cp) - cp = final_cp(identity) + cp = final_cp(identity, hybrid=hybrid) cp.safetyConfigs = [structs.CarParams.SafetyConfig(safetyModel="noOutput"), cp.safetyConfigs[0]] assert not qualified(cp) diff --git a/openpilot/selfdrive/car/tests/test_honda_aol.py b/openpilot/selfdrive/car/tests/test_honda_aol.py index 067477f6fe..6f4b6469de 100644 --- a/openpilot/selfdrive/car/tests/test_honda_aol.py +++ b/openpilot/selfdrive/car/tests/test_honda_aol.py @@ -30,6 +30,43 @@ class HondaFamilyQualificationTests(unittest.TestCase): # Some upstream interfaces set this shared table while constructing CP. self.addCleanup(setattr, CarControllerParams, 'BOSCH_GAS_LOOKUP_V', list(CarControllerParams.BOSCH_GAS_LOOKUP_V)) + def test_stock_cruise_off_disables_standard_state_without_disarming_aol(self): + from openpilot.selfdrive.car.car_events import CarEvents + from openpilot.selfdrive.selfdrived.events import ET + from openpilot.selfdrive.selfdrived.state import StateMachine, State + from openpilot.starpilot.aol.intent import disarming_fault + from opendbc.car.honda.stock_aol import qualified + fingerprint = gen_empty_fingerprint() + fingerprint[1][0x1A3] = 8 + cp = CarInterface.get_params(CAR.HONDA_ACCORD, fingerprint, [], False, False, False) + cp.alternativeExperience = 32 + self.assertTrue(qualified(cp, marked_only=True)) + for speed, name in ((20., log.OnroadEvent.EventName.cruiseDisabled), + (0., log.OnroadEvent.EventName.speedTooLow)): + with self.subTest(speed=speed): + state = car_state() + state.vEgo = speed + state.cruiseState.available = True + events = CarEvents(cp).update(state, state, car.CarControl()) + event = next(event for event in events.to_msg() if event.name == name) + self.assertTrue(event.userDisable) + self.assertFalse(event.immediateDisable) + self.assertFalse(disarming_fault([event], state)) + machine = StateMachine() + machine.state = State.enabled + machine.update(events) + self.assertEqual(machine.state, State.disabled) + for fault in (log.OnroadEvent.EventName.accFaulted, log.OnroadEvent.EventName.canError, + log.OnroadEvent.EventName.steerUnavailable): + guarded = CarEvents(cp).update(state, state, car.CarControl()) + guarded.add(fault) + self.assertTrue(disarming_fault(guarded.to_msg(), state)) + cp.alternativeExperience = 0 + ordinary = CarEvents(cp).update(state, state, car.CarControl()) + self.assertTrue(ordinary.contains(ET.IMMEDIATE_DISABLE)) + self.assertTrue(disarming_fault(ordinary.to_msg(), state)) + cp.alternativeExperience = 32 + def test_exact_classic_bosch_cp_family_and_rejections(self): self.assertEqual(len(CLASSIC_BOSCH_AOL_CARS), 10) all_honda = tuple(candidate for candidate in CAR if candidate.config.flags & HondaFlags.BOSCH) diff --git a/openpilot/starpilot/car/events.py b/openpilot/starpilot/car/events.py index 7ce6725a73..a9ce19f1ea 100644 --- a/openpilot/starpilot/car/events.py +++ b/openpilot/starpilot/car/events.py @@ -2,6 +2,9 @@ def event_rules(cp) -> dict: if cp.brand == "gm": from openpilot.starpilot.car.gm.events import event_rules as gm_rules return gm_rules(cp) + if cp.brand == "honda": + from openpilot.starpilot.car.honda.events import event_rules as honda_rules + return honda_rules(cp) return {} diff --git a/openpilot/starpilot/car/honda/events.py b/openpilot/starpilot/car/honda/events.py new file mode 100644 index 0000000000..a9b0c65235 --- /dev/null +++ b/openpilot/starpilot/car/honda/events.py @@ -0,0 +1,10 @@ +from opendbc.car.honda.stock_aol import qualified +from openpilot.cereal import log +from openpilot.selfdrive.selfdrived.events import EVENTS, ET + + +def event_rules(cp) -> dict: + if not qualified(cp, marked_only=True): + return {} + names = (log.OnroadEvent.EventName.cruiseDisabled, log.OnroadEvent.EventName.speedTooLow) + return {name: {ET.USER_DISABLE: EVENTS[name][ET.IMMEDIATE_DISABLE]} for name in names} diff --git a/tools/ci/run_local_tests.py b/tools/ci/run_local_tests.py index 2dce7ecc4d..15c91fffb8 100755 --- a/tools/ci/run_local_tests.py +++ b/tools/ci/run_local_tests.py @@ -52,6 +52,8 @@ QUICK_TARGETS = ( 'opendbc_repo/opendbc/safety/tests/test_tesla_screen_button.py', 'opendbc_repo/opendbc/safety/tests/test_toyota.py', 'opendbc_repo/opendbc/car/toyota/tests/test_retrofit.py', + 'opendbc_repo/opendbc/car/honda/tests/test_stock_aol.py', + 'openpilot/selfdrive/car/tests/test_honda_aol.py::HondaFamilyQualificationTests', 'opendbc_repo/opendbc/car/hyundai/tests/test_ioniq6_stock_parser.py', 'opendbc_repo/opendbc/car/hyundai/tests/test_ioniq6_engagement_messages.py', 'opendbc_repo/opendbc/safety/tests/test_hyundai_ioniq6_long.py',