Skip to content

Commit

Permalink
HKG: Car Port for Hyundai Palisade and Kia Telluride 2023-24 (HDA2)
Browse files Browse the repository at this point in the history
  • Loading branch information
sunnyhaibin committed Sep 24, 2024
1 parent 0771622 commit 24ed081
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 41 deletions.
10 changes: 6 additions & 4 deletions opendbc/car/hyundai/carcontroller.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,11 @@ def update(self, CC, CS, now_nanos):
if self.CP.flags & HyundaiFlags.ENABLE_BLINKERS:
can_sends.append(make_tester_present_msg(0x7b1, self.CAN.ECAN, suppress_response=True))

can_canfd_hybrid = self.CP.flags & HyundaiFlags.CAN_CANFD_HYBRID

# CAN-FD platforms
hda2 = self.CP.flags & HyundaiFlags.CANFD_HDA2
if self.CP.carFingerprint in CANFD_CAR:
hda2 = self.CP.flags & HyundaiFlags.CANFD_HDA2
hda2_long = hda2 and self.CP.openpilotLongitudinalControl

# steering control
Expand Down Expand Up @@ -132,7 +134,7 @@ def update(self, CC, CS, now_nanos):
self.accel_last = accel
else:
# button presses
can_sends.extend(self.create_button_messages(CC, CS, use_clu11=False))
can_sends.extend(self.create_button_messages(CC, CS, use_clu11=(hda2 and can_canfd_hybrid)))
else:
can_sends.append(hyundaican.create_lkas11(self.packer, self.frame, self.CP, apply_steer, apply_steer_req,
torque_fault, CS.lkas11, sys_warning, sys_state, CC.enabled,
Expand Down Expand Up @@ -174,12 +176,12 @@ def create_button_messages(self, CC: structs.CarControl, CS: CarState, use_clu11
can_sends = []
if use_clu11:
if CC.cruiseControl.cancel:
can_sends.append(hyundaican.create_clu11(self.packer, self.frame, CS.clu11, Buttons.CANCEL, self.CP))
can_sends.append(hyundaican.create_clu11(self.packer, self.frame, CS.clu11, Buttons.CANCEL, self.CP, self.CAN))
elif CC.cruiseControl.resume:
# send resume at a max freq of 10Hz
if (self.frame - self.last_button_frame) * DT_CTRL > 0.1:
# send 25 messages at a time to increases the likelihood of resume being accepted
can_sends.extend([hyundaican.create_clu11(self.packer, self.frame, CS.clu11, Buttons.RES_ACCEL, self.CP)] * 25)
can_sends.extend([hyundaican.create_clu11(self.packer, self.frame, CS.clu11, Buttons.RES_ACCEL, self.CP, self.CAN)] * 25)
if (self.frame - self.last_button_frame) * DT_CTRL >= 0.15:
self.last_button_frame = self.frame
else:
Expand Down
54 changes: 35 additions & 19 deletions opendbc/car/hyundai/carstate.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from opendbc.car.common.conversions import Conversions as CV
from opendbc.car.hyundai.hyundaicanfd import CanBus
from opendbc.car.hyundai.values import HyundaiFlags, CAR, DBC, CAN_GEARS, CAMERA_SCC_CAR, \
CANFD_CAR, Buttons, CarControllerParams
CANFD_CAR, Buttons, CarControllerParams, CAN_CANFD_HYBRID_CAR
from opendbc.car.interfaces import CarStateBase

ButtonType = structs.CarState.ButtonEvent.Type
Expand All @@ -32,7 +32,7 @@ def __init__(self, CP):
self.gear_msg_canfd = "GEAR_ALT" if CP.flags & HyundaiFlags.CANFD_ALT_GEARS else \
"GEAR_ALT_2" if CP.flags & HyundaiFlags.CANFD_ALT_GEARS_2 else \
"GEAR_SHIFTER"
if CP.carFingerprint in CANFD_CAR:
if CP.carFingerprint in (CANFD_CAR - CAN_CANFD_HYBRID_CAR):
self.shifter_values = can_define.dv[self.gear_msg_canfd]["GEAR"]
elif self.CP.carFingerprint in CAN_GEARS["use_cluster_gears"]:
self.shifter_values = can_define.dv["CLU15"]["CF_Clu_Gear"]
Expand All @@ -58,7 +58,7 @@ def __init__(self, CP):
self.params = CarControllerParams(CP)

def update(self, cp, cp_cam, *_) -> structs.CarState:
if self.CP.carFingerprint in CANFD_CAR:
if self.CP.carFingerprint in (CANFD_CAR - CAN_CANFD_HYBRID_CAR):
return self.update_canfd(cp, cp_cam)

ret = structs.CarState()
Expand Down Expand Up @@ -112,11 +112,12 @@ def update(self, cp, cp_cam, *_) -> structs.CarState:
ret.cruiseState.standstill = False
ret.cruiseState.nonAdaptive = False
else:
ret.cruiseState.available = cp_cruise.vl["SCC11"]["MainMode_ACC"] == 1
scc_bus = "SCC12" if self.CP.flags & HyundaiFlags.CAN_CANFD_HYBRID else "SCC11"
ret.cruiseState.available = cp_cruise.vl[scc_bus]["MainMode_ACC"] == 1
ret.cruiseState.enabled = cp_cruise.vl["SCC12"]["ACCMode"] != 0
ret.cruiseState.standstill = cp_cruise.vl["SCC11"]["SCCInfoDisplay"] == 4.
ret.cruiseState.nonAdaptive = cp_cruise.vl["SCC11"]["SCCInfoDisplay"] == 2. # Shows 'Cruise Control' on dash
ret.cruiseState.speed = cp_cruise.vl["SCC11"]["VSetDis"] * speed_conv
ret.cruiseState.standstill = cp_cruise.vl[scc_bus]["SCCInfoDisplay"] == 4.
ret.cruiseState.nonAdaptive = cp_cruise.vl[scc_bus]["SCCInfoDisplay"] == 2. # Shows 'Cruise Control' on dash
ret.cruiseState.speed = cp_cruise.vl[scc_bus]["VSetDis"] * speed_conv

# TODO: Find brake pressure
ret.brake = 0
Expand Down Expand Up @@ -150,7 +151,7 @@ def update(self, cp, cp_cam, *_) -> structs.CarState:

ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(gear))

if not self.CP.openpilotLongitudinalControl:
if not self.CP.openpilotLongitudinalControl and not (self.CP.flags & HyundaiFlags.CAN_CANFD_HYBRID):
aeb_src = "FCA11" if self.CP.flags & HyundaiFlags.USE_FCA.value else "SCC12"
aeb_sig = "FCA_CmdAct" if self.CP.flags & HyundaiFlags.USE_FCA.value else "AEB_CmdAct"
aeb_warning = cp_cruise.vl[aeb_src]["CF_VSM_Warn"] != 0
Expand All @@ -164,13 +165,17 @@ def update(self, cp, cp_cam, *_) -> structs.CarState:
ret.rightBlindspot = cp.vl["LCA11"]["CF_Lca_IndRight"] != 0

# save the entire LKAS11 and CLU11
self.lkas11 = copy.copy(cp_cam.vl["LKAS11"])
if not (self.CP.flags & HyundaiFlags.CAN_CANFD_HYBRID):
self.lkas11 = copy.copy(cp_cam.vl["LKAS11"])
self.clu11 = copy.copy(cp.vl["CLU11"])
self.steer_state = cp.vl["MDPS12"]["CF_Mdps_ToiActive"] # 0 NOT ACTIVE, 1 ACTIVE
prev_cruise_buttons = self.cruise_buttons[-1]
self.cruise_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwState"])
self.main_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwMain"])

if self.CP.flags & (HyundaiFlags.CAN_CANFD_HYBRID | HyundaiFlags.CANFD_HDA2):
self.hda2_lfa_block_msg = copy.copy(cp_cam.vl["CAM_0x2a4"])

if self.CP.openpilotLongitudinalControl:
ret.buttonEvents = create_button_events(self.cruise_buttons[-1], prev_cruise_buttons, BUTTONS_DICT)

Expand Down Expand Up @@ -262,12 +267,14 @@ def update_canfd(self, cp, cp_cam) -> structs.CarState:
return ret

def get_can_parser(self, CP):
if CP.carFingerprint in CANFD_CAR:
if CP.carFingerprint in (CANFD_CAR - CAN_CANFD_HYBRID_CAR):
return self.get_can_parser_canfd(CP)

mdps12_freq = 100 if CP.flags & HyundaiFlags.CAN_CANFD_HYBRID else 50

messages = [
# address, frequency
("MDPS12", 50),
("MDPS12", mdps12_freq),
("TCS11", 100),
("TCS13", 50),
("TCS15", 10),
Expand All @@ -281,16 +288,20 @@ def get_can_parser(self, CP):
("SAS11", 100),
]

if not CP.openpilotLongitudinalControl and CP.carFingerprint not in CAMERA_SCC_CAR:
if not CP.openpilotLongitudinalControl and not CP.flags & (HyundaiFlags.CAMERA_SCC | HyundaiFlags.CAN_CANFD_HYBRID):
messages += [
("SCC11", 50),
("SCC12", 50),
]
if CP.flags & HyundaiFlags.USE_FCA.value:
messages.append(("FCA11", 50))

if not CP.openpilotLongitudinalControl and CP.flags & HyundaiFlags.CAN_CANFD_HYBRID:
messages.append(("SCC12", 50))

if CP.enableBsm:
messages.append(("LCA11", 50))
bsm_freq = 20 if CP.flags & HyundaiFlags.CAN_CANFD_HYBRID else 50
messages.append(("LCA11", bsm_freq))

if CP.flags & (HyundaiFlags.HYBRID | HyundaiFlags.EV):
messages.append(("E_EMS11", 50))
Expand All @@ -309,16 +320,20 @@ def get_can_parser(self, CP):
else:
messages.append(("LVR12", 100))

return CANParser(DBC[CP.carFingerprint]["pt"], messages, 0)
bus = CanBus(CP).ECAN if CP.flags & HyundaiFlags.CAN_CANFD_HYBRID else 0
return CANParser(DBC[CP.carFingerprint]["pt"], messages, bus)

@staticmethod
def get_cam_can_parser(CP):
if CP.carFingerprint in CANFD_CAR:
if CP.carFingerprint in (CANFD_CAR - CAN_CANFD_HYBRID_CAR):
return CarState.get_cam_can_parser_canfd(CP)

messages = [
("LKAS11", 100)
]
messages = []

if CP.flags & HyundaiFlags.CAN_CANFD_HYBRID:
messages.append(("CAM_0x2a4", 20))
else:
messages.append(("LKAS11", 100))

if not CP.openpilotLongitudinalControl and CP.carFingerprint in CAMERA_SCC_CAR:
messages += [
Expand All @@ -329,7 +344,8 @@ def get_cam_can_parser(CP):
if CP.flags & HyundaiFlags.USE_FCA.value:
messages.append(("FCA11", 50))

return CANParser(DBC[CP.carFingerprint]["pt"], messages, 2)
bus = CanBus(CP).CAM if CP.flags & HyundaiFlags.CAN_CANFD_HYBRID else 2
return CANParser(DBC[CP.carFingerprint]["pt"], messages, bus)

def get_can_parser_canfd(self, CP):
messages = [
Expand Down
17 changes: 17 additions & 0 deletions opendbc/car/hyundai/fingerprints.py
Original file line number Diff line number Diff line change
Expand Up @@ -1139,4 +1139,21 @@
b'\xf1\x00US4_ RDR ----- 1.00 1.00 99110-CG000 ',
],
},
CAR.HYUNDAI_PALISADE_2023: {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00LX2 MFC AT USA LHD 1.00 1.04 99211-S8150 220622',
b'\xf1\x00ON MFC AT USA LHD 1.00 1.01 99211-S9150 220708',
b'\xf1\x00LX2 MFC AT USA LHD 1.00 1.03 99211-S8150 220527',
b'\xf1\x00ON MFC AT USA LHD 1.00 1.00 99211-S9160 230303',
b'\xf1\x00LX2 MFC AT USA LHD 1.00 1.00 99211-S8600 230317',
b'\xf1\x00LX2 MFC AT USA LHD 1.00 1.01 99211-S8600 230817',
],
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00LX2_ SCC ----- 1.00 1.01 99110-S8150 ',
b'\xf1\x00ON__ SCC ----- 1.00 1.01 99110-S9150 ',
b'\xf1\x00LX2_ SCC ----- 1.00 1.00 99110-S8150 ',
b'\xf1\x00ON__ SCC ----- 1.00 1.00 99110-S9160 ',
b'\xf1\x00LX2_ SCC ----- 1.00 1.00 99110-S8600 ',
],
},
}
12 changes: 9 additions & 3 deletions opendbc/car/hyundai/hyundaican.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ def create_lkas11(packer, frame, CP, apply_steer, steer_req,
return packer.make_can_msg("LKAS11", 0, values)


def create_clu11(packer, frame, clu11, button, CP):
def create_clu11(packer, frame, clu11, button, CP, CAN):
values = {s: clu11[s] for s in [
"CF_Clu_CruiseSwState",
"CF_Clu_CruiseSwMain",
Expand All @@ -112,8 +112,14 @@ def create_clu11(packer, frame, clu11, button, CP):
]}
values["CF_Clu_CruiseSwState"] = button
values["CF_Clu_AliveCnt1"] = frame % 0x10
# send buttons to camera on camera-scc based cars
bus = 2 if CP.flags & HyundaiFlags.CAMERA_SCC else 0

if CP.flags & HyundaiFlags.CAMERA_SCC: # send buttons to camera on camera-scc based cars
bus = 2
elif CP.flags & HyundaiFlags.CAN_CANFD_HYBRID:
bus = CAN.ECAN
else:
bus = 0

return packer.make_can_msg("CLU11", bus, values)


Expand Down
38 changes: 25 additions & 13 deletions opendbc/car/hyundai/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from opendbc.car.hyundai.hyundaicanfd import CanBus
from opendbc.car.hyundai.values import HyundaiFlags, CAR, DBC, CANFD_CAR, CAMERA_SCC_CAR, CANFD_RADAR_SCC_CAR, \
CANFD_UNSUPPORTED_LONGITUDINAL_CAR, EV_CAR, HYBRID_CAR, LEGACY_SAFETY_MODE_CAR, \
UNSUPPORTED_LONGITUDINAL_CAR, Buttons
UNSUPPORTED_LONGITUDINAL_CAR, CAN_CANFD_HYBRID_CAR, Buttons
from opendbc.car.hyundai.radar_interface import RADAR_START_ADDR
from opendbc.car.interfaces import CarInterfaceBase
from opendbc.car.disable_ecu import disable_ecu
Expand All @@ -19,25 +19,29 @@ def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, experime
ret.carName = "hyundai"
ret.radarUnavailable = RADAR_START_ADDR not in fingerprint[1] or DBC[ret.carFingerprint]["radar"] is None

hda2 = Ecu.adas in [fw.ecu for fw in car_fw]
CAN = CanBus(None, hda2, fingerprint)

# These cars have been put into dashcam only due to both a lack of users and test coverage.
# These cars likely still work fine. Once a user confirms each car works and a test route is
# added to opendbc/car/tests/routes.py, we can remove it from this list.
# FIXME: the Optima Hybrid 2017 uses a different SCC12 checksum
ret.dashcamOnly = candidate in {CAR.KIA_OPTIMA_H, }
ret.dashcamOnly = candidate in {CAR.KIA_OPTIMA_H, } or (candidate in (CAR.HYUNDAI_PALISADE_2023, ) and not hda2)

hda2 = Ecu.adas in [fw.ecu for fw in car_fw]
CAN = CanBus(None, hda2, fingerprint)
pure_canfd_car = CANFD_CAR - CAN_CANFD_HYBRID_CAR

# detect HDA2 with ADAS Driving ECU
if hda2:
ret.flags |= HyundaiFlags.CANFD_HDA2.value

if candidate in CANFD_CAR:
if candidate in pure_canfd_car:
# detect if car is hybrid
if 0x105 in fingerprint[CAN.ECAN]:
ret.flags |= HyundaiFlags.HYBRID.value
elif candidate in EV_CAR:
ret.flags |= HyundaiFlags.EV.value

# detect HDA2 with ADAS Driving ECU
if hda2:
ret.flags |= HyundaiFlags.CANFD_HDA2.value
if 0x110 in fingerprint[CAN.CAM]:
ret.flags |= HyundaiFlags.CANFD_HDA2_ALT_STEERING.value
else:
Expand Down Expand Up @@ -75,7 +79,7 @@ def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, experime
ret.steerActuatorDelay = 0.2

# *** longitudinal control ***
if candidate in CANFD_CAR:
if candidate in pure_canfd_car:
ret.experimentalLongitudinalAvailable = candidate not in (CANFD_UNSUPPORTED_LONGITUDINAL_CAR | CANFD_RADAR_SCC_CAR)
else:
ret.experimentalLongitudinalAvailable = candidate not in (UNSUPPORTED_LONGITUDINAL_CAR | CAMERA_SCC_CAR)
Expand All @@ -89,20 +93,20 @@ def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, experime
ret.longitudinalActuatorDelay = 0.5

# *** feature detection ***
if candidate in CANFD_CAR:
if candidate in pure_canfd_car:
ret.enableBsm = 0x1e5 in fingerprint[CAN.ECAN]
else:
ret.enableBsm = 0x58b in fingerprint[0]
bus = CAN.ECAN if ret.flags & HyundaiFlags.CAN_CANFD_HYBRID else 0
ret.enableBsm = 0x58b in fingerprint[bus]

# *** panda safety config ***
if candidate in CANFD_CAR:
if candidate in pure_canfd_car:
cfgs = [get_safety_config(structs.CarParams.SafetyModel.hyundaiCanfd), ]
if CAN.ECAN >= 4:
cfgs.insert(0, get_safety_config(structs.CarParams.SafetyModel.noOutput))
ret.safetyConfigs = cfgs

if ret.flags & HyundaiFlags.CANFD_HDA2:
ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_CANFD_HDA2
if ret.flags & HyundaiFlags.CANFD_HDA2_ALT_STEERING:
ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_CANFD_HDA2_ALT_STEERING
if ret.flags & HyundaiFlags.CANFD_ALT_BUTTONS:
Expand All @@ -114,11 +118,19 @@ def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, experime
# these cars require a special panda safety mode due to missing counters and checksums in the messages
ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.hyundaiLegacy)]
else:
ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.hyundai, 0)]
cfgs = [get_safety_config(structs.CarParams.SafetyModel.hyundai), ]
if CAN.ECAN >= 4:
cfgs.insert(0, get_safety_config(structs.CarParams.SafetyModel.noOutput))
ret.safetyConfigs = cfgs

if candidate in CAMERA_SCC_CAR:
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_HYUNDAI_CAMERA_SCC

if candidate in CAN_CANFD_HYBRID_CAR:
ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_CAN_CANFD_HYBRID

if ret.flags & HyundaiFlags.CANFD_HDA2:
ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_CANFD_HDA2
if ret.openpilotLongitudinalControl:
ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_LONG
if ret.flags & HyundaiFlags.HYBRID:
Expand Down
Loading

0 comments on commit 24ed081

Please sign in to comment.