diff --git a/common/params_keys.h b/common/params_keys.h index 34780cece..a2302f30c 100644 --- a/common/params_keys.h +++ b/common/params_keys.h @@ -162,4 +162,5 @@ inline static std::unordered_map keys = { {"dp_dev_tethering", {PERSISTENT, BOOL, "0"}}, {"dp_ui_mici", {PERSISTENT, BOOL, "0"}}, {"dp_lat_offset_cm", {PERSISTENT, INT, "0"}}, + {"dp_honda_nidec_stock_long", {PERSISTENT, BOOL, "0"}}, }; diff --git a/dragonpilot/settings.py b/dragonpilot/settings.py index 0b9b368b6..289c9dc43 100644 --- a/dragonpilot/settings.py +++ b/dragonpilot/settings.py @@ -4,6 +4,19 @@ except: from openpilot.system.ui.lib.multilang import tr SETTINGS = [ + { + "title": "Honda / Acura", + "condition": "brand == 'honda'", + "settings": [ + { + "key": "dp_honda_nidec_stock_long", + "type": "toggle_item", + "title": lambda: tr("Nidec: Use Stock Longitudinal Control"), + "description": lambda: tr("Use Honda's factory ACC for gas/brake control instead of openpilot. openpilot will only control steering. Requires reboot to take effect."), + "brands": ["honda"], + }, + ], + }, { "title": "Toyota / Lexus", "condition": "brand == 'toyota'", diff --git a/opendbc_repo/opendbc/car/honda/interface.py b/opendbc_repo/opendbc/car/honda/interface.py index a2eb7eaee..be1e4ce3d 100755 --- a/opendbc_repo/opendbc/car/honda/interface.py +++ b/opendbc_repo/opendbc/car/honda/interface.py @@ -54,6 +54,9 @@ class CarInterface(CarInterfaceBase): ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.hondaNidec)] ret.openpilotLongitudinalControl = True + if dp_params & structs.DPFlags.HondaNidecStockLong: + ret.openpilotLongitudinalControl = False + ret.pcmCruise = True if candidate == CAR.HONDA_CRV_5G: @@ -208,6 +211,8 @@ class CarInterface(CarInterfaceBase): ret.safetyConfigs[-1].safetyParam |= HondaSafetyFlags.RADARLESS.value if candidate in HONDA_BOSCH_CANFD: ret.safetyConfigs[-1].safetyParam |= HondaSafetyFlags.BOSCH_CANFD.value + if not ret.openpilotLongitudinalControl and candidate not in HONDA_BOSCH: + ret.safetyConfigs[-1].safetyParam |= HondaSafetyFlags.NIDEC_STOCK_LONG.value # min speed to enable ACC. if car can do stop and go, then set enabling speed # to a negative value, so it won't matter. Otherwise, add 0.5 mph margin to not diff --git a/opendbc_repo/opendbc/car/honda/values.py b/opendbc_repo/opendbc/car/honda/values.py index 4171a02e7..df6b14478 100644 --- a/opendbc_repo/opendbc/car/honda/values.py +++ b/opendbc_repo/opendbc/car/honda/values.py @@ -56,6 +56,7 @@ class HondaSafetyFlags(IntFlag): NIDEC_ALT = 4 RADARLESS = 8 BOSCH_CANFD = 16 + NIDEC_STOCK_LONG = 32 class HondaFlags(IntFlag): diff --git a/opendbc_repo/opendbc/car/structs.py b/opendbc_repo/opendbc/car/structs.py index 1f8d36083..ce711fab6 100644 --- a/opendbc_repo/opendbc/car/structs.py +++ b/opendbc_repo/opendbc/car/structs.py @@ -22,4 +22,5 @@ CarParamsT = capnp.lib.capnp._StructModule class DPFlags: LatALKA = 1 ExtRadar = 2 + HondaNidecStockLong = 2 ** 2 pass diff --git a/opendbc_repo/opendbc/safety/modes/honda.h b/opendbc_repo/opendbc/safety/modes/honda.h index e236066d1..e445f0131 100644 --- a/opendbc_repo/opendbc/safety/modes/honda.h +++ b/opendbc_repo/opendbc/safety/modes/honda.h @@ -32,6 +32,7 @@ static bool honda_fwd_brake = false; static bool honda_bosch_long = false; static bool honda_bosch_radarless = false; static bool honda_bosch_canfd = false; +static bool honda_nidec_stock_long = false; typedef enum {HONDA_NIDEC, HONDA_BOSCH} HondaHw; static HondaHw honda_hw = HONDA_NIDEC; @@ -279,6 +280,10 @@ static bool honda_tx_hook(const CANPacket_t *msg) { static safety_config honda_nidec_init(uint16_t param) { alka_allowed = true; // dp - ALKA enabled for Honda Nidec + // Steering-only (stock long) + static CanMsg HONDA_N_STOCK_LONG_TX_MSGS[] = {{0xE4, 0, 5, .check_relay = true}, {0x194, 0, 4, .check_relay = true}, + {0x33D, 0, 5, .check_relay = true}}; + // 0x1FA is dynamically forwarded based on stock AEB // 0xE4 is steering on all cars except CRV and RDX, 0x194 for CRV and RDX, // 0x1FA is brake control, 0x30C is acc hud, 0x33D is lkas hud @@ -286,6 +291,7 @@ static safety_config honda_nidec_init(uint16_t param) { {0x30C, 0, 8, .check_relay = true}, {0x33D, 0, 5, .check_relay = true}}; const uint16_t HONDA_PARAM_NIDEC_ALT = 4; + const uint16_t HONDA_PARAM_NIDEC_STOCK_LONG = 32; honda_hw = HONDA_NIDEC; honda_brake = 0; @@ -295,6 +301,7 @@ static safety_config honda_nidec_init(uint16_t param) { honda_bosch_long = false; honda_bosch_radarless = false; honda_bosch_canfd = false; + honda_nidec_stock_long = GET_FLAG(param, HONDA_PARAM_NIDEC_STOCK_LONG); safety_config ret; @@ -318,7 +325,11 @@ static safety_config honda_nidec_init(uint16_t param) { SET_RX_CHECKS(honda_nidec_common_rx_checks, ret); } - SET_TX_MSGS(HONDA_N_TX_MSGS, ret); + if (honda_nidec_stock_long) { + SET_TX_MSGS(HONDA_N_STOCK_LONG_TX_MSGS, ret); + } else { + SET_TX_MSGS(HONDA_N_TX_MSGS, ret); + } return ret; } @@ -418,7 +429,7 @@ static bool honda_nidec_fwd_hook(int bus_num, int addr) { if (bus_num == 2) { // forwarded if stock AEB is active bool is_brake_msg = addr == 0x1FA; - block_msg = is_brake_msg && !honda_fwd_brake; + block_msg = is_brake_msg && !honda_fwd_brake && !honda_nidec_stock_long; } return block_msg; diff --git a/opendbc_repo/opendbc/safety/tests/test_honda.py b/opendbc_repo/opendbc/safety/tests/test_honda.py index 44220095a..1ece4abd0 100755 --- a/opendbc_repo/opendbc/safety/tests/test_honda.py +++ b/opendbc_repo/opendbc/safety/tests/test_honda.py @@ -338,6 +338,47 @@ class TestHondaNidecPcmSafety(HondaPcmEnableBase, TestHondaNidecSafetyBase): pass +class TestHondaNidecStockLongSafety(HondaPcmEnableBase, TestHondaNidecSafetyBase): + """ + Covers Honda Nidec with stock longitudinal control + """ + TX_MSGS = [[0xE4, 0], [0x194, 0], [0x33D, 0]] + FWD_BLACKLISTED_ADDRS = {2: [0xE4, 0x194, 0x33D]} + RELAY_MALFUNCTION_ADDRS = {0: (0xE4, 0x194, 0x33D)} + + def setUp(self): + self.packer = CANPackerSafety("honda_civic_touring_2016_can_generated") + self.safety = libsafety_py.libsafety + self.safety.set_safety_hooks(CarParams.SafetyModel.hondaNidec, HondaSafetyFlags.NIDEC_STOCK_LONG) + self.safety.init_tests() + + # Nidec doesn't disengage on falling edge of cruise + def test_disable_control_allowed_from_cruise(self): + pass + + # No-op longitudinal tests (stock handles it) + def test_brake_safety_check(self): + pass + + def test_acc_hud_safety_check(self): + pass + + def test_fwd_hook(self): + pass + + def test_honda_fwd_brake_latching(self): + pass + + def _send_brake_msg(self, brake, aeb_req=0, bus=0): + pass + + def _rx_brake_msg(self, brake, aeb_req=0): + pass + + def _send_acc_hud_msg(self, pcm_gas, pcm_speed): + pass + + class TestHondaNidecPcmAltSafety(TestHondaNidecPcmSafety): """ Covers the Honda Nidec safety mode with alt SCM messages diff --git a/selfdrive/car/card.py b/selfdrive/car/card.py index f4c7010f0..5f786253d 100755 --- a/selfdrive/car/card.py +++ b/selfdrive/car/card.py @@ -105,6 +105,9 @@ class Car: if self.params.get_bool("dp_lat_alka"): dp_params |= structs.DPFlags.LatALKA + if self.params.get_bool("dp_honda_nidec_stock_long"): + dp_params |= structs.DPFlags.HondaNidecStockLong + dp_fingerprint = str(self.params.get("dp_dev_model_selected") or "") self.CI = get_car(*self.can_callbacks, obd_callback(self.params), alpha_long_allowed, is_release, num_pandas, dp_params, cached_params, dp_fingerprint=dp_fingerprint) self.RI = interfaces[self.CI.CP.carFingerprint].RadarInterface(self.CI.CP)