diff --git a/opendbc/car/hyundai/carstate.py b/opendbc/car/hyundai/carstate.py index 58b086a1808..8099eaa15f5 100644 --- a/opendbc/car/hyundai/carstate.py +++ b/opendbc/car/hyundai/carstate.py @@ -41,6 +41,8 @@ def __init__(self, CP): self.shifter_values = can_define.dv["CLU15"]["CF_Clu_Gear"] elif self.CP.flags & HyundaiFlags.TCU_GEARS: self.shifter_values = can_define.dv["TCU12"]["CUR_GR"] + elif CP.flags & HyundaiFlags.FCEV: + self.shifter_values = can_define.dv["EMS20"]["HYDROGEN_GEAR_SHIFTER"] else: self.shifter_values = can_define.dv["LVR12"]["CF_Lvr_Gear"] @@ -133,8 +135,10 @@ def update(self, can_parsers) -> structs.CarState: ret.espActive = cp.vl["TCS11"]["ABS_ACT"] == 1 ret.accFaulted = cp.vl["TCS13"]["ACCEnable"] != 0 # 0 ACC CONTROL ENABLED, 1-3 ACC CONTROL DISABLED - if self.CP.flags & (HyundaiFlags.HYBRID | HyundaiFlags.EV): - if self.CP.flags & HyundaiFlags.HYBRID: + if self.CP.flags & (HyundaiFlags.HYBRID | HyundaiFlags.EV | HyundaiFlags.FCEV): + if self.CP.flags & HyundaiFlags.FCEV: + ret.gas = cp.vl["FCEV_ACCELERATOR"]["ACCELERATOR_PEDAL"] / 254. + elif self.CP.flags & HyundaiFlags.HYBRID: ret.gas = cp.vl["E_EMS11"]["CR_Vcu_AccPedDep_Pos"] / 254. else: ret.gas = cp.vl["E_EMS11"]["Accel_Pedal_Pos"] / 254. @@ -147,6 +151,8 @@ def update(self, can_parsers) -> structs.CarState: # as this seems to be standard over all cars, but is not the preferred method. if self.CP.flags & (HyundaiFlags.HYBRID | HyundaiFlags.EV): gear = cp.vl["ELECT_GEAR"]["Elect_Gear_Shifter"] + elif self.CP.flags & HyundaiFlags.FCEV: + gear = cp.vl["EMS20"]["HYDROGEN_GEAR_SHIFTER"] elif self.CP.flags & HyundaiFlags.CLUSTER_GEARS: gear = cp.vl["CLU15"]["CF_Clu_Gear"] elif self.CP.flags & HyundaiFlags.TCU_GEARS: @@ -363,6 +369,8 @@ def get_can_parsers(self, CP): if CP.flags & (HyundaiFlags.HYBRID | HyundaiFlags.EV): pt_messages.append(("E_EMS11", 50)) + elif CP.flags & HyundaiFlags.FCEV: + pt_messages.append(("FCEV_ACCELERATOR", 100)) else: pt_messages += [ ("EMS12", 100), @@ -371,6 +379,8 @@ def get_can_parsers(self, CP): if CP.flags & (HyundaiFlags.HYBRID | HyundaiFlags.EV): pt_messages.append(("ELECT_GEAR", 20)) + elif CP.flags & HyundaiFlags.FCEV: + pt_messages.append(("EMS20", 100)) elif CP.flags & HyundaiFlags.CLUSTER_GEARS: pass elif CP.flags & HyundaiFlags.TCU_GEARS: diff --git a/opendbc/car/hyundai/fingerprints.py b/opendbc/car/hyundai/fingerprints.py index b6e51ee74b6..558d4509869 100644 --- a/opendbc/car/hyundai/fingerprints.py +++ b/opendbc/car/hyundai/fingerprints.py @@ -1199,4 +1199,18 @@ b'\xf1\x00US4_ RDR ----- 1.00 1.00 99110-CG000 ', ], }, + CAR.HYUNDAI_NEXO_1ST_GEN: { + (Ecu.abs, 0x7D1, None): [ + b'\xf1\x00FE IEB \x01 312 \x11\x13 58520-M5000', + ], + (Ecu.fwdCamera, 0x7C4, None): [ + b'\xf1\x00FE MFC AT KOR LHD 1.00 1.00 99211-M5100 201218', + ], + (Ecu.eps, 0x7D4, None): [ + b'\xf1\x00FE MDPS C 1.00 1.05 56340-M5000 9903', + ], + (Ecu.fwdRadar, 0x7D0, None): [ + b'\xf1\x00FE__ SCC FHCUP 1.00 1.05 99110-M5000 ', + ], + }, } diff --git a/opendbc/car/hyundai/interface.py b/opendbc/car/hyundai/interface.py index 68eded7d7cb..8c31e835ce1 100644 --- a/opendbc/car/hyundai/interface.py +++ b/opendbc/car/hyundai/interface.py @@ -117,6 +117,8 @@ def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, experime ret.safetyConfigs[-1].safetyParam |= HyundaiSafetyFlags.HYBRID_GAS.value elif ret.flags & HyundaiFlags.EV: ret.safetyConfigs[-1].safetyParam |= HyundaiSafetyFlags.EV_GAS.value + elif ret.flags & HyundaiFlags.FCEV: + ret.safetyConfigs[-1].safetyParam |= HyundaiSafetyFlags.FCEV_GAS.value # Car specific configuration overrides diff --git a/opendbc/car/hyundai/values.py b/opendbc/car/hyundai/values.py index a71b6b4da72..24eb1de76bb 100644 --- a/opendbc/car/hyundai/values.py +++ b/opendbc/car/hyundai/values.py @@ -59,6 +59,7 @@ class HyundaiSafetyFlags(IntFlag): CANFD_ALT_BUTTONS = 32 ALT_LIMITS = 64 CANFD_LKA_STEERING_ALT = 128 + FCEV_GAS = 256 class HyundaiFlags(IntFlag): @@ -115,6 +116,8 @@ class HyundaiFlags(IntFlag): HAS_LDA_BUTTON = 2 ** 24 + FCEV = 2 ** 25 + class Footnote(Enum): CANFD = CarFootnote( @@ -260,6 +263,11 @@ class CAR(Platforms): CarSpecs(mass=1425, wheelbase=2.6, steerRatio=13.42, tireStiffnessFactor=0.385), flags=HyundaiFlags.HYBRID | HyundaiFlags.ALT_LIMITS, ) + HYUNDAI_NEXO_1ST_GEN = HyundaiPlatformConfig( + [HyundaiCarDocs("Hyundai Nexo 2021", "All", car_parts=CarParts.common([CarHarness.hyundai_h]))], + CarSpecs(mass=3990 * CV.LB_TO_KG, wheelbase=2.79, steerRatio=14.19), # https://www.hyundainews.com/assets/documents/original/42768-2021NEXOProductGuideSpecs.pdf + flags=HyundaiFlags.FCEV, + ) HYUNDAI_SANTA_FE = HyundaiPlatformConfig( [HyundaiCarDocs("Hyundai Santa Fe 2019-20", "All", video_link="https://youtu.be/bjDR0YjM__s", car_parts=CarParts.common([CarHarness.hyundai_d]))], diff --git a/opendbc/car/tests/routes.py b/opendbc/car/tests/routes.py index 226a9d1fe31..cda5f383845 100644 --- a/opendbc/car/tests/routes.py +++ b/opendbc/car/tests/routes.py @@ -160,6 +160,8 @@ class CarTestRoute(NamedTuple): CarTestRoute("ff973b941a69366f|2022-07-28--22-01-19", HYUNDAI.HYUNDAI_KONA_EV_2022, segment=11), CarTestRoute("1618132d68afc876|2023-08-27--09-32-14", HYUNDAI.HYUNDAI_KONA_EV_2ND_GEN, segment=13), CarTestRoute("49f3c13141b6bc87|2021-07-28--08-05-13", HYUNDAI.HYUNDAI_KONA_HEV), + CarTestRoute("a74afe0cf708748f/0000000e--a2885a9a71", HYUNDAI.HYUNDAI_NEXO_1ST_GEN), + CarTestRoute("a74afe0cf708748f/0000000c--b476a8fd00", HYUNDAI.HYUNDAI_NEXO_1ST_GEN), # openpilot longitudinal enabled CarTestRoute("5dddcbca6eb66c62|2020-07-26--13-24-19", HYUNDAI.KIA_STINGER), CarTestRoute("5b50b883a4259afb|2022-11-09--15-00-42", HYUNDAI.KIA_STINGER_2022), CarTestRoute("d624b3d19adce635|2020-08-01--14-59-12", HYUNDAI.HYUNDAI_VELOSTER), diff --git a/opendbc/car/torque_data/override.toml b/opendbc/car/torque_data/override.toml index 3eab899cf30..2cc2aca3bcc 100644 --- a/opendbc/car/torque_data/override.toml +++ b/opendbc/car/torque_data/override.toml @@ -74,6 +74,7 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"] "GENESIS_GV70_ELECTRIFIED_1ST_GEN" = [1.9, 1.9, 0.09] "GENESIS_G80_2ND_GEN_FL" = [2.5819356441497803, 2.5, 0.11244568973779678] "RIVIAN_R1_GEN1" = [3.3, 2.5, 0.07] +"HYUNDAI_NEXO_1ST_GEN" = [2.5, 2.5, 0.1] # Dashcam or fallback configured as ideal car "MOCK" = [10.0, 10, 0.0] diff --git a/opendbc/safety/safety/safety_hyundai.h b/opendbc/safety/safety/safety_hyundai.h index cf73afee621..000b5be790e 100644 --- a/opendbc/safety/safety/safety_hyundai.h +++ b/opendbc/safety/safety/safety_hyundai.h @@ -32,14 +32,15 @@ static const CanMsg HYUNDAI_TX_MSGS[] = { {0x485, 0, 4}, // LFAHDA_MFC Bus 0 }; -#define HYUNDAI_COMMON_RX_CHECKS(legacy) \ +#define HYUNDAI_COMMON_RX_CHECKS(legacy) \ {.msg = {{0x260, 0, 8, .check_checksum = true, .max_counter = 3U, .frequency = 100U}, \ - {0x371, 0, 8, .frequency = 100U}, { 0 }}}, \ + {0x371, 0, 8, .frequency = 100U}, \ + {0x91, 0, 8, .frequency = 100U}}}, \ {.msg = {{0x386, 0, 8, .check_checksum = !(legacy), .max_counter = (legacy) ? 0U : 15U, .frequency = 100U}, { 0 }, { 0 }}}, \ {.msg = {{0x394, 0, 8, .check_checksum = !(legacy), .max_counter = (legacy) ? 0U : 7U, .frequency = 100U}, { 0 }, { 0 }}}, \ -#define HYUNDAI_SCC12_ADDR_CHECK(scc_bus) \ - {.msg = {{0x421, (scc_bus), 8, .check_checksum = true, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}}, \ +#define HYUNDAI_SCC12_ADDR_CHECK(scc_bus) \ + {.msg = {{0x421, (scc_bus), 8, .check_checksum = true, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}}, \ static bool hyundai_legacy = false; @@ -145,6 +146,8 @@ static void hyundai_rx_hook(const CANPacket_t *to_push) { gas_pressed = (((GET_BYTE(to_push, 4) & 0x7FU) << 1) | GET_BYTE(to_push, 3) >> 7) != 0U; } else if ((addr == 0x371) && hyundai_hybrid_gas_signal) { gas_pressed = GET_BYTE(to_push, 7) != 0U; + } else if ((addr == 0x91) && hyundai_fcev_gas_signal) { + gas_pressed = GET_BYTE(to_push, 6) != 0U; } else if ((addr == 0x260) && !hyundai_ev_gas_signal && !hyundai_hybrid_gas_signal) { gas_pressed = (GET_BYTE(to_push, 7) >> 6) != 0U; } else { diff --git a/opendbc/safety/safety/safety_hyundai_common.h b/opendbc/safety/safety/safety_hyundai_common.h index 8c8c8759a52..ea1c04da73e 100644 --- a/opendbc/safety/safety/safety_hyundai_common.h +++ b/opendbc/safety/safety/safety_hyundai_common.h @@ -36,6 +36,9 @@ bool hyundai_canfd_lka_steering = false; extern bool hyundai_alt_limits; bool hyundai_alt_limits = false; +extern bool hyundai_fcev_gas_signal; +bool hyundai_fcev_gas_signal = false; + static uint8_t hyundai_last_button_interaction; // button messages since the user pressed an enable button void hyundai_common_init(uint16_t param) { @@ -44,12 +47,14 @@ void hyundai_common_init(uint16_t param) { const int HYUNDAI_PARAM_CAMERA_SCC = 8; const int HYUNDAI_PARAM_CANFD_LKA_STEERING = 16; const int HYUNDAI_PARAM_ALT_LIMITS = 64; // TODO: shift this down with the rest of the common flags + const int HYUNDAI_PARAM_FCEV_GAS = 256; hyundai_ev_gas_signal = GET_FLAG(param, HYUNDAI_PARAM_EV_GAS); hyundai_hybrid_gas_signal = !hyundai_ev_gas_signal && GET_FLAG(param, HYUNDAI_PARAM_HYBRID_GAS); hyundai_camera_scc = GET_FLAG(param, HYUNDAI_PARAM_CAMERA_SCC); hyundai_canfd_lka_steering = GET_FLAG(param, HYUNDAI_PARAM_CANFD_LKA_STEERING); hyundai_alt_limits = GET_FLAG(param, HYUNDAI_PARAM_ALT_LIMITS); + hyundai_fcev_gas_signal = GET_FLAG(param, HYUNDAI_PARAM_FCEV_GAS); hyundai_last_button_interaction = HYUNDAI_PREV_BUTTON_SAMPLES; diff --git a/opendbc/safety/tests/test_hyundai.py b/opendbc/safety/tests/test_hyundai.py index 791b62f612c..f9cef7cd515 100755 --- a/opendbc/safety/tests/test_hyundai.py +++ b/opendbc/safety/tests/test_hyundai.py @@ -138,6 +138,18 @@ def setUp(self): self.safety.init_tests() +class TestHyundaiSafetyFCEV(TestHyundaiSafety): + def setUp(self): + self.packer = CANPackerPanda("hyundai_kia_generic") + self.safety = libsafety_py.libsafety + self.safety.set_safety_hooks(CarParams.SafetyModel.hyundai, HyundaiSafetyFlags.FCEV_GAS) + self.safety.init_tests() + + def _user_gas_msg(self, gas): + values = {"ACCELERATOR_PEDAL": gas} + return self.packer.make_can_msg_panda("FCEV_ACCELERATOR", 0, values) + + class TestHyundaiLegacySafety(TestHyundaiSafety): def setUp(self): self.packer = CANPackerPanda("hyundai_kia_generic")