diff --git a/selfdrive/car/hyundai org/__init__.py b/selfdrive/car/hyundai org/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/selfdrive/car/hyundai org/carcontroller.org b/selfdrive/car/hyundai org/carcontroller.org
new file mode 100644
index 0000000..726f708
--- /dev/null
+++ b/selfdrive/car/hyundai org/carcontroller.org
@@ -0,0 +1,210 @@
+from cereal import car
+from openpilot.common.conversions import Conversions as CV
+from openpilot.common.numpy_fast import clip
+from openpilot.common.realtime import DT_CTRL
+from opendbc.can.packer import CANPacker
+from openpilot.selfdrive.car import apply_driver_steer_torque_limits, common_fault_avoidance
+from openpilot.selfdrive.car.hyundai import hyundaicanfd, hyundaican
+from openpilot.selfdrive.car.hyundai.hyundaicanfd import CanBus
+from openpilot.selfdrive.car.hyundai.values import HyundaiFlags, Buttons, CarControllerParams, CANFD_CAR, CAR
+
+VisualAlert = car.CarControl.HUDControl.VisualAlert
+LongCtrlState = car.CarControl.Actuators.LongControlState
+
+# EPS faults if you apply torque while the steering angle is above 90 degrees for more than 1 second
+# All slightly below EPS thresholds to avoid fault
+MAX_ANGLE = 85
+MAX_ANGLE_FRAMES = 89
+MAX_ANGLE_CONSECUTIVE_FRAMES = 2
+
+
+def process_hud_alert(enabled, fingerprint, hud_control):
+ sys_warning = (hud_control.visualAlert in (VisualAlert.steerRequired, VisualAlert.ldw))
+
+ # initialize to no line visible
+ # TODO: this is not accurate for all cars
+ sys_state = 1
+ if hud_control.leftLaneVisible and hud_control.rightLaneVisible or sys_warning: # HUD alert only display when LKAS status is active
+ sys_state = 3 if enabled or sys_warning else 4
+ elif hud_control.leftLaneVisible:
+ sys_state = 5
+ elif hud_control.rightLaneVisible:
+ sys_state = 6
+
+ # initialize to no warnings
+ left_lane_warning = 0
+ right_lane_warning = 0
+ if hud_control.leftLaneDepart:
+ left_lane_warning = 1 if fingerprint in (CAR.GENESIS_G90, CAR.GENESIS_G80) else 2
+ if hud_control.rightLaneDepart:
+ right_lane_warning = 1 if fingerprint in (CAR.GENESIS_G90, CAR.GENESIS_G80) else 2
+
+ return sys_warning, sys_state, left_lane_warning, right_lane_warning
+
+
+class CarController:
+ def __init__(self, dbc_name, CP, VM):
+ self.CP = CP
+ self.CAN = CanBus(CP)
+ self.params = CarControllerParams(CP)
+ self.packer = CANPacker(dbc_name)
+ self.angle_limit_counter = 0
+ self.frame = 0
+
+ self.accel_last = 0
+ self.apply_steer_last = 0
+ self.car_fingerprint = CP.carFingerprint
+ self.last_button_frame = 0
+
+ def update(self, CC, CS, now_nanos, sport_plus):
+ actuators = CC.actuators
+ hud_control = CC.hudControl
+
+ # steering torque
+ new_steer = int(round(actuators.steer * self.params.STEER_MAX))
+ apply_steer = apply_driver_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, self.params)
+
+ # >90 degree steering fault prevention
+ self.angle_limit_counter, apply_steer_req = common_fault_avoidance(abs(CS.out.steeringAngleDeg) >= MAX_ANGLE, CC.latActive,
+ self.angle_limit_counter, MAX_ANGLE_FRAMES,
+ MAX_ANGLE_CONSECUTIVE_FRAMES)
+
+ if not CC.latActive:
+ apply_steer = 0
+
+ # Hold torque with induced temporary fault when cutting the actuation bit
+ torque_fault = CC.latActive and not apply_steer_req
+
+ self.apply_steer_last = apply_steer
+
+ # accel + longitudinal
+ if sport_plus:
+ accel = clip(actuators.accel, CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX_PLUS)
+ else:
+ accel = clip(actuators.accel, CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX)
+ stopping = actuators.longControlState == LongCtrlState.stopping
+ set_speed_in_units = hud_control.setSpeed * (CV.MS_TO_KPH if CS.is_metric else CV.MS_TO_MPH)
+
+ # HUD messages
+ sys_warning, sys_state, left_lane_warning, right_lane_warning = process_hud_alert(CC.enabled, self.car_fingerprint,
+ hud_control)
+
+ can_sends = []
+
+ # *** common hyundai stuff ***
+
+ # tester present - w/ no response (keeps relevant ECU disabled)
+ if self.frame % 100 == 0 and not (self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC.value) and self.CP.openpilotLongitudinalControl:
+ # for longitudinal control, either radar or ADAS driving ECU
+ addr, bus = 0x7d0, 0
+ if self.CP.flags & HyundaiFlags.CANFD_HDA2.value:
+ addr, bus = 0x730, self.CAN.ECAN
+ can_sends.append([addr, 0, b"\x02\x3E\x80\x00\x00\x00\x00\x00", bus])
+
+ # for blinkers
+ if self.CP.flags & HyundaiFlags.ENABLE_BLINKERS:
+ can_sends.append([0x7b1, 0, b"\x02\x3E\x80\x00\x00\x00\x00\x00", self.CAN.ECAN])
+
+ # CAN-FD platforms
+ if self.CP.carFingerprint in CANFD_CAR:
+ hda2 = self.CP.flags & HyundaiFlags.CANFD_HDA2
+ hda2_long = hda2 and self.CP.openpilotLongitudinalControl
+
+ # steering control
+ can_sends.extend(hyundaicanfd.create_steering_messages(self.packer, self.CP, self.CAN, CC.enabled, apply_steer_req, apply_steer))
+
+ # prevent LFA from activating on HDA2 by sending "no lane lines detected" to ADAS ECU
+ if self.frame % 5 == 0 and hda2:
+ can_sends.append(hyundaicanfd.create_suppress_lfa(self.packer, self.CAN, CS.hda2_lfa_block_msg,
+ self.CP.flags & HyundaiFlags.CANFD_HDA2_ALT_STEERING))
+
+ # LFA and HDA icons
+ if self.frame % 5 == 0 and (not hda2 or hda2_long):
+ can_sends.append(hyundaicanfd.create_lfahda_cluster(self.packer, self.CAN, CC.enabled))
+
+ # blinkers
+ if hda2 and self.CP.flags & HyundaiFlags.ENABLE_BLINKERS:
+ can_sends.extend(hyundaicanfd.create_spas_messages(self.packer, self.CAN, self.frame, CC.leftBlinker, CC.rightBlinker))
+
+ if self.CP.openpilotLongitudinalControl:
+ if hda2:
+ can_sends.extend(hyundaicanfd.create_adrv_messages(self.packer, self.CAN, self.frame))
+ if self.frame % 2 == 0:
+ can_sends.append(hyundaicanfd.create_acc_control(self.packer, self.CAN, CC.enabled, self.accel_last, accel, stopping, CC.cruiseControl.override,
+ set_speed_in_units, CS.personality_profile))
+ self.accel_last = accel
+ else:
+ # button presses
+ can_sends.extend(self.create_button_messages(CC, CS, use_clu11=False))
+ else:
+ can_sends.append(hyundaican.create_lkas11(self.packer, self.frame, self.car_fingerprint, apply_steer, apply_steer_req,
+ torque_fault, CS.lkas11, sys_warning, sys_state, CC.enabled,
+ hud_control.leftLaneVisible, hud_control.rightLaneVisible,
+ left_lane_warning, right_lane_warning))
+
+ if not self.CP.openpilotLongitudinalControl:
+ can_sends.extend(self.create_button_messages(CC, CS, use_clu11=True))
+
+ if self.frame % 2 == 0 and self.CP.openpilotLongitudinalControl:
+ # TODO: unclear if this is needed
+ jerk = 3.0 if actuators.longControlState == LongCtrlState.pid else 1.0
+ use_fca = self.CP.flags & HyundaiFlags.USE_FCA.value
+ can_sends.extend(hyundaican.create_acc_commands(self.packer, CC.enabled, accel, jerk, int(self.frame / 2),
+ hud_control.leadVisible, set_speed_in_units, stopping,
+ CC.cruiseControl.override, use_fca, CS.out.cruiseState.available, CS.personality_profile))
+
+ # 20 Hz LFA MFA message
+ if self.frame % 5 == 0 and self.CP.flags & HyundaiFlags.SEND_LFA.value:
+ can_sends.append(hyundaican.create_lfahda_mfc(self.packer, CC.enabled))
+
+ # 5 Hz ACC options
+ if self.frame % 20 == 0 and self.CP.openpilotLongitudinalControl:
+ can_sends.extend(hyundaican.create_acc_opt(self.packer))
+
+ # 2 Hz front radar options
+ if self.frame % 50 == 0 and self.CP.openpilotLongitudinalControl:
+ can_sends.append(hyundaican.create_frt_radar_opt(self.packer))
+
+ new_actuators = actuators.copy()
+ new_actuators.steer = apply_steer / self.params.STEER_MAX
+ new_actuators.steerOutputCan = apply_steer
+ new_actuators.accel = accel
+
+ self.frame += 1
+ return new_actuators, can_sends
+
+ def create_button_messages(self, CC: car.CarControl, CS: car.CarState, use_clu11: bool):
+ 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.carFingerprint))
+ 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.carFingerprint)] * 25)
+ if (self.frame - self.last_button_frame) * DT_CTRL >= 0.15:
+ self.last_button_frame = self.frame
+ else:
+ if (self.frame - self.last_button_frame) * DT_CTRL > 0.25:
+ # cruise cancel
+ if CC.cruiseControl.cancel:
+ if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS:
+ can_sends.append(hyundaicanfd.create_acc_cancel(self.packer, self.CP, self.CAN, CS.cruise_info))
+ self.last_button_frame = self.frame
+ else:
+ for _ in range(20):
+ can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, CS.buttons_counter+1, Buttons.CANCEL))
+ self.last_button_frame = self.frame
+
+ # cruise standstill resume
+ elif CC.cruiseControl.resume:
+ if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS:
+ # TODO: resume for alt button cars
+ pass
+ else:
+ for _ in range(20):
+ can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, CS.buttons_counter+1, Buttons.RES_ACCEL))
+ self.last_button_frame = self.frame
+
+ return can_sends
diff --git a/selfdrive/car/hyundai org/carstate.org b/selfdrive/car/hyundai org/carstate.org
new file mode 100644
index 0000000..20d6967
--- /dev/null
+++ b/selfdrive/car/hyundai org/carstate.org
@@ -0,0 +1,500 @@
+from collections import deque
+import copy
+import math
+
+from cereal import car
+from openpilot.common.conversions import Conversions as CV
+from opendbc.can.parser import CANParser
+from opendbc.can.can_define import CANDefine
+from openpilot.selfdrive.car.hyundai.hyundaicanfd import CanBus
+from openpilot.selfdrive.car.hyundai.values import HyundaiFlags, CAR, DBC, CAN_GEARS, CAMERA_SCC_CAR, \
+ CANFD_CAR, EV_CAR, HYBRID_CAR, Buttons, CarControllerParams
+from openpilot.selfdrive.car.interfaces import CarStateBase
+from openpilot.selfdrive.frogpilot.functions.speed_limit_controller import SpeedLimitController
+
+from openpilot.common.watcher import Watcher
+
+PREV_BUTTON_SAMPLES = 8
+CLUSTER_SAMPLE_RATE = 20 # frames
+STANDSTILL_THRESHOLD = 12 * 0.03125 * CV.KPH_TO_MS
+
+
+class CarState(CarStateBase):
+ def __init__(self, CP):
+ super().__init__(CP)
+ can_define = CANDefine(DBC[CP.carFingerprint]["pt"])
+
+ self.cruise_buttons = deque([Buttons.NONE] * PREV_BUTTON_SAMPLES, maxlen=PREV_BUTTON_SAMPLES)
+ self.main_buttons = deque([Buttons.NONE] * PREV_BUTTON_SAMPLES, maxlen=PREV_BUTTON_SAMPLES)
+
+ 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:
+ 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"]
+ elif self.CP.carFingerprint in CAN_GEARS["use_tcu_gears"]:
+ self.shifter_values = can_define.dv["TCU12"]["CUR_GR"]
+ else: # preferred and elect gear methods use same definition
+ self.shifter_values = can_define.dv["LVR12"]["CF_Lvr_Gear"]
+
+ self.accelerator_msg_canfd = "ACCELERATOR" if CP.carFingerprint in EV_CAR else \
+ "ACCELERATOR_ALT" if CP.carFingerprint in HYBRID_CAR else \
+ "ACCELERATOR_BRAKE_ALT"
+ self.cruise_btns_msg_canfd = "CRUISE_BUTTONS_ALT" if CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS else \
+ "CRUISE_BUTTONS"
+ self.is_metric = False
+ self.buttons_counter = 0
+
+ self.cruise_info = {}
+
+ # On some cars, CLU15->CF_Clu_VehicleSpeed can oscillate faster than the dash updates. Sample at 5 Hz
+ self.cluster_speed = 0
+ self.cluster_speed_counter = CLUSTER_SAMPLE_RATE
+
+ self.params = CarControllerParams(CP)
+
+ def update(self, cp, cp_cam):
+ Watcher.log_watch("hyundai_carstate_update_cp", cp)
+ Watcher.log_watch("hyundai_carstate_update_cp_cam", cp_cam)
+
+ if self.CP.carFingerprint in CANFD_CAR:
+ return self.update_canfd(cp, cp_cam)
+
+ ret = car.CarState.new_message()
+ cp_cruise = cp_cam if self.CP.carFingerprint in CAMERA_SCC_CAR else cp
+ self.is_metric = cp.vl["CLU11"]["CF_Clu_SPEED_UNIT"] == 0
+ speed_conv = CV.KPH_TO_MS if self.is_metric else CV.MPH_TO_MS
+
+ ret.doorOpen = any([cp.vl["CGW1"]["CF_Gway_DrvDrSw"], cp.vl["CGW1"]["CF_Gway_AstDrSw"],
+ cp.vl["CGW2"]["CF_Gway_RLDrSw"], cp.vl["CGW2"]["CF_Gway_RRDrSw"]])
+
+ ret.seatbeltUnlatched = cp.vl["CGW1"]["CF_Gway_DrvSeatBeltSw"] == 0
+
+ ret.wheelSpeeds = self.get_wheel_speeds(
+ cp.vl["WHL_SPD11"]["WHL_SPD_FL"],
+ cp.vl["WHL_SPD11"]["WHL_SPD_FR"],
+ cp.vl["WHL_SPD11"]["WHL_SPD_RL"],
+ cp.vl["WHL_SPD11"]["WHL_SPD_RR"],
+ )
+ ret.vEgoRaw = (ret.wheelSpeeds.fl + ret.wheelSpeeds.fr + ret.wheelSpeeds.rl + ret.wheelSpeeds.rr) / 4.
+ ret.vEgo, ret.aEgo = self.update_speed_kf(ret.vEgoRaw)
+ ret.standstill = ret.wheelSpeeds.fl <= STANDSTILL_THRESHOLD and ret.wheelSpeeds.rr <= STANDSTILL_THRESHOLD
+
+ self.cluster_speed_counter += 1
+ if self.cluster_speed_counter > CLUSTER_SAMPLE_RATE:
+ self.cluster_speed = cp.vl["CLU15"]["CF_Clu_VehicleSpeed"]
+ self.cluster_speed_counter = 0
+
+ # Mimic how dash converts to imperial.
+ # Sorento is the only platform where CF_Clu_VehicleSpeed is already imperial when not is_metric
+ # TODO: CGW_USM1->CF_Gway_DrLockSoundRValue may describe this
+ if not self.is_metric and self.CP.carFingerprint not in (CAR.KIA_SORENTO,):
+ self.cluster_speed = math.floor(self.cluster_speed * CV.KPH_TO_MPH + CV.KPH_TO_MPH)
+
+ ret.vEgoCluster = self.cluster_speed * speed_conv
+
+ ret.steeringAngleDeg = cp.vl["SAS11"]["SAS_Angle"]
+ ret.steeringRateDeg = cp.vl["SAS11"]["SAS_Speed"]
+ ret.yawRate = cp.vl["ESP12"]["YAW_RATE"]
+ ret.leftBlinker, ret.rightBlinker = self.update_blinker_from_lamp(
+ 50, cp.vl["CGW1"]["CF_Gway_TurnSigLh"], cp.vl["CGW1"]["CF_Gway_TurnSigRh"])
+ ret.steeringTorque = cp.vl["MDPS12"]["CR_Mdps_StrColTq"]
+ ret.steeringTorqueEps = cp.vl["MDPS12"]["CR_Mdps_OutTq"]
+ ret.steeringPressed = self.update_steering_pressed(abs(ret.steeringTorque) > self.params.STEER_THRESHOLD, 5)
+ ret.steerFaultTemporary = cp.vl["MDPS12"]["CF_Mdps_ToiUnavail"] != 0 or cp.vl["MDPS12"]["CF_Mdps_ToiFlt"] != 0
+
+ # cruise state
+ if self.CP.openpilotLongitudinalControl:
+ # These are not used for engage/disengage since openpilot keeps track of state using the buttons
+ ret.cruiseState.available = self.main_enabled
+ ret.cruiseState.enabled = cp.vl["TCS13"]["ACC_REQ"] == 1
+ ret.cruiseState.standstill = False
+ ret.cruiseState.nonAdaptive = False
+ else:
+ ret.cruiseState.available = cp_cruise.vl["SCC11"]["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
+
+ # TODO: Find brake pressure
+ ret.brake = 0
+ ret.brakePressed = cp.vl["TCS13"]["DriverOverride"] == 2 # 2 includes regen braking by user on HEV/EV
+ ret.brakeHoldActive = cp.vl["TCS15"]["AVH_LAMP"] == 2 # 0 OFF, 1 ERROR, 2 ACTIVE, 3 READY
+ ret.parkingBrake = cp.vl["TCS13"]["PBRAKE_ACT"] == 1
+ ret.accFaulted = cp.vl["TCS13"]["ACCEnable"] != 0 # 0 ACC CONTROL ENABLED, 1-3 ACC CONTROL DISABLED
+
+ if self.CP.carFingerprint in (HYBRID_CAR | EV_CAR):
+ if self.CP.carFingerprint in HYBRID_CAR:
+ ret.gas = cp.vl["E_EMS11"]["CR_Vcu_AccPedDep_Pos"] / 254.
+ else:
+ ret.gas = cp.vl["E_EMS11"]["Accel_Pedal_Pos"] / 254.
+ ret.gasPressed = ret.gas > 0
+ else:
+ ret.gas = cp.vl["EMS12"]["PV_AV_CAN"] / 100.
+ ret.gasPressed = bool(cp.vl["EMS16"]["CF_Ems_AclAct"])
+
+ # Gear Selection via Cluster - For those Kia/Hyundai which are not fully discovered, we can use the Cluster Indicator for Gear Selection,
+ # as this seems to be standard over all cars, but is not the preferred method.
+ if self.CP.carFingerprint in (HYBRID_CAR | EV_CAR):
+ gear = cp.vl["ELECT_GEAR"]["Elect_Gear_Shifter"]
+ elif self.CP.carFingerprint in CAN_GEARS["use_cluster_gears"]:
+ gear = cp.vl["CLU15"]["CF_Clu_Gear"]
+ elif self.CP.carFingerprint in CAN_GEARS["use_tcu_gears"]:
+ gear = cp.vl["TCU12"]["CUR_GR"]
+ else:
+ gear = cp.vl["LVR12"]["CF_Lvr_Gear"]
+
+ ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(gear))
+
+ if not self.CP.openpilotLongitudinalControl:
+ 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
+ scc_warning = cp_cruise.vl["SCC12"]["TakeOverReq"] == 1 # sometimes only SCC system shows an FCW
+ aeb_braking = cp_cruise.vl[aeb_src]["CF_VSM_DecCmdAct"] != 0 or cp_cruise.vl[aeb_src][aeb_sig] != 0
+ ret.stockFcw = (aeb_warning or scc_warning) and not aeb_braking
+ ret.stockAeb = aeb_warning and aeb_braking
+
+ if self.CP.enableBsm:
+ ret.leftBlindspot = cp.vl["LCA11"]["CF_Lca_IndLeft"] != 0
+ ret.rightBlindspot = cp.vl["LCA11"]["CF_Lca_IndRight"] != 0
+
+ # save the entire LKAS11 and CLU11
+ 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
+ self.prev_cruise_buttons = self.cruise_buttons[-1]
+ self.cruise_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwState"])
+ self.prev_main_buttons = self.main_buttons[-1]
+ self.main_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwMain"])
+ if self.prev_main_buttons == 0 and self.main_buttons[-1] != 0:
+ self.main_enabled = not self.main_enabled
+
+ # BBot functions for lfa and gap buttons - test speed up / down
+ self.oscar_lane_center_btn_pressed= False
+ self.oscar_slc_decel = False
+ self.oscar_slc_accel = False
+
+ self.param_memory.put("oscar_debug", "Hello World")
+
+ # if self.cruise_buttons[-1] == Buttons.GAP_DIST and self.prev_cruise_buttons == 0:
+ # self.oscar_lane_center_btn_pressed= True
+
+ # lkas_pressed = cp.vl["BCM_PO_11"]["LFA_Pressed"]
+ # if lkas_pressed and not self.lkas_previously_pressed:
+ # self.custom_speed_up = True
+ # self.lkas_previously_pressed = lkas_pressed
+
+ # Driving personalities function
+ # if self.personalities_via_wheel and ret.cruiseState.available:
+ # # Sync with the onroad UI button
+ # if self.param_memory.get_bool("PersonalityChangedViaUI"):
+ # self.personality_profile = self.param.get_int("LongitudinalPersonality")
+ # self.param_memory.put_bool("PersonalityChangedViaUI", False)
+
+ # # Change personality upon steering wheel button press
+ # if self.cruise_buttons[-1] == Buttons.GAP_DIST and self.prev_cruise_buttons == 0:
+ # self.param_memory.put_bool("PersonalityChangedViaWheel", True)
+ # self.personality_profile = (self.previous_personality_profile + 2) % 3
+
+ # if self.personality_profile != self.previous_personality_profile and self.personality_profile >= 0:
+ # self.param.put_int("LongitudinalPersonality", self.personality_profile)
+ # self.previous_personality_profile = self.personality_profile
+
+ # # Toggle Experimental Mode from steering wheel function
+ # if self.experimental_mode_via_lkas and ret.cruiseState.available:
+ # lkas_pressed = cp.vl["BCM_PO_11"]["LFA_Pressed"]
+ # if lkas_pressed and not self.lkas_previously_pressed:
+ # if self.conditional_experimental_mode:
+ # # Set "CEStatus" to work with "Conditional Experimental Mode"
+ # conditional_status = self.param_memory.get_int("CEStatus")
+ # override_value = 0 if conditional_status in (1, 2, 3, 4) else 1 if conditional_status >= 5 else 2
+ # self.param_memory.put_int("CEStatus", override_value)
+ # else:
+ # experimental_mode = self.param.get_bool("ExperimentalMode")
+ # # Invert the value of "ExperimentalMode"
+ # put_bool_nonblocking("ExperimentalMode", not experimental_mode)
+ # self.lkas_previously_pressed = lkas_pressed
+
+ Watcher.log_watch("hyundai_carstate_update_self", self)
+ return ret
+
+ def update_canfd(self, cp, cp_cam):
+ Watcher.log_watch("hyundai_carstate_update_canfd_cp", cp)
+ Watcher.log_watch("hyundai_carstate_update_canfd_cp_cam", cp_cam)
+
+ ret = car.CarState.new_message()
+
+ self.is_metric = cp.vl["CRUISE_BUTTONS_ALT"]["DISTANCE_UNIT"] != 1
+ speed_factor = CV.KPH_TO_MS if self.is_metric else CV.MPH_TO_MS
+
+ if self.CP.carFingerprint in (EV_CAR | HYBRID_CAR):
+ offset = 255. if self.CP.carFingerprint in EV_CAR else 1023.
+ ret.gas = cp.vl[self.accelerator_msg_canfd]["ACCELERATOR_PEDAL"] / offset
+ ret.gasPressed = ret.gas > 1e-5
+ else:
+ ret.gasPressed = bool(cp.vl[self.accelerator_msg_canfd]["ACCELERATOR_PEDAL_PRESSED"])
+
+ ret.brakePressed = cp.vl["TCS"]["DriverBraking"] == 1
+
+ ret.doorOpen = cp.vl["DOORS_SEATBELTS"]["DRIVER_DOOR"] == 1
+ ret.seatbeltUnlatched = cp.vl["DOORS_SEATBELTS"]["DRIVER_SEATBELT"] == 0
+
+ gear = cp.vl[self.gear_msg_canfd]["GEAR"]
+ ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(gear))
+
+ # TODO: figure out positions
+ ret.wheelSpeeds = self.get_wheel_speeds(
+ cp.vl["WHEEL_SPEEDS"]["WHEEL_SPEED_1"],
+ cp.vl["WHEEL_SPEEDS"]["WHEEL_SPEED_2"],
+ cp.vl["WHEEL_SPEEDS"]["WHEEL_SPEED_3"],
+ cp.vl["WHEEL_SPEEDS"]["WHEEL_SPEED_4"],
+ )
+ ret.vEgoRaw = (ret.wheelSpeeds.fl + ret.wheelSpeeds.fr + ret.wheelSpeeds.rl + ret.wheelSpeeds.rr) / 4.
+ ret.vEgo, ret.aEgo = self.update_speed_kf(ret.vEgoRaw)
+ ret.standstill = ret.wheelSpeeds.fl <= STANDSTILL_THRESHOLD and ret.wheelSpeeds.rr <= STANDSTILL_THRESHOLD
+
+ ret.steeringRateDeg = cp.vl["STEERING_SENSORS"]["STEERING_RATE"]
+ ret.steeringAngleDeg = cp.vl["STEERING_SENSORS"]["STEERING_ANGLE"] * -1
+ ret.steeringTorque = cp.vl["MDPS"]["STEERING_COL_TORQUE"]
+ ret.steeringTorqueEps = cp.vl["MDPS"]["STEERING_OUT_TORQUE"]
+ ret.steeringPressed = self.update_steering_pressed(abs(ret.steeringTorque) > self.params.STEER_THRESHOLD, 5)
+ ret.steerFaultTemporary = cp.vl["MDPS"]["LKA_FAULT"] != 0
+
+ # TODO: alt signal usage may be described by cp.vl['BLINKERS']['USE_ALT_LAMP']
+ left_blinker_sig, right_blinker_sig = "LEFT_LAMP", "RIGHT_LAMP"
+ if self.CP.carFingerprint == CAR.KONA_EV_2ND_GEN:
+ left_blinker_sig, right_blinker_sig = "LEFT_LAMP_ALT", "RIGHT_LAMP_ALT"
+ ret.leftBlinker, ret.rightBlinker = self.update_blinker_from_lamp(50, cp.vl["BLINKERS"][left_blinker_sig],
+ cp.vl["BLINKERS"][right_blinker_sig])
+ if self.CP.enableBsm:
+ ret.leftBlindspot = cp.vl["BLINDSPOTS_REAR_CORNERS"]["FL_INDICATOR"] != 0
+ ret.rightBlindspot = cp.vl["BLINDSPOTS_REAR_CORNERS"]["FR_INDICATOR"] != 0
+
+ # cruise state
+ # CAN FD cars enable on main button press, set available if no TCS faults preventing engagement
+ ret.cruiseState.available = self.main_enabled
+ if self.CP.openpilotLongitudinalControl:
+ # These are not used for engage/disengage since openpilot keeps track of state using the buttons
+ ret.cruiseState.enabled = cp.vl["TCS"]["ACC_REQ"] == 1
+ ret.cruiseState.standstill = False
+ else:
+ cp_cruise_info = cp_cam if self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC else cp
+ ret.cruiseState.enabled = cp_cruise_info.vl["SCC_CONTROL"]["ACCMode"] in (1, 2)
+ ret.cruiseState.standstill = cp_cruise_info.vl["SCC_CONTROL"]["CRUISE_STANDSTILL"] == 1
+ ret.cruiseState.speed = cp_cruise_info.vl["SCC_CONTROL"]["VSetDis"] * speed_factor
+ self.cruise_info = copy.copy(cp_cruise_info.vl["SCC_CONTROL"])
+
+ # Manual Speed Limit Assist is a feature that replaces non-adaptive cruise control on EV CAN FD platforms.
+ # It limits the vehicle speed, overridable by pressing the accelerator past a certain point.
+ # The car will brake, but does not respect positive acceleration commands in this mode
+ # TODO: find this message on ICE & HYBRID cars + cruise control signals (if exists)
+ if self.CP.carFingerprint in EV_CAR:
+ ret.cruiseState.nonAdaptive = cp.vl["MANUAL_SPEED_LIMIT_ASSIST"]["MSLA_ENABLED"] == 1
+
+ self.prev_cruise_buttons = self.cruise_buttons[-1]
+ self.cruise_buttons.extend(cp.vl_all[self.cruise_btns_msg_canfd]["CRUISE_BUTTONS"])
+ self.prev_main_buttons = self.main_buttons[-1]
+ self.main_buttons.extend(cp.vl_all[self.cruise_btns_msg_canfd]["ADAPTIVE_CRUISE_MAIN_BTN"])
+ if self.prev_main_buttons == 0 and self.main_buttons[-1] != 0:
+ self.main_enabled = not self.main_enabled
+ self.buttons_counter = cp.vl[self.cruise_btns_msg_canfd]["COUNTER"]
+ ret.accFaulted = cp.vl["TCS"]["ACCEnable"] != 0 # 0 ACC CONTROL ENABLED, 1-3 ACC CONTROL DISABLED
+
+ if self.CP.flags & HyundaiFlags.CANFD_HDA2:
+ self.hda2_lfa_block_msg = copy.copy(cp_cam.vl["CAM_0x362"] if self.CP.flags & HyundaiFlags.CANFD_HDA2_ALT_STEERING
+ else cp_cam.vl["CAM_0x2a4"])
+
+ SpeedLimitController.load_state()
+ SpeedLimitController.car_speed_limit = self.calculate_speed_limit_canfd(self.CP, cp, cp_cam) * speed_factor
+ SpeedLimitController.write_car_state()
+
+ # self.custom_speed_up = False
+ self.oscar_lane_center_btn_pressed = False
+
+ if ret.cruiseState.available:
+
+ if self.cruise_buttons[-1] == Buttons.GAP_DIST and self.prev_cruise_buttons == 0:
+ self.oscar_lane_center_btn_pressed = True
+
+ lkas_pressed = False
+ try:
+ lkas_pressed = cp.vl[self.cruise_btns_msg_canfd]["LKAS_BTN"]
+ except:
+ nothing = 0
+
+ # intentionally cause a failure
+ if lkas_pressed:
+ floog=norpdywoop
+ # if self.cruise_buttons[-1] == Buttons.GAP_DIST and self.prev_cruise_buttons == 0:
+ # self.oscar_lane_center_btn_pressed= True
+
+ # Driving personalities function
+ # if self.personalities_via_wheel and ret.cruiseState.available:
+ # # Sync with the onroad UI button
+ # if self.param_memory.get_bool("PersonalityChangedViaUI"):
+ # self.personality_profile = self.param.get_int("LongitudinalPersonality")
+ # self.param_memory.put_bool("PersonalityChangedViaUI", False)
+
+ # # Change personality upon steering wheel button press
+ # if self.cruise_buttons[-1] == Buttons.GAP_DIST and self.prev_cruise_buttons == 0:
+ # self.param_memory.put_bool("PersonalityChangedViaWheel", True)
+ # self.personality_profile = (self.previous_personality_profile + 2) % 3
+
+ # if self.personality_profile != self.previous_personality_profile and self.personality_profile >= 0:
+ # self.param.put_int("LongitudinalPersonality", self.personality_profile)
+ # self.previous_personality_profile = self.personality_profile
+
+ # # Toggle Experimental Mode from steering wheel function
+ # if self.experimental_mode_via_lkas and ret.cruiseState.available:
+ # lkas_pressed = cp.vl[self.cruise_btns_msg_canfd]["LKAS_BTN"]
+ # if lkas_pressed and not self.lkas_previously_pressed:
+ # if self.conditional_experimental_mode:
+ # # Set "CEStatus" to work with "Conditional Experimental Mode"
+ # conditional_status = self.param_memory.get_int("CEStatus")
+ # override_value = 0 if conditional_status in (1, 2, 3, 4) else 1 if conditional_status >= 5 else 2
+ # self.param_memory.put_int("CEStatus", override_value)
+ # else:
+ # experimental_mode = self.param.get_bool("ExperimentalMode")
+ # # Invert the value of "ExperimentalMode"
+ # put_bool_nonblocking("ExperimentalMode", not experimental_mode)
+ # self.lkas_previously_pressed = lkas_pressed
+
+ Watcher.log_watch("hyundai_carstate_update_canfd_self", self)
+
+ return ret
+
+ # BBOT does not work
+ def calculate_speed_limit_canfd(self, CP, cp, cp_cam):
+ try:
+ self._speed_limit_clu = cp.vl["CLUSTER_SPEED_LIMIT"]["SPEED_LIMIT_1"]
+ return self._speed_limit_clu if self._speed_limit_clu not in (0, 255) else 0
+ except:
+ return 0
+
+ def get_can_parser(self, CP):
+ if CP.carFingerprint in CANFD_CAR:
+ return self.get_can_parser_canfd(CP)
+
+ messages = [
+ # address, frequency
+ ("MDPS12", 50),
+ ("TCS13", 50),
+ ("TCS15", 10),
+ ("CLU11", 50),
+ ("CLU15", 5),
+ ("ESP12", 100),
+ ("CGW1", 10),
+ ("CGW2", 5),
+ ("CGW4", 5),
+ ("WHL_SPD11", 50),
+ ("SAS11", 100),
+ ]
+
+ if not CP.openpilotLongitudinalControl and CP.carFingerprint not in CAMERA_SCC_CAR:
+ messages += [
+ ("SCC11", 50),
+ ("SCC12", 50),
+ ]
+ if CP.flags & HyundaiFlags.USE_FCA.value:
+ messages.append(("FCA11", 50))
+
+ if CP.enableBsm:
+ messages.append(("LCA11", 50))
+
+ if CP.carFingerprint in (HYBRID_CAR | EV_CAR):
+ messages.append(("E_EMS11", 50))
+ else:
+ messages += [
+ ("EMS12", 100),
+ ("EMS16", 100),
+ ]
+
+ if CP.carFingerprint in (HYBRID_CAR | EV_CAR):
+ messages.append(("ELECT_GEAR", 20))
+ elif CP.carFingerprint in CAN_GEARS["use_cluster_gears"]:
+ pass
+ elif CP.carFingerprint in CAN_GEARS["use_tcu_gears"]:
+ messages.append(("TCU12", 100))
+ else:
+ messages.append(("LVR12", 100))
+
+ messages.append(("BCM_PO_11", 50))
+
+ return CANParser(DBC[CP.carFingerprint]["pt"], messages, 0)
+
+ @staticmethod
+ def get_cam_can_parser(CP):
+ if CP.carFingerprint in CANFD_CAR:
+ return CarState.get_cam_can_parser_canfd(CP)
+
+ messages = [
+ ("LKAS11", 100)
+ ]
+
+ if not CP.openpilotLongitudinalControl and CP.carFingerprint in CAMERA_SCC_CAR:
+ messages += [
+ ("SCC11", 50),
+ ("SCC12", 50),
+ ]
+
+ if CP.flags & HyundaiFlags.USE_FCA.value:
+ messages.append(("FCA11", 50))
+
+ return CANParser(DBC[CP.carFingerprint]["pt"], messages, 2)
+
+ def get_can_parser_canfd(self, CP):
+ messages = [
+ (self.gear_msg_canfd, 100),
+ (self.accelerator_msg_canfd, 100),
+ ("WHEEL_SPEEDS", 100),
+ ("STEERING_SENSORS", 100),
+ ("MDPS", 100),
+ ("TCS", 50),
+ ("CRUISE_BUTTONS_ALT", 50),
+ ("BLINKERS", 4),
+ ("DOORS_SEATBELTS", 4),
+ ]
+
+ if CP.carFingerprint in EV_CAR:
+ messages += [
+ ("MANUAL_SPEED_LIMIT_ASSIST", 10),
+ ]
+
+ if not (CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS):
+ messages += [
+ ("CRUISE_BUTTONS", 50)
+ ]
+
+ if CP.enableBsm:
+ messages += [
+ ("BLINDSPOTS_REAR_CORNERS", 20),
+ ]
+
+ # if CP.nav_msg:
+ # messages.append(("CLUSTER_SPEED_LIMIT", 10))
+
+ if not (CP.flags & HyundaiFlags.CANFD_CAMERA_SCC.value) and not CP.openpilotLongitudinalControl:
+ messages += [
+ ("SCC_CONTROL", 50),
+ ]
+
+ return CANParser(DBC[CP.carFingerprint]["pt"], messages, CanBus(CP).ECAN)
+
+ @staticmethod
+ def get_cam_can_parser_canfd(CP):
+ messages = []
+ if CP.flags & HyundaiFlags.CANFD_HDA2:
+ block_lfa_msg = "CAM_0x362" if CP.flags & HyundaiFlags.CANFD_HDA2_ALT_STEERING else "CAM_0x2a4"
+ messages += [(block_lfa_msg, 20)]
+ elif CP.flags & HyundaiFlags.CANFD_CAMERA_SCC:
+ messages += [
+ ("SCC_CONTROL", 50),
+ ]
+
+
+
+ return CANParser(DBC[CP.carFingerprint]["pt"], messages, CanBus(CP).CAM)
diff --git a/selfdrive/car/hyundai org/fingerprints.org b/selfdrive/car/hyundai org/fingerprints.org
new file mode 100644
index 0000000..fa6b565
--- /dev/null
+++ b/selfdrive/car/hyundai org/fingerprints.org
@@ -0,0 +1,1710 @@
+# ruff: noqa: E501
+from cereal import car
+from openpilot.selfdrive.car.hyundai.values import CAR
+
+Ecu = car.CarParams.Ecu
+
+FINGERPRINTS = {
+ CAR.HYUNDAI_GENESIS: [{
+ 67: 8, 68: 8, 304: 8, 320: 8, 339: 8, 356: 4, 544: 7, 593: 8, 608: 8, 688: 5, 809: 8, 832: 8, 854: 7, 870: 7, 871: 8, 872: 5, 897: 8, 902: 8, 903: 6, 916: 8, 1024: 2, 1040: 8, 1056: 8, 1057: 8, 1078: 4, 1107: 5, 1136: 8, 1151: 6, 1168: 7, 1170: 8, 1173: 8, 1184: 8, 1265: 4, 1280: 1, 1287: 4, 1292: 8, 1312: 8, 1322: 8, 1331: 8, 1332: 8, 1333: 8, 1334: 8, 1335: 8, 1342: 6, 1345: 8, 1363: 8, 1369: 8, 1370: 8, 1371: 8, 1378: 4, 1384: 5, 1407: 8, 1419: 8, 1427: 6, 1434: 2, 1456: 4
+ },
+ {
+ 67: 8, 68: 8, 304: 8, 320: 8, 339: 8, 356: 4, 544: 7, 593: 8, 608: 8, 688: 5, 809: 8, 832: 8, 854: 7, 870: 7, 871: 8, 872: 5, 897: 8, 902: 8, 903: 6, 916: 8, 1024: 2, 1040: 8, 1056: 8, 1057: 8, 1078: 4, 1107: 5, 1136: 8, 1151: 6, 1168: 7, 1170: 8, 1173: 8, 1184: 8, 1265: 4, 1280: 1, 1281: 3, 1287: 4, 1292: 8, 1312: 8, 1322: 8, 1331: 8, 1332: 8, 1333: 8, 1334: 8, 1335: 8, 1345: 8, 1363: 8, 1369: 8, 1370: 8, 1378: 4, 1379: 8, 1384: 5, 1407: 8, 1419: 8, 1427: 6, 1434: 2, 1456: 4
+ },
+ {
+ 67: 8, 68: 8, 304: 8, 320: 8, 339: 8, 356: 4, 544: 7, 593: 8, 608: 8, 688: 5, 809: 8, 854: 7, 870: 7, 871: 8, 872: 5, 897: 8, 902: 8, 903: 6, 912: 7, 916: 8, 1040: 8, 1056: 8, 1057: 8, 1078: 4, 1107: 5, 1136: 8, 1151: 6, 1168: 7, 1170: 8, 1173: 8, 1184: 8, 1265: 4, 1268: 8, 1280: 1, 1281: 3, 1287: 4, 1292: 8, 1312: 8, 1322: 8, 1331: 8, 1332: 8, 1333: 8, 1334: 8, 1335: 8, 1345: 8, 1363: 8, 1369: 8, 1370: 8, 1371: 8, 1378: 4, 1384: 5, 1407: 8, 1419: 8, 1427: 6, 1434: 2, 1437: 8, 1456: 4
+ },
+ {
+ 67: 8, 68: 8, 304: 8, 320: 8, 339: 8, 356: 4, 544: 7, 593: 8, 608: 8, 688: 5, 809: 8, 832: 8, 854: 7, 870: 7, 871: 8, 872: 5, 897: 8, 902: 8, 903: 6, 916: 8, 1040: 8, 1056: 8, 1057: 8, 1078: 4, 1107: 5, 1136: 8, 1151: 6, 1168: 7, 1170: 8, 1173: 8, 1184: 8, 1265: 4, 1280: 1, 1287: 4, 1292: 8, 1312: 8, 1322: 8, 1331: 8, 1332: 8, 1333: 8, 1334: 8, 1335: 8, 1345: 8, 1363: 8, 1369: 8, 1370: 8, 1378: 4, 1379: 8, 1384: 5, 1407: 8, 1425: 2, 1427: 6, 1437: 8, 1456: 4
+ },
+ {
+ 67: 8, 68: 8, 304: 8, 320: 8, 339: 8, 356: 4, 544: 7, 593: 8, 608: 8, 688: 5, 809: 8, 832: 8, 854: 7, 870: 7, 871: 8, 872: 5, 897: 8, 902: 8, 903: 6, 916: 8, 1040: 8, 1056: 8, 1057: 8, 1078: 4, 1107: 5, 1136: 8, 1151: 6, 1168: 7, 1170: 8, 1173: 8, 1184: 8, 1265: 4, 1280: 1, 1287: 4, 1292: 8, 1312: 8, 1322: 8, 1331: 8, 1332: 8, 1333: 8, 1334: 8, 1335: 8, 1345: 8, 1363: 8, 1369: 8, 1370: 8, 1371: 8, 1378: 4, 1384: 5, 1407: 8, 1419: 8, 1425: 2, 1427: 6, 1437: 8, 1456: 4
+ }],
+ CAR.SANTA_FE: [{
+ 67: 8, 127: 8, 304: 8, 320: 8, 339: 8, 356: 4, 544: 8, 593: 8, 608: 8, 688: 6, 809: 8, 832: 8, 854: 7, 870: 7, 871: 8, 872: 8, 897: 8, 902: 8, 903: 8, 905: 8, 909: 8, 916: 8, 1040: 8, 1042: 8, 1056: 8, 1057: 8, 1078: 4, 1107: 5, 1136: 8, 1151: 6, 1155: 8, 1156: 8, 1162: 8, 1164: 8, 1168: 7, 1170: 8, 1173: 8, 1183: 8, 1186: 2, 1191: 2, 1227: 8, 1265: 4, 1280: 1, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1363: 8, 1369: 8, 1379: 8, 1384: 8, 1407: 8, 1414: 3, 1419: 8, 1427: 6, 1456: 4, 1470: 8
+ },
+ {
+ 67: 8, 127: 8, 304: 8, 320: 8, 339: 8, 356: 4, 544: 8, 593: 8, 608: 8, 688: 6, 764: 8, 809: 8, 854: 7, 870: 7, 871: 8, 872: 8, 897: 8, 902: 8, 903: 8, 905: 8, 909: 8, 916: 8, 1040: 8, 1042: 8, 1056: 8, 1057: 8, 1064: 8, 1078: 4, 1107: 5, 1136: 8, 1151: 6, 1155: 8, 1162: 8, 1164: 8, 1168: 7, 1170: 8, 1173: 8, 1180: 8, 1183: 8, 1186: 2, 1227: 8, 1265: 4, 1280: 1, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1345: 8, 1348: 8, 1363: 8, 1369: 8, 1371: 8, 1378: 8, 1384: 8, 1407: 8, 1414: 3, 1419: 8, 1427: 6, 1456: 4, 1470: 8, 1988: 8, 2000: 8, 2004: 8, 2008: 8, 2012: 8
+ },
+ {
+ 67: 8, 68: 8, 80: 4, 160: 8, 161: 8, 272: 8, 288: 4, 339: 8, 356: 8, 357: 8, 399: 8, 544: 8, 608: 8, 672: 8, 688: 5, 704: 1, 790: 8, 809: 8, 848: 8, 880: 8, 898: 8, 900: 8, 901: 8, 904: 8, 1056: 8, 1064: 8, 1065: 8, 1072: 8, 1075: 8, 1087: 8, 1088: 8, 1151: 8, 1200: 8, 1201: 8, 1232: 4, 1264: 8, 1265: 8, 1266: 8, 1296: 8, 1306: 8, 1312: 8, 1322: 8, 1331: 8, 1332: 8, 1333: 8, 1348: 8, 1349: 8, 1369: 8, 1370: 8, 1371: 8, 1407: 8, 1415: 8, 1419: 8, 1440: 8, 1442: 4, 1461: 8, 1470: 8
+ }],
+ CAR.SONATA: [{
+ 67: 8, 68: 8, 127: 8, 304: 8, 320: 8, 339: 8, 356: 4, 544: 8, 546: 8, 549: 8, 550: 8, 576: 8, 593: 8, 608: 8, 688: 6, 809: 8, 832: 8, 854: 8, 865: 8, 870: 7, 871: 8, 872: 8, 897: 8, 902: 8, 903: 8, 905: 8, 908: 8, 909: 8, 912: 7, 913: 8, 916: 8, 1040: 8, 1042: 8, 1056: 8, 1057: 8, 1078: 4, 1089: 5, 1096: 8, 1107: 5, 1108: 8, 1114: 8, 1136: 8, 1145: 8, 1151: 8, 1155: 8, 1156: 8, 1157: 4, 1162: 8, 1164: 8, 1168: 8, 1170: 8, 1173: 8, 1180: 8, 1183: 8, 1184: 8, 1186: 2, 1191: 2, 1193: 8, 1210: 8, 1225: 8, 1227: 8, 1265: 4, 1268: 8, 1280: 8, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1330: 8, 1339: 8, 1342: 6, 1343: 8, 1345: 8, 1348: 8, 1363: 8, 1369: 8, 1371: 8, 1378: 8, 1379: 8, 1384: 8, 1394: 8, 1407: 8, 1419: 8, 1427: 6, 1446: 8, 1456: 4, 1460: 8, 1470: 8, 1485: 8, 1504: 3, 1988: 8, 1996: 8, 2000: 8, 2004: 8, 2008: 8, 2012: 8, 2015: 8
+ }],
+ CAR.SONATA_LF: [{
+ 66: 8, 67: 8, 68: 8, 127: 8, 273: 8, 274: 8, 275: 8, 339: 8, 356: 4, 399: 8, 447: 8, 512: 6, 544: 8, 593: 8, 608: 8, 688: 5, 790: 8, 809: 8, 832: 8, 884: 8, 897: 8, 899: 8, 902: 8, 903: 6, 916: 8, 1040: 8, 1056: 8, 1057: 8, 1078: 4, 1151: 6, 1168: 7, 1170: 8, 1253: 8, 1254: 8, 1255: 8, 1265: 4, 1280: 1, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1314: 8, 1322: 8, 1331: 8, 1332: 8, 1333: 8, 1342: 6, 1345: 8, 1348: 8, 1349: 8, 1351: 8, 1353: 8, 1363: 8, 1365: 8, 1366: 8, 1367: 8, 1369: 8, 1397: 8, 1407: 8, 1415: 8, 1419: 8, 1425: 2, 1427: 6, 1440: 8, 1456: 4, 1470: 8, 1472: 8, 1486: 8, 1487: 8, 1491: 8, 1530: 8, 1532: 5, 2000: 8, 2001: 8, 2004: 8, 2005: 8, 2008: 8, 2009: 8, 2012: 8, 2013: 8, 2014: 8, 2016: 8, 2017: 8, 2024: 8, 2025: 8
+ }],
+ CAR.KIA_SORENTO: [{
+ 67: 8, 68: 8, 127: 8, 304: 8, 320: 8, 339: 8, 356: 4, 544: 8, 593: 8, 608: 8, 688: 5, 809: 8, 832: 8, 854: 7, 870: 7, 871: 8, 872: 8, 897: 8, 902: 8, 903: 8, 916: 8, 1040: 8, 1042: 8, 1056: 8, 1057: 8, 1064: 8, 1078: 4, 1107: 5, 1136: 8, 1151: 6, 1168: 7, 1170: 8, 1173: 8, 1265: 4, 1280: 1, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1331: 8, 1332: 8, 1333: 8, 1342: 6, 1345: 8, 1348: 8, 1363: 8, 1369: 8, 1370: 8, 1371: 8, 1384: 8, 1407: 8, 1411: 8, 1419: 8, 1425: 2, 1427: 6, 1444: 8, 1456: 4, 1470: 8, 1489: 1
+ }],
+ CAR.KIA_STINGER: [{
+ 67: 8, 127: 8, 304: 8, 320: 8, 339: 8, 356: 4, 358: 6, 359: 8, 544: 8, 576: 8, 593: 8, 608: 8, 688: 5, 809: 8, 832: 8, 854: 7, 870: 7, 871: 8, 872: 8, 897: 8, 902: 8, 909: 8, 916: 8, 1040: 8, 1042: 8, 1056: 8, 1057: 8, 1064: 8, 1078: 4, 1107: 5, 1136: 8, 1151: 6, 1168: 7, 1170: 8, 1173: 8, 1184: 8, 1265: 4, 1280: 1, 1281: 4, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1363: 8, 1369: 8, 1371: 8, 1378: 4, 1379: 8, 1384: 8, 1407: 8, 1419: 8, 1425: 2, 1427: 6, 1456: 4, 1470: 8
+ }],
+ CAR.GENESIS_G80: [{
+ 67: 8, 68: 8, 127: 8, 304: 8, 320: 8, 339: 8, 356: 4, 358: 6, 544: 8, 593: 8, 608: 8, 688: 5, 809: 8, 832: 8, 854: 7, 870: 7, 871: 8, 872: 8, 897: 8, 902: 8, 903: 8, 916: 8, 1024: 2, 1040: 8, 1042: 8, 1056: 8, 1057: 8, 1078: 4, 1107: 5, 1136: 8, 1151: 6, 1156: 8, 1168: 7, 1170: 8, 1173: 8, 1184: 8, 1191: 2, 1265: 4, 1280: 1, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1363: 8, 1369: 8, 1370: 8, 1371: 8, 1378: 4, 1384: 8, 1407: 8, 1419: 8, 1425: 2, 1427: 6, 1434: 2, 1456: 4, 1470: 8
+ },
+ {
+ 67: 8, 68: 8, 127: 8, 304: 8, 320: 8, 339: 8, 356: 4, 358: 6, 359: 8, 544: 8, 546: 8, 593: 8, 608: 8, 688: 5, 809: 8, 832: 8, 854: 7, 870: 7, 871: 8, 872: 8, 897: 8, 902: 8, 903: 8, 916: 8, 1040: 8, 1042: 8, 1056: 8, 1057: 8, 1064: 8, 1078: 4, 1107: 5, 1136: 8, 1151: 6, 1156: 8, 1157: 4, 1168: 7, 1170: 8, 1173: 8, 1184: 8, 1265: 4, 1280: 1, 1281: 3, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1363: 8, 1369: 8, 1370: 8, 1371: 8, 1378: 4, 1384: 8, 1407: 8, 1419: 8, 1425: 2, 1427: 6, 1434: 2, 1437: 8, 1456: 4, 1470: 8
+ },
+ {
+ 67: 8, 68: 8, 127: 8, 304: 8, 320: 8, 339: 8, 356: 4, 358: 6, 544: 8, 593: 8, 608: 8, 688: 5, 809: 8, 832: 8, 854: 7, 870: 7, 871: 8, 872: 8, 897: 8, 902: 8, 903: 8, 916: 8, 1040: 8, 1042: 8, 1056: 8, 1057: 8, 1064: 8, 1078: 4, 1107: 5, 1136: 8, 1151: 6, 1156: 8, 1157: 4, 1162: 8, 1168: 7, 1170: 8, 1173: 8, 1184: 8, 1193: 8, 1265: 4, 1280: 1, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1363: 8, 1369: 8, 1371: 8, 1378: 4, 1384: 8, 1407: 8, 1419: 8, 1425: 2, 1427: 6, 1437: 8, 1456: 4, 1470: 8
+ }],
+ CAR.GENESIS_G90: [{
+ 67: 8, 68: 8, 127: 8, 304: 8, 320: 8, 339: 8, 356: 4, 358: 6, 359: 8, 544: 8, 593: 8, 608: 8, 688: 5, 809: 8, 854: 7, 870: 7, 871: 8, 872: 8, 897: 8, 902: 8, 903: 8, 916: 8, 1040: 8, 1056: 8, 1057: 8, 1078: 4, 1107: 5, 1136: 8, 1151: 6, 1162: 4, 1168: 7, 1170: 8, 1173: 8, 1184: 8, 1265: 4, 1280: 1, 1281: 3, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1345: 8, 1348: 8, 1363: 8, 1369: 8, 1370: 8, 1371: 8, 1378: 4, 1384: 8, 1407: 8, 1419: 8, 1425: 2, 1427: 6, 1434: 2, 1456: 4, 1470: 8, 1988: 8, 2000: 8, 2003: 8, 2004: 8, 2005: 8, 2008: 8, 2011: 8, 2012: 8, 2013: 8
+ }],
+ CAR.IONIQ_EV_2020: [{
+ 127: 8, 304: 8, 320: 8, 339: 8, 352: 8, 356: 4, 524: 8, 544: 7, 593: 8, 688: 5, 832: 8, 881: 8, 882: 8, 897: 8, 902: 8, 903: 8, 905: 8, 909: 8, 916: 8, 1040: 8, 1042: 8, 1056: 8, 1057: 8, 1078: 4, 1136: 8, 1151: 6, 1155: 8, 1156: 8, 1157: 4, 1164: 8, 1168: 7, 1173: 8, 1183: 8, 1186: 2, 1191: 2, 1225: 8, 1265: 4, 1280: 1, 1287: 4, 1290: 8, 1291: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1355: 8, 1363: 8, 1369: 8, 1379: 8, 1407: 8, 1419: 8, 1426: 8, 1427: 6, 1429: 8, 1430: 8, 1456: 4, 1470: 8, 1473: 8, 1507: 8, 1535: 8, 1988: 8, 1996: 8, 2000: 8, 2004: 8, 2005: 8, 2008: 8, 2012: 8, 2013: 8
+ }],
+ CAR.IONIQ: [{
+ 68: 8, 127: 8, 304: 8, 320: 8, 339: 8, 352: 8, 356: 4, 524: 8, 544: 8, 576: 8, 593: 8, 688: 5, 832: 8, 881: 8, 882: 8, 897: 8, 902: 8, 903: 8, 905: 8, 909: 8, 916: 8, 1040: 8, 1042: 8, 1056: 8, 1057: 8, 1078: 4, 1136: 6, 1151: 6, 1155: 8, 1156: 8, 1157: 4, 1164: 8, 1168: 7, 1173: 8, 1183: 8, 1186: 2, 1191: 2, 1225: 8, 1265: 4, 1280: 1, 1287: 4, 1290: 8, 1291: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1355: 8, 1363: 8, 1369: 8, 1379: 8, 1407: 8, 1419: 8, 1426: 8, 1427: 6, 1429: 8, 1430: 8, 1448: 8, 1456: 4, 1470: 8, 1473: 8, 1476: 8, 1507: 8, 1535: 8, 1988: 8, 1996: 8, 2000: 8, 2004: 8, 2005: 8, 2008: 8, 2012: 8, 2013: 8
+ }],
+ CAR.KONA_EV: [{
+ 127: 8, 304: 8, 320: 8, 339: 8, 352: 8, 356: 4, 544: 8, 549: 8, 593: 8, 688: 5, 832: 8, 881: 8, 882: 8, 897: 8, 902: 8, 903: 8, 905: 8, 909: 8, 916: 8, 1040: 8, 1042: 8, 1056: 8, 1057: 8, 1078: 4, 1136: 8, 1151: 6, 1168: 7, 1173: 8, 1183: 8, 1186: 2, 1191: 2, 1225: 8, 1265: 4, 1280: 1, 1287: 4, 1290: 8, 1291: 8, 1292: 8, 1294: 8, 1307: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1355: 8, 1363: 8, 1369: 8, 1378: 4, 1407: 8, 1419: 8, 1426: 8, 1427: 6, 1429: 8, 1430: 8, 1456: 4, 1470: 8, 1473: 8, 1507: 8, 1535: 8, 2000: 8, 2004: 8, 2008: 8, 2012: 8, 1157: 4, 1193: 8, 1379: 8, 1988: 8, 1996: 8
+ }],
+ CAR.KONA_EV_2022: [{
+ 127: 8, 304: 8, 320: 8, 339: 8, 352: 8, 356: 4, 544: 8, 593: 8, 688: 5, 832: 8, 881: 8, 882: 8, 897: 8, 902: 8, 903: 8, 905: 8, 909: 8, 913: 8, 916: 8, 1040: 8, 1042: 8, 1056: 8, 1057: 8, 1069: 8, 1078: 4, 1136: 8, 1145: 8, 1151: 8, 1155: 8, 1156: 8, 1157: 4, 1162: 8, 1164: 8, 1168: 8, 1173: 8, 1183: 8, 1188: 8, 1191: 2, 1193: 8, 1225: 8, 1227: 8, 1265: 4, 1280: 1, 1287: 4, 1290: 8, 1291: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1339: 8, 1342: 8, 1343: 8, 1345: 8, 1348: 8, 1355: 8, 1363: 8, 1369: 8, 1379: 8, 1407: 8, 1419: 8, 1426: 8, 1427: 6, 1429: 8, 1430: 8, 1446: 8, 1456: 4, 1470: 8, 1473: 8, 1485: 8, 1507: 8, 1535: 8, 1990: 8, 1998: 8
+ }],
+ CAR.KIA_NIRO_EV: [{
+ 127: 8, 304: 8, 320: 8, 339: 8, 352: 8, 356: 4, 516: 8, 544: 8, 593: 8, 688: 5, 832: 8, 881: 8, 882: 8, 897: 8, 902: 8, 903: 8, 905: 8, 909: 8, 916: 8, 1040: 8, 1042: 8, 1056: 8, 1057: 8, 1078: 4, 1136: 8, 1151: 6, 1156: 8, 1157: 4, 1168: 7, 1173: 8, 1183: 8, 1186: 2, 1191: 2, 1193: 8, 1225: 8, 1260: 8, 1265: 4, 1280: 1, 1287: 4, 1290: 8, 1291: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1355: 8, 1363: 8, 1369: 8, 1407: 8, 1419: 8, 1426: 8, 1427: 6, 1429: 8, 1430: 8, 1456: 4, 1470: 8, 1473: 8, 1507: 8, 1535: 8, 1990: 8, 1998: 8, 1996: 8, 2000: 8, 2004: 8, 2008: 8, 2012: 8, 2015: 8
+ }],
+ CAR.KIA_OPTIMA_H: [{
+ 68: 8, 127: 8, 304: 8, 320: 8, 339: 8, 352: 8, 356: 4, 544: 8, 593: 8, 688: 5, 832: 8, 881: 8, 882: 8, 897: 8, 902: 8, 903: 6, 916: 8, 1040: 8, 1056: 8, 1057: 8, 1078: 4, 1136: 6, 1151: 6, 1168: 7, 1173: 8, 1236: 2, 1265: 4, 1280: 1, 1287: 4, 1290: 8, 1291: 8, 1292: 8, 1322: 8, 1331: 8, 1332: 8, 1333: 8, 1342: 6, 1345: 8, 1348: 8, 1355: 8, 1363: 8, 1369: 8, 1371: 8, 1407: 8, 1419: 8, 1427: 6, 1429: 8, 1430: 8, 1448: 8, 1456: 4, 1470: 8, 1476: 8, 1535: 8
+ },
+ {
+ 68: 8, 127: 8, 304: 8, 320: 8, 339: 8, 352: 8, 356: 4, 544: 8, 576: 8, 593: 8, 688: 5, 881: 8, 882: 8, 897: 8, 902: 8, 903: 8, 909: 8, 912: 7, 916: 8, 1040: 8, 1056: 8, 1057: 8, 1078: 4, 1136: 6, 1151: 6, 1168: 7, 1173: 8, 1180: 8, 1186: 2, 1191: 2, 1265: 4, 1268: 8, 1280: 1, 1287: 4, 1290: 8, 1291: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1355: 8, 1363: 8, 1369: 8, 1371: 8, 1407: 8, 1419: 8, 1420: 8, 1425: 2, 1427: 6, 1429: 8, 1430: 8, 1448: 8, 1456: 4, 1470: 8, 1476: 8, 1535: 8
+ }],
+ CAR.PALISADE: [{
+ 67: 8, 127: 8, 304: 8, 320: 8, 339: 8, 356: 4, 544: 8, 546: 8, 547: 8, 548: 8, 549: 8, 576: 8, 593: 8, 608: 8, 688: 6, 809: 8, 832: 8, 854: 7, 870: 7, 871: 8, 872: 8, 897: 8, 902: 8, 903: 8, 905: 8, 909: 8, 913: 8, 916: 8, 1040: 8, 1042: 8, 1056: 8, 1057: 8, 1064: 8, 1078: 4, 1107: 5, 1123: 8, 1136: 8, 1151: 6, 1155: 8, 1156: 8, 1157: 4, 1162: 8, 1164: 8, 1168: 7, 1170: 8, 1173: 8, 1180: 8, 1186: 2, 1191: 2, 1193: 8, 1210: 8, 1225: 8, 1227: 8, 1265: 4, 1280: 8, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1363: 8, 1369: 8, 1371: 8, 1378: 8, 1384: 8, 1407: 8, 1419: 8, 1427: 6, 1456: 4, 1470: 8, 1988: 8, 1996: 8, 2000: 8, 2004: 8, 2005: 8, 2008: 8, 2012: 8
+ }],
+}
+
+FW_VERSIONS = {
+ CAR.AZERA_6TH_GEN: {
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00IG__ SCC F-CU- 1.00 1.00 99110-G8100 ',
+ ],
+ (Ecu.eps, 0x7d4, None): [
+ b'\xf1\x00IG MDPS C 1.00 1.02 56310G8510\x00 4IGSC103',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00IG MFC AT MES LHD 1.00 1.04 99211-G8100 200511',
+ ],
+ (Ecu.transmission, 0x7e1, None): [
+ b'\xf1\x00bcsh8p54 U912\x00\x00\x00\x00\x00\x00SIG0M35MH0\xa4 |.',
+ ],
+ (Ecu.engine, 0x7e0, None): [
+ b'\xf1\x81641KA051\x00\x00\x00\x00\x00\x00\x00\x00',
+ ],
+ },
+ CAR.AZERA_HEV_6TH_GEN: {
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00IGH MFC AT KOR LHD 1.00 1.00 99211-G8000 180903',
+ b'\xf1\x00IGH MFC AT KOR LHD 1.00 1.02 99211-G8100 191029',
+ ],
+ (Ecu.eps, 0x7d4, None): [
+ b'\xf1\x00IG MDPS C 1.00 1.00 56310M9600\x00 4IHSC100',
+ b'\xf1\x00IG MDPS C 1.00 1.01 56310M9350\x00 4IH8C101',
+ ],
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00IGhe SCC FHCUP 1.00 1.00 99110-M9100 ',
+ b'\xf1\x00IGhe SCC FHCUP 1.00 1.01 99110-M9000 ',
+ ],
+ (Ecu.transmission, 0x7e1, None): [
+ b'\xf1\x006T7N0_C2\x00\x006T7Q2051\x00\x00TIG2H24KA2\x12@\x11\xb7',
+ b'\xf1\x006T7N0_C2\x00\x006T7VA051\x00\x00TIGSH24KA1\xc7\x85\xe2`',
+ ],
+ (Ecu.engine, 0x7e0, None): [
+ b'\xf1\x816H570051\x00\x00\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x816H590051\x00\x00\x00\x00\x00\x00\x00\x00',
+ ],
+ },
+ CAR.HYUNDAI_GENESIS: {
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00DH LKAS 1.1 -150210',
+ b'\xf1\x00DH LKAS 1.4 -140110',
+ b'\xf1\x00DH LKAS 1.5 -140425',
+ ],
+ },
+ CAR.IONIQ: {
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00AEhe SCC H-CUP 1.01 1.01 96400-G2000 ',
+ ],
+ (Ecu.eps, 0x7d4, None): [
+ b'\xf1\x00AE MDPS C 1.00 1.07 56310/G2301 4AEHC107',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00AEH MFC AT EUR LHD 1.00 1.00 95740-G2400 180222',
+ ],
+ (Ecu.engine, 0x7e0, None): [
+ b'\xf1\x816H6F2051\x00\x00\x00\x00\x00\x00\x00\x00',
+ ],
+ (Ecu.transmission, 0x7e1, None): [
+ b'\xf1\x816U3H1051\x00\x00\xf1\x006U3H0_C2\x00\x006U3H1051\x00\x00HAE0G16US2\x00\x00\x00\x00',
+ ],
+ },
+ CAR.IONIQ_PHEV_2019: {
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00AEhe SCC H-CUP 1.01 1.01 96400-G2100 ',
+ ],
+ (Ecu.eps, 0x7d4, None): [
+ b'\xf1\x00AE MDPS C 1.00 1.07 56310/G2501 4AEHC107',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00AEP MFC AT USA LHD 1.00 1.00 95740-G2400 180222',
+ ],
+ (Ecu.engine, 0x7e0, None): [
+ b'\xf1\x816H6F6051\x00\x00\x00\x00\x00\x00\x00\x00',
+ ],
+ (Ecu.transmission, 0x7e1, None): [
+ b'\xf1\x816U3J2051\x00\x00\xf1\x006U3H0_C2\x00\x006U3J2051\x00\x00PAE0G16NS1\x00\x00\x00\x00',
+ b'\xf1\x816U3J2051\x00\x00\xf1\x006U3H0_C2\x00\x006U3J2051\x00\x00PAE0G16NS1\xdbD\r\x81',
+ ],
+ },
+ CAR.IONIQ_PHEV: {
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00AEhe SCC F-CUP 1.00 1.00 99110-G2200 ',
+ b'\xf1\x00AEhe SCC F-CUP 1.00 1.00 99110-G2600 ',
+ b'\xf1\x00AEhe SCC F-CUP 1.00 1.02 99110-G2100 ',
+ b'\xf1\x00AEhe SCC FHCUP 1.00 1.00 99110-G2600 ',
+ b'\xf1\x00AEhe SCC FHCUP 1.00 1.02 99110-G2100 ',
+ ],
+ (Ecu.eps, 0x7d4, None): [
+ b'\xf1\x00AE MDPS C 1.00 1.01 56310/G2310 4APHC101',
+ b'\xf1\x00AE MDPS C 1.00 1.01 56310/G2510 4APHC101',
+ b'\xf1\x00AE MDPS C 1.00 1.01 56310/G2560 4APHC101',
+ b'\xf1\x00AE MDPS C 1.00 1.01 56310G2510\x00 4APHC101',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00AEP MFC AT EUR LHD 1.00 1.01 95740-G2600 190819',
+ b'\xf1\x00AEP MFC AT EUR RHD 1.00 1.01 95740-G2600 190819',
+ b'\xf1\x00AEP MFC AT USA LHD 1.00 1.00 95740-G2700 201027',
+ b'\xf1\x00AEP MFC AT USA LHD 1.00 1.01 95740-G2600 190819',
+ ],
+ (Ecu.engine, 0x7e0, None): [
+ b'\xf1\x816H6F6051\x00\x00\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x816H6G5051\x00\x00\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x816H6G6051\x00\x00\x00\x00\x00\x00\x00\x00',
+ ],
+ (Ecu.transmission, 0x7e1, None): [
+ b'\xf1\x006U3H1_C2\x00\x006U3J8051\x00\x00PAETG16UL0\x00\x00\x00\x00',
+ b'\xf1\x006U3H1_C2\x00\x006U3J9051\x00\x00PAE0G16NL0\x00\x00\x00\x00',
+ b'\xf1\x006U3H1_C2\x00\x006U3J9051\x00\x00PAE0G16NL2\xad\xeb\xabt',
+ b'\xf1\x816U3J8051\x00\x00\xf1\x006U3H1_C2\x00\x006U3J8051\x00\x00PAETG16UL0\x00\x00\x00\x00',
+ b'\xf1\x816U3J9051\x00\x00\xf1\x006U3H1_C2\x00\x006U3J9051\x00\x00PAE0G16NL0\x82zT\xd2',
+ b'\xf1\x816U3J9051\x00\x00\xf1\x006U3H1_C2\x00\x006U3J9051\x00\x00PAE0G16NL2\x00\x00\x00\x00',
+ ],
+ },
+ CAR.IONIQ_EV_2020: {
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00AEev SCC F-CUP 1.00 1.00 99110-G7200 ',
+ b'\xf1\x00AEev SCC F-CUP 1.00 1.01 99110-G7000 ',
+ ],
+ (Ecu.eps, 0x7d4, None): [
+ b'\xf1\x00AE MDPS C 1.00 1.01 56310/G7310 4APEC101',
+ b'\xf1\x00AE MDPS C 1.00 1.01 56310/G7560 4APEC101',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00AEE MFC AT EUR LHD 1.00 1.00 95740-G2600 190730',
+ b'\xf1\x00AEE MFC AT EUR LHD 1.00 1.01 95740-G2600 190819',
+ b'\xf1\x00AEE MFC AT EUR LHD 1.00 1.03 95740-G2500 190516',
+ b'\xf1\x00AEE MFC AT EUR RHD 1.00 1.01 95740-G2600 190819',
+ ],
+ },
+ CAR.IONIQ_EV_LTD: {
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00AEev SCC F-CUP 1.00 1.00 96400-G7000 ',
+ b'\xf1\x00AEev SCC F-CUP 1.00 1.00 96400-G7100 ',
+ ],
+ (Ecu.eps, 0x7d4, None): [
+ b'\xf1\x00AE MDPS C 1.00 1.02 56310G7300\x00 4AEEC102',
+ b'\xf1\x00AE MDPS C 1.00 1.03 56310/G7300 4AEEC103',
+ b'\xf1\x00AE MDPS C 1.00 1.03 56310G7300\x00 4AEEC103',
+ b'\xf1\x00AE MDPS C 1.00 1.04 56310/G7301 4AEEC104',
+ b'\xf1\x00AE MDPS C 1.00 1.04 56310/G7501 4AEEC104',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00AEE MFC AT EUR LHD 1.00 1.00 95740-G2300 170703',
+ b'\xf1\x00AEE MFC AT EUR LHD 1.00 1.00 95740-G2400 180222',
+ b'\xf1\x00AEE MFC AT EUR LHD 1.00 1.00 95740-G7200 160418',
+ b'\xf1\x00AEE MFC AT USA LHD 1.00 1.00 95740-G2400 180222',
+ ],
+ },
+ CAR.IONIQ_HEV_2022: {
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00AEhe SCC F-CUP 1.00 1.00 99110-G2600 ',
+ b'\xf1\x00AEhe SCC FHCUP 1.00 1.00 99110-G2600 ',
+ ],
+ (Ecu.eps, 0x7d4, None): [
+ b'\xf1\x00AE MDPS C 1.00 1.01 56310G2510\x00 4APHC101',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00AEH MFC AT USA LHD 1.00 1.00 95740-G2700 201027',
+ ],
+ (Ecu.engine, 0x7e0, None): [
+ b'\xf1\x816H6G5051\x00\x00\x00\x00\x00\x00\x00\x00',
+ ],
+ (Ecu.transmission, 0x7e1, None): [
+ b'\xf1\x006U3H1_C2\x00\x006U3J9051\x00\x00HAE0G16NL2\x96\xda\xd4\xee',
+ b'\xf1\x816U3J9051\x00\x00\xf1\x006U3H1_C2\x00\x006U3J9051\x00\x00HAE0G16NL2\x00\x00\x00\x00',
+ ],
+ },
+ CAR.SONATA: {
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00DN8_ SCC F-CU- 1.00 1.00 99110-L0000 ',
+ b'\xf1\x00DN8_ SCC F-CUP 1.00 1.00 99110-L0000 ',
+ b'\xf1\x00DN8_ SCC F-CUP 1.00 1.02 99110-L1000 ',
+ b'\xf1\x00DN8_ SCC FHCUP 1.00 1.00 99110-L0000 ',
+ b'\xf1\x00DN8_ SCC FHCUP 1.00 1.01 99110-L1000 ',
+ b'\xf1\x00DN8_ SCC FHCUP 1.00 1.02 99110-L1000 ',
+ ],
+ (Ecu.abs, 0x7d1, None): [
+ b'\xf1\x00DN ESC \x01 102\x19\x04\x13 58910-L1300',
+ b'\xf1\x00DN ESC \x03 100 \x08\x01 58910-L0300',
+ b'\xf1\x00DN ESC \x06 104\x19\x08\x01 58910-L0100',
+ b'\xf1\x00DN ESC \x06 106 \x07\x01 58910-L0100',
+ b'\xf1\x00DN ESC \x06 107 \x07\x03 58910-L1300',
+ b'\xf1\x00DN ESC \x07 104\x19\x08\x01 58910-L0100',
+ b'\xf1\x00DN ESC \x07 106 \x07\x01 58910-L0100',
+ b'\xf1\x00DN ESC \x07 107"\x08\x07 58910-L0100',
+ b'\xf1\x00DN ESC \x08 103\x19\x06\x01 58910-L1300',
+ b'\xf1\x8758910-L0100\xf1\x00DN ESC \x06 104\x19\x08\x01 58910-L0100',
+ b'\xf1\x8758910-L0100\xf1\x00DN ESC \x06 106 \x07\x01 58910-L0100',
+ b'\xf1\x8758910-L0100\xf1\x00DN ESC \x07 104\x19\x08\x01 58910-L0100',
+ b'\xf1\x8758910-L0100\xf1\x00DN ESC \x07 106 \x07\x01 58910-L0100',
+ ],
+ (Ecu.engine, 0x7e0, None): [
+ b'HM6M1_0a0_F00',
+ b'HM6M1_0a0_G20',
+ b'HM6M2_0a0_BD0',
+ b'\xf1\x81HM6M1_0a0_F00',
+ b'\xf1\x81HM6M1_0a0_G20',
+ b'\xf1\x82DNBVN5GMCCXXXDCA',
+ b'\xf1\x82DNBVN5GMCCXXXG2F',
+ b'\xf1\x82DNBWN5TMDCXXXG2E',
+ b'\xf1\x82DNCVN5GMCCXXXF0A',
+ b'\xf1\x82DNCVN5GMCCXXXG2B',
+ b'\xf1\x870\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x81HM6M1_0a0_J10',
+ b'\xf1\x870\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x82DNDWN5TMDCXXXJ1A',
+ b'\xf1\x8739110-2S041\xf1\x81HM6M1_0a0_M00',
+ b'\xf1\x8739110-2S041\xf1\x81HM6M1_0a0_M10',
+ b'\xf1\x8739110-2S042\xf1\x81HM6M1_0a0_M00',
+ b'\xf1\x8739110-2S278\xf1\x82DNDVD5GMCCXXXL5B',
+ b'\xf1\x87391162M003',
+ b'\xf1\x87391162M010',
+ b'\xf1\x87391162M013',
+ b'\xf1\x87391162M023',
+ ],
+ (Ecu.eps, 0x7d4, None): [
+ b'\xf1\x00DN8 MDPS C 1,00 1,01 56310L0010\x00 4DNAC101',
+ b'\xf1\x00DN8 MDPS C 1.00 1.01 56310-L0010 4DNAC101',
+ b'\xf1\x00DN8 MDPS C 1.00 1.01 56310-L0210 4DNAC102',
+ b'\xf1\x00DN8 MDPS C 1.00 1.01 56310L0010\x00 4DNAC101',
+ b'\xf1\x00DN8 MDPS C 1.00 1.01 56310L0200\x00 4DNAC102',
+ b'\xf1\x00DN8 MDPS C 1.00 1.01 56310L0210\x00 4DNAC102',
+ b'\xf1\x00DN8 MDPS R 1.00 1.00 57700-L0000 4DNAP100',
+ b'\xf1\x00DN8 MDPS R 1.00 1.00 57700-L0000 4DNAP101',
+ b'\xf1\x00DN8 MDPS R 1.00 1.02 57700-L1000 4DNDP105',
+ b'\xf1\x8756310-L0010\xf1\x00DN8 MDPS C 1.00 1.01 56310-L0010 4DNAC101',
+ b'\xf1\x8756310-L0210\xf1\x00DN8 MDPS C 1.00 1.01 56310-L0210 4DNAC101',
+ b'\xf1\x8756310-L1010\xf1\x00DN8 MDPS C 1.00 1.03 56310-L1010 4DNDC103',
+ b'\xf1\x8756310-L1030\xf1\x00DN8 MDPS C 1.00 1.03 56310-L1030 4DNDC103',
+ b'\xf1\x8756310L0010\x00\xf1\x00DN8 MDPS C 1,00 1,01 56310L0010\x00 4DNAC101',
+ b'\xf1\x8756310L0010\x00\xf1\x00DN8 MDPS C 1.00 1.01 56310L0010\x00 4DNAC101',
+ b'\xf1\x8756310L0210\x00\xf1\x00DN8 MDPS C 1.00 1.01 56310L0210\x00 4DNAC101',
+ b'\xf1\x8757700-L0000\xf1\x00DN8 MDPS R 1.00 1.00 57700-L0000 4DNAP100',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00DN8 MFC AT KOR LHD 1.00 1.02 99211-L1000 190422',
+ b'\xf1\x00DN8 MFC AT KOR LHD 1.00 1.04 99211-L1000 191016',
+ b'\xf1\x00DN8 MFC AT RUS LHD 1.00 1.03 99211-L1000 190705',
+ b'\xf1\x00DN8 MFC AT USA LHD 1.00 1.00 99211-L0000 190716',
+ b'\xf1\x00DN8 MFC AT USA LHD 1.00 1.01 99211-L0000 191016',
+ b'\xf1\x00DN8 MFC AT USA LHD 1.00 1.03 99211-L0000 210603',
+ b'\xf1\x00DN8 MFC AT USA LHD 1.00 1.05 99211-L1000 201109',
+ b'\xf1\x00DN8 MFC AT USA LHD 1.00 1.06 99211-L1000 210325',
+ b'\xf1\x00DN8 MFC AT USA LHD 1.00 1.07 99211-L1000 211223',
+ ],
+ (Ecu.transmission, 0x7e1, None): [
+ b'\xf1\x00HT6TA260BLHT6TA800A1TDN8C20KS4\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x00HT6TA260BLHT6TA810A1TDN8M25GS0\x00\x00\x00\x00\x00\x00\xaa\x8c\xd9p',
+ b'\xf1\x00HT6WA250BLHT6WA910A1SDN8G25NB1\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x00HT6WA250BLHT6WA910A1SDN8G25NB1\x00\x00\x00\x00\x00\x00\x96\xa1\xf1\x92',
+ b'\xf1\x00HT6WA280BLHT6WAD10A1SDN8G25NB2\x00\x00\x00\x00\x00\x00\x08\xc9O:',
+ b'\xf1\x00HT6WA280BLHT6WAD10A1SDN8G25NB4\x00\x00\x00\x00\x00\x00g!l[',
+ b'\xf1\x00HT6WA280BLHT6WAE10A1SDN8G25NB5\x00\x00\x00\x00\x00\x00\xe0t\xa9\xba',
+ b'\xf1\x00T02601BL T02730A1 VDN8T25XXX730NS5\xf7_\x92\xf5',
+ b'\xf1\x00T02601BL T02832A1 VDN8T25XXX832NS8G\x0e\xfeE',
+ b'\xf1\x00T02601BL T02900A1 VDN8T25XXX900NSA\xb9\x13\xf9p',
+ b'\xf1\x00T02601BL T02900A1 VDN8T25XXX900NSCF\xe4!Y',
+ b'\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00SDN8T16KB05\x95h%',
+ b'\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00SDN8T16NB0z{\xd4v',
+ b'\xf1\x00bcsh8p54 U913\x00\x00\x00\x00\x00\x00SDN8T16NB1\xe3\xc10\xa1',
+ b'\xf1\x00bcsh8p54 U913\x00\x00\x00\x00\x00\x00SDN8T16NB2\n\xdd^\xbc',
+ b'\xf1\x87954A02N060\x00\x00\x00\x00\x00\xf1\x81T02730A1 \xf1\x00T02601BL T02730A1 VDN8T25XXX730NS5\xf7_\x92\xf5',
+ b'\xf1\x87SAKFBA2926554GJ2VefVww\x87xwwwww\x88\x87xww\x87wTo\xfb\xffvUo\xff\x8d\x16\xf1\x81U903\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00SDN8T16NB0z{\xd4v',
+ b'\xf1\x87SAKFBA3030524GJ2UVugww\x97yx\x88\x87\x88vw\x87gww\x87wto\xf9\xfffUo\xff\xa2\x0c\xf1\x81U903\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00SDN8T16NB0z{\xd4v',
+ b'\xf1\x87SAKFBA3356084GJ2\x86fvgUUuWgw\x86www\x87wffvf\xb6\xcf\xfc\xffeUO\xff\x12\x19\xf1\x81U903\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00SDN8T16NB0z{\xd4v',
+ b'\xf1\x87SAKFBA3474944GJ2ffvgwwwwg\x88\x86x\x88\x88\x98\x88ffvfeo\xfa\xff\x86fo\xff\t\xae\xf1\x81U903\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00SDN8T16NB0z{\xd4v',
+ b'\xf1\x87SAKFBA3475714GJ2Vfvgvg\x96yx\x88\x97\x88ww\x87ww\x88\x87xs_\xfb\xffvUO\xff\x0f\xff\xf1\x81U903\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00SDN8T16NB0z{\xd4v',
+ b'\xf1\x87SALDBA3510954GJ3ww\x87xUUuWx\x88\x87\x88\x87w\x88wvfwfc_\xf9\xff\x98wO\xffl\xe0\xf1\x89HT6WA910A1\xf1\x82SDN8G25NB1\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x87SALDBA3573534GJ3\x89\x98\x89\x88EUuWgwvwwwwww\x88\x87xTo\xfa\xff\x86f\x7f\xffo\x0e\xf1\x89HT6WA910A1\xf1\x82SDN8G25NB1\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x87SALDBA3601464GJ3\x88\x88\x88\x88ffvggwvwvw\x87gww\x87wvo\xfb\xff\x98\x88\x7f\xffjJ\xf1\x89HT6WA910A1\xf1\x82SDN8G25NB1\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x87SALDBA3753044GJ3UUeVff\x86hwwwwvwwgvfgfvo\xf9\xfffU_\xffC\xae\xf1\x89HT6WA910A1\xf1\x82SDN8G25NB1\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x87SALDBA3862294GJ3vfvgvefVxw\x87\x87w\x88\x87xwwwwc_\xf9\xff\x87w\x9f\xff\xd5\xdc\xf1\x89HT6WA910A1\xf1\x82SDN8G25NB1\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x87SALDBA3873834GJ3fefVwuwWx\x88\x97\x88w\x88\x97xww\x87wU_\xfb\xff\x86f\x8f\xffN\x04\xf1\x89HT6WA910A1\xf1\x82SDN8G25NB1\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x87SALDBA4525334GJ3\x89\x99\x99\x99fevWh\x88\x86\x88fwvgw\x88\x87xfo\xfa\xffuDo\xff\xd1>\xf1\x89HT6WA910A1\xf1\x82SDN8G25NB1\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x87SALDBA4626804GJ3wwww\x88\x87\x88xx\x88\x87\x88wwgw\x88\x88\x98\x88\x95_\xf9\xffuDo\xff|\xe7\xf1\x89HT6WA910A1\xf1\x82SDN8G25NB1\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x87SALDBA4803224GJ3wwwwwvwg\x88\x88\x98\x88wwww\x87\x88\x88xu\x9f\xfc\xff\x87f\x8f\xff\xea\xea\xf1\x89HT6WA910A1\xf1\x82SDN8G25NB1\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x87SALDBA6212564GJ3\x87wwwUTuGg\x88\x86xx\x88\x87\x88\x87\x88\x98xu?\xf9\xff\x97f\x7f\xff\xb8\n\xf1\x89HT6WA910A1\xf1\x82SDN8G25NB1\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x87SALDBA6347404GJ3wwwwff\x86hx\x88\x97\x88\x88\x88\x88\x88vfgf\x88?\xfc\xff\x86Uo\xff\xec/\xf1\x89HT6WA910A1\xf1\x82SDN8G25NB1\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x87SALDBA6901634GJ3UUuWVeVUww\x87wwwwwvUge\x86/\xfb\xff\xbb\x99\x7f\xff]2\xf1\x89HT6WA910A1\xf1\x82SDN8G25NB1\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x87SALDBA7077724GJ3\x98\x88\x88\x88ww\x97ygwvwww\x87ww\x88\x87x\x87_\xfd\xff\xba\x99o\xff\x99\x01\xf1\x89HT6WA910A1\xf1\x82SDN8G25NB1\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x87SALFBA3525114GJ2wvwgvfvggw\x86wffvffw\x86g\x85_\xf9\xff\xa8wo\xffv\xcd\xf1\x81U903\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00SDN8T16NB0z{\xd4v',
+ b'\xf1\x87SALFBA3624024GJ2\x88\x88\x88\x88wv\x87hx\x88\x97\x88x\x88\x97\x88ww\x87w\x86o\xfa\xffvU\x7f\xff\xd1\xec\xf1\x81U903\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00SDN8T16NB0z{\xd4v',
+ b'\xf1\x87SALFBA3960824GJ2wwwwff\x86hffvfffffvfwfg_\xf9\xff\xa9\x88\x8f\xffb\x99\xf1\x81U903\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00SDN8T16NB0z{\xd4v',
+ b'\xf1\x87SALFBA4011074GJ2fgvwwv\x87hw\x88\x87xww\x87wwfgvu_\xfa\xffefo\xff\x87\xc0\xf1\x81U903\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00SDN8T16NB0z{\xd4v',
+ b'\xf1\x87SALFBA4121304GJ2x\x87xwff\x86hwwwwww\x87wwwww\x84_\xfc\xff\x98\x88\x9f\xffi\xa6\xf1\x81U903\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00SDN8T16NB0z{\xd4v',
+ b'\xf1\x87SALFBA4195874GJ2EVugvf\x86hgwvwww\x87wgw\x86wc_\xfb\xff\x98\x88\x8f\xff\xe23\xf1\x81U903\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00SDN8T16NB0z{\xd4v',
+ b'\xf1\x87SALFBA4625294GJ2eVefeUeVx\x88\x97\x88wwwwwwww\xa7o\xfb\xffvw\x9f\xff\xee.\xf1\x81U903\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00SDN8T16NB0z{\xd4v',
+ b'\xf1\x87SALFBA4728774GJ2vfvg\x87vwgww\x87ww\x88\x97xww\x87w\x86_\xfb\xffeD?\xffk0\xf1\x81U903\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00SDN8T16NB0z{\xd4v',
+ b'\xf1\x87SALFBA5129064GJ2vfvgwv\x87hx\x88\x87\x88ww\x87www\x87wd_\xfa\xffvfo\xff\x1d\x00\xf1\x81U903\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00SDN8T16NB0z{\xd4v',
+ b'\xf1\x87SALFBA5454914GJ2\x98\x88\x88\x88\x87vwgx\x88\x87\x88xww\x87ffvf\xa7\x7f\xf9\xff\xa8w\x7f\xff\x1b\x90\xf1\x81U903\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00SDN8T16NB0z{\xd4v',
+ b'\xf1\x87SALFBA5987784GJ2UVugDDtGx\x88\x87\x88w\x88\x87xwwwwd/\xfb\xff\x97fO\xff\xb0h\xf1\x81U903\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00SDN8T16NB0z{\xd4v',
+ b'\xf1\x87SALFBA5987864GJ2fgvwUUuWgwvw\x87wxwwwww\x84/\xfc\xff\x97w\x7f\xff\xdf\x1d\xf1\x81U903\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00SDN8T16NB0z{\xd4v',
+ b'\xf1\x87SALFBA6337644GJ2vgvwwv\x87hgffvwwwwwwww\x85O\xfa\xff\xa7w\x7f\xff\xc5\xfc\xf1\x81U903\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00SDN8T16NB0z{\xd4v',
+ b'\xf1\x87SALFBA6802004GJ2UUuWUUuWgw\x86www\x87www\x87w\x96?\xf9\xff\xa9\x88\x7f\xff\x9fK\xf1\x81U903\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00SDN8T16NB0z{\xd4v',
+ b'\xf1\x87SALFBA6892284GJ233S5\x87w\x87xx\x88\x87\x88vwwgww\x87w\x84?\xfb\xff\x98\x88\x8f\xff*\x9e\xf1\x81U903\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00SDN8T16NB0z{\xd4v',
+ b'\xf1\x87SALFBA7005534GJ2eUuWfg\x86xxww\x87x\x88\x87\x88\x88w\x88\x87\x87O\xfc\xffuUO\xff\xa3k\xf1\x81U913\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U913\x00\x00\x00\x00\x00\x00SDN8T16NB1\xe3\xc10\xa1',
+ b'\xf1\x87SALFBA7152454GJ2gvwgFf\x86hx\x88\x87\x88vfWfffffd?\xfa\xff\xba\x88o\xff,\xcf\xf1\x81U913\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U913\x00\x00\x00\x00\x00\x00SDN8T16NB1\xe3\xc10\xa1',
+ b'\xf1\x87SALFBA7460044GJ2gx\x87\x88Vf\x86hx\x88\x87\x88wwwwgw\x86wd?\xfa\xff\x86U_\xff\xaf\x1f\xf1\x81U913\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U913\x00\x00\x00\x00\x00\x00SDN8T16NB2\n\xdd^\xbc',
+ b'\xf1\x87SALFBA7485034GJ2ww\x87xww\x87xfwvgwwwwvfgf\xa5/\xfc\xff\xa9w_\xff40\xf1\x81U913\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U913\x00\x00\x00\x00\x00\x00SDN8T16NB2\n\xdd^\xbc',
+ b'\xf1\x87SAMDBA7743924GJ3wwwwww\x87xgwvw\x88\x88\x88\x88wwww\x85_\xfa\xff\x86f\x7f\xff0\x9d\xf1\x89HT6WAD10A1\xf1\x82SDN8G25NB2\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x87SAMDBA7817334GJ3Vgvwvfvgww\x87wwwwwwfgv\x97O\xfd\xff\x88\x88o\xff\x8e\xeb\xf1\x89HT6WAD10A1\xf1\x82SDN8G25NB2\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x87SAMDBA8054504GJ3gw\x87xffvgffffwwwweUVUf?\xfc\xffvU_\xff\xddl\xf1\x89HT6WAD10A1\xf1\x82SDN8G25NB2\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x87SAMFB41553621GC7ww\x87xUU\x85Xvwwg\x88\x88\x88\x88wwgw\x86\xaf\xfb\xffuDo\xff\xaa\x8f\xf1\x81U913\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U913\x00\x00\x00\x00\x00\x00SDN8T16NB2\n\xdd^\xbc',
+ b'\xf1\x87SAMFB42555421GC7\x88\x88\x88\x88wvwgx\x88\x87\x88wwgw\x87wxw3\x8f\xfc\xff\x98f\x8f\xffga\xf1\x81U913\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U913\x00\x00\x00\x00\x00\x00SDN8T16NB2\n\xdd^\xbc',
+ b'\xf1\x87SAMFBA7978674GJ2gw\x87xgw\x97ywwwwvUGeUUeU\x87O\xfb\xff\x98w\x8f\xfffF\xf1\x81U913\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U913\x00\x00\x00\x00\x00\x00SDN8T16NB2\n\xdd^\xbc',
+ b'\xf1\x87SAMFBA8105254GJ2wx\x87\x88Vf\x86hx\x88\x87\x88wwwwwwww\x86O\xfa\xff\x99\x88\x7f\xffZG\xf1\x81U913\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U913\x00\x00\x00\x00\x00\x00SDN8T16NB2\n\xdd^\xbc',
+ b'\xf1\x87SAMFBA9283024GJ2wwwwEUuWwwgwwwwwwwww\x87/\xfb\xff\x98w\x8f\xff<\xd3\xf1\x81U913\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U913\x00\x00\x00\x00\x00\x00SDN8T16NB2\n\xdd^\xbc',
+ b'\xf1\x87SAMFBA9708354GJ2wwwwVf\x86h\x88wx\x87xww\x87\x88\x88\x88\x88w/\xfa\xff\x97w\x8f\xff\x86\xa0\xf1\x81U913\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U913\x00\x00\x00\x00\x00\x00SDN8T16NB2\n\xdd^\xbc',
+ b'\xf1\x87SANDB45316691GC6\x99\x99\x99\x99\x88\x88\xa8\x8avfwfwwww\x87wxwT\x9f\xfd\xff\x88wo\xff\x1c\xfa\xf1\x89HT6WAD10A1\xf1\x82SDN8G25NB3\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x87SANFB45889451GC7wx\x87\x88gw\x87x\x88\x88x\x88\x87wxw\x87wxw\x87\x8f\xfc\xffeU\x8f\xff+Q\xf1\x81U913\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U913\x00\x00\x00\x00\x00\x00SDN8T16NB2\n\xdd^\xbc',
+ ],
+ },
+ CAR.SONATA_LF: {
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00LF__ SCC F-CUP 1.00 1.00 96401-C2200 ',
+ ],
+ (Ecu.abs, 0x7d1, None): [
+ b'\xf1\x00LF ESC \t 11 \x17\x01\x13 58920-C2610',
+ b'\xf1\x00LF ESC \x0c 11 \x17\x01\x13 58920-C2610',
+ ],
+ (Ecu.engine, 0x7e0, None): [
+ b'\xf1\x81606D5051\x00\x00\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x81606D5K51\x00\x00\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x81606G1051\x00\x00\x00\x00\x00\x00\x00\x00',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00LFF LKAS AT USA LHD 1.00 1.01 95740-C1000 E51',
+ b'\xf1\x00LFF LKAS AT USA LHD 1.01 1.02 95740-C1000 E52',
+ ],
+ (Ecu.transmission, 0x7e1, None): [
+ b'\xf1\x006T6H0_C2\x00\x006T6B4051\x00\x00TLF0G24NL1\xb0\x9f\xee\xf5',
+ b'\xf1\x87LAHSGN012918KF10\x98\x88x\x87\x88\x88x\x87\x88\x88\x98\x88\x87w\x88w\x88\x88\x98\x886o\xf6\xff\x98w\x7f\xff3\x00\xf1\x816W3B1051\x00\x00\xf1\x006W351_C2\x00\x006W3B1051\x00\x00TLF0T20NL2\x00\x00\x00\x00',
+ b'\xf1\x87LAHSGN012918KF10\x98\x88x\x87\x88\x88x\x87\x88\x88\x98\x88\x87w\x88w\x88\x88\x98\x886o\xf6\xff\x98w\x7f\xff3\x00\xf1\x816W3B1051\x00\x00\xf1\x006W351_C2\x00\x006W3B1051\x00\x00TLF0T20NL2H\r\xbdm',
+ b'\xf1\x87LAJSG49645724HF0\x87x\x87\x88\x87www\x88\x99\xa8\x89\x88\x99\xa8\x89\x88\x99\xa8\x89S_\xfb\xff\x87f\x7f\xff^2\xf1\x816W3B1051\x00\x00\xf1\x006W351_C2\x00\x006W3B1051\x00\x00TLF0T20NL2H\r\xbdm',
+ b'\xf1\x87\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xf1\x816T6B4051\x00\x00\xf1\x006T6H0_C2\x00\x006T6B4051\x00\x00TLF0G24NL1\x00\x00\x00\x00',
+ b'\xf1\x87\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xf1\x816T6B4051\x00\x00\xf1\x006T6H0_C2\x00\x006T6B4051\x00\x00TLF0G24NL1\xb0\x9f\xee\xf5',
+ b'\xf1\x87\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xf1\x816T6B4051\x00\x00\xf1\x006T6H0_C2\x00\x006T6B4051\x00\x00TLF0G24SL2n\x8d\xbe\xd8',
+ ],
+ },
+ CAR.TUCSON: {
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00TL__ FCA F-CUP 1.00 1.01 99110-D3500 ',
+ b'\xf1\x00TL__ FCA F-CUP 1.00 1.02 99110-D3510 ',
+ ],
+ (Ecu.engine, 0x7e0, None): [
+ b'\xf1\x81606G3051\x00\x00\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x8971TLC2NAIDDIR002\xf1\x8271TLC2NAIDDIR002',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00TL MFC AT KOR LHD 1.00 1.02 95895-D3800 180719',
+ b'\xf1\x00TL MFC AT USA LHD 1.00 1.06 95895-D3800 190107',
+ ],
+ (Ecu.transmission, 0x7e1, None): [
+ b'\xf1\x87KMLDCU585233TJ20wx\x87\x88x\x88\x98\x89vfwfwwww\x87f\x9f\xff\x98\xff\x7f\xf9\xf7s\xf1\x816T6G4051\x00\x00\xf1\x006T6J0_C2\x00\x006T6G4051\x00\x00TTL4G24NH2\x00\x00\x00\x00',
+ b'\xf1\x87LBJXAN202299KF22\x87x\x87\x88ww\x87xx\x88\x97\x88\x87\x88\x98x\x88\x99\x98\x89\x87o\xf6\xff\x87w\x7f\xff\x12\x9a\xf1\x81U083\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U083\x00\x00\x00\x00\x00\x00TTL2V20KL1\x8fRn\x8a',
+ ],
+ },
+ CAR.SANTA_FE: {
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00TM__ SCC F-CUP 1.00 1.00 99110-S1210 ',
+ b'\xf1\x00TM__ SCC F-CUP 1.00 1.01 99110-S2000 ',
+ b'\xf1\x00TM__ SCC F-CUP 1.00 1.02 99110-S2000 ',
+ b'\xf1\x00TM__ SCC F-CUP 1.00 1.03 99110-S2000 ',
+ ],
+ (Ecu.abs, 0x7d1, None): [
+ b'\xf1\x00TM ESC \x02 100\x18\x030 58910-S2600',
+ b'\xf1\x00TM ESC \x02 102\x18\x07\x01 58910-S2600',
+ b'\xf1\x00TM ESC \x02 103\x18\x11\x07 58910-S2600',
+ b'\xf1\x00TM ESC \x02 104\x19\x07\x07 58910-S2600',
+ b'\xf1\x00TM ESC \x03 103\x18\x11\x07 58910-S2600',
+ b'\xf1\x00TM ESC \x0c 103\x18\x11\x08 58910-S2650',
+ b'\xf1\x00TM ESC \r 100\x18\x031 58910-S2650',
+ b'\xf1\x00TM ESC \r 103\x18\x11\x08 58910-S2650',
+ b'\xf1\x00TM ESC \r 104\x19\x07\x08 58910-S2650',
+ b'\xf1\x00TM ESC \r 105\x19\x05# 58910-S1500',
+ ],
+ (Ecu.engine, 0x7e0, None): [
+ b'\xf1\x81606EA051\x00\x00\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x81606G1051\x00\x00\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x81606G3051\x00\x00\x00\x00\x00\x00\x00\x00',
+ ],
+ (Ecu.eps, 0x7d4, None): [
+ b'\xf1\x00TM MDPS C 1.00 1.00 56340-S2000 8409',
+ b'\xf1\x00TM MDPS C 1.00 1.00 56340-S2000 8A12',
+ b'\xf1\x00TM MDPS C 1.00 1.01 56340-S2000 9129',
+ b'\xf1\x00TM MDPS R 1.00 1.02 57700-S1100 4TMDP102',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00TM MFC AT EUR LHD 1.00 1.01 99211-S1010 181207',
+ b'\xf1\x00TM MFC AT USA LHD 1.00 1.00 99211-S2000 180409',
+ ],
+ (Ecu.transmission, 0x7e1, None): [
+ b'\xf1\x006W351_C2\x00\x006W3E1051\x00\x00TTM4T20NS5\x00\x00\x00\x00',
+ b'\xf1\x00bcsh8p54 U833\x00\x00\x00\x00\x00\x00TTM4V22US3_<]\xf1',
+ b'\xf1\x87LBJSGA7082574HG0\x87www\x98\x88\x88\x88\x99\xaa\xb9\x9afw\x86gx\x99\xa7\x89co\xf8\xffvU_\xffR\xaf\xf1\x816W3C2051\x00\x00\xf1\x006W351_C2\x00\x006W3C2051\x00\x00TTM2T20NS1\x00\xa6\xe0\x91',
+ b'\xf1\x87LBKSGA0458404HG0vfvg\x87www\x89\x99\xa8\x99y\xaa\xa7\x9ax\x88\xa7\x88t_\xf9\xff\x86w\x8f\xff\x15x\xf1\x816W3C2051\x00\x00\xf1\x006W351_C2\x00\x006W3C2051\x00\x00TTM2T20NS1\x00\x00\x00\x00',
+ b'\xf1\x87LDJUEA6010814HG1\x87w\x87x\x86gvw\x88\x88\x98\x88gw\x86wx\x88\x97\x88\x85o\xf8\xff\x86f_\xff\xd37\xf1\x816W3C2051\x00\x00\xf1\x006W351_C2\x00\x006W3C2051\x00\x00TTM4T20NS0\xf8\x19\x92g',
+ b'\xf1\x87LDJUEA6458264HG1ww\x87x\x97x\x87\x88\x88\x99\x98\x89g\x88\x86xw\x88\x97x\x86o\xf7\xffvw\x8f\xff3\x9a\xf1\x816W3C2051\x00\x00\xf1\x006W351_C2\x00\x006W3C2051\x00\x00TTM4T20NS0\xf8\x19\x92g',
+ b'\xf1\x87LDKUEA2045844HG1wwww\x98\x88x\x87\x88\x88\xa8\x88x\x99\x97\x89x\x88\xa7\x88U\x7f\xf8\xffvfO\xffC\x1e\xf1\x816W3E0051\x00\x00\xf1\x006W351_C2\x00\x006W3E0051\x00\x00TTM4T20NS3\x00\x00\x00\x00',
+ b'\xf1\x87LDKUEA9993304HG1\x87www\x97x\x87\x88\x99\x99\xa9\x99x\x99\xa7\x89w\x88\x97x\x86_\xf7\xffwwO\xffl#\xf1\x816W3C2051\x00\x00\xf1\x006W351_C2\x00\x006W3C2051\x00\x00TTM4T20NS1R\x7f\x90\n',
+ b'\xf1\x87LDLUEA6061564HG1\xa9\x99\x89\x98\x87wwwx\x88\x97\x88x\x99\xa7\x89x\x99\xa7\x89sO\xf9\xffvU_\xff<\xde\xf1\x816W3E1051\x00\x00\xf1\x006W351_C2\x00\x006W3E1051\x00\x00TTM4T20NS50\xcb\xc3\xed',
+ b'\xf1\x87LDLUEA6159884HG1\x88\x87hv\x99\x99y\x97\x89\xaa\xb8\x9ax\x99\x87\x89y\x99\xb7\x99\xa7?\xf7\xff\x97wo\xff\xf3\x05\xf1\x816W3E1051\x00\x00\xf1\x006W351_C2\x00\x006W3E1051\x00\x00TTM4T20NS5\x00\x00\x00\x00',
+ b'\xf1\x87LDLUEA6852664HG1\x97wWu\x97www\x89\xaa\xc8\x9ax\x99\x97\x89x\x99\xa7\x89SO\xf7\xff\xa8\x88\x7f\xff\x03z\xf1\x816W3E1051\x00\x00\xf1\x006W351_C2\x00\x006W3E1051\x00\x00TTM4T20NS50\xcb\xc3\xed',
+ b'\xf1\x87LDLUEA6898374HG1fevW\x87wwwx\x88\x97\x88h\x88\x96\x88x\x88\xa7\x88ao\xf9\xff\x98\x99\x7f\xffD\xe2\xf1\x816W3E1051\x00\x00\xf1\x006W351_C2\x00\x006W3E1051\x00\x00TTM4T20NS5\x00\x00\x00\x00',
+ b'\xf1\x87LDLUEA6898374HG1fevW\x87wwwx\x88\x97\x88h\x88\x96\x88x\x88\xa7\x88ao\xf9\xff\x98\x99\x7f\xffD\xe2\xf1\x816W3E1051\x00\x00\xf1\x006W351_C2\x00\x006W3E1051\x00\x00TTM4T20NS50\xcb\xc3\xed',
+ b'\xf1\x87SBJWAA5842214GG0\x88\x87\x88xww\x87x\x89\x99\xa8\x99\x88\x99\x98\x89w\x88\x87xw_\xfa\xfffU_\xff\xd1\x8d\xf1\x816W3C2051\x00\x00\xf1\x006W351_C2\x00\x006W3C2051\x00\x00TTM2G24NS1\x98{|\xe3',
+ b'\xf1\x87SBJWAA5890864GG0\xa9\x99\x89\x98\x98\x87\x98y\x89\x99\xa8\x99w\x88\x87xww\x87wvo\xfb\xffuD_\xff\x9f\xb5\xf1\x816W3C2051\x00\x00\xf1\x006W351_C2\x00\x006W3C2051\x00\x00TTM2G24NS1\x98{|\xe3',
+ b'\xf1\x87SBJWAA6562474GG0ffvgeTeFx\x88\x97\x88ww\x87www\x87w\x84o\xfa\xff\x87fO\xff\xc2 \xf1\x816W3C2051\x00\x00\xf1\x006W351_C2\x00\x006W3C2051\x00\x00TTM2G24NS1\x00\x00\x00\x00',
+ b'\xf1\x87SBJWAA6562474GG0ffvgeTeFx\x88\x97\x88ww\x87www\x87w\x84o\xfa\xff\x87fO\xff\xc2 \xf1\x816W3C2051\x00\x00\xf1\x006W351_C2\x00\x006W3C2051\x00\x00TTM2G24NS1\x98{|\xe3',
+ b'\xf1\x87SBJWAA7780564GG0wvwgUUeVwwwwx\x88\x87\x88wwwwd_\xfc\xff\x86f\x7f\xff\xd7*\xf1\x816W3C2051\x00\x00\xf1\x006W351_C2\x00\x006W3C2051\x00\x00TTM2G24NS2F\x84<\xc0',
+ b'\xf1\x87SBJWAA8278284GG0ffvgUU\x85Xx\x88\x87\x88x\x88w\x88ww\x87w\x96o\xfd\xff\xa7U_\xff\xf2\xa0\xf1\x816W3C2051\x00\x00\xf1\x006W351_C2\x00\x006W3C2051\x00\x00TTM2G24NS2F\x84<\xc0',
+ b'\xf1\x87SBLWAA4363244GG0wvwgwv\x87hgw\x86ww\x88\x87xww\x87wdo\xfb\xff\x86f\x7f\xff3$\xf1\x816W3E1051\x00\x00\xf1\x006W351_C2\x00\x006W3E1051\x00\x00TTM2G24NS6\x00\x00\x00\x00',
+ b'\xf1\x87SBLWAA4363244GG0wvwgwv\x87hgw\x86ww\x88\x87xww\x87wdo\xfb\xff\x86f\x7f\xff3$\xf1\x816W3E1051\x00\x00\xf1\x006W351_C2\x00\x006W3E1051\x00\x00TTM2G24NS6x0\x17\xfe',
+ b'\xf1\x87SBLWAA4899564GG0VfvgUU\x85Xx\x88\x87\x88vfgf\x87wxwvO\xfb\xff\x97f\xb1\xffSB\xf1\x816W3E1051\x00\x00\xf1\x006W351_C2\x00\x006W3E1051\x00\x00TTM2G24NS7\x00\x00\x00\x00',
+ b'\xf1\x87SBLWAA6622844GG0wwwwff\x86hwwwwx\x88\x87\x88\x88\x88\x88\x88\x98?\xfd\xff\xa9\x88\x7f\xffn\xe5\xf1\x816W3E1051\x00\x00\xf1\x006W351_C2\x00\x006W3E1051\x00\x00TTM2G24NS7u\x1e{\x1c',
+ b'\xf1\x87SDJXAA7656854GG1DEtWUU\x85X\x88\x88\x98\x88w\x88\x87xx\x88\x87\x88\x96o\xfb\xff\x86f\x7f\xff.\xca\xf1\x816W3C2051\x00\x00\xf1\x006W351_C2\x00\x006W3C2051\x00\x00TTM4G24NS2\x00\x00\x00\x00',
+ b'\xf1\x87SDJXAA7656854GG1DEtWUU\x85X\x88\x88\x98\x88w\x88\x87xx\x88\x87\x88\x96o\xfb\xff\x86f\x7f\xff.\xca\xf1\x816W3C2051\x00\x00\xf1\x006W351_C2\x00\x006W3C2051\x00\x00TTM4G24NS2K\xdaV0',
+ b'\xf1\x87SDKXAA2443414GG1vfvgwv\x87h\x88\x88\x88\x88ww\x87wwwww\x99_\xfc\xffvD?\xffl\xd2\xf1\x816W3E1051\x00\x00\xf1\x006W351_C2\x00\x006W3E1051\x00\x00TTM4G24NS6\x00\x00\x00\x00',
+ ],
+ },
+ CAR.SANTA_FE_2022: {
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00TM__ SCC F-CUP 1.00 1.00 99110-S1500 ',
+ b'\xf1\x00TM__ SCC FHCUP 1.00 1.00 99110-S1500 ',
+ ],
+ (Ecu.abs, 0x7d1, None): [
+ b'\xf1\x00TM ESC \x01 102!\x04\x03 58910-S2DA0',
+ b'\xf1\x00TM ESC \x02 101 \x08\x04 58910-S2GA0',
+ b'\xf1\x00TM ESC \x02 103"\x07\x08 58910-S2GA0',
+ b'\xf1\x00TM ESC \x03 101 \x08\x02 58910-S2DA0',
+ b'\xf1\x00TM ESC \x04 101 \x08\x04 58910-S2GA0',
+ b'\xf1\x00TM ESC \x04 102!\x04\x05 58910-S2GA0',
+ b'\xf1\x00TM ESC 103!\x030 58910-S1MA0',
+ b'\xf1\x8758910-S1DA0\xf1\x00TM ESC \x1e 102 \x08\x08 58910-S1DA0',
+ b'\xf1\x8758910-S2DA0\xf1\x00TM ESC \x03 101 \x08\x02 58910-S2DA0',
+ b'\xf1\x8758910-S2GA0\xf1\x00TM ESC \x02 101 \x08\x04 58910-S2GA0',
+ b'\xf1\x8758910-S2GA0\xf1\x00TM ESC \x04 102!\x04\x05 58910-S2GA0',
+ ],
+ (Ecu.engine, 0x7e0, None): [
+ b'\xf1\x81HM6M1_0a0_G20',
+ b'\xf1\x81HM6M1_0a0_H00',
+ b'\xf1\x81HM6M2_0a0_G00',
+ b'\xf1\x82TACVN5GMI3XXXH0A',
+ b'\xf1\x82TACVN5GSI3XXXH0A',
+ b'\xf1\x82TMBZN5TMD3XXXG2E',
+ b'\xf1\x82TMCFD5MMCXXXXG0A',
+ b'\xf1\x87 \xf1\x81 ',
+ b'\xf1\x870\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x81HM6M1_0a0_J10',
+ b'\xf1\x870\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x81HM6M1_0a0_L50',
+ b'\xf1\x870\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x82TMDWN5TMD3TXXJ1A',
+ b'\xf1\x8739101-2STN8\xf1\x81HM6M1_0a0_M00',
+ ],
+ (Ecu.eps, 0x7d4, None): [
+ b'\xf1\x00TM MDPS C 1.00 1.01 56310-S1AB0 4TSDC101',
+ b'\xf1\x00TM MDPS C 1.00 1.01 56310-S1EB0 4TSDC101',
+ b'\xf1\x00TM MDPS C 1.00 1.02 56370-S2AA0 0B19',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00TM MFC AT EUR LHD 1.00 1.03 99211-S1500 210224',
+ b'\xf1\x00TM MFC AT MES LHD 1.00 1.05 99211-S1500 220126',
+ b'\xf1\x00TMA MFC AT MEX LHD 1.00 1.01 99211-S2500 210205',
+ b'\xf1\x00TMA MFC AT USA LHD 1.00 1.00 99211-S2500 200720',
+ b'\xf1\x00TMA MFC AT USA LHD 1.00 1.01 99211-S2500 210205',
+ b'\xf1\x00TMA MFC AT USA LHD 1.00 1.03 99211-S2500 220414',
+ ],
+ (Ecu.transmission, 0x7e1, None): [
+ b'\xf1\x00HT6TA290BLHT6TAF00A1STM0M25GS1\x00\x00\x00\x00\x00\x006\xd8\x97\x15',
+ b'\xf1\x00HT6WA280BLHT6WAD00A1STM2G25NH2\x00\x00\x00\x00\x00\x00\xf8\xc0\xc3\xaa',
+ b'\xf1\x00HT6WA280BLHT6WAD00A1STM4G25NH1\x00\x00\x00\x00\x00\x00\x9cl\x04\xbc',
+ b'\xf1\x00T02601BL T02730A1 VTMPT25XXX730NS2\xa6\x06\x88\xf7',
+ b'\xf1\x00T02601BL T02800A1 VTMPT25XXX800NS4\xed\xaf\xed\xf5',
+ b'\xf1\x00T02601BL T02900A1 VTMPT25XXW900NS1c\x918\xc5',
+ b'\xf1\x00T02601BL T02900A1 VTMPT25XXX900NS8\xb7\xaa\xfe\xfc',
+ b'\xf1\x00T02601BL T02900A1 VTMPT25XXX900NSA\xf3\xf4Uj',
+ b'\xf1\x87954A02N250\x00\x00\x00\x00\x00\xf1\x81T02730A1 \xf1\x00T02601BL T02730A1 VTMPT25XXX730NS2\xa6',
+ b'\xf1\x87954A02N250\x00\x00\x00\x00\x00\xf1\x81T02730A1 \xf1\x00T02601BL T02730A1 VTMPT25XXX730NS2\xa6\x06\x88\xf7',
+ b'\xf1\x87954A02N250\x00\x00\x00\x00\x00\xf1\x81T02900A1 \xf1\x00T02601BL T02900A1 VTMPT25XXX900NS8\xb7\xaa\xfe\xfc',
+ b'\xf1\x87KMMYBU034207SB72x\x89\x88\x98h\x88\x98\x89\x87fhvvfWf33_\xff\x87\xff\x8f\xfa\x81\xe5\xf1\x89HT6TAF00A1\xf1\x82STM0M25GS1\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x87SDMXCA8653204GN1EVugEUuWwwwwww\x87wwwwwv/\xfb\xff\xa8\x88\x9f\xff\xa5\x9c\xf1\x89HT6WAD00A1\xf1\x82STM4G25NH1\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x87SDMXCA9087684GN1VfvgUUeVwwgwwwwwffffU?\xfb\xff\x97\x88\x7f\xff+\xa4\xf1\x89HT6WAD00A1\xf1\x82STM4G25NH1\x00\x00\x00\x00\x00\x00',
+ ],
+ },
+ CAR.SANTA_FE_HEV_2022: {
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00TMhe SCC FHCUP 1.00 1.00 99110-CL500 ',
+ ],
+ (Ecu.eps, 0x7d4, None): [
+ b'\xf1\x00TM MDPS C 1.00 1.02 56310-CLAC0 4TSHC102',
+ b'\xf1\x00TM MDPS C 1.00 1.02 56310-CLEC0 4TSHC102',
+ b'\xf1\x00TM MDPS C 1.00 1.02 56310-GA000 4TSHA100',
+ b'\xf1\x00TM MDPS R 1.00 1.05 57700-CL000 4TSHP105',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00TMA MFC AT USA LHD 1.00 1.03 99211-S2500 220414',
+ b'\xf1\x00TMH MFC AT EUR LHD 1.00 1.06 99211-S1500 220727',
+ b'\xf1\x00TMH MFC AT USA LHD 1.00 1.03 99211-S1500 210224',
+ b'\xf1\x00TMH MFC AT USA LHD 1.00 1.06 99211-S1500 220727',
+ ],
+ (Ecu.transmission, 0x7e1, None): [
+ b'\xf1\x00PSBG2333 E16\x00\x00\x00\x00\x00\x00\x00TTM2H16SA3\xa3\x1b\xe14',
+ b'\xf1\x00PSBG2333 E16\x00\x00\x00\x00\x00\x00\x00TTM2H16UA3I\x94\xac\x8f',
+ b'\xf1\x87959102T250\x00\x00\x00\x00\x00\xf1\x81E14\x00\x00\x00\x00\x00\x00\x00\xf1\x00PSBG2333 E14\x00\x00\x00\x00\x00\x00\x00TTM2H16SA2\x80\xd7l\xb2',
+ ],
+ (Ecu.engine, 0x7e0, None): [
+ b'\xf1\x87391312MTC1',
+ b'\xf1\x87391312MTE0',
+ b'\xf1\x87391312MTL0',
+ ],
+ },
+ CAR.SANTA_FE_PHEV_2022: {
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00TMhe SCC FHCUP 1.00 1.01 99110-CL500 ',
+ b'\xf1\x8799110CL500\xf1\x00TMhe SCC FHCUP 1.00 1.00 99110-CL500 ',
+ ],
+ (Ecu.eps, 0x7d4, None): [
+ b'\xf1\x00TM MDPS C 1.00 1.02 56310-CLAC0 4TSHC102',
+ b'\xf1\x00TM MDPS C 1.00 1.02 56310-CLEC0 4TSHC102',
+ b'\xf1\x00TM MDPS C 1.00 1.02 56310CLEC0\x00 4TSHC102',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00TMP MFC AT USA LHD 1.00 1.03 99211-S1500 210224',
+ b'\xf1\x00TMP MFC AT USA LHD 1.00 1.06 99211-S1500 220727',
+ ],
+ (Ecu.transmission, 0x7e1, None): [
+ b'\xf1\x00PSBG2333 E16\x00\x00\x00\x00\x00\x00\x00TTM2P16SA1\x0b\xc5\x0f\xea',
+ b'\xf1\x8795441-3D121\x00\xf1\x81E16\x00\x00\x00\x00\x00\x00\x00\xf1\x00PSBG2333 E16\x00\x00\x00\x00\x00\x00\x00TTM2P16SA0o\x88^\xbe',
+ b'\xf1\x8795441-3D121\x00\xf1\x81E16\x00\x00\x00\x00\x00\x00\x00\xf1\x00PSBG2333 E16\x00\x00\x00\x00\x00\x00\x00TTM2P16SA1\x0b\xc5\x0f\xea',
+ ],
+ (Ecu.engine, 0x7e0, None): [
+ b'\xf1\x87391312MTF0',
+ b'\xf1\x87391312MTF1',
+ ],
+ },
+ CAR.CUSTIN_1ST_GEN: {
+ (Ecu.abs, 0x7d1, None): [
+ b'\xf1\x00KU ESC \x01 101!\x02\x03 58910-O3200',
+ ],
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00KU__ SCC F-CUP 1.00 1.01 99110-O3000 ',
+ ],
+ (Ecu.eps, 0x7d4, None): [
+ b'\xf1\x00KU MDPS C 1.00 1.01 56310/O3100 4KUCC101',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00KU2 MFC AT CHN LHD 1.00 1.02 99211-O3000 220923',
+ ],
+ (Ecu.engine, 0x7e0, None): [
+ b'\xf1\x87391212MEC0',
+ ],
+ (Ecu.transmission, 0x7e1, None): [
+ b'\xf1\x00bcsh8p54 U928\x00\x00\x00\x00\x00\x00SKU0T15KB2\x92U\xf9M',
+ ],
+ },
+ CAR.KIA_STINGER: {
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00CK__ SCC F_CUP 1.00 1.01 96400-J5000 ',
+ b'\xf1\x00CK__ SCC F_CUP 1.00 1.01 96400-J5100 ',
+ b'\xf1\x00CK__ SCC F_CUP 1.00 1.02 96400-J5100 ',
+ b'\xf1\x00CK__ SCC F_CUP 1.00 1.03 96400-J5100 ',
+ ],
+ (Ecu.engine, 0x7e0, None): [
+ b'\xe0\x19\xff\xe7\xe7g\x01\xa2\x00\x0f\x00\x9e\x00\x06\x00\xff\xff\xff\xff\xff\xff\x00\x00\xff\xff\xff\xff\xff\xff\x00\x00\x0f\x0e\x0f\x0f\x0e\r\x00\x00\x7f\x02.\xff\x00\x00~p\x00\x00\x00\x00u\xff\xf9\xff\x00\x00\x00\x00V\t\xd5\x01\xc0\x00\x00\x00\x007\xfb\xfc\x0b\x8d\x00',
+ b'\xf1\x81606DE051\x00\x00\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x81640E0051\x00\x00\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x81640H0051\x00\x00\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x82CKJN3TMSDE0B\x00\x00\x00\x00',
+ b'\xf1\x82CKKN3TMD_H0A\x00\x00\x00\x00',
+ ],
+ (Ecu.eps, 0x7d4, None): [
+ b'\xf1\x00CK MDPS R 1.00 1.04 57700-J5200 4C2CL104',
+ b'\xf1\x00CK MDPS R 1.00 1.04 57700-J5220 4C2VL104',
+ b'\xf1\x00CK MDPS R 1.00 1.04 57700-J5420 4C4VL104',
+ b'\xf1\x00CK MDPS R 1.00 1.06 57700-J5220 4C2VL106',
+ b'\xf1\x00CK MDPS R 1.00 1.06 57700-J5420 4C4VL106',
+ b'\xf1\x00CK MDPS R 1.00 1.07 57700-J5220 4C2VL107',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00CK MFC AT EUR LHD 1.00 1.03 95740-J5000 170822',
+ b'\xf1\x00CK MFC AT USA LHD 1.00 1.03 95740-J5000 170822',
+ b'\xf1\x00CK MFC AT USA LHD 1.00 1.04 95740-J5000 180504',
+ ],
+ (Ecu.transmission, 0x7e1, None): [
+ b'\xf1\x00bcsh8p54 E21\x00\x00\x00\x00\x00\x00\x00SCK0T33NB0\t\xb7\x17\xf5',
+ b'\xf1\x00bcsh8p54 E21\x00\x00\x00\x00\x00\x00\x00SCK0T33NB0\x88\xa2\xe6\xf0',
+ b'\xf1\x00bcsh8p54 E25\x00\x00\x00\x00\x00\x00\x00SCK0T33NB2\xb3\xee\xba\xdc',
+ b'\xf1\x87VCJLE17622572DK0vd6D\x99\x98y\x97vwVffUfvfC%CuT&Dx\x87o\xff{\x1c\xf1\x81E21\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E21\x00\x00\x00\x00\x00\x00\x00SCK0T33NB0\x88\xa2\xe6\xf0',
+ b'\xf1\x87VDHLG17000192DK2xdFffT\xa5VUD$DwT\x86wveVeeD&T\x99\xba\x8f\xff\xcc\x99\xf1\x81E21\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E21\x00\x00\x00\x00\x00\x00\x00SCK0T33NB0\t\xb7\x17\xf5',
+ b'\xf1\x87VDHLG17000192DK2xdFffT\xa5VUD$DwT\x86wveVeeD&T\x99\xba\x8f\xff\xcc\x99\xf1\x81E21\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E21\x00\x00\x00\x00\x00\x00\x00SCK0T33NB0\x88\xa2\xe6\xf0',
+ b'\xf1\x87VDHLG17000192DK2xdFffT\xa5VUD$DwT\x86wveVeeD&T\x99\xba\x8f\xff\xcc\x99\xf1\x89E21\x00\x00\x00\x00\x00\x00\x00\xf1\x82SCK0T33NB0',
+ b'\xf1\x87VDHLG17034412DK2vD6DfVvVTD$D\x99w\x88\x98EDEDeT6DgfO\xff\xc3=\xf1\x81E21\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E21\x00\x00\x00\x00\x00\x00\x00SCK0T33NB0\x88\xa2\xe6\xf0',
+ b'\xf1\x87VDHLG17118862DK2\x8awWwgu\x96wVfUVwv\x97xWvfvUTGTx\x87o\xff\xc9\xed\xf1\x81E21\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E21\x00\x00\x00\x00\x00\x00\x00SCK0T33NB0\x88\xa2\xe6\xf0',
+ b'\xf1\x87VDHLG17274082DK2wfFf\x89x\x98wUT5T\x88v\x97xgeGefTGTVvO\xff\x1c\x14\xf1\x81E19\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E19\x00\x00\x00\x00\x00\x00\x00SCK0T33UB2\xee[\x97S',
+ b'\xf1\x87VDKLJ18675252DK6\x89vhgwwwwveVU\x88w\x87w\x99vgf\x97vXfgw_\xff\xc2\xfb\xf1\x89E25\x00\x00\x00\x00\x00\x00\x00\xf1\x82TCK0T33NB2',
+ b'\xf1\x87WAJTE17552812CH4vfFffvfVeT5DwvvVVdFeegeg\x88\x88o\xff\x1a]\xf1\x81E21\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E21\x00\x00\x00\x00\x00\x00\x00TCK2T20NB1\x19\xd2\x00\x94',
+ ],
+ },
+ CAR.KIA_STINGER_2022: {
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00CK__ SCC F-CUP 1.00 1.00 99110-J5500 ',
+ b'\xf1\x00CK__ SCC FHCUP 1.00 1.00 99110-J5500 ',
+ b'\xf1\x00CK__ SCC FHCUP 1.00 1.00 99110-J5600 ',
+ b'\xf1\x00CK__ SCC FHCUP 1.00 1.01 99110-J5100 ',
+ ],
+ (Ecu.engine, 0x7e0, None): [
+ b'\xf1\x81640N2051\x00\x00\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x81640R0051\x00\x00\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x81HM6M1_0a0_H00',
+ ],
+ (Ecu.eps, 0x7d4, None): [
+ b'\xf1\x00CK MDPS R 1.00 5.03 57700-J5300 4C2CL503',
+ b'\xf1\x00CK MDPS R 1.00 5.03 57700-J5320 4C2VL503',
+ b'\xf1\x00CK MDPS R 1.00 5.03 57700-J5380 4C2VR503',
+ b'\xf1\x00CK MDPS R 1.00 5.04 57700-J5520 4C4VL504',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00CK MFC AT AUS RHD 1.00 1.00 99211-J5500 210622',
+ b'\xf1\x00CK MFC AT KOR LHD 1.00 1.00 99211-J5500 210622',
+ b'\xf1\x00CK MFC AT USA LHD 1.00 1.00 99211-J5500 210622',
+ b'\xf1\x00CK MFC AT USA LHD 1.00 1.03 99211-J5000 201209',
+ ],
+ (Ecu.transmission, 0x7e1, None): [
+ b'\xf1\x00bcsh8p54 E31\x00\x00\x00\x00\x00\x00\x00SCK0T25KH2B\xfbI\xe2',
+ b'\xf1\x00bcsh8p54 E31\x00\x00\x00\x00\x00\x00\x00SCK0T33NH07\xdf\xf0\xc1',
+ b'\xf1\x00bcsh8p54 E31\x00\x00\x00\x00\x00\x00\x00TCK0T33NH0%g~\xd3',
+ b'\xf1\x87VCNLF11383972DK1vffV\x99\x99\x89\x98\x86eUU\x88wg\x89vfff\x97fff\x99\x87o\xff"\xc1\xf1\x81E30\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E30\x00\x00\x00\x00\x00\x00\x00SCK0T33GH0\xbe`\xfb\xc6',
+ ],
+ },
+ CAR.PALISADE: {
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00LX2 SCC FHCUP 1.00 1.04 99110-S8100 ',
+ b'\xf1\x00LX2_ SCC F-CUP 1.00 1.04 99110-S8100 ',
+ b'\xf1\x00LX2_ SCC F-CUP 1.00 1.05 99110-S8100 ',
+ b'\xf1\x00LX2_ SCC FHCU- 1.00 1.05 99110-S8100 ',
+ b'\xf1\x00LX2_ SCC FHCUP 1.00 1.00 99110-S8110 ',
+ b'\xf1\x00LX2_ SCC FHCUP 1.00 1.04 99110-S8100 ',
+ b'\xf1\x00LX2_ SCC FHCUP 1.00 1.05 99110-S8100 ',
+ b'\xf1\x00ON__ FCA FHCUP 1.00 1.01 99110-S9110 ',
+ b'\xf1\x00ON__ FCA FHCUP 1.00 1.02 99110-S9100 ',
+ ],
+ (Ecu.abs, 0x7d1, None): [
+ b'\xf1\x00LX ESC \x01 103\x19\t\x10 58910-S8360',
+ b'\xf1\x00LX ESC \x01 1031\t\x10 58910-S8360',
+ b'\xf1\x00LX ESC \x0b 101\x19\x03\x17 58910-S8330',
+ b'\xf1\x00LX ESC \x0b 102\x19\x05\x07 58910-S8330',
+ b'\xf1\x00LX ESC \x0b 103\x19\t\x07 58910-S8330',
+ b'\xf1\x00LX ESC \x0b 103\x19\t\t 58910-S8350',
+ b'\xf1\x00LX ESC \x0b 103\x19\t\x10 58910-S8360',
+ b'\xf1\x00LX ESC \x0b 104 \x10\x16 58910-S8360',
+ b'\xf1\x00ON ESC \x01 101\x19\t\x08 58910-S9360',
+ b'\xf1\x00ON ESC \x0b 100\x18\x12\x18 58910-S9360',
+ b'\xf1\x00ON ESC \x0b 101\x19\t\x05 58910-S9320',
+ b'\xf1\x00ON ESC \x0b 101\x19\t\x08 58910-S9360',
+ ],
+ (Ecu.engine, 0x7e0, None): [
+ b'\xf1\x81640J0051\x00\x00\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x81640K0051\x00\x00\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x81640S1051\x00\x00\x00\x00\x00\x00\x00\x00',
+ ],
+ (Ecu.eps, 0x7d4, None): [
+ b'\xf1\x00LX2 MDPS C 1,00 1,03 56310-S8020 4LXDC103',
+ b'\xf1\x00LX2 MDPS C 1.00 1.03 56310-S8000 4LXDC103',
+ b'\xf1\x00LX2 MDPS C 1.00 1.03 56310-S8020 4LXDC103',
+ b'\xf1\x00LX2 MDPS C 1.00 1.04 56310-S8020 4LXDC104',
+ b'\xf1\x00ON MDPS C 1.00 1.00 56340-S9000 8B13',
+ b'\xf1\x00ON MDPS C 1.00 1.01 56340-S9000 9201',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00LX2 MFC AT USA LHD 1.00 1.00 99211-S8110 210226',
+ b'\xf1\x00LX2 MFC AT USA LHD 1.00 1.03 99211-S8100 190125',
+ b'\xf1\x00LX2 MFC AT USA LHD 1.00 1.05 99211-S8100 190909',
+ b'\xf1\x00LX2 MFC AT USA LHD 1.00 1.07 99211-S8100 200422',
+ b'\xf1\x00LX2 MFC AT USA LHD 1.00 1.08 99211-S8100 200903',
+ b'\xf1\x00ON MFC AT USA LHD 1.00 1.01 99211-S9100 181105',
+ b'\xf1\x00ON MFC AT USA LHD 1.00 1.03 99211-S9100 200720',
+ b'\xf1\x00ON MFC AT USA LHD 1.00 1.04 99211-S9100 211227',
+ ],
+ (Ecu.transmission, 0x7e1, None): [
+ b'\xf1\x00bcsh8p54 U872\x00\x00\x00\x00\x00\x00TON4G38NB1\x96z28',
+ b'\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX4G38NB3X\xa8\xc08',
+ b'\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00TON4G38NB2[v\\\xb6',
+ b'\xf1\x00bcsh8p54 U922\x00\x00\x00\x00\x00\x00TON2G38NB5j\x94.\xde',
+ b'\xf1\x87LBLUFN591307KF25vgvw\x97wwwy\x99\xa7\x99\x99\xaa\xa9\x9af\x88\x96h\x95o\xf7\xff\x99f/\xff\xe4c\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX2G38NB2\xd7\xc1/\xd1',
+ b"\xf1\x87LBLUFN622950KF36\xa8\x88\x88\x88\x87w\x87xh\x99\x96\x89\x88\x99\x98\x89\x88\x99\x98\x89\x87o\xf6\xff\x98\x88o\xffx'\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX2G38NB3\xd1\xc3\xf8\xa8",
+ b'\xf1\x87LBLUFN650868KF36\xa9\x98\x89\x88\xa8\x88\x88\x88h\x99\xa6\x89fw\x86gw\x88\x97x\xaa\x7f\xf6\xff\xbb\xbb\x8f\xff+\x82\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX2G38NB3\xd1\xc3\xf8\xa8',
+ b'\xf1\x87LBLUFN655162KF36\x98\x88\x88\x88\x98\x88\x88\x88x\x99\xa7\x89x\x99\xa7\x89x\x99\x97\x89g\x7f\xf7\xffwU_\xff\xe9!\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX2G38NB3\xd1\xc3\xf8\xa8',
+ b'\xf1\x87LBLUFN731381KF36\xb9\x99\x89\x98\x98\x88\x88\x88\x89\x99\xa8\x99\x88\x99\xa8\x89\x88\x88\x98\x88V\x7f\xf6\xff\x99w\x8f\xff\xad\xd8\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX2G38NB3\xd1\xc3\xf8\xa8',
+ b'\xf1\x87LDKVAA0028604HH1\xa8\x88x\x87vgvw\x88\x99\xa8\x89gw\x86ww\x88\x97x\x97o\xf9\xff\x97w\x7f\xffo\x02\xf1\x81U872\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U872\x00\x00\x00\x00\x00\x00TON4G38NB1\x96z28',
+ b'\xf1\x87LDKVAA3068374HH1wwww\x87xw\x87y\x99\xa7\x99w\x88\x87xw\x88\x97x\x85\xaf\xfa\xffvU/\xffU\xdc\xf1\x81U872\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U872\x00\x00\x00\x00\x00\x00TON4G38NB1\x96z28',
+ b'\xf1\x87LDKVBN382172KF26\x98\x88\x88\x88\xa8\x88\x88\x88x\x99\xa7\x89\x87\x88\x98x\x98\x99\xa9\x89\xa5_\xf6\xffDDO\xff\xcd\x16\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX4G38NB2\xafL]\xe7',
+ b'\xf1\x87LDKVBN424201KF26\xba\xaa\x9a\xa9\x99\x99\x89\x98\x89\x99\xa8\x99\x88\x99\x98\x89\x88\x99\xa8\x89v\x7f\xf7\xffwf_\xffq\xa6\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX4G38NB2\xafL]\xe7',
+ b'\xf1\x87LDKVBN540766KF37\x87wgv\x87w\x87xx\x99\x97\x89v\x88\x97h\x88\x88\x88\x88x\x7f\xf6\xffvUo\xff\xd3\x01\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX4G38NB2\xafL]\xe7',
+ b'\xf1\x87LDLVAA4225634HH1\x98\x88\x88\x88eUeVx\x88\x87\x88g\x88\x86xx\x88\x87\x88\x86o\xf9\xff\x87w\x7f\xff\xf2\xf7\xf1\x81U903\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00TON4G38NB2[v\\\xb6',
+ b'\xf1\x87LDLVAA4478824HH1\x87wwwvfvg\x89\x99\xa8\x99w\x88\x87x\x89\x99\xa8\x99\xa6o\xfa\xfffU/\xffu\x92\xf1\x81U903\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00TON4G38NB2[v\\\xb6',
+ b'\xf1\x87LDLVAA4777834HH1\x98\x88x\x87\x87wwwx\x88\x87\x88x\x99\x97\x89x\x88\x97\x88\x86o\xfa\xff\x86fO\xff\x1d9\xf1\x81U903\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00TON4G38NB2[v\\\xb6',
+ b'\xf1\x87LDLVAA5194534HH1ffvguUUUx\x88\xa7\x88h\x99\x96\x89x\x88\x97\x88ro\xf9\xff\x98wo\xff\xaaM\xf1\x81U903\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00TON4G38NB2[v\\\xb6',
+ b'\xf1\x87LDLVAA5949924HH1\xa9\x99y\x97\x87wwwx\x99\x97\x89x\x99\xa7\x89x\x99\xa7\x89\x87_\xfa\xffeD?\xff\xf1\xfd\xf1\x81U903\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00TON4G38NB2[v\\\xb6',
+ b'\xf1\x87LDLVBN560098KF26\x86fff\x87vgfg\x88\x96xfw\x86gfw\x86g\x95\xf6\xffeU_\xff\x92c\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX4G38NB2\xafL]\xe7',
+ b'\xf1\x87LDLVBN602045KF26\xb9\x99\x89\x98\x97vwgy\xaa\xb7\x9af\x88\x96hw\x99\xa7y\xa9\x7f\xf5\xff\x99w\x7f\xff,\xd3\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX4G38NB3X\xa8\xc08',
+ b'\xf1\x87LDLVBN628911KF26\xa9\x99\x89\x98\x98\x88\x88\x88y\x99\xa7\x99fw\x86gw\x88\x87x\x83\x7f\xf6\xff\x98wo\xff2\xda\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX4G38NB3X\xa8\xc08',
+ b'\xf1\x87LDLVBN645817KF37\x87www\x98\x87xwx\x99\x97\x89\x99\x99\x99\x99g\x88\x96x\xb6_\xf7\xff\x98fo\xff\xe2\x86\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX4G38NB3X\xa8\xc08',
+ b'\xf1\x87LDLVBN662115KF37\x98\x88\x88\x88\xa8\x88\x88\x88x\x99\x97\x89x\x99\xa7\x89\x88\x99\xa8\x89\x88\x7f\xf7\xfffD_\xff\xdc\x84\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX4G38NB3X\xa8\xc08',
+ b'\xf1\x87LDLVBN667933KF37\xb9\x99\x89\x98\xb9\x99\x99\x99x\x88\x87\x88w\x88\x87x\x88\x88\x98\x88\xcbo\xf7\xffe3/\xffQ!\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX4G38NB3X\xa8\xc08',
+ b'\xf1\x87LDLVBN673087KF37\x97www\x86fvgx\x99\x97\x89\x99\xaa\xa9\x9ag\x88\x86x\xe9_\xf8\xff\x98w\x7f\xff"\xad\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX4G38NB3X\xa8\xc08',
+ b'\xf1\x87LDLVBN673841KF37\x98\x88x\x87\x86g\x86xy\x99\xa7\x99\x88\x99\xa8\x89w\x88\x97xdo\xf5\xff\x98\x88\x8f\xffT\xec\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX4G38NB3X\xa8\xc08',
+ b'\xf1\x87LDLVBN681363KF37\x98\x88\x88\x88\x97x\x87\x88y\xaa\xa7\x9a\x88\x88\x98\x88\x88\x88\x88\x88vo\xf6\xffvD\x7f\xff%v\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX4G38NB3X\xa8\xc08',
+ b'\xf1\x87LDLVBN713782KF37\x99\x99y\x97\x98\x88\x88\x88x\x88\x97\x88\x88\x99\x98\x89\x88\x99\xa8\x89\x87o\xf7\xffeU?\xff7,\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX4G38NB3X\xa8\xc08',
+ b'\xf1\x87LDLVBN713890KF26\xb9\x99\x89\x98\xa9\x99\x99\x99x\x99\x97\x89\x88\x99\xa8\x89\x88\x99\xb8\x89Do\xf7\xff\xa9\x88o\xffs\r\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX4G38NB3X\xa8\xc08',
+ b'\xf1\x87LDLVBN733215KF37\x99\x98y\x87\x97wwwi\x99\xa6\x99x\x99\xa7\x89V\x88\x95h\x86o\xf7\xffeDO\xff\x12\xe7\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX4G38NB3X\xa8\xc08',
+ b'\xf1\x87LDLVBN750044KF37\xca\xa9\x8a\x98\xa7wwwy\xaa\xb7\x9ag\x88\x96x\x88\x99\xa8\x89\xb9\x7f\xf6\xff\xa8w\x7f\xff\xbe\xde\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX4G38NB3X\xa8\xc08',
+ b'\xf1\x87LDLVBN752612KF37\xba\xaa\x8a\xa8\x87w\x87xy\xaa\xa7\x9a\x88\x99\x98\x89x\x88\x97\x88\x96o\xf6\xffvU_\xffh\x1b\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX4G38NB3X\xa8\xc08',
+ b'\xf1\x87LDLVBN755553KF37\x87xw\x87\x97w\x87xy\x99\xa7\x99\x99\x99\xa9\x99Vw\x95gwo\xf6\xffwUO\xff\xb5T\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX4G38NB3X\xa8\xc08',
+ b'\xf1\x87LDLVBN757883KF37\x98\x87xw\x98\x87\x88xy\xaa\xb7\x9ag\x88\x96x\x89\x99\xa8\x99e\x7f\xf6\xff\xa9\x88o\xff5\x15\xf1\x81U922\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U922\x00\x00\x00\x00\x00\x00SLX4G38NB4\xd6\xe8\xd7\xa6',
+ b'\xf1\x87LDMVBN778156KF37\x87vWe\xa9\x99\x99\x99y\x99\xb7\x99\x99\x99\x99\x99x\x99\x97\x89\xa8\x7f\xf8\xffwf\x7f\xff\x82_\xf1\x81U922\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U922\x00\x00\x00\x00\x00\x00SLX4G38NB4\xd6\xe8\xd7\xa6',
+ b'\xf1\x87LDMVBN780576KF37\x98\x87hv\x97x\x97\x89x\x99\xa7\x89\x88\x99\x98\x89w\x88\x97x\x98\x7f\xf7\xff\xba\x88\x8f\xff\x1e0\xf1\x81U922\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U922\x00\x00\x00\x00\x00\x00SLX4G38NB4\xd6\xe8\xd7\xa6',
+ b'\xf1\x87LDMVBN783485KF37\x87www\x87vwgy\x99\xa7\x99\x99\x99\xa9\x99Vw\x95g\x89_\xf6\xff\xa9w_\xff\xc5\xd6\xf1\x81U922\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U922\x00\x00\x00\x00\x00\x00SLX4G38NB4\xd6\xe8\xd7\xa6',
+ b'\xf1\x87LDMVBN811844KF37\x87vwgvfffx\x99\xa7\x89Vw\x95gg\x88\xa6xe\x8f\xf6\xff\x97wO\xff\t\x80\xf1\x81U922\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U922\x00\x00\x00\x00\x00\x00SLX4G38NB4\xd6\xe8\xd7\xa6',
+ b'\xf1\x87LDMVBN830601KF37\xa7www\xa8\x87xwx\x99\xa7\x89Uw\x85Ww\x88\x97x\x88o\xf6\xff\x8a\xaa\x7f\xff\xe2:\xf1\x81U922\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U922\x00\x00\x00\x00\x00\x00SLX4G38NB4\xd6\xe8\xd7\xa6',
+ b'\xf1\x87LDMVBN848789KF37\x87w\x87x\x87w\x87xy\x99\xb7\x99\x87\x88\x98x\x88\x99\xa8\x89\x87\x7f\xf6\xfffUo\xff\xe3!\xf1\x81U922\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U922\x00\x00\x00\x00\x00\x00SLX4G38NB5\xb9\x94\xe8\x89',
+ b'\xf1\x87LDMVBN851595KF37\x97wgvvfffx\x99\xb7\x89\x88\x99\x98\x89\x87\x88\x98x\x99\x7f\xf7\xff\x97w\x7f\xff@\xf3\xf1\x81U922\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U922\x00\x00\x00\x00\x00\x00SLX4G38NB5\xb9\x94\xe8\x89',
+ b'\xf1\x87LDMVBN871852KF37\xb9\x99\x99\x99\xa8\x88\x88\x88y\x99\xa7\x99x\x99\xa7\x89\x88\x88\x98\x88\x89o\xf7\xff\xaa\x88o\xff\x0e\xed\xf1\x81U922\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U922\x00\x00\x00\x00\x00\x00SLX4G38NB5\xb9\x94\xe8\x89',
+ b'\xf1\x87LDMVBN873175KF26\xa8\x88\x88\x88vfVex\x99\xb7\x89\x88\x99\x98\x89x\x88\x97\x88f\x7f\xf7\xff\xbb\xaa\x8f\xff,\x04\xf1\x81U922\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U922\x00\x00\x00\x00\x00\x00SLX4G38NB5\xb9\x94\xe8\x89',
+ b'\xf1\x87LDMVBN879401KF26veVU\xa8\x88\x88\x88g\x88\xa6xVw\x95gx\x88\xa7\x88v\x8f\xf9\xff\xdd\xbb\xbf\xff\xb3\x99\xf1\x81U922\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U922\x00\x00\x00\x00\x00\x00SLX4G38NB5\xb9\x94\xe8\x89',
+ b'\xf1\x87LDMVBN881314KF37\xa8\x88h\x86\x97www\x89\x99\xa8\x99w\x88\x97xx\x99\xa7\x89\xca\x7f\xf8\xff\xba\x99\x8f\xff\xd8v\xf1\x81U922\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U922\x00\x00\x00\x00\x00\x00SLX4G38NB5\xb9\x94\xe8\x89',
+ b'\xf1\x87LDMVBN888651KF37\xa9\x99\x89\x98vfff\x88\x99\x98\x89w\x99\xa7y\x88\x88\x98\x88D\x8f\xf9\xff\xcb\x99\x8f\xff\xa5\x1e\xf1\x81U922\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U922\x00\x00\x00\x00\x00\x00SLX4G38NB5\xb9\x94\xe8\x89',
+ b'\xf1\x87LDMVBN889419KF37\xa9\x99y\x97\x87w\x87xx\x88\x97\x88w\x88\x97x\x88\x99\x98\x89e\x9f\xf9\xffeUo\xff\x901\xf1\x81U922\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U922\x00\x00\x00\x00\x00\x00SLX4G38NB5\xb9\x94\xe8\x89',
+ b'\xf1\x87LDMVBN895969KF37vefV\x87vgfx\x99\xa7\x89\x99\x99\xb9\x99f\x88\x96he_\xf7\xffxwo\xff\x14\xf9\xf1\x81U922\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U922\x00\x00\x00\x00\x00\x00SLX4G38NB5\xb9\x94\xe8\x89',
+ b'\xf1\x87LDMVBN899222KF37\xa8\x88x\x87\x97www\x98\x99\x99\x89\x88\x99\x98\x89f\x88\x96hdo\xf7\xff\xbb\xaa\x9f\xff\xe2U\xf1\x81U922\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U922\x00\x00\x00\x00\x00\x00SLX4G38NB5\xb9\x94\xe8\x89',
+ b'\xf1\x87LDMVBN950669KF37\x97www\x96fffy\x99\xa7\x99\xa9\x99\xaa\x99g\x88\x96x\xb8\x8f\xf9\xffTD/\xff\xa7\xcb\xf1\x81U922\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U922\x00\x00\x00\x00\x00\x00SLX4G38NB5\xb9\x94\xe8\x89',
+ ],
+ },
+ CAR.VELOSTER: {
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00JS__ SCC H-CUP 1.00 1.02 95650-J3200 ',
+ b'\xf1\x00JS__ SCC HNCUP 1.00 1.02 95650-J3100 ',
+ ],
+ (Ecu.abs, 0x7d1, None): [
+ b'\xf1\x00\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x816V8RAC00121.ELF\xf1\x00\x00\x00\x00\x00\x00\x00',
+ ],
+ (Ecu.engine, 0x7e0, None): [
+ b'\x01TJS-JDK06F200H0A',
+ b'\x01TJS-JNU06F200H0A',
+ b'391282BJF5 ',
+ ],
+ (Ecu.eps, 0x7d4, None): [
+ b'\xf1\x00JSL MDPS C 1.00 1.03 56340-J3000 8308',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00JS LKAS AT KOR LHD 1.00 1.03 95740-J3000 K33',
+ b'\xf1\x00JS LKAS AT USA LHD 1.00 1.02 95740-J3000 K32',
+ ],
+ (Ecu.transmission, 0x7e1, None): [
+ b'\xf1\x816U2V8051\x00\x00\xf1\x006U2V0_C2\x00\x006U2V8051\x00\x00DJS0T16KS2\x0e\xba\x1e\xa2',
+ b'\xf1\x816U2V8051\x00\x00\xf1\x006U2V0_C2\x00\x006U2V8051\x00\x00DJS0T16NS1\x00\x00\x00\x00',
+ b'\xf1\x816U2V8051\x00\x00\xf1\x006U2V0_C2\x00\x006U2V8051\x00\x00DJS0T16NS1\xba\x02\xb8\x80',
+ ],
+ },
+ CAR.GENESIS_G70: {
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00IK__ SCC F-CUP 1.00 1.01 96400-G9100 ',
+ b'\xf1\x00IK__ SCC F-CUP 1.00 1.02 96400-G9100 ',
+ ],
+ (Ecu.engine, 0x7e0, None): [
+ b'\xf1\x81640F0051\x00\x00\x00\x00\x00\x00\x00\x00',
+ ],
+ (Ecu.eps, 0x7d4, None): [
+ b'\xf1\x00IK MDPS R 1.00 1.06 57700-G9420 4I4VL106',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00IK MFC AT USA LHD 1.00 1.01 95740-G9000 170920',
+ ],
+ (Ecu.transmission, 0x7e1, None): [
+ b'\xf1\x00bcsh8p54 E25\x00\x00\x00\x00\x00\x00\x00SIK0T33NB2\x11\x1am\xda',
+ b'\xf1\x87VDJLT17895112DN4\x88fVf\x99\x88\x88\x88\x87fVe\x88vhwwUFU\x97eFex\x99\x7f\xff\xb7\x82\xf1\x81E25\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E25\x00\x00\x00\x00\x00\x00\x00SIK0T33NB2\x11\x1am\xda',
+ ],
+ },
+ CAR.GENESIS_G70_2020: {
+ (Ecu.eps, 0x7d4, None): [
+ b'\xf1\x00IK MDPS R 1.00 1.07 57700-G9220 4I2VL107',
+ b'\xf1\x00IK MDPS R 1.00 1.07 57700-G9420 4I4VL107',
+ b'\xf1\x00IK MDPS R 1.00 1.08 57700-G9200 4I2CL108',
+ b'\xf1\x00IK MDPS R 1.00 1.08 57700-G9420 4I4VL108',
+ ],
+ (Ecu.transmission, 0x7e1, None): [
+ b'\x00\x00\x00\x00\xf1\x00bcsh8p54 E25\x00\x00\x00\x00\x00\x00\x00SIK0T33NB4\xecE\xefL',
+ b'\xf1\x00bcsh8p54 E25\x00\x00\x00\x00\x00\x00\x00SIK0T20KB3Wuvz',
+ b'\xf1\x87VCJLP18407832DN3\x88vXfvUVT\x97eFU\x87d7v\x88eVeveFU\x89\x98\x7f\xff\xb2\xb0\xf1\x81E25\x00\x00\x00',
+ b'\xf1\x87VDJLC18480772DK9\x88eHfwfff\x87eFUeDEU\x98eFe\x86T5DVyo\xff\x87s\xf1\x81E25\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E25\x00\x00\x00\x00\x00\x00\x00SIK0T33KB5\x9f\xa5&\x81',
+ b'\xf1\x87VDKLT18912362DN4wfVfwefeveVUwfvw\x88vWfvUFU\x89\xa9\x8f\xff\x87w\xf1\x81E25\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E25\x00\x00\x00\x00\x00\x00\x00SIK0T33NB4\xecE\xefL',
+ ],
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00IK__ SCC F-CUP 1.00 1.02 96400-G9100 ',
+ b'\xf1\x00IK__ SCC F-CUP 1.00 1.02 96400-G9100 \xf1\xa01.02',
+ b'\xf1\x00IK__ SCC FHCUP 1.00 1.02 96400-G9000 ',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00IK MFC AT KOR LHD 1.00 1.01 95740-G9000 170920',
+ b'\xf1\x00IK MFC AT USA LHD 1.00 1.01 95740-G9000 170920',
+ ],
+ (Ecu.engine, 0x7e0, None): [
+ b'\xf1\x81606G2051\x00\x00\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x81640H0051\x00\x00\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x81640J0051\x00\x00\x00\x00\x00\x00\x00\x00',
+ ],
+ },
+ CAR.GENESIS_G80: {
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00DH__ SCC F-CUP 1.00 1.01 96400-B1120 ',
+ b'\xf1\x00DH__ SCC FHCUP 1.00 1.01 96400-B1110 ',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00DH LKAS AT KOR LHD 1.01 1.02 95895-B1500 170810',
+ b'\xf1\x00DH LKAS AT USA LHD 1.01 1.01 95895-B1500 161014',
+ b'\xf1\x00DH LKAS AT USA LHD 1.01 1.02 95895-B1500 170810',
+ b'\xf1\x00DH LKAS AT USA LHD 1.01 1.03 95895-B1500 180713',
+ ],
+ (Ecu.transmission, 0x7e1, None): [
+ b'\xf1\x00bcsh8p54 E18\x00\x00\x00\x00\x00\x00\x00SDH0G33KH2\xae\xde\xd5!',
+ b'\xf1\x00bcsh8p54 E18\x00\x00\x00\x00\x00\x00\x00SDH0G38NH2j\x9dA\x1c',
+ b'\xf1\x00bcsh8p54 E18\x00\x00\x00\x00\x00\x00\x00SDH0T33NH3\x97\xe6\xbc\xb8',
+ b'\xf1\x00bcsh8p54 E18\x00\x00\x00\x00\x00\x00\x00TDH0G38NH3:-\xa9n',
+ b'\xf1\x00bcsh8p54 E21\x00\x00\x00\x00\x00\x00\x00SDH0T33NH4\xd7O\x9e\xc9',
+ ],
+ (Ecu.engine, 0x7e0, None): [
+ b'\xf1\x81640A4051\x00\x00\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x81640F0051\x00\x00\x00\x00\x00\x00\x00\x00',
+ ],
+ },
+ CAR.GENESIS_G90: {
+ (Ecu.transmission, 0x7e1, None): [
+ b'\xf1\x87VDGMD15352242DD3w\x87gxwvgv\x87wvw\x88wXwffVfffUfw\x88o\xff\x06J\xf1\x81E14\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcshcm49 E14\x00\x00\x00\x00\x00\x00\x00SHI0G50NB1tc5\xb7',
+ b'\xf1\x87VDGMD15866192DD3x\x88x\x89wuFvvfUf\x88vWwgwwwvfVgx\x87o\xff\xbc^\xf1\x81E14\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcshcm49 E14\x00\x00\x00\x00\x00\x00\x00SHI0G50NB1tc5\xb7',
+ ],
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00HI__ SCC F-CUP 1.00 1.01 96400-D2100 ',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00HI LKAS AT USA LHD 1.00 1.00 95895-D2020 160302',
+ ],
+ (Ecu.engine, 0x7e0, None): [
+ b'\xf1\x810000000000\x00',
+ ],
+ },
+ CAR.KONA: {
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00OS__ SCC F-CUP 1.00 1.00 95655-J9200 ',
+ ],
+ (Ecu.abs, 0x7d1, None): [
+ b'\xf1\x816V5RAK00018.ELF\xf1\x00\x00\x00\x00\x00\x00\x00',
+ ],
+ (Ecu.engine, 0x7e0, None): [
+ b'"\x01TOS-0NU06F301J02',
+ ],
+ (Ecu.eps, 0x7d4, None): [
+ b'\xf1\x00OS MDPS C 1.00 1.05 56310J9030\x00 4OSDC105',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00OS9 LKAS AT USA LHD 1.00 1.00 95740-J9300 g21',
+ ],
+ (Ecu.transmission, 0x7e1, None): [
+ b'\xf1\x816U2VE051\x00\x00\xf1\x006U2V0_C2\x00\x006U2VE051\x00\x00DOS4T16NS3\x00\x00\x00\x00',
+ ],
+ },
+ CAR.KIA_CEED: {
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00CD__ SCC F-CUP 1.00 1.02 99110-J7000 ',
+ ],
+ (Ecu.eps, 0x7d4, None): [
+ b'\xf1\x00CD MDPS C 1.00 1.06 56310-XX000 4CDEC106',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00CD LKAS AT EUR LHD 1.00 1.01 99211-J7000 B40',
+ ],
+ (Ecu.engine, 0x7e0, None): [
+ b'\x01TCD-JECU4F202H0K',
+ ],
+ (Ecu.transmission, 0x7e1, None): [
+ b'\xf1\x816U2V7051\x00\x00\xf1\x006U2V0_C2\x00\x006U2V7051\x00\x00DCD0T14US1\x00\x00\x00\x00',
+ b'\xf1\x816U2V7051\x00\x00\xf1\x006U2V0_C2\x00\x006U2V7051\x00\x00DCD0T14US1U\x867Z',
+ ],
+ (Ecu.abs, 0x7d1, None): [
+ b'\xf1\x00CD ESC \x03 102\x18\x08\x05 58920-J7350',
+ ],
+ },
+ CAR.KIA_FORTE: {
+ (Ecu.eps, 0x7d4, None): [
+ b'\xf1\x00BD MDPS C 1.00 1.02 56310-XX000 4BD2C102',
+ b'\xf1\x00BD MDPS C 1.00 1.08 56310/M6300 4BDDC108',
+ b'\xf1\x00BD MDPS C 1.00 1.08 56310M6300\x00 4BDDC108',
+ b'\xf1\x00BDm MDPS C A.01 1.03 56310M7800\x00 4BPMC103',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00BD LKAS AT USA LHD 1.00 1.04 95740-M6000 J33',
+ b'\xf1\x00BDP LKAS AT USA LHD 1.00 1.05 99211-M6500 744',
+ ],
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00BDPE_SCC FHCUPC 1.00 1.04 99110-M6500\x00\x00\x00\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x00BD__ SCC H-CUP 1.00 1.02 99110-M6000 ',
+ ],
+ (Ecu.engine, 0x7e0, None): [
+ b'\x01TBDM1NU06F200H01',
+ b'391182B945\x00',
+ b'\xf1\x81616F2051\x00\x00\x00\x00\x00\x00\x00\x00',
+ ],
+ (Ecu.abs, 0x7d1, None): [
+ b'\xf1\x816VGRAH00018.ELF\xf1\x00\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x8758900-M7AB0 \xf1\x816VQRAD00127.ELF\xf1\x00\x00\x00\x00\x00\x00\x00',
+ ],
+ (Ecu.transmission, 0x7e1, None): [
+ b'\xf1\x006V2B0_C2\x00\x006V2C6051\x00\x00CBD0N20NL1\x00\x00\x00\x00',
+ b'\xf1\x816U2VC051\x00\x00\xf1\x006U2V0_C2\x00\x006U2VC051\x00\x00DBD0T16SS0\x00\x00\x00\x00',
+ b"\xf1\x816U2VC051\x00\x00\xf1\x006U2V0_C2\x00\x006U2VC051\x00\x00DBD0T16SS0\xcf\x1e'\xc3",
+ ],
+ },
+ CAR.KIA_K5_2021: {
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00DL3_ SCC F-CUP 1.00 1.03 99110-L2100 ',
+ b'\xf1\x00DL3_ SCC FHCUP 1.00 1.03 99110-L2000 ',
+ b'\xf1\x00DL3_ SCC FHCUP 1.00 1.03 99110-L2100 ',
+ b'\xf1\x00DL3_ SCC FHCUP 1.00 1.04 99110-L2100 ',
+ b'\xf1\x8799110L2000\xf1\x00DL3_ SCC FHCUP 1.00 1.03 99110-L2000 ',
+ b'\xf1\x8799110L2100\xf1\x00DL3_ SCC F-CUP 1.00 1.03 99110-L2100 ',
+ b'\xf1\x8799110L2100\xf1\x00DL3_ SCC FHCUP 1.00 1.03 99110-L2100 ',
+ ],
+ (Ecu.eps, 0x7d4, None): [
+ b'\xf1\x00DL3 MDPS C 1.00 1.01 56310-L3220 4DLAC101',
+ b'\xf1\x00DL3 MDPS C 1.00 1.02 56310-L2220 4DLDC102',
+ b'\xf1\x00DL3 MDPS C 1.00 1.02 56310L3220\x00 4DLAC102',
+ b'\xf1\x8756310-L3110\xf1\x00DL3 MDPS C 1.00 1.01 56310-L3110 4DLAC101',
+ b'\xf1\x8756310-L3220\xf1\x00DL3 MDPS C 1.00 1.01 56310-L3220 4DLAC101',
+ b'\xf1\x8757700-L3000\xf1\x00DL3 MDPS R 1.00 1.02 57700-L3000 4DLAP102',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00DL3 MFC AT KOR LHD 1.00 1.04 99210-L2000 210527',
+ b'\xf1\x00DL3 MFC AT USA LHD 1.00 1.03 99210-L3000 200915',
+ b'\xf1\x00DL3 MFC AT USA LHD 1.00 1.04 99210-L3000 210208',
+ b'\xf1\x00DL3 MFC AT USA LHD 1.00 1.05 99210-L3000 211222',
+ ],
+ (Ecu.abs, 0x7d1, None): [
+ b'\xf1\x00DL ESC \x01 104 \x07\x12 58910-L2200',
+ b'\xf1\x00DL ESC \x06 101 \x04\x02 58910-L3200',
+ b'\xf1\x00DL ESC \x06 103"\x08\x06 58910-L3200',
+ b'\xf1\x00DL ESC \t 100 \x06\x02 58910-L3800',
+ b'\xf1\x8758910-L3200\xf1\x00DL ESC \x06 101 \x04\x02 58910-L3200',
+ b'\xf1\x8758910-L3600\xf1\x00DL ESC \x03 100 \x08\x02 58910-L3600',
+ b'\xf1\x8758910-L3800\xf1\x00DL ESC \t 101 \x07\x02 58910-L3800',
+ ],
+ (Ecu.engine, 0x7e0, None): [
+ b'\xf1\x81HM6M2_0a0_DQ0',
+ b'\xf1\x870\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x82DLDWN5TMDCXXXJ1B',
+ b'\xf1\x87391212MKT0',
+ b'\xf1\x87391212MKT3',
+ b'\xf1\x87391212MKV0',
+ ],
+ (Ecu.transmission, 0x7e1, None): [
+ b'\xf1\x00HT6TA261BLHT6TAB00A1SDL0C20KS0\x00\x00\x00\x00\x00\x00\\\x9f\xa5\x15',
+ b'\xf1\x00bcsh8p54 U913\x00\x00\x00\x00\x00\x00TDL2T16NB1ia\x0b\xb8',
+ b'\xf1\x00bcsh8p54 U913\x00\x00\x00\x00\x00\x00TDL2T16NB2.\x13\xf6\xed',
+ b'\xf1\x00bcsh8p54 U913\x00\x00\x00\x00\x00\x00TDL4T16NB05\x94t\x18',
+ b'\xf1\x87954A02N300\x00\x00\x00\x00\x00\xf1\x81T02730A1 \xf1\x00T02601BL T02730A1 WDL3T25XXX730NS2b\x1f\xb8%',
+ b'\xf1\x87SALFEA5652514GK2UUeV\x88\x87\x88xxwg\x87ww\x87wwfwvd/\xfb\xffvU_\xff\x93\xd3\xf1\x81U913\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U913\x00\x00\x00\x00\x00\x00TDL2T16NB1ia\x0b\xb8',
+ b'\xf1\x87SALFEA6046104GK2wvwgeTeFg\x88\x96xwwwwffvfe?\xfd\xff\x86fo\xff\x97A\xf1\x81U913\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U913\x00\x00\x00\x00\x00\x00TDL2T16NB1ia\x0b\xb8',
+ b'\xf1\x87SCMSAA8572454GK1\x87x\x87\x88Vf\x86hgwvwvwwgvwwgT?\xfb\xff\x97fo\xffH\xb8\xf1\x81U913\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U913\x00\x00\x00\x00\x00\x00TDL4T16NB05\x94t\x18',
+ ],
+ },
+ CAR.KIA_K5_HEV_2020: {
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00DLhe SCC FHCUP 1.00 1.02 99110-L7000 ',
+ ],
+ (Ecu.eps, 0x7d4, None): [
+ b'\xf1\x00DL3 MDPS C 1.00 1.02 56310-L7000 4DLHC102',
+ b'\xf1\x00DL3 MDPS C 1.00 1.02 56310-L7220 4DLHC102',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00DL3HMFC AT KOR LHD 1.00 1.02 99210-L2000 200309',
+ b'\xf1\x00DL3HMFC AT KOR LHD 1.00 1.04 99210-L2000 210527',
+ ],
+ (Ecu.engine, 0x7e0, None): [
+ b'\xf1\x87391162JLA0',
+ ],
+ (Ecu.transmission, 0x7e1, None): [
+ b'\xf1\x00PSBG2323 E08\x00\x00\x00\x00\x00\x00\x00TDL2H20KA2\xe3\xc6cz',
+ b'\xf1\x00PSBG2333 E16\x00\x00\x00\x00\x00\x00\x00TDL2H20KA5T\xf2\xc9\xc2',
+ ],
+ },
+ CAR.KONA_EV: {
+ (Ecu.abs, 0x7d1, None): [
+ b'\xf1\x00OS IEB \x01 212 \x11\x13 58520-K4000',
+ b'\xf1\x00OS IEB \x02 212 \x11\x13 58520-K4000',
+ b'\xf1\x00OS IEB \x03 210 \x02\x14 58520-K4000',
+ b'\xf1\x00OS IEB \x03 212 \x11\x13 58520-K4000',
+ b'\xf1\x00OS IEB \r 105\x18\t\x18 58520-K4000',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00OE2 LKAS AT EUR LHD 1.00 1.00 95740-K4200 200',
+ b'\xf1\x00OSE LKAS AT EUR LHD 1.00 1.00 95740-K4100 W40',
+ b'\xf1\x00OSE LKAS AT EUR RHD 1.00 1.00 95740-K4100 W40',
+ b'\xf1\x00OSE LKAS AT KOR LHD 1.00 1.00 95740-K4100 W40',
+ b'\xf1\x00OSE LKAS AT USA LHD 1.00 1.00 95740-K4300 W50',
+ ],
+ (Ecu.eps, 0x7d4, None): [
+ b'\xf1\x00OS MDPS C 1.00 1.03 56310/K4550 4OEDC103',
+ b'\xf1\x00OS MDPS C 1.00 1.04 56310K4000\x00 4OEDC104',
+ b'\xf1\x00OS MDPS C 1.00 1.04 56310K4050\x00 4OEDC104',
+ ],
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00OSev SCC F-CUP 1.00 1.00 99110-K4000 ',
+ b'\xf1\x00OSev SCC F-CUP 1.00 1.00 99110-K4100 ',
+ b'\xf1\x00OSev SCC F-CUP 1.00 1.01 99110-K4000 ',
+ b'\xf1\x00OSev SCC FNCUP 1.00 1.01 99110-K4000 ',
+ ],
+ },
+ CAR.KONA_EV_2022: {
+ (Ecu.abs, 0x7d1, None): [
+ b'\xf1\x00OS IEB \x02 102"\x05\x16 58520-K4010',
+ b'\xf1\x00OS IEB \x03 102"\x05\x16 58520-K4010',
+ b'\xf1\x00OS IEB \r 102"\x05\x16 58520-K4010',
+ b'\xf1\x8758520-K4010\xf1\x00OS IEB \x02 101 \x11\x13 58520-K4010',
+ b'\xf1\x8758520-K4010\xf1\x00OS IEB \x03 101 \x11\x13 58520-K4010',
+ b'\xf1\x8758520-K4010\xf1\x00OS IEB \x04 101 \x11\x13 58520-K4010',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00OSP LKA AT AUS RHD 1.00 1.04 99211-J9200 904',
+ b'\xf1\x00OSP LKA AT CND LHD 1.00 1.02 99211-J9110 802',
+ b'\xf1\x00OSP LKA AT EUR LHD 1.00 1.04 99211-J9200 904',
+ b'\xf1\x00OSP LKA AT EUR RHD 1.00 1.02 99211-J9110 802',
+ b'\xf1\x00OSP LKA AT EUR RHD 1.00 1.04 99211-J9200 904',
+ b'\xf1\x00OSP LKA AT USA LHD 1.00 1.04 99211-J9200 904',
+ ],
+ (Ecu.eps, 0x7d4, None): [
+ b'\xf1\x00OSP MDPS C 1.00 1.02 56310-K4271 4OEPC102',
+ b'\xf1\x00OSP MDPS C 1.00 1.02 56310/K4271 4OEPC102',
+ b'\xf1\x00OSP MDPS C 1.00 1.02 56310/K4970 4OEPC102',
+ b'\xf1\x00OSP MDPS C 1.00 1.02 56310K4260\x00 4OEPC102',
+ b'\xf1\x00OSP MDPS C 1.00 1.02 56310K4261\x00 4OEPC102',
+ b'\xf1\x00OSP MDPS C 1.00 1.02 56310K4971\x00 4OEPC102',
+ ],
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00YB__ FCA ----- 1.00 1.01 99110-K4500 \x00\x00\x00',
+ ],
+ },
+ CAR.KONA_EV_2ND_GEN: {
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00SXev RDR ----- 1.00 1.00 99110-BF000 ',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00SX2EMFC AT KOR LHD 1.00 1.00 99211-BF000 230410',
+ ],
+ },
+ CAR.KIA_NIRO_EV: {
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00DEev SCC F-CUP 1.00 1.00 99110-Q4000 ',
+ b'\xf1\x00DEev SCC F-CUP 1.00 1.02 96400-Q4000 ',
+ b'\xf1\x00DEev SCC F-CUP 1.00 1.02 96400-Q4100 ',
+ b'\xf1\x00DEev SCC F-CUP 1.00 1.03 96400-Q4100 ',
+ b'\xf1\x00DEev SCC FHCUP 1.00 1.03 96400-Q4000 ',
+ b'\xf1\x8799110Q4000\xf1\x00DEev SCC F-CUP 1.00 1.00 99110-Q4000 ',
+ b'\xf1\x8799110Q4100\xf1\x00DEev SCC F-CUP 1.00 1.00 99110-Q4100 ',
+ b'\xf1\x8799110Q4500\xf1\x00DEev SCC F-CUP 1.00 1.00 99110-Q4500 ',
+ b'\xf1\x8799110Q4600\xf1\x00DEev SCC F-CUP 1.00 1.00 99110-Q4600 ',
+ b'\xf1\x8799110Q4600\xf1\x00DEev SCC FHCUP 1.00 1.00 99110-Q4600 ',
+ b'\xf1\x8799110Q4600\xf1\x00DEev SCC FNCUP 1.00 1.00 99110-Q4600 ',
+ ],
+ (Ecu.eps, 0x7d4, None): [
+ b'\xf1\x00DE MDPS C 1.00 1.04 56310Q4100\x00 4DEEC104',
+ b'\xf1\x00DE MDPS C 1.00 1.05 56310Q4000\x00 4DEEC105',
+ b'\xf1\x00DE MDPS C 1.00 1.05 56310Q4100\x00 4DEEC105',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00DEE MFC AT EUR LHD 1.00 1.00 99211-Q4000 191211',
+ b'\xf1\x00DEE MFC AT EUR LHD 1.00 1.00 99211-Q4100 200706',
+ b'\xf1\x00DEE MFC AT EUR LHD 1.00 1.03 95740-Q4000 180821',
+ b'\xf1\x00DEE MFC AT KOR LHD 1.00 1.03 95740-Q4000 180821',
+ b'\xf1\x00DEE MFC AT USA LHD 1.00 1.00 99211-Q4000 191211',
+ b'\xf1\x00DEE MFC AT USA LHD 1.00 1.01 99211-Q4500 210428',
+ b'\xf1\x00DEE MFC AT USA LHD 1.00 1.03 95740-Q4000 180821',
+ ],
+ },
+ CAR.KIA_NIRO_EV_2ND_GEN: {
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00SG2_ RDR ----- 1.00 1.01 99110-AT000 ',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00SG2EMFC AT EUR LHD 1.01 1.09 99211-AT000 220801',
+ b'\xf1\x00SG2EMFC AT USA LHD 1.01 1.09 99211-AT000 220801',
+ ],
+ },
+ CAR.KIA_NIRO_PHEV: {
+ (Ecu.engine, 0x7e0, None): [
+ b'\xf1\x816H6D1051\x00\x00\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x816H6F4051\x00\x00\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x816H6F6051\x00\x00\x00\x00\x00\x00\x00\x00',
+ ],
+ (Ecu.transmission, 0x7e1, None): [
+ b'\xf1\x006U3H1_C2\x00\x006U3J9051\x00\x00PDE0G16NL2&[\xc3\x01',
+ b'\xf1\x816U3H3051\x00\x00\xf1\x006U3H0_C2\x00\x006U3H3051\x00\x00PDE0G16NS1\x00\x00\x00\x00',
+ b'\xf1\x816U3H3051\x00\x00\xf1\x006U3H0_C2\x00\x006U3H3051\x00\x00PDE0G16NS1\x13\xcd\x88\x92',
+ b'\xf1\x816U3J2051\x00\x00\xf1\x006U3H0_C2\x00\x006U3J2051\x00\x00PDE0G16NS2\x00\x00\x00\x00',
+ b"\xf1\x816U3J2051\x00\x00\xf1\x006U3H0_C2\x00\x006U3J2051\x00\x00PDE0G16NS2\xf4'\\\x91",
+ ],
+ (Ecu.eps, 0x7d4, None): [
+ b'\xf1\x00DE MDPS C 1.00 1.01 56310G5520\x00 4DEPC101',
+ b'\xf1\x00DE MDPS C 1.00 1.09 56310G5301\x00 4DEHC109',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00DEP MFC AT USA LHD 1.00 1.00 95740-G5010 170117',
+ b'\xf1\x00DEP MFC AT USA LHD 1.00 1.01 95740-G5010 170424',
+ b'\xf1\x00DEP MFC AT USA LHD 1.00 1.05 99211-G5000 190826',
+ ],
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00DEhe SCC F-CUP 1.00 1.02 99110-G5100 ',
+ b'\xf1\x00DEhe SCC H-CUP 1.01 1.02 96400-G5100 ',
+ ],
+ },
+ CAR.KIA_NIRO_PHEV_2022: {
+ (Ecu.engine, 0x7e0, None): [
+ b'\xf1\x816H6G6051\x00\x00\x00\x00\x00\x00\x00\x00',
+ ],
+ (Ecu.transmission, 0x7e1, None): [
+ b'\xf1\x006U3H1_C2\x00\x006U3J9051\x00\x00PDE0G16NL3\x00\x00\x00\x00',
+ ],
+ (Ecu.eps, 0x7d4, None): [
+ b'\xf1\x00DE MDPS C 1.00 1.01 56310G5520\x00 4DEPC101',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00DEP MFC AT USA LHD 1.00 1.00 99211-G5500 210428',
+ ],
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00DEhe SCC F-CUP 1.00 1.00 99110-G5600 ',
+ ],
+ },
+ CAR.KIA_NIRO_HEV_2021: {
+ (Ecu.engine, 0x7e0, None): [
+ b'\xf1\x816H6G5051\x00\x00\x00\x00\x00\x00\x00\x00',
+ ],
+ (Ecu.transmission, 0x7e1, None): [
+ b'\xf1\x816U3J9051\x00\x00\xf1\x006U3H1_C2\x00\x006U3J9051\x00\x00HDE0G16NL3\x00\x00\x00\x00',
+ b'\xf1\x816U3J9051\x00\x00\xf1\x006U3H1_C2\x00\x006U3J9051\x00\x00HDE0G16NL3\xb9\xd3\xfaW',
+ ],
+ (Ecu.eps, 0x7d4, None): [
+ b'\xf1\x00DE MDPS C 1.00 1.01 56310G5520\x00 4DEPC101',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00DEH MFC AT USA LHD 1.00 1.00 99211-G5500 210428',
+ b'\xf1\x00DEH MFC AT USA LHD 1.00 1.07 99211-G5000 201221',
+ ],
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00DEhe SCC FHCUP 1.00 1.00 99110-G5600 ',
+ ],
+ },
+ CAR.KIA_SELTOS: {
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x8799110Q5100\xf1\x00SP2_ SCC FHCUP 1.01 1.05 99110-Q5100 ',
+ ],
+ (Ecu.abs, 0x7d1, None): [
+ b'\xf1\x8758910-Q5450\xf1\x00SP ESC \x07 101\x19\t\x05 58910-Q5450',
+ b'\xf1\x8758910-Q5450\xf1\x00SP ESC \t 101\x19\t\x05 58910-Q5450',
+ ],
+ (Ecu.engine, 0x7e0, None): [
+ b'\x01TSP2KNL06F100J0K',
+ b'\x01TSP2KNL06F200J0K',
+ b'\xf1\x81616D2051\x00\x00\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x81616D5051\x00\x00\x00\x00\x00\x00\x00\x00',
+ ],
+ (Ecu.eps, 0x7d4, None): [
+ b'\xf1\x00SP2 MDPS C 1.00 1.04 56300Q5200 ',
+ b'\xf1\x00SP2 MDPS C 1.01 1.05 56300Q5200 ',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00SP2 MFC AT USA LHD 1.00 1.04 99210-Q5000 191114',
+ b'\xf1\x00SP2 MFC AT USA LHD 1.00 1.05 99210-Q5000 201012',
+ ],
+ (Ecu.transmission, 0x7e1, None): [
+ b'\xf1\x87954A22D200\xf1\x81T01950A1 \xf1\x00T0190XBL T01950A1 DSP2T16X4X950NS6\xd30\xa5\xb9',
+ b'\xf1\x87954A22D200\xf1\x81T01950A1 \xf1\x00T0190XBL T01950A1 DSP2T16X4X950NS8\r\xfe\x9c\x8b',
+ b'\xf1\x87CZLUB49370612JF7h\xa8y\x87\x99\xa7hv\x99\x97fv\x88\x87x\x89x\x96O\xff\x88\xff\xff\xff.@\xf1\x816V2C2051\x00\x00\xf1\x006V2B0_C2\x00\x006V2C2051\x00\x00CSP4N20NS3\x00\x00\x00\x00',
+ ],
+ },
+ CAR.KIA_OPTIMA_G4: {
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00JF__ SCC F-CUP 1.00 1.00 96400-D4100 ',
+ ],
+ (Ecu.abs, 0x7d1, None): [
+ b'\xf1\x00JF ESC \x0f 16 \x16\x06\x17 58920-D5080',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00JFWGN LDWS AT USA LHD 1.00 1.02 95895-D4100 G21',
+ ],
+ (Ecu.transmission, 0x7e1, None): [
+ b'\xf1\x87\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xf1\x816T6J0051\x00\x00\xf1\x006T6J0_C2\x00\x006T6J0051\x00\x00TJF0T20NSB\x00\x00\x00\x00',
+ ],
+ },
+ CAR.KIA_OPTIMA_G4_FL: {
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00JF__ SCC F-CUP 1.00 1.00 96400-D4110 ',
+ ],
+ (Ecu.abs, 0x7d1, None): [
+ b"\xf1\x00JF ESC \t 11 \x18\x03' 58920-D5260",
+ b'\xf1\x00JF ESC \x0b 11 \x18\x030 58920-D5180',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00JFA LKAS AT USA LHD 1.00 1.00 95895-D5001 h32',
+ b'\xf1\x00JFA LKAS AT USA LHD 1.00 1.00 95895-D5100 h32',
+ ],
+ (Ecu.transmission, 0x7e1, None): [
+ b'\xf1\x006U2V0_C2\x00\x006U2V8051\x00\x00DJF0T16NL0\t\xd2GW',
+ b'\xf1\x006U2V0_C2\x00\x006U2VA051\x00\x00DJF0T16NL1\x00\x00\x00\x00',
+ b'\xf1\x006U2V0_C2\x00\x006U2VA051\x00\x00DJF0T16NL1\xca3\xeb.',
+ b'\xf1\x006U2V0_C2\x00\x006U2VC051\x00\x00DJF0T16NL2\x9eA\x80\x01',
+ b'\xf1\x816U2V8051\x00\x00\xf1\x006U2V0_C2\x00\x006U2V8051\x00\x00DJF0T16NL0\t\xd2GW',
+ b'\xf1\x816U2VA051\x00\x00\xf1\x006U2V0_C2\x00\x006U2VA051\x00\x00DJF0T16NL1\x00\x00\x00\x00',
+ b'\xf1\x816U2VA051\x00\x00\xf1\x006U2V0_C2\x00\x006U2VA051\x00\x00DJF0T16NL1\xca3\xeb.',
+ b'\xf1\x816U2VC051\x00\x00\xf1\x006U2V0_C2\x00\x006U2VC051\x00\x00DJF0T16NL2\x9eA\x80\x01',
+ b'\xf1\x87\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xf1\x816T6B8051\x00\x00\xf1\x006T6H0_C2\x00\x006T6B8051\x00\x00TJFSG24NH27\xa7\xc2\xb4',
+ ],
+ },
+ CAR.KIA_OPTIMA_H: {
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00JFhe SCC FNCUP 1.00 1.00 96400-A8000 ',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00JFP LKAS AT EUR LHD 1.00 1.03 95895-A8100 160711',
+ ],
+ },
+ CAR.KIA_OPTIMA_H_G4_FL: {
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00JFhe SCC FHCUP 1.00 1.01 99110-A8500 ',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00JFH MFC AT KOR LHD 1.00 1.01 95895-A8200 180323',
+ ],
+ (Ecu.engine, 0x7e0, None): [
+ b'\xf1\x816H6D1051\x00\x00\x00\x00\x00\x00\x00\x00',
+ ],
+ },
+ CAR.ELANTRA: {
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00AD LKAS AT USA LHD 1.01 1.01 95895-F2000 251',
+ b'\xf1\x00ADP LKAS AT USA LHD 1.00 1.03 99211-F2000 X31',
+ ],
+ (Ecu.transmission, 0x7e1, None): [
+ b'\xf1\x006T6J0_C2\x00\x006T6F0051\x00\x00TAD0N20NS2\x00\x00\x00\x00',
+ b'\xf1\x006T6J0_C2\x00\x006T6F0051\x00\x00TAD0N20NS2\xc5\x92\x9e\x8a',
+ b'\xf1\x006T6J0_C2\x00\x006T6F0051\x00\x00TAD0N20SS2.~\x90\x87',
+ b'\xf1\x006T6K0_C2\x00\x006T6S2051\x00\x00TAD0N20NSD\x00\x00\x00\x00',
+ b'\xf1\x006T6K0_C2\x00\x006T6S2051\x00\x00TAD0N20NSD(\xfcA\x9d',
+ ],
+ (Ecu.engine, 0x7e0, None): [
+ b'\xf1\x8161657051\x00\x00\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x816165D051\x00\x00\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x816165E051\x00\x00\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x8161698051\x00\x00\x00\x00\x00\x00\x00\x00',
+ ],
+ (Ecu.abs, 0x7d1, None): [
+ b'\xf1\x00AD ESC \x11 11 \x18\x05\x06 58910-F2840',
+ b'\xf1\x00AD ESC \x11 12 \x15\t\t 58920-F2810',
+ ],
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00AD__ SCC H-CUP 1.00 1.00 99110-F2100 ',
+ b'\xf1\x00AD__ SCC H-CUP 1.00 1.01 96400-F2100 ',
+ ],
+ },
+ CAR.ELANTRA_GT_I30: {
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00PD LKAS AT KOR LHD 1.00 1.02 95740-G3000 A51',
+ b'\xf1\x00PD LKAS AT USA LHD 1.01 1.01 95740-G3100 A54',
+ ],
+ (Ecu.transmission, 0x7e1, None): [
+ b'\xf1\x006U2U0_C2\x00\x006U2T0051\x00\x00DPD0D16KS0u\xce\x1fk',
+ b'\xf1\x006U2V0_C2\x00\x006U2VA051\x00\x00DPD0H16NS0e\x0e\xcd\x8e',
+ ],
+ (Ecu.eps, 0x7d4, None): [
+ b'\xf1\x00PD MDPS C 1.00 1.00 56310G3300\x00 4PDDC100',
+ b'\xf1\x00PD MDPS C 1.00 1.04 56310/G3300 4PDDC104',
+ ],
+ (Ecu.abs, 0x7d1, None): [
+ b'\xf1\x00PD ESC \t 104\x18\t\x03 58920-G3350',
+ b'\xf1\x00PD ESC \x0b 104\x18\t\x03 58920-G3350',
+ ],
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00PD__ SCC F-CUP 1.00 1.00 96400-G3300 ',
+ b'\xf1\x00PD__ SCC FNCUP 1.01 1.00 96400-G3000 ',
+ ],
+ },
+ CAR.ELANTRA_2021: {
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00CN7_ SCC F-CUP 1.00 1.01 99110-AA000 ',
+ b'\xf1\x00CN7_ SCC FHCUP 1.00 1.01 99110-AA000 ',
+ b'\xf1\x00CN7_ SCC FNCUP 1.00 1.01 99110-AA000 ',
+ b'\xf1\x8799110AA000\xf1\x00CN7_ SCC F-CUP 1.00 1.01 99110-AA000 ',
+ b'\xf1\x8799110AA000\xf1\x00CN7_ SCC FHCUP 1.00 1.01 99110-AA000 ',
+ ],
+ (Ecu.eps, 0x7d4, None): [
+ b'\xf1\x00CN7 MDPS C 1.00 1.06 56310/AA070 4CNDC106',
+ b'\xf1\x00CN7 MDPS C 1.00 1.06 56310AA050\x00 4CNDC106',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.00 99210-AB000 200819',
+ b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.01 99210-AB000 210205',
+ b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.03 99210-AA000 200819',
+ b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.03 99210-AB000 220426',
+ b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.06 99210-AA000 220111',
+ ],
+ (Ecu.abs, 0x7d1, None): [
+ b'\xf1\x00CN ESC \t 101 \x10\x03 58910-AB800',
+ b'\xf1\x8758910-AA800\xf1\x00CN ESC \t 104 \x08\x03 58910-AA800',
+ b'\xf1\x8758910-AA800\xf1\x00CN ESC \t 105 \x10\x03 58910-AA800',
+ b'\xf1\x8758910-AB800\xf1\x00CN ESC \t 101 \x10\x03 58910-AB800\xf1\xa01.01',
+ ],
+ (Ecu.transmission, 0x7e1, None): [
+ b'\xf1\x00HT6WA280BLHT6VA640A1CCN0N20NS5\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x00HT6WA280BLHT6VA640A1CCN0N20NS5\x00\x00\x00\x00\x00\x00\xe8\xba\xce\xfa',
+ b'\xf1\x87CXLQF40189012JL2f\x88\x86\x88\x88vUex\xb8\x88\x88\x88\x87\x88\x89fh?\xffz\xff\xff\xff\x08z\xf1\x89HT6VA640A1\xf1\x82CCN0N20NS5\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x87CXMQFM1916035JB2\x88vvgg\x87Wuwgev\xa9\x98\x88\x98h\x99\x9f\xffh\xff\xff\xff\xa5\xee\xf1\x89HT6VA640A1\xf1\x82CCN0N20NS5\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x87CXMQFM2135005JB2E\xb9\x89\x98W\xa9y\x97h\xa9\x98\x99wxvwh\x87\x7f\xffx\xff\xff\xff,,\xf1\x89HT6VA640A1\xf1\x82CCN0N20NS5\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x87CXMQFM2728305JB2E\x97\x87xw\x87vwgw\x84x\x88\x88w\x89EI\xbf\xff{\xff\xff\xff\xe6\x0e\xf1\x89HT6VA640A1\xf1\x82CCN0N20NS5\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x87CXMQFM3806705JB2\x89\x87wwx\x88g\x86\x99\x87\x86xwwv\x88yv\x7f\xffz\xff\xff\xffV\x15\xf1\x89HT6VA640A1\xf1\x82CCN0N20NS5\x00\x00\x00\x00\x00\x00',
+ ],
+ (Ecu.engine, 0x7e0, None): [
+ b'\xf1\x81HM6M2_0a0_FF0',
+ b'\xf1\x82CNCVD0AMFCXCSFFB',
+ b'\xf1\x82CNCWD0AMFCXCSFFA',
+ b'\xf1\x870\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x81HM6M2_0a0_G80',
+ b'\xf1\x870\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x81HM6M2_0a0_HC0',
+ ],
+ },
+ CAR.ELANTRA_HEV_2021: {
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00CN7HMFC AT USA LHD 1.00 1.03 99210-AA000 200819',
+ b'\xf1\x00CN7HMFC AT USA LHD 1.00 1.05 99210-AA000 210930',
+ b'\xf1\x00CN7HMFC AT USA LHD 1.00 1.07 99210-AA000 220426',
+ b'\xf1\x00CN7HMFC AT USA LHD 1.00 1.08 99210-AA000 220728',
+ b'\xf1\x00CN7HMFC AT USA LHD 1.00 1.09 99210-AA000 221108',
+ ],
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00CNhe SCC FHCUP 1.00 1.01 99110-BY000 ',
+ b'\xf1\x8799110BY000\xf1\x00CNhe SCC FHCUP 1.00 1.01 99110-BY000 ',
+ ],
+ (Ecu.eps, 0x7d4, None): [
+ b'\xf1\x00CN7 MDPS C 1.00 1.03 56310BY0500 4CNHC103',
+ b'\xf1\x00CN7 MDPS C 1.00 1.04 56310BY050\x00 4CNHC104',
+ b'\xf1\x8756310/BY050\xf1\x00CN7 MDPS C 1.00 1.02 56310/BY050 4CNHC102',
+ b'\xf1\x8756310/BY050\xf1\x00CN7 MDPS C 1.00 1.03 56310/BY050 4CNHC103',
+ ],
+ (Ecu.transmission, 0x7e1, None): [
+ b'\xf1\x006U3L0_C2\x00\x006U3K3051\x00\x00HCN0G16NS0\x00\x00\x00\x00',
+ b'\xf1\x006U3L0_C2\x00\x006U3K3051\x00\x00HCN0G16NS0\xb9?A\xaa',
+ b'\xf1\x006U3L0_C2\x00\x006U3K9051\x00\x00HCN0G16NS1\x00\x00\x00\x00',
+ b'\xf1\x816U3K3051\x00\x00\xf1\x006U3L0_C2\x00\x006U3K3051\x00\x00HCN0G16NS0\x00\x00\x00\x00',
+ b'\xf1\x816U3K3051\x00\x00\xf1\x006U3L0_C2\x00\x006U3K3051\x00\x00HCN0G16NS0\xb9?A\xaa',
+ ],
+ (Ecu.engine, 0x7e0, None): [
+ b'\xf1\x816H6G5051\x00\x00\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x816H6G6051\x00\x00\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x816H6G8051\x00\x00\x00\x00\x00\x00\x00\x00',
+ ],
+ },
+ CAR.KONA_HEV: {
+ (Ecu.abs, 0x7d1, None): [
+ b'\xf1\x00OS IEB \x01 104 \x11 58520-CM000',
+ ],
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00OShe SCC FNCUP 1.00 1.01 99110-CM000 ',
+ ],
+ (Ecu.eps, 0x7d4, None): [
+ b'\xf1\x00OS MDPS C 1.00 1.00 56310CM030\x00 4OHDC100',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00OSH LKAS AT KOR LHD 1.00 1.01 95740-CM000 l31',
+ ],
+ (Ecu.transmission, 0x7e1, None): [
+ b'\xf1\x816U3J9051\x00\x00\xf1\x006U3H1_C2\x00\x006U3J9051\x00\x00HOS0G16DS1\x16\xc7\xb0\xd9',
+ ],
+ (Ecu.engine, 0x7e0, None): [
+ b'\xf1\x816H6F6051\x00\x00\x00\x00\x00\x00\x00\x00',
+ ],
+ },
+ CAR.SONATA_HYBRID: {
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00DNhe SCC F-CUP 1.00 1.02 99110-L5000 ',
+ b'\xf1\x00DNhe SCC FHCUP 1.00 1.02 99110-L5000 ',
+ b'\xf1\x8799110L5000\xf1\x00DNhe SCC F-CUP 1.00 1.02 99110-L5000 ',
+ b'\xf1\x8799110L5000\xf1\x00DNhe SCC FHCUP 1.00 1.02 99110-L5000 ',
+ ],
+ (Ecu.eps, 0x7d4, None): [
+ b'\xf1\x00DN8 MDPS C 1.00 1.03 56310L5450\x00 4DNHC104',
+ b'\xf1\x8756310-L5450\xf1\x00DN8 MDPS C 1.00 1.02 56310-L5450 4DNHC102',
+ b'\xf1\x8756310-L5450\xf1\x00DN8 MDPS C 1.00 1.03 56310-L5450 4DNHC103',
+ b'\xf1\x8756310-L5500\xf1\x00DN8 MDPS C 1.00 1.02 56310-L5500 4DNHC102',
+ b'\xf1\x8756310L5450\x00\xf1\x00DN8 MDPS C 1.00 1.03 56310L5450\x00 4DNHC104',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00DN8HMFC AT USA LHD 1.00 1.04 99211-L1000 191016',
+ b'\xf1\x00DN8HMFC AT USA LHD 1.00 1.05 99211-L1000 201109',
+ b'\xf1\x00DN8HMFC AT USA LHD 1.00 1.06 99211-L1000 210325',
+ b'\xf1\x00DN8HMFC AT USA LHD 1.00 1.07 99211-L1000 211223',
+ ],
+ (Ecu.transmission, 0x7e1, None): [
+ b'\xf1\x00PSBG2323 E09\x00\x00\x00\x00\x00\x00\x00TDN2H20SA5\x97R\x88\x9e',
+ b'\xf1\x00PSBG2333 E14\x00\x00\x00\x00\x00\x00\x00TDN2H20SA6N\xc2\xeeW',
+ b'\xf1\x00PSBG2333 E16\x00\x00\x00\x00\x00\x00\x00TDN2H20SA7\x1a3\xf9\xab',
+ b'\xf1\x87959102T250\x00\x00\x00\x00\x00\xf1\x81E09\x00\x00\x00\x00\x00\x00\x00\xf1\x00PSBG2323 E09\x00\x00\x00\x00\x00\x00\x00TDN2H20SA5\x97R\x88\x9e',
+ b'\xf1\x87959102T250\x00\x00\x00\x00\x00\xf1\x81E14\x00\x00\x00\x00\x00\x00\x00\xf1\x00PSBG2333 E14\x00\x00\x00\x00\x00\x00\x00TDN2H20SA6N\xc2\xeeW',
+ b'\xf1\x87PCU\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x81E16\x00\x00\x00\x00\x00\x00\x00\xf1\x00PSBG2333 E16\x00\x00\x00\x00\x00\x00\x00TDN2H20SA7\x1a3\xf9\xab',
+ ],
+ (Ecu.engine, 0x7e0, None): [
+ b'\xf1\x87391062J002',
+ b'\xf1\x87391162J012',
+ b'\xf1\x87391162J013',
+ b'\xf1\x87391162J014',
+ ],
+ },
+ CAR.KIA_SORENTO: {
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00UMP LKAS AT USA LHD 1.01 1.01 95740-C6550 d01',
+ ],
+ (Ecu.abs, 0x7d1, None): [
+ b'\xf1\x00UM ESC \x0c 12 \x18\x05\x06 58910-C6330',
+ ],
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00UM__ SCC F-CUP 1.00 1.00 96400-C6500 ',
+ ],
+ (Ecu.transmission, 0x7e1, None): [
+ b'\xf1\x87LDKUAA0348164HE3\x87www\x87www\x88\x88\xa8\x88w\x88\x97xw\x88\x97x\x86o\xf8\xff\x87f\x7f\xff\x15\xe0\xf1\x81U811\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U811\x00\x00\x00\x00\x00\x00TUM4G33NL3V|DG',
+ ],
+ (Ecu.engine, 0x7e0, None): [
+ b'\xf1\x81640F0051\x00\x00\x00\x00\x00\x00\x00\x00',
+ ],
+ },
+ CAR.KIA_SORENTO_PHEV_4TH_GEN: {
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00MQhe SCC FHCUP 1.00 1.06 99110-P4000 ',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00MQ4HMFC AT USA LHD 1.00 1.10 99210-P2000 210406',
+ b'\xf1\x00MQ4HMFC AT USA LHD 1.00 1.11 99210-P2000 211217',
+ ],
+ },
+ CAR.KIA_EV6: {
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00CV1_ RDR ----- 1.00 1.01 99110-CV000 ',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00CV1 MFC AT EUR LHD 1.00 1.05 99210-CV000 211027',
+ b'\xf1\x00CV1 MFC AT EUR LHD 1.00 1.06 99210-CV000 220328',
+ b'\xf1\x00CV1 MFC AT EUR RHD 1.00 1.00 99210-CV100 220630',
+ b'\xf1\x00CV1 MFC AT KOR LHD 1.00 1.04 99210-CV000 210823',
+ b'\xf1\x00CV1 MFC AT KOR LHD 1.00 1.05 99210-CV000 211027',
+ b'\xf1\x00CV1 MFC AT KOR LHD 1.00 1.06 99210-CV000 220328',
+ b'\xf1\x00CV1 MFC AT USA LHD 1.00 1.00 99210-CV100 220630',
+ b'\xf1\x00CV1 MFC AT USA LHD 1.00 1.05 99210-CV000 211027',
+ b'\xf1\x00CV1 MFC AT USA LHD 1.00 1.06 99210-CV000 220328',
+ ],
+ },
+ CAR.IONIQ_5: {
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00NE1_ RDR ----- 1.00 1.00 99110-GI000 ',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00NE1 MFC AT EUR LHD 1.00 1.06 99211-GI000 210813',
+ b'\xf1\x00NE1 MFC AT EUR RHD 1.00 1.01 99211-GI010 211007',
+ b'\xf1\x00NE1 MFC AT EUR RHD 1.00 1.02 99211-GI010 211206',
+ b'\xf1\x00NE1 MFC AT KOR LHD 1.00 1.05 99211-GI010 220614',
+ b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.01 99211-GI010 211007',
+ b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.02 99211-GI010 211206',
+ b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.03 99211-GI010 220401',
+ b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.05 99211-GI010 220614',
+ b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.06 99211-GI010 230110',
+ ],
+ },
+ CAR.IONIQ_6: {
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00CE__ RDR ----- 1.00 1.01 99110-KL000 ',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00CE MFC AT EUR LHD 1.00 1.03 99211-KL000 221011',
+ b'\xf1\x00CE MFC AT USA LHD 1.00 1.04 99211-KL000 221213',
+ ],
+ },
+ CAR.TUCSON_4TH_GEN: {
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.00 99211-N9210 14G',
+ b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.01 99211-N9240 14T',
+ ],
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00NX4__ 1.00 1.00 99110-N9100 ',
+ b'\xf1\x00NX4__ 1.01 1.00 99110-N9100 ',
+ ],
+ },
+ CAR.TUCSON_HYBRID_4TH_GEN: {
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00NX4 FR_CMR AT EUR LHD 1.00 2.02 99211-N9000 14E',
+ b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.00 99211-N9220 14K',
+ b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.00 99211-N9240 14Q',
+ b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.00 99211-N9250 14W',
+ b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.00 99211-N9260 14Y',
+ b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.01 99211-N9100 14A',
+ ],
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00NX4__ 1.00 1.00 99110-N9100 ',
+ b'\xf1\x00NX4__ 1.00 1.01 99110-N9000 ',
+ b'\xf1\x00NX4__ 1.01 1.00 99110-N9100 ',
+ ],
+ },
+ CAR.KIA_SPORTAGE_HYBRID_5TH_GEN: {
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00NQ5 FR_CMR AT GEN LHD 1.00 1.00 99211-P1060 665',
+ b'\xf1\x00NQ5 FR_CMR AT USA LHD 1.00 1.00 99211-P1060 665',
+ ],
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00NQ5__ 1.01 1.03 99110-CH000 ',
+ ],
+ },
+ CAR.SANTA_CRUZ_1ST_GEN: {
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.00 99211-CW000 14M',
+ b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.00 99211-CW010 14X',
+ ],
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00NX4__ 1.00 1.00 99110-K5000 ',
+ b'\xf1\x00NX4__ 1.01 1.00 99110-K5000 ',
+ ],
+ },
+ CAR.KIA_SPORTAGE_5TH_GEN: {
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00NQ5 FR_CMR AT AUS RHD 1.00 1.00 99211-P1040 663',
+ b'\xf1\x00NQ5 FR_CMR AT USA LHD 1.00 1.00 99211-P1030 662',
+ b'\xf1\x00NQ5 FR_CMR AT USA LHD 1.00 1.00 99211-P1040 663',
+ ],
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00NQ5__ 1.00 1.02 99110-P1000 ',
+ b'\xf1\x00NQ5__ 1.00 1.03 99110-P1000 ',
+ b'\xf1\x00NQ5__ 1.01 1.03 99110-P1000 ',
+ ],
+ },
+ CAR.GENESIS_GV70_1ST_GEN: {
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00JK1 MFC AT USA LHD 1.00 1.01 99211-AR200 220125',
+ b'\xf1\x00JK1 MFC AT USA LHD 1.00 1.01 99211-AR300 220125',
+ b'\xf1\x00JK1 MFC AT USA LHD 1.00 1.04 99211-AR000 210204',
+ ],
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00JK1_ SCC FHCUP 1.00 1.00 99110-AR200 ',
+ b'\xf1\x00JK1_ SCC FHCUP 1.00 1.00 99110-AR300 ',
+ b'\xf1\x00JK1_ SCC FHCUP 1.00 1.02 99110-AR000 ',
+ ],
+ },
+ CAR.GENESIS_GV60_EV_1ST_GEN: {
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00JW1 MFC AT USA LHD 1.00 1.02 99211-CU000 211215',
+ b'\xf1\x00JW1 MFC AT USA LHD 1.00 1.02 99211-CU100 211215',
+ b'\xf1\x00JW1 MFC AT USA LHD 1.00 1.03 99211-CU000 221118',
+ ],
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00JW1_ RDR ----- 1.00 1.00 99110-CU000 ',
+ ],
+ },
+ CAR.KIA_SORENTO_4TH_GEN: {
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00MQ4 MFC AT USA LHD 1.00 1.00 99210-R5100 221019',
+ b'\xf1\x00MQ4 MFC AT USA LHD 1.00 1.03 99210-R5000 200903',
+ b'\xf1\x00MQ4 MFC AT USA LHD 1.00 1.05 99210-R5000 210623',
+ ],
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00MQ4_ SCC F-CUP 1.00 1.06 99110-P2000 ',
+ b'\xf1\x00MQ4_ SCC FHCUP 1.00 1.06 99110-P2000 ',
+ b'\xf1\x00MQ4_ SCC FHCUP 1.00 1.08 99110-P2000 ',
+ ],
+ },
+ CAR.KIA_NIRO_HEV_2ND_GEN: {
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00SG2HMFC AT USA LHD 1.01 1.08 99211-AT000 220531',
+ b'\xf1\x00SG2HMFC AT USA LHD 1.01 1.09 99211-AT000 220801',
+ ],
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00SG2_ RDR ----- 1.00 1.01 99110-AT000 ',
+ ],
+ },
+ CAR.GENESIS_GV80: {
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00JX1 MFC AT USA LHD 1.00 1.02 99211-T6110 220513',
+ ],
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00JX1_ SCC FHCUP 1.00 1.01 99110-T6100 ',
+ ],
+ },
+ CAR.KIA_CARNIVAL_4TH_GEN: {
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00KA4 MFC AT KOR LHD 1.00 1.06 99210-R0000 220221',
+ b'\xf1\x00KA4 MFC AT USA LHD 1.00 1.00 99210-R0100 230105',
+ b'\xf1\x00KA4 MFC AT USA LHD 1.00 1.05 99210-R0000 201221',
+ b'\xf1\x00KA4 MFC AT USA LHD 1.00 1.06 99210-R0000 220221',
+ b'\xf1\x00KA4CMFC AT CHN LHD 1.00 1.01 99211-I4000 210525',
+ ],
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00KA4_ SCC FHCUP 1.00 1.00 99110-R0100 ',
+ b'\xf1\x00KA4_ SCC FHCUP 1.00 1.03 99110-R0000 ',
+ b'\xf1\x00KA4c SCC FHCUP 1.00 1.01 99110-I4000 ',
+ ],
+ },
+ CAR.KIA_SORENTO_HEV_4TH_GEN: {
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00MQ4HMFC AT KOR LHD 1.00 1.04 99210-P2000 200330',
+ b'\xf1\x00MQ4HMFC AT KOR LHD 1.00 1.12 99210-P2000 230331',
+ b'\xf1\x00MQ4HMFC AT USA LHD 1.00 1.11 99210-P2000 211217',
+ ],
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00MQhe SCC FHCUP 1.00 1.04 99110-P4000 ',
+ b'\xf1\x00MQhe SCC FHCUP 1.00 1.07 99110-P4000 ',
+ ],
+ },
+ CAR.KIA_K8_HEV_1ST_GEN: {
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00GL3HMFC AT KOR LHD 1.00 1.03 99211-L8000 210907',
+ ],
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00GL3_ RDR ----- 1.00 1.02 99110-L8000 ',
+ ],
+ },
+ CAR.STARIA_4TH_GEN: {
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00US4 MFC AT KOR LHD 1.00 1.06 99211-CG000 230524',
+ ],
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00US4_ RDR ----- 1.00 1.00 99110-CG000 ',
+ ],
+ },
+}
diff --git a/selfdrive/car/hyundai org/hyundaican.org b/selfdrive/car/hyundai org/hyundaican.org
new file mode 100644
index 0000000..e5febf4
--- /dev/null
+++ b/selfdrive/car/hyundai org/hyundaican.org
@@ -0,0 +1,213 @@
+import crcmod
+from openpilot.selfdrive.car.hyundai.values import CAR, CHECKSUM, CAMERA_SCC_CAR
+
+hyundai_checksum = crcmod.mkCrcFun(0x11D, initCrc=0xFD, rev=False, xorOut=0xdf)
+
+def create_lkas11(packer, frame, car_fingerprint, apply_steer, steer_req,
+ torque_fault, lkas11, sys_warning, sys_state, enabled,
+ left_lane, right_lane,
+ left_lane_depart, right_lane_depart):
+ values = {s: lkas11[s] for s in [
+ "CF_Lkas_LdwsActivemode",
+ "CF_Lkas_LdwsSysState",
+ "CF_Lkas_SysWarning",
+ "CF_Lkas_LdwsLHWarning",
+ "CF_Lkas_LdwsRHWarning",
+ "CF_Lkas_HbaLamp",
+ "CF_Lkas_FcwBasReq",
+ "CF_Lkas_HbaSysState",
+ "CF_Lkas_FcwOpt",
+ "CF_Lkas_HbaOpt",
+ "CF_Lkas_FcwSysState",
+ "CF_Lkas_FcwCollisionWarning",
+ "CF_Lkas_FusionState",
+ "CF_Lkas_FcwOpt_USM",
+ "CF_Lkas_LdwsOpt_USM",
+ ]}
+ values["CF_Lkas_LdwsSysState"] = sys_state
+ values["CF_Lkas_SysWarning"] = 3 if sys_warning else 0
+ values["CF_Lkas_LdwsLHWarning"] = left_lane_depart
+ values["CF_Lkas_LdwsRHWarning"] = right_lane_depart
+ values["CR_Lkas_StrToqReq"] = apply_steer
+ values["CF_Lkas_ActToi"] = steer_req
+ values["CF_Lkas_ToiFlt"] = torque_fault # seems to allow actuation on CR_Lkas_StrToqReq
+ values["CF_Lkas_MsgCount"] = frame % 0x10
+
+ if car_fingerprint in (CAR.SONATA, CAR.PALISADE, CAR.KIA_NIRO_EV, CAR.KIA_NIRO_HEV_2021, CAR.SANTA_FE,
+ CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.KIA_SELTOS, CAR.ELANTRA_2021, CAR.GENESIS_G70_2020,
+ CAR.ELANTRA_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_EV, CAR.KONA_HEV, CAR.KONA_EV_2022,
+ CAR.SANTA_FE_2022, CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022,
+ CAR.SANTA_FE_PHEV_2022, CAR.KIA_STINGER_2022, CAR.KIA_K5_HEV_2020, CAR.KIA_CEED,
+ CAR.AZERA_6TH_GEN, CAR.AZERA_HEV_6TH_GEN, CAR.CUSTIN_1ST_GEN):
+ values["CF_Lkas_LdwsActivemode"] = int(left_lane) + (int(right_lane) << 1)
+ values["CF_Lkas_LdwsOpt_USM"] = 2
+
+ # FcwOpt_USM 5 = Orange blinking car + lanes
+ # FcwOpt_USM 4 = Orange car + lanes
+ # FcwOpt_USM 3 = Green blinking car + lanes
+ # FcwOpt_USM 2 = Green car + lanes
+ # FcwOpt_USM 1 = White car + lanes
+ # FcwOpt_USM 0 = No car + lanes
+ values["CF_Lkas_FcwOpt_USM"] = 2 if enabled else 1
+
+ # SysWarning 4 = keep hands on wheel
+ # SysWarning 5 = keep hands on wheel (red)
+ # SysWarning 6 = keep hands on wheel (red) + beep
+ # Note: the warning is hidden while the blinkers are on
+ values["CF_Lkas_SysWarning"] = 4 if sys_warning else 0
+
+ # Likely cars lacking the ability to show individual lane lines in the dash
+ elif car_fingerprint in (CAR.KIA_OPTIMA_G4, CAR.KIA_OPTIMA_G4_FL):
+ # SysWarning 4 = keep hands on wheel + beep
+ values["CF_Lkas_SysWarning"] = 4 if sys_warning else 0
+
+ # SysState 0 = no icons
+ # SysState 1-2 = white car + lanes
+ # SysState 3 = green car + lanes, green steering wheel
+ # SysState 4 = green car + lanes
+ values["CF_Lkas_LdwsSysState"] = 3 if enabled else 1
+ values["CF_Lkas_LdwsOpt_USM"] = 2 # non-2 changes above SysState definition
+
+ # these have no effect
+ values["CF_Lkas_LdwsActivemode"] = 0
+ values["CF_Lkas_FcwOpt_USM"] = 0
+
+ elif car_fingerprint == CAR.HYUNDAI_GENESIS:
+ # This field is actually LdwsActivemode
+ # Genesis and Optima fault when forwarding while engaged
+ values["CF_Lkas_LdwsActivemode"] = 2
+
+ dat = packer.make_can_msg("LKAS11", 0, values)[2]
+
+ if car_fingerprint in CHECKSUM["crc8"]:
+ # CRC Checksum as seen on 2019 Hyundai Santa Fe
+ dat = dat[:6] + dat[7:8]
+ checksum = hyundai_checksum(dat)
+ elif car_fingerprint in CHECKSUM["6B"]:
+ # Checksum of first 6 Bytes, as seen on 2018 Kia Sorento
+ checksum = sum(dat[:6]) % 256
+ else:
+ # Checksum of first 6 Bytes and last Byte as seen on 2018 Kia Stinger
+ checksum = (sum(dat[:6]) + dat[7]) % 256
+
+ values["CF_Lkas_Chksum"] = checksum
+
+ return packer.make_can_msg("LKAS11", 0, values)
+
+
+def create_clu11(packer, frame, clu11, button, car_fingerprint):
+ values = {s: clu11[s] for s in [
+ "CF_Clu_CruiseSwState",
+ "CF_Clu_CruiseSwMain",
+ "CF_Clu_SldMainSW",
+ "CF_Clu_ParityBit1",
+ "CF_Clu_VanzDecimal",
+ "CF_Clu_Vanz",
+ "CF_Clu_SPEED_UNIT",
+ "CF_Clu_DetentOut",
+ "CF_Clu_RheostatLevel",
+ "CF_Clu_CluInfo",
+ "CF_Clu_AmpInfo",
+ "CF_Clu_AliveCnt1",
+ ]}
+ values["CF_Clu_CruiseSwState"] = button
+ values["CF_Clu_AliveCnt1"] = frame % 0x10
+ # send buttons to camera on camera-scc based cars
+ bus = 2 if car_fingerprint in CAMERA_SCC_CAR else 0
+ return packer.make_can_msg("CLU11", bus, values)
+
+
+def create_lfahda_mfc(packer, enabled, hda_set_speed=0):
+ values = {
+ "LFA_Icon_State": 2 if enabled else 0,
+ "HDA_Active": 1 if hda_set_speed else 0,
+ "HDA_Icon_State": 2 if hda_set_speed else 0,
+ "HDA_VSetReq": hda_set_speed,
+ }
+ return packer.make_can_msg("LFAHDA_MFC", 0, values)
+
+def create_acc_commands(packer, enabled, accel, upper_jerk, idx, lead_visible, set_speed, stopping, long_override, use_fca, cruise_available, personality):
+ commands = []
+
+ scc11_values = {
+ "MainMode_ACC": 1 if cruise_available else 0,
+ "TauGapSet": personality + 1,
+ "VSetDis": set_speed if enabled else 0,
+ "AliveCounterACC": idx % 0x10,
+ "ObjValid": 1, # close lead makes controls tighter
+ "ACC_ObjStatus": 1, # close lead makes controls tighter
+ "ACC_ObjLatPos": 0,
+ "ACC_ObjRelSpd": 0,
+ "ACC_ObjDist": 1, # close lead makes controls tighter
+ }
+ commands.append(packer.make_can_msg("SCC11", 0, scc11_values))
+
+ scc12_values = {
+ "ACCMode": 2 if enabled and long_override else 1 if enabled else 0,
+ "StopReq": 1 if stopping else 0,
+ "aReqRaw": accel,
+ "aReqValue": accel, # stock ramps up and down respecting jerk limit until it reaches aReqRaw
+ "CR_VSM_Alive": idx % 0xF,
+ }
+
+ # show AEB disabled indicator on dash with SCC12 if not sending FCA messages.
+ # these signals also prevent a TCS fault on non-FCA cars with alpha longitudinal
+ if not use_fca:
+ scc12_values["CF_VSM_ConfMode"] = 1
+ scc12_values["AEB_Status"] = 1 # AEB disabled
+
+ scc12_dat = packer.make_can_msg("SCC12", 0, scc12_values)[2]
+ scc12_values["CR_VSM_ChkSum"] = 0x10 - sum(sum(divmod(i, 16)) for i in scc12_dat) % 0x10
+
+ commands.append(packer.make_can_msg("SCC12", 0, scc12_values))
+
+ scc14_values = {
+ "ComfortBandUpper": 0.0, # stock usually is 0 but sometimes uses higher values
+ "ComfortBandLower": 0.0, # stock usually is 0 but sometimes uses higher values
+ "JerkUpperLimit": upper_jerk, # stock usually is 1.0 but sometimes uses higher values
+ "JerkLowerLimit": 5.0, # stock usually is 0.5 but sometimes uses higher values
+ "ACCMode": 2 if enabled and long_override else 1 if enabled else 4, # stock will always be 4 instead of 0 after first disengage
+ "ObjGap": 2 if lead_visible else 0, # 5: >30, m, 4: 25-30 m, 3: 20-25 m, 2: < 20 m, 0: no lead
+ }
+ commands.append(packer.make_can_msg("SCC14", 0, scc14_values))
+
+ # Only send FCA11 on cars where it exists on the bus
+ if use_fca:
+ # note that some vehicles most likely have an alternate checksum/counter definition
+ # https://github.com/commaai/opendbc/commit/9ddcdb22c4929baf310295e832668e6e7fcfa602
+ fca11_values = {
+ "CR_FCA_Alive": idx % 0xF,
+ "PAINT1_Status": 1,
+ "FCA_DrvSetStatus": 1,
+ "FCA_Status": 1, # AEB disabled
+ }
+ fca11_dat = packer.make_can_msg("FCA11", 0, fca11_values)[2]
+ fca11_values["CR_FCA_ChkSum"] = hyundai_checksum(fca11_dat[:7])
+ commands.append(packer.make_can_msg("FCA11", 0, fca11_values))
+
+ return commands
+
+def create_acc_opt(packer):
+ commands = []
+
+ scc13_values = {
+ "SCCDrvModeRValue": 2,
+ "SCC_Equip": 1,
+ "Lead_Veh_Dep_Alert_USM": 2,
+ }
+ commands.append(packer.make_can_msg("SCC13", 0, scc13_values))
+
+ # TODO: this needs to be detected and conditionally sent on unsupported long cars
+ fca12_values = {
+ "FCA_DrvSetState": 2,
+ "FCA_USM": 1, # AEB disabled
+ }
+ commands.append(packer.make_can_msg("FCA12", 0, fca12_values))
+
+ return commands
+
+def create_frt_radar_opt(packer):
+ frt_radar11_values = {
+ "CF_FCA_Equip_Front_Radar": 1,
+ }
+ return packer.make_can_msg("FRT_RADAR11", 0, frt_radar11_values)
diff --git a/selfdrive/car/hyundai org/hyundaicanfd.org b/selfdrive/car/hyundai org/hyundaicanfd.org
new file mode 100644
index 0000000..d660a2d
--- /dev/null
+++ b/selfdrive/car/hyundai org/hyundaicanfd.org
@@ -0,0 +1,224 @@
+from openpilot.common.numpy_fast import clip
+from openpilot.selfdrive.car import CanBusBase
+from openpilot.selfdrive.car.hyundai.values import HyundaiFlags
+
+
+class CanBus(CanBusBase):
+ def __init__(self, CP, hda2=None, fingerprint=None) -> None:
+ super().__init__(CP, fingerprint)
+
+ if hda2 is None:
+ assert CP is not None
+ hda2 = CP.flags & HyundaiFlags.CANFD_HDA2.value
+
+ # On the CAN-FD platforms, the LKAS camera is on both A-CAN and E-CAN. HDA2 cars
+ # have a different harness than the HDA1 and non-HDA variants in order to split
+ # a different bus, since the steering is done by different ECUs.
+ self._a, self._e = 1, 0
+ if hda2:
+ self._a, self._e = 0, 1
+
+ self._a += self.offset
+ self._e += self.offset
+ self._cam = 2 + self.offset
+
+ @property
+ def ECAN(self):
+ return self._e
+
+ @property
+ def ACAN(self):
+ return self._a
+
+ @property
+ def CAM(self):
+ return self._cam
+
+
+def create_steering_messages(packer, CP, CAN, enabled, lat_active, apply_steer):
+
+ ret = []
+
+ values = {
+ "LKA_MODE": 2,
+ "LKA_ICON": 2 if enabled else 1 if lat_active else 0,
+ "TORQUE_REQUEST": apply_steer,
+ "LKA_ASSIST": 0,
+ "STEER_REQ": 1 if lat_active else 0,
+ "STEER_MODE": 0,
+ "HAS_LANE_SAFETY": 0, # hide LKAS settings
+ "NEW_SIGNAL_1": 0,
+ "NEW_SIGNAL_2": 0,
+ }
+
+ if CP.flags & HyundaiFlags.CANFD_HDA2:
+ hda2_lkas_msg = "LKAS_ALT" if CP.flags & HyundaiFlags.CANFD_HDA2_ALT_STEERING else "LKAS"
+ if CP.openpilotLongitudinalControl:
+ ret.append(packer.make_can_msg("LFA", CAN.ECAN, values))
+ ret.append(packer.make_can_msg(hda2_lkas_msg, CAN.ACAN, values))
+ else:
+ ret.append(packer.make_can_msg("LFA", CAN.ECAN, values))
+
+ return ret
+
+def create_suppress_lfa(packer, CAN, hda2_lfa_block_msg, hda2_alt_steering):
+ suppress_msg = "CAM_0x362" if hda2_alt_steering else "CAM_0x2a4"
+ msg_bytes = 32 if hda2_alt_steering else 24
+
+ values = {f"BYTE{i}": hda2_lfa_block_msg[f"BYTE{i}"] for i in range(3, msg_bytes) if i != 7}
+ values["COUNTER"] = hda2_lfa_block_msg["COUNTER"]
+ values["SET_ME_0"] = 0
+ values["SET_ME_0_2"] = 0
+ values["LEFT_LANE_LINE"] = 0
+ values["RIGHT_LANE_LINE"] = 0
+ return packer.make_can_msg(suppress_msg, CAN.ACAN, values)
+
+def create_buttons(packer, CP, CAN, cnt, btn):
+ values = {
+ "COUNTER": cnt,
+ "SET_ME_1": 1,
+ "CRUISE_BUTTONS": btn,
+ }
+
+ bus = CAN.ECAN if CP.flags & HyundaiFlags.CANFD_HDA2 else CAN.CAM
+ return packer.make_can_msg("CRUISE_BUTTONS", bus, values)
+
+def create_acc_cancel(packer, CP, CAN, cruise_info_copy):
+ # TODO: why do we copy different values here?
+ if CP.flags & HyundaiFlags.CANFD_CAMERA_SCC.value:
+ values = {s: cruise_info_copy[s] for s in [
+ "COUNTER",
+ "CHECKSUM",
+ "NEW_SIGNAL_1",
+ "MainMode_ACC",
+ "ACCMode",
+ "ZEROS_9",
+ "CRUISE_STANDSTILL",
+ "ZEROS_5",
+ "DISTANCE_SETTING",
+ "VSetDis",
+ ]}
+ else:
+ values = {s: cruise_info_copy[s] for s in [
+ "COUNTER",
+ "CHECKSUM",
+ "ACCMode",
+ "VSetDis",
+ "CRUISE_STANDSTILL",
+ ]}
+ values.update({
+ "ACCMode": 4,
+ "aReqRaw": 0.0,
+ "aReqValue": 0.0,
+ })
+ return packer.make_can_msg("SCC_CONTROL", CAN.ECAN, values)
+
+def create_lfahda_cluster(packer, CAN, enabled):
+ values = {
+ "HDA_ICON": 1 if enabled else 0,
+ # 0 off, 1 gray, 2 green, 3 blinking (wheel icon)
+ "LFA_ICON": 0 if enabled else 0, # was green before i think in 2? 3 should be flashing?
+ # "LFA_ICON": 2 if enabled else 0,
+ }
+ return packer.make_can_msg("LFAHDA_CLUSTER", CAN.ECAN, values)
+
+
+def create_acc_control(packer, CAN, enabled, accel_last, accel, stopping, gas_override, set_speed, personality):
+ jerk = 5
+ jn = jerk / 50
+ if not enabled or gas_override:
+ a_val, a_raw = 0, 0
+ else:
+ a_raw = accel
+ a_val = clip(accel, accel_last - jn, accel_last + jn)
+
+ values = {
+ "ACCMode": 0 if not enabled else (2 if gas_override else 1),
+ "MainMode_ACC": 1,
+ "StopReq": 1 if stopping else 0,
+ "aReqValue": a_val,
+ "aReqRaw": a_raw,
+ "VSetDis": set_speed,
+ "JerkLowerLimit": jerk if enabled else 1,
+ "JerkUpperLimit": 3.0,
+
+ "ACC_ObjDist": 1,
+ "ObjValid": 0,
+ "OBJ_STATUS": 2,
+ "SET_ME_2": 0x4,
+ "SET_ME_3": 0x3,
+ "SET_ME_TMP_64": 0x64,
+ "DISTANCE_SETTING": personality + 1,
+ }
+
+ return packer.make_can_msg("SCC_CONTROL", CAN.ECAN, values)
+
+def create_spas_messages(packer, CAN, frame, left_blink, right_blink):
+ ret = []
+
+ values = {
+ }
+ ret.append(packer.make_can_msg("SPAS1", CAN.ECAN, values))
+
+ blink = 0
+ if left_blink:
+ blink = 3
+ elif right_blink:
+ blink = 4
+ values = {
+ "BLINKER_CONTROL": blink,
+ }
+ ret.append(packer.make_can_msg("SPAS2", CAN.ECAN, values))
+
+ return ret
+
+
+def create_adrv_messages(packer, CAN, frame):
+ # messages needed to car happy after disabling
+ # the ADAS Driving ECU to do longitudinal control
+
+ ret = []
+
+ values = {
+ }
+ ret.append(packer.make_can_msg("ADRV_0x51", CAN.ACAN, values))
+
+ if frame % 2 == 0:
+ values = {
+ 'AEB_SETTING': 0x1, # show AEB disabled icon
+ 'SET_ME_2': 0x2,
+ 'SET_ME_FF': 0xff,
+ 'SET_ME_FC': 0xfc,
+ 'SET_ME_9': 0x9,
+ }
+ ret.append(packer.make_can_msg("ADRV_0x160", CAN.ECAN, values))
+
+ if frame % 5 == 0:
+ values = {
+ 'SET_ME_1C': 0x1c,
+ 'SET_ME_FF': 0xff,
+ 'SET_ME_TMP_F': 0xf,
+ 'SET_ME_TMP_F_2': 0xf,
+ }
+ ret.append(packer.make_can_msg("ADRV_0x1ea", CAN.ECAN, values))
+
+ values = {
+ 'SET_ME_E1': 0xe1,
+ 'SET_ME_3A': 0x3a,
+ }
+ ret.append(packer.make_can_msg("ADRV_0x200", CAN.ECAN, values))
+
+ if frame % 20 == 0:
+ values = {
+ 'SET_ME_15': 0x15,
+ }
+ ret.append(packer.make_can_msg("ADRV_0x345", CAN.ECAN, values))
+
+ if frame % 100 == 0:
+ values = {
+ 'SET_ME_22': 0x22,
+ 'SET_ME_41': 0x41,
+ }
+ ret.append(packer.make_can_msg("ADRV_0x1da", CAN.ECAN, values))
+
+ return ret
diff --git a/selfdrive/car/hyundai org/interface.org b/selfdrive/car/hyundai org/interface.org
new file mode 100644
index 0000000..b5e8f51
--- /dev/null
+++ b/selfdrive/car/hyundai org/interface.org
@@ -0,0 +1,375 @@
+from cereal import car
+from panda import Panda
+from openpilot.common.conversions import Conversions as CV
+from openpilot.selfdrive.car.hyundai.hyundaicanfd import CanBus
+from openpilot.selfdrive.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
+from openpilot.selfdrive.car.hyundai.radar_interface import RADAR_START_ADDR
+from openpilot.selfdrive.car import create_button_events, get_safety_config
+from openpilot.selfdrive.car.interfaces import CarInterfaceBase
+from openpilot.selfdrive.car.disable_ecu import disable_ecu
+from openpilot.common.params import Params
+
+params_memory = Params("/dev/shm/params")
+
+Ecu = car.CarParams.Ecu
+SafetyModel = car.CarParams.SafetyModel
+ButtonType = car.CarState.ButtonEvent.Type
+EventName = car.CarEvent.EventName
+ENABLE_BUTTONS = (Buttons.RES_ACCEL, Buttons.SET_DECEL, Buttons.CANCEL)
+BUTTONS_DICT = {Buttons.RES_ACCEL: ButtonType.accelCruise, Buttons.SET_DECEL: ButtonType.decelCruise,
+ Buttons.GAP_DIST: ButtonType.gapAdjustCruise, Buttons.CANCEL: ButtonType.cancel}
+
+
+def set_safety_config_hyundai(candidate, CAN, can_fd=False):
+ platform = SafetyModel.hyundaiCanfd if can_fd else \
+ SafetyModel.hyundaiLegacy if candidate in LEGACY_SAFETY_MODE_CAR else \
+ SafetyModel.hyundai
+ cfgs = [get_safety_config(platform), ]
+ if CAN.ECAN >= 4:
+ cfgs.insert(0, get_safety_config(SafetyModel.noOutput))
+
+ return cfgs
+
+
+class CarInterface(CarInterfaceBase):
+ @staticmethod
+ def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs):
+ ret.carName = "hyundai"
+ ret.radarUnavailable = RADAR_START_ADDR not in fingerprint[1] or DBC[ret.carFingerprint]["radar"] is None
+ params_memory.put_bool("CSLCAvailable", True)
+
+ # 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 selfdrive/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, }
+
+ hda2 = Ecu.adas in [fw.ecu for fw in car_fw]
+ CAN = CanBus(None, hda2, fingerprint)
+
+ if candidate in CANFD_CAR:
+ # detect HDA2 with ADAS Driving ECU
+ if hda2:
+ if 0x110 in fingerprint[CAN.CAM]:
+ ret.flags |= HyundaiFlags.CANFD_HDA2_ALT_STEERING.value
+ params_memory.put_bool("CSLCAvailable", False)
+ else:
+ # non-HDA2
+ if 0x1cf not in fingerprint[CAN.ECAN]:
+ ret.flags |= HyundaiFlags.CANFD_ALT_BUTTONS.value
+ # ICE cars do not have 0x130; GEARS message on 0x40 or 0x70 instead
+ if 0x130 not in fingerprint[CAN.ECAN]:
+ if 0x40 not in fingerprint[CAN.ECAN]:
+ ret.flags |= HyundaiFlags.CANFD_ALT_GEARS_2.value
+ else:
+ ret.flags |= HyundaiFlags.CANFD_ALT_GEARS.value
+ if candidate not in CANFD_RADAR_SCC_CAR:
+ ret.flags |= HyundaiFlags.CANFD_CAMERA_SCC.value
+ else:
+ # Send LFA message on cars with HDA
+ if 0x485 in fingerprint[2]:
+ ret.flags |= HyundaiFlags.SEND_LFA.value
+
+ # These cars use the FCA11 message for the AEB and FCW signals, all others use SCC12
+ if 0x38d in fingerprint[0] or 0x38d in fingerprint[2]:
+ ret.flags |= HyundaiFlags.USE_FCA.value
+
+ ret.steerActuatorDelay = 0.1 # Default delay
+ ret.steerLimitTimer = 0.4
+ CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
+
+ if candidate in (CAR.AZERA_6TH_GEN, CAR.AZERA_HEV_6TH_GEN):
+ ret.mass = 1600. if candidate == CAR.AZERA_6TH_GEN else 1675. # ICE is ~average of 2.5L and 3.5L
+ ret.wheelbase = 2.885
+ ret.steerRatio = 14.5
+ elif candidate in (CAR.SANTA_FE, CAR.SANTA_FE_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022):
+ ret.mass = 3982. * CV.LB_TO_KG
+ ret.wheelbase = 2.766
+ # Values from optimizer
+ ret.steerRatio = 16.55 # 13.8 is spec end-to-end
+ ret.tireStiffnessFactor = 0.82
+ elif candidate in (CAR.SONATA, CAR.SONATA_HYBRID):
+ ret.mass = 1513.
+ ret.wheelbase = 2.84
+ ret.steerRatio = 13.27 * 1.15 # 15% higher at the center seems reasonable
+ ret.tireStiffnessFactor = 0.65
+ elif candidate == CAR.SONATA_LF:
+ ret.mass = 1536.
+ ret.wheelbase = 2.804
+ ret.steerRatio = 13.27 * 1.15 # 15% higher at the center seems reasonable
+ elif candidate == CAR.PALISADE:
+ ret.mass = 1999.
+ ret.wheelbase = 2.90
+ ret.steerRatio = 15.6 * 1.15
+ ret.tireStiffnessFactor = 0.63
+ elif candidate in (CAR.ELANTRA, CAR.ELANTRA_GT_I30):
+ ret.mass = 1275.
+ ret.wheelbase = 2.7
+ ret.steerRatio = 15.4 # 14 is Stock | Settled Params Learner values are steerRatio: 15.401566348670535
+ ret.tireStiffnessFactor = 0.385 # stiffnessFactor settled on 1.0081302973865127
+ ret.minSteerSpeed = 32 * CV.MPH_TO_MS
+ elif candidate == CAR.ELANTRA_2021:
+ ret.mass = 2800. * CV.LB_TO_KG
+ ret.wheelbase = 2.72
+ ret.steerRatio = 12.9
+ ret.tireStiffnessFactor = 0.65
+ elif candidate == CAR.ELANTRA_HEV_2021:
+ ret.mass = 3017. * CV.LB_TO_KG
+ ret.wheelbase = 2.72
+ ret.steerRatio = 12.9
+ ret.tireStiffnessFactor = 0.65
+ elif candidate == CAR.HYUNDAI_GENESIS:
+ ret.mass = 2060.
+ ret.wheelbase = 3.01
+ ret.steerRatio = 16.5
+ ret.minSteerSpeed = 60 * CV.KPH_TO_MS
+ elif candidate in (CAR.KONA, CAR.KONA_EV, CAR.KONA_HEV, CAR.KONA_EV_2022, CAR.KONA_EV_2ND_GEN):
+ ret.mass = {CAR.KONA_EV: 1685., CAR.KONA_HEV: 1425., CAR.KONA_EV_2022: 1743., CAR.KONA_EV_2ND_GEN: 1740.}.get(candidate, 1275.)
+ ret.wheelbase = {CAR.KONA_EV_2ND_GEN: 2.66, }.get(candidate, 2.6)
+ ret.steerRatio = {CAR.KONA_EV_2ND_GEN: 13.6, }.get(candidate, 13.42) # Spec
+ ret.tireStiffnessFactor = 0.385
+ elif candidate in (CAR.IONIQ, CAR.IONIQ_EV_LTD, CAR.IONIQ_PHEV_2019, CAR.IONIQ_HEV_2022, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV):
+ ret.mass = 1490. # weight per hyundai site https://www.hyundaiusa.com/ioniq-electric/specifications.aspx
+ ret.wheelbase = 2.7
+ ret.steerRatio = 13.73 # Spec
+ ret.tireStiffnessFactor = 0.385
+ if candidate in (CAR.IONIQ, CAR.IONIQ_EV_LTD, CAR.IONIQ_PHEV_2019):
+ ret.minSteerSpeed = 32 * CV.MPH_TO_MS
+ elif candidate in (CAR.IONIQ_5, CAR.IONIQ_6):
+ ret.mass = 1948
+ ret.wheelbase = 2.97
+ ret.steerRatio = 14.26
+ ret.tireStiffnessFactor = 0.65
+ elif candidate == CAR.VELOSTER:
+ ret.mass = 2917. * CV.LB_TO_KG
+ ret.wheelbase = 2.80
+ ret.steerRatio = 13.75 * 1.15
+ ret.tireStiffnessFactor = 0.5
+ elif candidate == CAR.TUCSON:
+ ret.mass = 3520. * CV.LB_TO_KG
+ ret.wheelbase = 2.67
+ ret.steerRatio = 14.00 * 1.15
+ ret.tireStiffnessFactor = 0.385
+ elif candidate in (CAR.TUCSON_4TH_GEN, CAR.TUCSON_HYBRID_4TH_GEN):
+ ret.steerActuatorDelay = 0.1 # Or .15? BBOT test oscarpilot
+ ret.mass = 1630. # average
+ ret.wheelbase = 2.756
+ ret.steerRatio = 16.
+ ret.tireStiffnessFactor = 0.385
+ elif candidate == CAR.SANTA_CRUZ_1ST_GEN:
+ ret.mass = 1870. # weight from Limited trim - the only supported trim
+ ret.wheelbase = 3.000
+ # steering ratio according to Hyundai News https://www.hyundainews.com/assets/documents/original/48035-2022SantaCruzProductGuideSpecsv2081521.pdf
+ ret.steerRatio = 14.2
+ elif candidate == CAR.CUSTIN_1ST_GEN:
+ ret.mass = 1690. # from https://www.hyundai-motor.com.tw/clicktobuy/custin#spec_0
+ ret.wheelbase = 3.055
+ ret.steerRatio = 17.0 # from learner
+ elif candidate == CAR.STARIA_4TH_GEN:
+ ret.mass = 2205.
+ ret.wheelbase = 3.273
+ ret.steerRatio = 11.94 # https://www.hyundai.com/content/dam/hyundai/au/en/models/staria-load/premium-pip-update-2023/spec-sheet/STARIA_Load_Spec-Table_March_2023_v3.1.pdf
+
+ # Kia
+ elif candidate == CAR.KIA_SORENTO:
+ ret.mass = 1985.
+ ret.wheelbase = 2.78
+ ret.steerRatio = 14.4 * 1.1 # 10% higher at the center seems reasonable
+ elif candidate in (CAR.KIA_NIRO_EV, CAR.KIA_NIRO_EV_2ND_GEN, CAR.KIA_NIRO_PHEV, CAR.KIA_NIRO_HEV_2021, CAR.KIA_NIRO_HEV_2ND_GEN, CAR.KIA_NIRO_PHEV_2022):
+ ret.mass = 3543. * CV.LB_TO_KG # average of all the cars
+ ret.wheelbase = 2.7
+ ret.steerRatio = 13.6 # average of all the cars
+ ret.tireStiffnessFactor = 0.385
+ if candidate == CAR.KIA_NIRO_PHEV:
+ ret.minSteerSpeed = 32 * CV.MPH_TO_MS
+ elif candidate == CAR.KIA_SELTOS:
+ ret.mass = 1337.
+ ret.wheelbase = 2.63
+ ret.steerRatio = 14.56
+ elif candidate == CAR.KIA_SPORTAGE_5TH_GEN:
+ ret.mass = 1700. # weight from SX and above trims, average of FWD and AWD versions
+ ret.wheelbase = 2.756
+ ret.steerRatio = 13.6 # steering ratio according to Kia News https://www.kiamedia.com/us/en/models/sportage/2023/specifications
+ elif candidate in (CAR.KIA_OPTIMA_G4, CAR.KIA_OPTIMA_G4_FL, CAR.KIA_OPTIMA_H, CAR.KIA_OPTIMA_H_G4_FL):
+ ret.mass = 3558. * CV.LB_TO_KG
+ ret.wheelbase = 2.80
+ ret.steerRatio = 13.75
+ ret.tireStiffnessFactor = 0.5
+ if candidate == CAR.KIA_OPTIMA_G4:
+ ret.minSteerSpeed = 32 * CV.MPH_TO_MS
+ elif candidate in (CAR.KIA_STINGER, CAR.KIA_STINGER_2022):
+ ret.mass = 1825.
+ ret.wheelbase = 2.78
+ ret.steerRatio = 14.4 * 1.15 # 15% higher at the center seems reasonable
+ elif candidate == CAR.KIA_FORTE:
+ ret.mass = 2878. * CV.LB_TO_KG
+ ret.wheelbase = 2.80
+ ret.steerRatio = 13.75
+ ret.tireStiffnessFactor = 0.5
+ elif candidate == CAR.KIA_CEED:
+ ret.mass = 1450.
+ ret.wheelbase = 2.65
+ ret.steerRatio = 13.75
+ ret.tireStiffnessFactor = 0.5
+ elif candidate in (CAR.KIA_K5_2021, CAR.KIA_K5_HEV_2020):
+ ret.mass = 3381. * CV.LB_TO_KG
+ ret.wheelbase = 2.85
+ ret.steerRatio = 13.27 # 2021 Kia K5 Steering Ratio (all trims)
+ ret.tireStiffnessFactor = 0.5
+ elif candidate == CAR.KIA_EV6:
+ ret.mass = 2055
+ ret.wheelbase = 2.9
+ ret.steerRatio = 16.
+ ret.tireStiffnessFactor = 0.65
+ elif candidate == CAR.KIA_SPORTAGE_HYBRID_5TH_GEN:
+ ret.mass = 1767. # SX Prestige trim support only
+ ret.wheelbase = 2.756
+ ret.steerRatio = 13.6
+ elif candidate in (CAR.KIA_SORENTO_4TH_GEN, CAR.KIA_SORENTO_HEV_4TH_GEN, CAR.KIA_SORENTO_PHEV_4TH_GEN):
+ ret.wheelbase = 2.81
+ ret.steerRatio = 13.5 # average of the platforms
+ if candidate == CAR.KIA_SORENTO_4TH_GEN:
+ ret.mass = 3957 * CV.LB_TO_KG
+ elif candidate == CAR.KIA_SORENTO_HEV_4TH_GEN:
+ ret.mass = 4255 * CV.LB_TO_KG
+ else:
+ ret.mass = 4537 * CV.LB_TO_KG
+ elif candidate == CAR.KIA_CARNIVAL_4TH_GEN:
+ ret.mass = 2087.
+ ret.wheelbase = 3.09
+ ret.steerRatio = 14.23
+ elif candidate == CAR.KIA_K8_HEV_1ST_GEN:
+ ret.mass = 1630. # https://carprices.ae/brands/kia/2023/k8/1.6-turbo-hybrid
+ ret.wheelbase = 2.895
+ ret.steerRatio = 13.27 # guesstimate from K5 platform
+
+ # Genesis
+ elif candidate == CAR.GENESIS_GV60_EV_1ST_GEN:
+ ret.mass = 2205
+ ret.wheelbase = 2.9
+ # https://www.motor1.com/reviews/586376/2023-genesis-gv60-first-drive/#:~:text=Relative%20to%20the%20related%20Ioniq,5%2FEV6%27s%2014.3%3A1.
+ ret.steerRatio = 12.6
+ elif candidate == CAR.GENESIS_G70:
+ ret.steerActuatorDelay = 0.1
+ ret.mass = 1640.0
+ ret.wheelbase = 2.84
+ ret.steerRatio = 13.56
+ elif candidate == CAR.GENESIS_G70_2020:
+ ret.mass = 3673.0 * CV.LB_TO_KG
+ ret.wheelbase = 2.83
+ ret.steerRatio = 12.9
+ elif candidate == CAR.GENESIS_GV70_1ST_GEN:
+ ret.mass = 1950.
+ ret.wheelbase = 2.87
+ ret.steerRatio = 14.6
+ elif candidate == CAR.GENESIS_G80:
+ ret.mass = 2060.
+ ret.wheelbase = 3.01
+ ret.steerRatio = 16.5
+ elif candidate == CAR.GENESIS_G90:
+ ret.mass = 2200.
+ ret.wheelbase = 3.15
+ ret.steerRatio = 12.069
+ elif candidate == CAR.GENESIS_GV80:
+ ret.mass = 2258.
+ ret.wheelbase = 2.95
+ ret.steerRatio = 14.14
+
+ # *** longitudinal control ***
+ if candidate in CANFD_CAR:
+ ret.longitudinalTuning.kpV = [0.1]
+ ret.longitudinalTuning.kiV = [0.0]
+ ret.experimentalLongitudinalAvailable = candidate not in (CANFD_UNSUPPORTED_LONGITUDINAL_CAR | CANFD_RADAR_SCC_CAR)
+ else:
+ ret.longitudinalTuning.kpV = [0.5]
+ ret.longitudinalTuning.kiV = [0.0]
+ ret.experimentalLongitudinalAvailable = candidate not in (UNSUPPORTED_LONGITUDINAL_CAR | CAMERA_SCC_CAR)
+ ret.openpilotLongitudinalControl = experimental_long and ret.experimentalLongitudinalAvailable
+ ret.pcmCruise = not ret.openpilotLongitudinalControl
+
+ ret.stoppingControl = True
+ ret.startingState = True
+ ret.vEgoStarting = 0.1
+ ret.startAccel = 1.0
+ ret.longitudinalActuatorDelayLowerBound = 0.5
+ ret.longitudinalActuatorDelayUpperBound = 0.5
+
+ # *** feature detection ***
+ # if candidate in CANFD_CAR:
+ # ret.enableBsm = 0x1e5 in fingerprint[CAN.ECAN]
+ # ret.nav_msg = 0x544 in fingerprint[0]
+ # else:
+ # ret.enableBsm = 0x58b in fingerprint[0]
+ # ret.nav_msg = False
+
+ # *** panda safety config ***
+ ret.safetyConfigs = set_safety_config_hyundai(candidate, CAN, can_fd=(candidate in CANFD_CAR))
+
+ if hda2:
+ ret.flags |= HyundaiFlags.CANFD_HDA2.value
+ ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_CANFD_HDA2
+
+ if candidate in CANFD_CAR:
+ if hda2 and 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:
+ ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_CANFD_ALT_BUTTONS
+
+ if ret.flags & HyundaiFlags.CANFD_CAMERA_SCC or candidate in CAMERA_SCC_CAR:
+ ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_CAMERA_SCC
+ if ret.openpilotLongitudinalControl:
+ ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_LONG
+ params_memory.put_bool("CSLCAvailable", False)
+ if candidate in HYBRID_CAR:
+ ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_HYBRID_GAS
+ elif candidate in EV_CAR:
+ ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_EV_GAS
+
+ if candidate in (CAR.KONA, CAR.KONA_EV, CAR.KONA_HEV, CAR.KONA_EV_2022):
+ ret.flags |= HyundaiFlags.ALT_LIMITS.value
+ ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_ALT_LIMITS
+
+ ret.centerToFront = ret.wheelbase * 0.4
+
+ return ret
+
+ @staticmethod
+ def init(CP, logcan, sendcan):
+ if CP.openpilotLongitudinalControl and not (CP.flags & HyundaiFlags.CANFD_CAMERA_SCC.value):
+ addr, bus = 0x7d0, 0
+ if CP.flags & HyundaiFlags.CANFD_HDA2.value:
+ addr, bus = 0x730, CanBus(CP).ECAN
+ disable_ecu(logcan, sendcan, bus=bus, addr=addr, com_cont_req=b'\x28\x83\x01')
+
+ # for blinkers
+ if CP.flags & HyundaiFlags.ENABLE_BLINKERS:
+ disable_ecu(logcan, sendcan, bus=CanBus(CP).ECAN, addr=0x7B1, com_cont_req=b'\x28\x83\x01')
+
+ def _update(self, c):
+ ret = self.CS.update(self.cp, self.cp_cam)
+
+ if self.CS.CP.openpilotLongitudinalControl:
+ ret.buttonEvents = create_button_events(self.CS.cruise_buttons[-1], self.CS.prev_cruise_buttons, BUTTONS_DICT)
+
+ # On some newer model years, the CANCEL button acts as a pause/resume button based on the PCM state
+ # To avoid re-engaging when openpilot cancels, check user engagement intention via buttons
+ # Main button also can trigger an engagement on these cars
+ allow_enable = any(btn in ENABLE_BUTTONS for btn in self.CS.cruise_buttons) or any(self.CS.main_buttons)
+ events = self.create_common_events(ret, pcm_enable=self.CS.CP.pcmCruise, allow_enable=allow_enable)
+
+ # low speed steer alert hysteresis logic (only for cars with steer cut off above 10 m/s)
+ if ret.vEgo < (self.CP.minSteerSpeed + 2.) and self.CP.minSteerSpeed > 10.:
+ self.low_speed_alert = True
+ if ret.vEgo > (self.CP.minSteerSpeed + 4.):
+ self.low_speed_alert = False
+ if self.low_speed_alert:
+ events.add(car.CarEvent.EventName.belowSteerSpeed)
+
+ ret.events = events.to_msg()
+
+ return ret
+
+ def apply(self, c, now_nanos, sport_plus):
+ return self.CC.update(c, self.CS, now_nanos, sport_plus)
diff --git a/selfdrive/car/hyundai org/radar_interface.org b/selfdrive/car/hyundai org/radar_interface.org
new file mode 100644
index 0000000..5260050
--- /dev/null
+++ b/selfdrive/car/hyundai org/radar_interface.org
@@ -0,0 +1,79 @@
+import math
+
+from cereal import car
+from opendbc.can.parser import CANParser
+from openpilot.selfdrive.car.interfaces import RadarInterfaceBase
+from openpilot.selfdrive.car.hyundai.values import DBC
+
+RADAR_START_ADDR = 0x500
+RADAR_MSG_COUNT = 32
+
+# POC for parsing corner radars: https://github.com/commaai/openpilot/pull/24221/
+
+def get_radar_can_parser(CP):
+ if DBC[CP.carFingerprint]['radar'] is None:
+ return None
+
+ messages = [(f"RADAR_TRACK_{addr:x}", 50) for addr in range(RADAR_START_ADDR, RADAR_START_ADDR + RADAR_MSG_COUNT)]
+ return CANParser(DBC[CP.carFingerprint]['radar'], messages, 1)
+
+
+class RadarInterface(RadarInterfaceBase):
+ def __init__(self, CP):
+ super().__init__(CP)
+ self.updated_messages = set()
+ self.trigger_msg = RADAR_START_ADDR + RADAR_MSG_COUNT - 1
+ self.track_id = 0
+
+ self.radar_off_can = CP.radarUnavailable
+ self.rcp = get_radar_can_parser(CP)
+
+ def update(self, can_strings):
+ if self.radar_off_can or (self.rcp is None):
+ return super().update(None)
+
+ vls = self.rcp.update_strings(can_strings)
+ self.updated_messages.update(vls)
+
+ if self.trigger_msg not in self.updated_messages:
+ return None
+
+ rr = self._update(self.updated_messages)
+ self.updated_messages.clear()
+
+ return rr
+
+ def _update(self, updated_messages):
+ ret = car.RadarData.new_message()
+ if self.rcp is None:
+ return ret
+
+ errors = []
+
+ if not self.rcp.can_valid:
+ errors.append("canError")
+ ret.errors = errors
+
+ for addr in range(RADAR_START_ADDR, RADAR_START_ADDR + RADAR_MSG_COUNT):
+ msg = self.rcp.vl[f"RADAR_TRACK_{addr:x}"]
+
+ if addr not in self.pts:
+ self.pts[addr] = car.RadarData.RadarPoint.new_message()
+ self.pts[addr].trackId = self.track_id
+ self.track_id += 1
+
+ valid = msg['STATE'] in (3, 4)
+ if valid:
+ azimuth = math.radians(msg['AZIMUTH'])
+ self.pts[addr].measured = True
+ self.pts[addr].dRel = math.cos(azimuth) * msg['LONG_DIST']
+ self.pts[addr].yRel = 0.5 * -math.sin(azimuth) * msg['LONG_DIST']
+ self.pts[addr].vRel = msg['REL_SPEED']
+ self.pts[addr].aRel = msg['REL_ACCEL']
+ self.pts[addr].yvRel = float('nan')
+
+ else:
+ del self.pts[addr]
+
+ ret.points = list(self.pts.values())
+ return ret
diff --git a/selfdrive/car/hyundai org/values.org b/selfdrive/car/hyundai org/values.org
new file mode 100644
index 0000000..f013365
--- /dev/null
+++ b/selfdrive/car/hyundai org/values.org
@@ -0,0 +1,591 @@
+import re
+from dataclasses import dataclass
+from enum import Enum, IntFlag, StrEnum
+from typing import Dict, List, Optional, Set, Tuple, Union
+
+from cereal import car
+from panda.python import uds
+from openpilot.common.conversions import Conversions as CV
+from openpilot.selfdrive.car import dbc_dict
+from openpilot.selfdrive.car.docs_definitions import CarFootnote, CarHarness, CarInfo, CarParts, Column
+from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, p16
+
+Ecu = car.CarParams.Ecu
+
+
+class CarControllerParams:
+ ACCEL_MIN = -3.5 # m/s
+ ACCEL_MAX = 2.0 # m/s
+ ACCEL_MAX_PLUS = 4.0 # m/s
+
+ def __init__(self, CP):
+ self.STEER_DELTA_UP = 3
+ self.STEER_DELTA_DOWN = 7
+ self.STEER_DRIVER_ALLOWANCE = 50
+ self.STEER_DRIVER_MULTIPLIER = 2
+ self.STEER_DRIVER_FACTOR = 1
+ self.STEER_THRESHOLD = 150
+ self.STEER_STEP = 1 # 100 Hz
+
+ if CP.carFingerprint in CANFD_CAR:
+ self.STEER_MAX = 270
+ self.STEER_DRIVER_ALLOWANCE = 250
+ self.STEER_DRIVER_MULTIPLIER = 2
+ self.STEER_THRESHOLD = 250
+ self.STEER_DELTA_UP = 2
+ self.STEER_DELTA_DOWN = 3
+
+ # To determine the limit for your car, find the maximum value that the stock LKAS will request.
+ # If the max stock LKAS request is <384, add your car to this list.
+ elif CP.carFingerprint in (CAR.GENESIS_G80, CAR.GENESIS_G90, CAR.ELANTRA, CAR.ELANTRA_GT_I30, CAR.IONIQ,
+ CAR.IONIQ_EV_LTD, CAR.SANTA_FE_PHEV_2022, CAR.SONATA_LF, CAR.KIA_FORTE, CAR.KIA_NIRO_PHEV,
+ CAR.KIA_OPTIMA_H, CAR.KIA_OPTIMA_H_G4_FL, CAR.KIA_SORENTO):
+ self.STEER_MAX = 255
+
+ # these cars have significantly more torque than most HKG; limit to 70% of max
+ elif CP.flags & HyundaiFlags.ALT_LIMITS:
+ self.STEER_MAX = 270
+ self.STEER_DELTA_UP = 2
+ self.STEER_DELTA_DOWN = 3
+
+ # Default for most HKG
+ else:
+ self.STEER_MAX = 384
+
+
+class HyundaiFlags(IntFlag):
+ CANFD_HDA2 = 1
+ CANFD_ALT_BUTTONS = 2
+ CANFD_ALT_GEARS = 4
+ CANFD_CAMERA_SCC = 8
+
+ ALT_LIMITS = 16
+ ENABLE_BLINKERS = 32
+ CANFD_ALT_GEARS_2 = 64
+ SEND_LFA = 128
+ USE_FCA = 256
+ CANFD_HDA2_ALT_STEERING = 512
+
+
+class CAR(StrEnum):
+ # Hyundai
+ AZERA_6TH_GEN = "HYUNDAI AZERA 6TH GEN"
+ AZERA_HEV_6TH_GEN = "HYUNDAI AZERA HYBRID 6TH GEN"
+ ELANTRA = "HYUNDAI ELANTRA 2017"
+ ELANTRA_GT_I30 = "HYUNDAI I30 N LINE 2019 & GT 2018 DCT"
+ ELANTRA_2021 = "HYUNDAI ELANTRA 2021"
+ ELANTRA_HEV_2021 = "HYUNDAI ELANTRA HYBRID 2021"
+ HYUNDAI_GENESIS = "HYUNDAI GENESIS 2015-2016"
+ IONIQ = "HYUNDAI IONIQ HYBRID 2017-2019"
+ IONIQ_HEV_2022 = "HYUNDAI IONIQ HYBRID 2020-2022"
+ IONIQ_EV_LTD = "HYUNDAI IONIQ ELECTRIC LIMITED 2019"
+ IONIQ_EV_2020 = "HYUNDAI IONIQ ELECTRIC 2020"
+ IONIQ_PHEV_2019 = "HYUNDAI IONIQ PLUG-IN HYBRID 2019"
+ IONIQ_PHEV = "HYUNDAI IONIQ PHEV 2020"
+ KONA = "HYUNDAI KONA 2020"
+ KONA_EV = "HYUNDAI KONA ELECTRIC 2019"
+ KONA_EV_2022 = "HYUNDAI KONA ELECTRIC 2022"
+ KONA_EV_2ND_GEN = "HYUNDAI KONA ELECTRIC 2ND GEN"
+ KONA_HEV = "HYUNDAI KONA HYBRID 2020"
+ SANTA_FE = "HYUNDAI SANTA FE 2019"
+ SANTA_FE_2022 = "HYUNDAI SANTA FE 2022"
+ SANTA_FE_HEV_2022 = "HYUNDAI SANTA FE HYBRID 2022"
+ SANTA_FE_PHEV_2022 = "HYUNDAI SANTA FE PlUG-IN HYBRID 2022"
+ SONATA = "HYUNDAI SONATA 2020"
+ SONATA_LF = "HYUNDAI SONATA 2019"
+ STARIA_4TH_GEN = "HYUNDAI STARIA 4TH GEN"
+ TUCSON = "HYUNDAI TUCSON 2019"
+ PALISADE = "HYUNDAI PALISADE 2020"
+ VELOSTER = "HYUNDAI VELOSTER 2019"
+ SONATA_HYBRID = "HYUNDAI SONATA HYBRID 2021"
+ IONIQ_5 = "HYUNDAI IONIQ 5 2022"
+ IONIQ_6 = "HYUNDAI IONIQ 6 2023"
+ TUCSON_4TH_GEN = "HYUNDAI TUCSON 4TH GEN"
+ TUCSON_HYBRID_4TH_GEN = "HYUNDAI TUCSON HYBRID 4TH GEN"
+ SANTA_CRUZ_1ST_GEN = "HYUNDAI SANTA CRUZ 1ST GEN"
+ CUSTIN_1ST_GEN = "HYUNDAI CUSTIN 1ST GEN"
+
+ # Kia
+ KIA_FORTE = "KIA FORTE E 2018 & GT 2021"
+ KIA_K5_2021 = "KIA K5 2021"
+ KIA_K5_HEV_2020 = "KIA K5 HYBRID 2020"
+ KIA_K8_HEV_1ST_GEN = "KIA K8 HYBRID 1ST GEN"
+ KIA_NIRO_EV = "KIA NIRO EV 2020"
+ KIA_NIRO_EV_2ND_GEN = "KIA NIRO EV 2ND GEN"
+ KIA_NIRO_PHEV = "KIA NIRO HYBRID 2019"
+ KIA_NIRO_PHEV_2022 = "KIA NIRO PLUG-IN HYBRID 2022"
+ KIA_NIRO_HEV_2021 = "KIA NIRO HYBRID 2021"
+ KIA_NIRO_HEV_2ND_GEN = "KIA NIRO HYBRID 2ND GEN"
+ KIA_OPTIMA_G4 = "KIA OPTIMA 4TH GEN"
+ KIA_OPTIMA_G4_FL = "KIA OPTIMA 4TH GEN FACELIFT"
+ KIA_OPTIMA_H = "KIA OPTIMA HYBRID 2017 & SPORTS 2019"
+ KIA_OPTIMA_H_G4_FL = "KIA OPTIMA HYBRID 4TH GEN FACELIFT"
+ KIA_SELTOS = "KIA SELTOS 2021"
+ KIA_SPORTAGE_5TH_GEN = "KIA SPORTAGE 5TH GEN"
+ KIA_SORENTO = "KIA SORENTO GT LINE 2018"
+ KIA_SORENTO_4TH_GEN = "KIA SORENTO 4TH GEN"
+ KIA_SORENTO_HEV_4TH_GEN = "KIA SORENTO HYBRID 4TH GEN"
+ KIA_SORENTO_PHEV_4TH_GEN = "KIA SORENTO PLUG-IN HYBRID 4TH GEN"
+ KIA_SPORTAGE_HYBRID_5TH_GEN = "KIA SPORTAGE HYBRID 5TH GEN"
+ KIA_STINGER = "KIA STINGER GT2 2018"
+ KIA_STINGER_2022 = "KIA STINGER 2022"
+ KIA_CEED = "KIA CEED INTRO ED 2019"
+ KIA_EV6 = "KIA EV6 2022"
+ KIA_CARNIVAL_4TH_GEN = "KIA CARNIVAL 4TH GEN"
+
+ # Genesis
+ GENESIS_GV60_EV_1ST_GEN = "GENESIS GV60 ELECTRIC 1ST GEN"
+ GENESIS_G70 = "GENESIS G70 2018"
+ GENESIS_G70_2020 = "GENESIS G70 2020"
+ GENESIS_GV70_1ST_GEN = "GENESIS GV70 1ST GEN"
+ GENESIS_G80 = "GENESIS G80 2017"
+ GENESIS_G90 = "GENESIS G90 2017"
+ GENESIS_GV80 = "GENESIS GV80 2023"
+
+
+class Footnote(Enum):
+ CANFD = CarFootnote(
+ "Requires a CAN FD panda kit if not using " +
+ "comma 3X for this CAN FD car.",
+ Column.MODEL, shop_footnote=False)
+
+
+@dataclass
+class HyundaiCarInfo(CarInfo):
+ package: str = "Smart Cruise Control (SCC)"
+
+ def init_make(self, CP: car.CarParams):
+ if CP.carFingerprint in CANFD_CAR:
+ self.footnotes.insert(0, Footnote.CANFD)
+
+
+CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = {
+ CAR.AZERA_6TH_GEN: HyundaiCarInfo("Hyundai Azera 2022", "All", car_parts=CarParts.common([CarHarness.hyundai_k])),
+ CAR.AZERA_HEV_6TH_GEN: [
+ HyundaiCarInfo("Hyundai Azera Hybrid 2019", "All", car_parts=CarParts.common([CarHarness.hyundai_c])),
+ HyundaiCarInfo("Hyundai Azera Hybrid 2020", "All", car_parts=CarParts.common([CarHarness.hyundai_k])),
+ ],
+ CAR.ELANTRA: [
+ # TODO: 2017-18 could be Hyundai G
+ HyundaiCarInfo("Hyundai Elantra 2017-18", min_enable_speed=19 * CV.MPH_TO_MS, car_parts=CarParts.common([CarHarness.hyundai_b])),
+ HyundaiCarInfo("Hyundai Elantra 2019", min_enable_speed=19 * CV.MPH_TO_MS, car_parts=CarParts.common([CarHarness.hyundai_g])),
+ ],
+ CAR.ELANTRA_GT_I30: [
+ HyundaiCarInfo("Hyundai Elantra GT 2017-19", car_parts=CarParts.common([CarHarness.hyundai_e])),
+ HyundaiCarInfo("Hyundai i30 2017-19", car_parts=CarParts.common([CarHarness.hyundai_e])),
+ ],
+ CAR.ELANTRA_2021: HyundaiCarInfo("Hyundai Elantra 2021-23", video_link="https://youtu.be/_EdYQtV52-c", car_parts=CarParts.common([CarHarness.hyundai_k])),
+ CAR.ELANTRA_HEV_2021: HyundaiCarInfo("Hyundai Elantra Hybrid 2021-23", video_link="https://youtu.be/_EdYQtV52-c",
+ car_parts=CarParts.common([CarHarness.hyundai_k])),
+ CAR.HYUNDAI_GENESIS: [
+ # TODO: check 2015 packages
+ HyundaiCarInfo("Hyundai Genesis 2015-16", min_enable_speed=19 * CV.MPH_TO_MS, car_parts=CarParts.common([CarHarness.hyundai_j])),
+ HyundaiCarInfo("Genesis G80 2017", "All", min_enable_speed=19 * CV.MPH_TO_MS, car_parts=CarParts.common([CarHarness.hyundai_j])),
+ ],
+ CAR.IONIQ: HyundaiCarInfo("Hyundai Ioniq Hybrid 2017-19", car_parts=CarParts.common([CarHarness.hyundai_c])),
+ CAR.IONIQ_HEV_2022: HyundaiCarInfo("Hyundai Ioniq Hybrid 2020-22", car_parts=CarParts.common([CarHarness.hyundai_h])), # TODO: confirm 2020-21 harness
+ CAR.IONIQ_EV_LTD: HyundaiCarInfo("Hyundai Ioniq Electric 2019", car_parts=CarParts.common([CarHarness.hyundai_c])),
+ CAR.IONIQ_EV_2020: HyundaiCarInfo("Hyundai Ioniq Electric 2020", "All", car_parts=CarParts.common([CarHarness.hyundai_h])),
+ CAR.IONIQ_PHEV_2019: HyundaiCarInfo("Hyundai Ioniq Plug-in Hybrid 2019", car_parts=CarParts.common([CarHarness.hyundai_c])),
+ CAR.IONIQ_PHEV: HyundaiCarInfo("Hyundai Ioniq Plug-in Hybrid 2020-22", "All", car_parts=CarParts.common([CarHarness.hyundai_h])),
+ CAR.KONA: HyundaiCarInfo("Hyundai Kona 2020", car_parts=CarParts.common([CarHarness.hyundai_b])),
+ CAR.KONA_EV: HyundaiCarInfo("Hyundai Kona Electric 2018-21", car_parts=CarParts.common([CarHarness.hyundai_g])),
+ CAR.KONA_EV_2022: HyundaiCarInfo("Hyundai Kona Electric 2022-23", car_parts=CarParts.common([CarHarness.hyundai_o])),
+ CAR.KONA_HEV: HyundaiCarInfo("Hyundai Kona Hybrid 2020", car_parts=CarParts.common([CarHarness.hyundai_i])), # TODO: check packages
+ # TODO: this is the 2024 US MY, not yet released
+ CAR.KONA_EV_2ND_GEN: HyundaiCarInfo("Hyundai Kona Electric (with HDA II, Korea only) 2023", video_link="https://www.youtube.com/watch?v=U2fOCmcQ8hw",
+ car_parts=CarParts.common([CarHarness.hyundai_r])),
+ CAR.SANTA_FE: HyundaiCarInfo("Hyundai Santa Fe 2019-20", "All", video_link="https://youtu.be/bjDR0YjM__s",
+ car_parts=CarParts.common([CarHarness.hyundai_d])),
+ CAR.SANTA_FE_2022: HyundaiCarInfo("Hyundai Santa Fe 2021-23", "All", video_link="https://youtu.be/VnHzSTygTS4",
+ car_parts=CarParts.common([CarHarness.hyundai_l])),
+ CAR.SANTA_FE_HEV_2022: HyundaiCarInfo("Hyundai Santa Fe Hybrid 2022-23", "All", car_parts=CarParts.common([CarHarness.hyundai_l])),
+ CAR.SANTA_FE_PHEV_2022: HyundaiCarInfo("Hyundai Santa Fe Plug-in Hybrid 2022-23", "All", car_parts=CarParts.common([CarHarness.hyundai_l])),
+ CAR.SONATA: HyundaiCarInfo("Hyundai Sonata 2020-23", "All", video_link="https://www.youtube.com/watch?v=ix63r9kE3Fw",
+ car_parts=CarParts.common([CarHarness.hyundai_a])),
+ CAR.STARIA_4TH_GEN: HyundaiCarInfo("Hyundai Staria 2023", "All", car_parts=CarParts.common([CarHarness.hyundai_k])),
+ CAR.SONATA_LF: HyundaiCarInfo("Hyundai Sonata 2018-19", car_parts=CarParts.common([CarHarness.hyundai_e])),
+ CAR.TUCSON: [
+ HyundaiCarInfo("Hyundai Tucson 2021", min_enable_speed=19 * CV.MPH_TO_MS, car_parts=CarParts.common([CarHarness.hyundai_l])),
+ HyundaiCarInfo("Hyundai Tucson Diesel 2019", car_parts=CarParts.common([CarHarness.hyundai_l])),
+ ],
+ CAR.PALISADE: [
+ HyundaiCarInfo("Hyundai Palisade 2020-22", "All", video_link="https://youtu.be/TAnDqjF4fDY?t=456", car_parts=CarParts.common([CarHarness.hyundai_h])),
+ HyundaiCarInfo("Kia Telluride 2020-22", "All", car_parts=CarParts.common([CarHarness.hyundai_h])),
+ ],
+ CAR.VELOSTER: HyundaiCarInfo("Hyundai Veloster 2019-20", min_enable_speed=5. * CV.MPH_TO_MS, car_parts=CarParts.common([CarHarness.hyundai_e])),
+ CAR.SONATA_HYBRID: HyundaiCarInfo("Hyundai Sonata Hybrid 2020-23", "All", car_parts=CarParts.common([CarHarness.hyundai_a])),
+ CAR.IONIQ_5: [
+ HyundaiCarInfo("Hyundai Ioniq 5 (Southeast Asia only) 2022-23", "All", car_parts=CarParts.common([CarHarness.hyundai_q])),
+ HyundaiCarInfo("Hyundai Ioniq 5 (without HDA II) 2022-23", "Highway Driving Assist", car_parts=CarParts.common([CarHarness.hyundai_k])),
+ HyundaiCarInfo("Hyundai Ioniq 5 (with HDA II) 2022-23", "Highway Driving Assist II", car_parts=CarParts.common([CarHarness.hyundai_q])),
+ ],
+ CAR.IONIQ_6: [
+ HyundaiCarInfo("Hyundai Ioniq 6 (with HDA II) 2023", "Highway Driving Assist II", car_parts=CarParts.common([CarHarness.hyundai_p])),
+ ],
+ CAR.TUCSON_4TH_GEN: [
+ HyundaiCarInfo("Hyundai Tucson 2022", car_parts=CarParts.common([CarHarness.hyundai_n])),
+ HyundaiCarInfo("Hyundai Tucson 2023", "All", car_parts=CarParts.common([CarHarness.hyundai_n])),
+ ],
+ CAR.TUCSON_HYBRID_4TH_GEN: HyundaiCarInfo("Hyundai Tucson Hybrid 2022-24", "All", car_parts=CarParts.common([CarHarness.hyundai_n])),
+ CAR.SANTA_CRUZ_1ST_GEN: HyundaiCarInfo("Hyundai Santa Cruz 2022-23", car_parts=CarParts.common([CarHarness.hyundai_n])),
+ CAR.CUSTIN_1ST_GEN: HyundaiCarInfo("Hyundai Custin 2023", "All", car_parts=CarParts.common([CarHarness.hyundai_k])),
+
+ # Kia
+ CAR.KIA_FORTE: [
+ HyundaiCarInfo("Kia Forte 2019-21", car_parts=CarParts.common([CarHarness.hyundai_g])),
+ HyundaiCarInfo("Kia Forte 2023", car_parts=CarParts.common([CarHarness.hyundai_e])),
+ ],
+ CAR.KIA_K5_2021: HyundaiCarInfo("Kia K5 2021-24", car_parts=CarParts.common([CarHarness.hyundai_a])),
+ CAR.KIA_K5_HEV_2020: HyundaiCarInfo("Kia K5 Hybrid 2020-22", car_parts=CarParts.common([CarHarness.hyundai_a])),
+ CAR.KIA_K8_HEV_1ST_GEN: HyundaiCarInfo("Kia K8 Hybrid (with HDA II) 2023", "Highway Driving Assist II", car_parts=CarParts.common([CarHarness.hyundai_q])),
+ CAR.KIA_NIRO_EV: [
+ HyundaiCarInfo("Kia Niro EV 2019", "All", video_link="https://www.youtube.com/watch?v=lT7zcG6ZpGo", car_parts=CarParts.common([CarHarness.hyundai_h])),
+ HyundaiCarInfo("Kia Niro EV 2020", "All", video_link="https://www.youtube.com/watch?v=lT7zcG6ZpGo", car_parts=CarParts.common([CarHarness.hyundai_f])),
+ HyundaiCarInfo("Kia Niro EV 2021", "All", video_link="https://www.youtube.com/watch?v=lT7zcG6ZpGo", car_parts=CarParts.common([CarHarness.hyundai_c])),
+ HyundaiCarInfo("Kia Niro EV 2022", "All", video_link="https://www.youtube.com/watch?v=lT7zcG6ZpGo", car_parts=CarParts.common([CarHarness.hyundai_h])),
+ ],
+ CAR.KIA_NIRO_EV_2ND_GEN: HyundaiCarInfo("Kia Niro EV 2023", "All", car_parts=CarParts.common([CarHarness.hyundai_a])),
+ CAR.KIA_NIRO_PHEV: [
+ HyundaiCarInfo("Kia Niro Plug-in Hybrid 2018-19", "All", min_enable_speed=10. * CV.MPH_TO_MS, car_parts=CarParts.common([CarHarness.hyundai_c])),
+ HyundaiCarInfo("Kia Niro Plug-in Hybrid 2020", "All", car_parts=CarParts.common([CarHarness.hyundai_d])),
+ ],
+ CAR.KIA_NIRO_PHEV_2022: HyundaiCarInfo("Kia Niro Plug-in Hybrid 2022", "All", car_parts=CarParts.common([CarHarness.hyundai_f])),
+ CAR.KIA_NIRO_HEV_2021: [
+ HyundaiCarInfo("Kia Niro Hybrid 2021", car_parts=CarParts.common([CarHarness.hyundai_d])),
+ HyundaiCarInfo("Kia Niro Hybrid 2022", car_parts=CarParts.common([CarHarness.hyundai_f])),
+ ],
+ CAR.KIA_NIRO_HEV_2ND_GEN: HyundaiCarInfo("Kia Niro Hybrid 2023", car_parts=CarParts.common([CarHarness.hyundai_a])),
+ CAR.KIA_OPTIMA_G4: HyundaiCarInfo("Kia Optima 2017", "Advanced Smart Cruise Control",
+ car_parts=CarParts.common([CarHarness.hyundai_b])), # TODO: may support 2016, 2018
+ CAR.KIA_OPTIMA_G4_FL: HyundaiCarInfo("Kia Optima 2019-20", car_parts=CarParts.common([CarHarness.hyundai_g])),
+ # TODO: may support adjacent years. may have a non-zero minimum steering speed
+ CAR.KIA_OPTIMA_H: HyundaiCarInfo("Kia Optima Hybrid 2017", "Advanced Smart Cruise Control", car_parts=CarParts.common([CarHarness.hyundai_c])),
+ CAR.KIA_OPTIMA_H_G4_FL: HyundaiCarInfo("Kia Optima Hybrid 2019", car_parts=CarParts.common([CarHarness.hyundai_h])),
+ CAR.KIA_SELTOS: HyundaiCarInfo("Kia Seltos 2021", car_parts=CarParts.common([CarHarness.hyundai_a])),
+ CAR.KIA_SPORTAGE_5TH_GEN: HyundaiCarInfo("Kia Sportage 2023", car_parts=CarParts.common([CarHarness.hyundai_n])),
+ CAR.KIA_SORENTO: [
+ HyundaiCarInfo("Kia Sorento 2018", "Advanced Smart Cruise Control & LKAS", video_link="https://www.youtube.com/watch?v=Fkh3s6WHJz8",
+ car_parts=CarParts.common([CarHarness.hyundai_e])),
+ HyundaiCarInfo("Kia Sorento 2019", video_link="https://www.youtube.com/watch?v=Fkh3s6WHJz8", car_parts=CarParts.common([CarHarness.hyundai_e])),
+ ],
+ CAR.KIA_SORENTO_4TH_GEN: HyundaiCarInfo("Kia Sorento 2021-23", car_parts=CarParts.common([CarHarness.hyundai_k])),
+ CAR.KIA_SORENTO_HEV_4TH_GEN: HyundaiCarInfo("Kia Sorento Hybrid 2021-23", "All", car_parts=CarParts.common([CarHarness.hyundai_a])),
+ CAR.KIA_SORENTO_PHEV_4TH_GEN: HyundaiCarInfo("Kia Sorento Plug-in Hybrid 2022-23", "All", car_parts=CarParts.common([CarHarness.hyundai_a])),
+ CAR.KIA_SPORTAGE_HYBRID_5TH_GEN: HyundaiCarInfo("Kia Sportage Hybrid 2023", car_parts=CarParts.common([CarHarness.hyundai_n])),
+ CAR.KIA_STINGER: HyundaiCarInfo("Kia Stinger 2018-20", video_link="https://www.youtube.com/watch?v=MJ94qoofYw0",
+ car_parts=CarParts.common([CarHarness.hyundai_c])),
+ CAR.KIA_STINGER_2022: HyundaiCarInfo("Kia Stinger 2022-23", "All", car_parts=CarParts.common([CarHarness.hyundai_k])),
+ CAR.KIA_CEED: HyundaiCarInfo("Kia Ceed 2019", car_parts=CarParts.common([CarHarness.hyundai_e])),
+ CAR.KIA_EV6: [
+ HyundaiCarInfo("Kia EV6 (Southeast Asia only) 2022-23", "All", car_parts=CarParts.common([CarHarness.hyundai_p])),
+ HyundaiCarInfo("Kia EV6 (without HDA II) 2022-23", "Highway Driving Assist", car_parts=CarParts.common([CarHarness.hyundai_l])),
+ HyundaiCarInfo("Kia EV6 (with HDA II) 2022-23", "Highway Driving Assist II", car_parts=CarParts.common([CarHarness.hyundai_p]))
+ ],
+ CAR.KIA_CARNIVAL_4TH_GEN: [
+ HyundaiCarInfo("Kia Carnival 2022-24", car_parts=CarParts.common([CarHarness.hyundai_a])),
+ HyundaiCarInfo("Kia Carnival (China only) 2023", car_parts=CarParts.common([CarHarness.hyundai_k]))
+ ],
+
+ # Genesis
+ CAR.GENESIS_GV60_EV_1ST_GEN: [
+ HyundaiCarInfo("Genesis GV60 (Advanced Trim) 2023", "All", car_parts=CarParts.common([CarHarness.hyundai_a])),
+ HyundaiCarInfo("Genesis GV60 (Performance Trim) 2023", "All", car_parts=CarParts.common([CarHarness.hyundai_k])),
+ ],
+ CAR.GENESIS_G70: HyundaiCarInfo("Genesis G70 2018-19", "All", car_parts=CarParts.common([CarHarness.hyundai_f])),
+ CAR.GENESIS_G70_2020: HyundaiCarInfo("Genesis G70 2020", "All", car_parts=CarParts.common([CarHarness.hyundai_f])),
+ CAR.GENESIS_GV70_1ST_GEN: [
+ HyundaiCarInfo("Genesis GV70 (2.5T Trim) 2022-23", "All", car_parts=CarParts.common([CarHarness.hyundai_l])),
+ HyundaiCarInfo("Genesis GV70 (3.5T Trim) 2022-23", "All", car_parts=CarParts.common([CarHarness.hyundai_m])),
+ ],
+ CAR.GENESIS_G80: HyundaiCarInfo("Genesis G80 2018-19", "All", car_parts=CarParts.common([CarHarness.hyundai_h])),
+ CAR.GENESIS_G90: HyundaiCarInfo("Genesis G90 2017-18", "All", car_parts=CarParts.common([CarHarness.hyundai_c])),
+ CAR.GENESIS_GV80: HyundaiCarInfo("Genesis GV80 2023", "All", car_parts=CarParts.common([CarHarness.hyundai_m])),
+}
+
+class Buttons:
+ NONE = 0
+ RES_ACCEL = 1
+ SET_DECEL = 2
+ GAP_DIST = 3
+ CANCEL = 4 # on newer models, this is a pause/resume button
+
+
+def get_platform_codes(fw_versions: List[bytes]) -> Set[Tuple[bytes, Optional[bytes]]]:
+ # Returns unique, platform-specific identification codes for a set of versions
+ codes = set() # (code-Optional[part], date)
+ for fw in fw_versions:
+ code_match = PLATFORM_CODE_FW_PATTERN.search(fw)
+ part_match = PART_NUMBER_FW_PATTERN.search(fw)
+ date_match = DATE_FW_PATTERN.search(fw)
+ if code_match is not None:
+ code: bytes = code_match.group()
+ part = part_match.group() if part_match else None
+ date = date_match.group() if date_match else None
+ if part is not None:
+ # part number starts with generic ECU part type, add what is specific to platform
+ code += b"-" + part[-5:]
+
+ codes.add((code, date))
+ return codes
+
+
+def match_fw_to_car_fuzzy(live_fw_versions, offline_fw_versions) -> Set[str]:
+ # Non-electric CAN FD platforms often do not have platform code specifiers needed
+ # to distinguish between hybrid and ICE. All EVs so far are either exclusively
+ # electric or specify electric in the platform code.
+ # TODO: whitelist platforms that we've seen hybrid and ICE versions of that have these specifiers
+ fuzzy_platform_blacklist = {str(c) for c in set(CANFD_CAR - EV_CAR)}
+ candidates: Set[str] = set()
+
+ for candidate, fws in offline_fw_versions.items():
+ # Keep track of ECUs which pass all checks (platform codes, within date range)
+ valid_found_ecus = set()
+ valid_expected_ecus = {ecu[1:] for ecu in fws if ecu[0] in PLATFORM_CODE_ECUS}
+ for ecu, expected_versions in fws.items():
+ addr = ecu[1:]
+ # Only check ECUs expected to have platform codes
+ if ecu[0] not in PLATFORM_CODE_ECUS:
+ continue
+
+ # Expected platform codes & dates
+ codes = get_platform_codes(expected_versions)
+ expected_platform_codes = {code for code, _ in codes}
+ expected_dates = {date for _, date in codes if date is not None}
+
+ # Found platform codes & dates
+ codes = get_platform_codes(live_fw_versions.get(addr, set()))
+ found_platform_codes = {code for code, _ in codes}
+ found_dates = {date for _, date in codes if date is not None}
+
+ # Check platform code + part number matches for any found versions
+ if not any(found_platform_code in expected_platform_codes for found_platform_code in found_platform_codes):
+ break
+
+ if ecu[0] in DATE_FW_ECUS:
+ # If ECU can have a FW date, require it to exist
+ # (this excludes candidates in the database without dates)
+ if not len(expected_dates) or not len(found_dates):
+ break
+
+ # Check any date within range in the database, format is %y%m%d
+ if not any(min(expected_dates) <= found_date <= max(expected_dates) for found_date in found_dates):
+ break
+
+ valid_found_ecus.add(addr)
+
+ # If all live ECUs pass all checks for candidate, add it as a match
+ if valid_expected_ecus.issubset(valid_found_ecus):
+ candidates.add(candidate)
+
+ return candidates - fuzzy_platform_blacklist
+
+
+HYUNDAI_VERSION_REQUEST_LONG = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER]) + \
+ p16(0xf100) # Long description
+
+HYUNDAI_VERSION_REQUEST_ALT = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER]) + \
+ p16(0xf110) # Alt long description
+
+HYUNDAI_VERSION_REQUEST_MULTI = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER]) + \
+ p16(uds.DATA_IDENTIFIER_TYPE.VEHICLE_MANUFACTURER_SPARE_PART_NUMBER) + \
+ p16(uds.DATA_IDENTIFIER_TYPE.APPLICATION_SOFTWARE_IDENTIFICATION) + \
+ p16(0xf100)
+
+HYUNDAI_VERSION_RESPONSE = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER + 0x40])
+
+# Regex patterns for parsing platform code, FW date, and part number from FW versions
+PLATFORM_CODE_FW_PATTERN = re.compile(b'((?<=' + HYUNDAI_VERSION_REQUEST_LONG[1:] +
+ b')[A-Z]{2}[A-Za-z0-9]{0,2})')
+DATE_FW_PATTERN = re.compile(b'(?<=[ -])([0-9]{6}$)')
+PART_NUMBER_FW_PATTERN = re.compile(b'(?<=[0-9][.,][0-9]{2} )([0-9]{5}[-/]?[A-Z][A-Z0-9]{3}[0-9])')
+
+# List of ECUs expected to have platform codes, camera and radar should exist on all cars
+# TODO: use abs, it has the platform code and part number on many platforms
+PLATFORM_CODE_ECUS = [Ecu.fwdRadar, Ecu.fwdCamera, Ecu.eps]
+# So far we've only seen dates in fwdCamera
+# TODO: there are date codes in the ABS firmware versions in hex
+DATE_FW_ECUS = [Ecu.fwdCamera]
+
+FW_QUERY_CONFIG = FwQueryConfig(
+ requests=[
+ # TODO: minimize shared whitelists for CAN and cornerRadar for CAN-FD
+ # CAN queries (OBD-II port)
+ Request(
+ [HYUNDAI_VERSION_REQUEST_LONG],
+ [HYUNDAI_VERSION_RESPONSE],
+ whitelist_ecus=[Ecu.transmission, Ecu.eps, Ecu.abs, Ecu.fwdRadar, Ecu.fwdCamera],
+ ),
+ Request(
+ [HYUNDAI_VERSION_REQUEST_MULTI],
+ [HYUNDAI_VERSION_RESPONSE],
+ whitelist_ecus=[Ecu.engine, Ecu.transmission, Ecu.eps, Ecu.abs, Ecu.fwdRadar],
+ ),
+
+ # CAN-FD queries (from camera)
+ # TODO: combine shared whitelists with CAN requests
+ Request(
+ [HYUNDAI_VERSION_REQUEST_LONG],
+ [HYUNDAI_VERSION_RESPONSE],
+ whitelist_ecus=[Ecu.fwdCamera, Ecu.fwdRadar, Ecu.cornerRadar, Ecu.hvac],
+ bus=0,
+ auxiliary=True,
+ ),
+ Request(
+ [HYUNDAI_VERSION_REQUEST_LONG],
+ [HYUNDAI_VERSION_RESPONSE],
+ whitelist_ecus=[Ecu.fwdCamera, Ecu.adas, Ecu.cornerRadar, Ecu.hvac],
+ bus=1,
+ auxiliary=True,
+ obd_multiplexing=False,
+ ),
+
+ # CAN-FD debugging queries
+ Request(
+ [HYUNDAI_VERSION_REQUEST_ALT],
+ [HYUNDAI_VERSION_RESPONSE],
+ whitelist_ecus=[Ecu.parkingAdas, Ecu.hvac],
+ bus=0,
+ auxiliary=True,
+ ),
+ Request(
+ [HYUNDAI_VERSION_REQUEST_ALT],
+ [HYUNDAI_VERSION_RESPONSE],
+ whitelist_ecus=[Ecu.parkingAdas, Ecu.hvac],
+ bus=1,
+ auxiliary=True,
+ obd_multiplexing=False,
+ ),
+ ],
+ extra_ecus=[
+ (Ecu.adas, 0x730, None), # ADAS Driving ECU on HDA2 platforms
+ (Ecu.parkingAdas, 0x7b1, None), # ADAS Parking ECU (may exist on all platforms)
+ (Ecu.hvac, 0x7b3, None), # HVAC Control Assembly
+ (Ecu.cornerRadar, 0x7b7, None),
+ ],
+ # Custom fuzzy fingerprinting function using platform codes, part numbers + FW dates:
+ match_fw_to_car_fuzzy=match_fw_to_car_fuzzy,
+)
+
+
+CHECKSUM = {
+ "crc8": [CAR.SANTA_FE, CAR.SONATA, CAR.PALISADE, CAR.KIA_SELTOS, CAR.ELANTRA_2021, CAR.ELANTRA_HEV_2021,
+ CAR.SONATA_HYBRID, CAR.SANTA_FE_2022, CAR.KIA_K5_2021, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022,
+ CAR.KIA_K5_HEV_2020, CAR.CUSTIN_1ST_GEN],
+ "6B": [CAR.KIA_SORENTO, CAR.HYUNDAI_GENESIS],
+}
+
+CAN_GEARS = {
+ # which message has the gear. hybrid and EV use ELECT_GEAR
+ "use_cluster_gears": {CAR.ELANTRA, CAR.ELANTRA_GT_I30, CAR.KONA},
+ "use_tcu_gears": {CAR.KIA_OPTIMA_G4, CAR.KIA_OPTIMA_G4_FL, CAR.SONATA_LF, CAR.VELOSTER, CAR.TUCSON},
+}
+
+CANFD_CAR = {CAR.KIA_EV6, CAR.IONIQ_5, CAR.IONIQ_6, CAR.TUCSON_4TH_GEN, CAR.TUCSON_HYBRID_4TH_GEN, CAR.KIA_SPORTAGE_HYBRID_5TH_GEN,
+ CAR.SANTA_CRUZ_1ST_GEN, CAR.KIA_SPORTAGE_5TH_GEN, CAR.GENESIS_GV70_1ST_GEN, CAR.KIA_SORENTO_PHEV_4TH_GEN,
+ CAR.GENESIS_GV60_EV_1ST_GEN, CAR.KIA_SORENTO_4TH_GEN, CAR.KIA_NIRO_HEV_2ND_GEN, CAR.KIA_NIRO_EV_2ND_GEN,
+ CAR.GENESIS_GV80, CAR.KIA_CARNIVAL_4TH_GEN, CAR.KIA_SORENTO_HEV_4TH_GEN, CAR.KONA_EV_2ND_GEN, CAR.KIA_K8_HEV_1ST_GEN,
+ CAR.STARIA_4TH_GEN}
+
+# The radar does SCC on these cars when HDA I, rather than the camera
+CANFD_RADAR_SCC_CAR = {CAR.GENESIS_GV70_1ST_GEN, CAR.KIA_SORENTO_PHEV_4TH_GEN, CAR.KIA_SORENTO_4TH_GEN, CAR.GENESIS_GV80,
+ CAR.KIA_CARNIVAL_4TH_GEN, CAR.KIA_SORENTO_HEV_4TH_GEN}
+
+# These CAN FD cars do not accept communication control to disable the ADAS ECU,
+# responds with 0x7F2822 - 'conditions not correct'
+CANFD_UNSUPPORTED_LONGITUDINAL_CAR = {CAR.IONIQ_6, CAR.KONA_EV_2ND_GEN}
+
+# The camera does SCC on these cars, rather than the radar
+CAMERA_SCC_CAR = {CAR.KONA_EV_2022, }
+
+# these cars use a different gas signal
+HYBRID_CAR = {CAR.IONIQ_PHEV, CAR.ELANTRA_HEV_2021, CAR.KIA_NIRO_PHEV, CAR.KIA_NIRO_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_HEV, CAR.IONIQ,
+ CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.IONIQ_PHEV_2019, CAR.TUCSON_HYBRID_4TH_GEN,
+ CAR.KIA_SPORTAGE_HYBRID_5TH_GEN, CAR.KIA_SORENTO_PHEV_4TH_GEN, CAR.KIA_K5_HEV_2020, CAR.KIA_NIRO_HEV_2ND_GEN,
+ CAR.KIA_SORENTO_HEV_4TH_GEN, CAR.KIA_OPTIMA_H, CAR.KIA_OPTIMA_H_G4_FL, CAR.KIA_K8_HEV_1ST_GEN,
+ CAR.AZERA_HEV_6TH_GEN, CAR.KIA_NIRO_PHEV_2022}
+
+EV_CAR = {CAR.IONIQ_EV_2020, CAR.IONIQ_EV_LTD, CAR.KONA_EV, CAR.KIA_NIRO_EV, CAR.KIA_NIRO_EV_2ND_GEN, CAR.KONA_EV_2022,
+ CAR.KIA_EV6, CAR.IONIQ_5, CAR.IONIQ_6, CAR.GENESIS_GV60_EV_1ST_GEN, CAR.KONA_EV_2ND_GEN}
+
+# these cars require a special panda safety mode due to missing counters and checksums in the messages
+LEGACY_SAFETY_MODE_CAR = {CAR.HYUNDAI_GENESIS, CAR.IONIQ_EV_LTD, CAR.KIA_OPTIMA_G4,
+ CAR.VELOSTER, CAR.GENESIS_G70, CAR.GENESIS_G80, CAR.KIA_CEED, CAR.ELANTRA, CAR.IONIQ_HEV_2022,
+ CAR.KIA_OPTIMA_H, CAR.ELANTRA_GT_I30}
+
+# these cars have not been verified to work with longitudinal yet - radar disable, sending correct messages, etc.
+UNSUPPORTED_LONGITUDINAL_CAR = LEGACY_SAFETY_MODE_CAR | {CAR.KIA_NIRO_PHEV, CAR.KIA_SORENTO, CAR.SONATA_LF, CAR.KIA_OPTIMA_G4_FL,
+ CAR.KIA_OPTIMA_H_G4_FL}
+
+# If 0x500 is present on bus 1 it probably has a Mando radar outputting radar points.
+# If no points are outputted by default it might be possible to turn it on using selfdrive/debug/hyundai_enable_radar_points.py
+DBC = {
+ CAR.AZERA_6TH_GEN: dbc_dict('hyundai_kia_generic', None),
+ CAR.AZERA_HEV_6TH_GEN: dbc_dict('hyundai_kia_generic', None),
+ CAR.ELANTRA: dbc_dict('hyundai_kia_generic', None),
+ CAR.ELANTRA_GT_I30: dbc_dict('hyundai_kia_generic', None),
+ CAR.ELANTRA_2021: dbc_dict('hyundai_kia_generic', None),
+ CAR.ELANTRA_HEV_2021: dbc_dict('hyundai_kia_generic', None),
+ CAR.GENESIS_G70: dbc_dict('hyundai_kia_generic', None),
+ CAR.GENESIS_G70_2020: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar_generated'),
+ CAR.GENESIS_G80: dbc_dict('hyundai_kia_generic', None),
+ CAR.GENESIS_G90: dbc_dict('hyundai_kia_generic', None),
+ CAR.HYUNDAI_GENESIS: dbc_dict('hyundai_kia_generic', None),
+ CAR.IONIQ_PHEV_2019: dbc_dict('hyundai_kia_generic', None),
+ CAR.IONIQ_PHEV: dbc_dict('hyundai_kia_generic', None),
+ CAR.IONIQ_EV_2020: dbc_dict('hyundai_kia_generic', None),
+ CAR.IONIQ_EV_LTD: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar_generated'),
+ CAR.IONIQ: dbc_dict('hyundai_kia_generic', None),
+ CAR.IONIQ_HEV_2022: dbc_dict('hyundai_kia_generic', None),
+ CAR.KIA_FORTE: dbc_dict('hyundai_kia_generic', None),
+ CAR.KIA_K5_2021: dbc_dict('hyundai_kia_generic', None),
+ CAR.KIA_K5_HEV_2020: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar_generated'),
+ CAR.KIA_NIRO_EV: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar_generated'),
+ CAR.KIA_NIRO_PHEV: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar_generated'),
+ CAR.KIA_NIRO_HEV_2021: dbc_dict('hyundai_kia_generic', None),
+ CAR.KIA_OPTIMA_G4: dbc_dict('hyundai_kia_generic', None),
+ CAR.KIA_OPTIMA_G4_FL: dbc_dict('hyundai_kia_generic', None),
+ CAR.KIA_OPTIMA_H: dbc_dict('hyundai_kia_generic', None),
+ CAR.KIA_OPTIMA_H_G4_FL: dbc_dict('hyundai_kia_generic', None),
+ CAR.KIA_SELTOS: dbc_dict('hyundai_kia_generic', None),
+ CAR.KIA_SORENTO: dbc_dict('hyundai_kia_generic', None), # Has 0x5XX messages, but different format
+ CAR.KIA_STINGER: dbc_dict('hyundai_kia_generic', None),
+ CAR.KIA_STINGER_2022: dbc_dict('hyundai_kia_generic', None),
+ CAR.KONA: dbc_dict('hyundai_kia_generic', None),
+ CAR.KONA_EV: dbc_dict('hyundai_kia_generic', None),
+ CAR.KONA_EV_2022: dbc_dict('hyundai_kia_generic', None),
+ CAR.KONA_HEV: dbc_dict('hyundai_kia_generic', None),
+ CAR.SANTA_FE: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar_generated'),
+ CAR.SANTA_FE_2022: dbc_dict('hyundai_kia_generic', None),
+ CAR.SANTA_FE_HEV_2022: dbc_dict('hyundai_kia_generic', None),
+ CAR.SANTA_FE_PHEV_2022: dbc_dict('hyundai_kia_generic', None),
+ CAR.SONATA: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar_generated'),
+ CAR.SONATA_LF: dbc_dict('hyundai_kia_generic', None), # Has 0x5XX messages, but different format
+ CAR.TUCSON: dbc_dict('hyundai_kia_generic', None),
+ CAR.PALISADE: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar_generated'),
+ CAR.VELOSTER: dbc_dict('hyundai_kia_generic', None),
+ CAR.KIA_CEED: dbc_dict('hyundai_kia_generic', None),
+ CAR.KIA_EV6: dbc_dict('hyundai_canfd', None),
+ CAR.SONATA_HYBRID: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar_generated'),
+ CAR.TUCSON_4TH_GEN: dbc_dict('hyundai_canfd', None),
+ CAR.TUCSON_HYBRID_4TH_GEN: dbc_dict('hyundai_canfd', None),
+ CAR.IONIQ_5: dbc_dict('hyundai_canfd', None),
+ CAR.IONIQ_6: dbc_dict('hyundai_canfd', None),
+ CAR.SANTA_CRUZ_1ST_GEN: dbc_dict('hyundai_canfd', None),
+ CAR.KIA_SPORTAGE_5TH_GEN: dbc_dict('hyundai_canfd', None),
+ CAR.KIA_SPORTAGE_HYBRID_5TH_GEN: dbc_dict('hyundai_canfd', None),
+ CAR.GENESIS_GV70_1ST_GEN: dbc_dict('hyundai_canfd', None),
+ CAR.KIA_SORENTO_PHEV_4TH_GEN: dbc_dict('hyundai_canfd', None),
+ CAR.GENESIS_GV60_EV_1ST_GEN: dbc_dict('hyundai_canfd', None),
+ CAR.KIA_SORENTO_4TH_GEN: dbc_dict('hyundai_canfd', None),
+ CAR.KIA_NIRO_HEV_2ND_GEN: dbc_dict('hyundai_canfd', None),
+ CAR.KIA_NIRO_EV_2ND_GEN: dbc_dict('hyundai_canfd', None),
+ CAR.GENESIS_GV80: dbc_dict('hyundai_canfd', None),
+ CAR.KIA_CARNIVAL_4TH_GEN: dbc_dict('hyundai_canfd', None),
+ CAR.KIA_SORENTO_HEV_4TH_GEN: dbc_dict('hyundai_canfd', None),
+ CAR.KONA_EV_2ND_GEN: dbc_dict('hyundai_canfd', None),
+ CAR.KIA_K8_HEV_1ST_GEN: dbc_dict('hyundai_canfd', None),
+ CAR.CUSTIN_1ST_GEN: dbc_dict('hyundai_kia_generic', None),
+ CAR.KIA_NIRO_PHEV_2022: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar_generated'),
+ CAR.STARIA_4TH_GEN: dbc_dict('hyundai_canfd', None),
+}
diff --git a/selfdrive/car/hyundai/carcontroller.2 b/selfdrive/car/hyundai/carcontroller.2
new file mode 100644
index 0000000..209ace6
--- /dev/null
+++ b/selfdrive/car/hyundai/carcontroller.2
@@ -0,0 +1,332 @@
+from cereal import car
+from openpilot.common.conversions import Conversions as CV
+from openpilot.common.numpy_fast import clip
+from openpilot.common.realtime import DT_CTRL
+from opendbc.can.packer import CANPacker
+from openpilot.selfdrive.car import apply_driver_steer_torque_limits, common_fault_avoidance
+from openpilot.selfdrive.car.hyundai import hyundaicanfd, hyundaican
+from openpilot.selfdrive.car.hyundai.hyundaicanfd import CanBus
+from openpilot.selfdrive.car.hyundai.values import HyundaiFlags, Buttons, CarControllerParams, CANFD_CAR, CAR, LEGACY_SAFETY_MODE_CAR
+from openpilot.selfdrive.controls.lib.drive_helpers import V_CRUISE_MAX
+from openpilot.common.params import Params
+
+from openpilot.common.watcher import Watcher
+
+VisualAlert = car.CarControl.HUDControl.VisualAlert
+LongCtrlState = car.CarControl.Actuators.LongControlState
+
+params_memory = Params("/dev/shm/params")
+
+# EPS faults if you apply torque while the steering angle is above 90 degrees for more than 1 second
+# All slightly below EPS thresholds to avoid fault
+MAX_ANGLE = 85
+MAX_ANGLE_FRAMES = 89
+MAX_ANGLE_CONSECUTIVE_FRAMES = 2
+
+
+def process_hud_alert(enabled, fingerprint, hud_control):
+ sys_warning = (hud_control.visualAlert in (VisualAlert.steerRequired, VisualAlert.ldw))
+
+ # initialize to no line visible
+ # TODO: this is not accurate for all cars
+ sys_state = 1
+ if hud_control.leftLaneVisible and hud_control.rightLaneVisible or sys_warning: # HUD alert only display when LKAS status is active
+ sys_state = 3 if enabled or sys_warning else 4
+ elif hud_control.leftLaneVisible:
+ sys_state = 5
+ elif hud_control.rightLaneVisible:
+ sys_state = 6
+
+ # initialize to no warnings
+ left_lane_warning = 0
+ right_lane_warning = 0
+ if hud_control.leftLaneDepart:
+ left_lane_warning = 1 if fingerprint in (CAR.GENESIS_G90, CAR.GENESIS_G80) else 2
+ if hud_control.rightLaneDepart:
+ right_lane_warning = 1 if fingerprint in (CAR.GENESIS_G90, CAR.GENESIS_G80) else 2
+
+ return sys_warning, sys_state, left_lane_warning, right_lane_warning
+
+
+class CarController:
+ def __init__(self, dbc_name, CP, VM):
+ self.CP = CP
+ self.CAN = CanBus(CP)
+ self.params = CarControllerParams(CP)
+ self.packer = CANPacker(dbc_name)
+ self.angle_limit_counter = 0
+ self.frame = 0
+
+ self.accel_last = 0
+ self.apply_steer_last = 0
+ self.car_fingerprint = CP.carFingerprint
+ self.last_button_frame = 0
+ self.last_resume_frame = 0
+ self.last_debug_frame = 0
+
+ def update(self, CC, CS, now_nanos, sport_plus):
+ actuators = CC.actuators
+ hud_control = CC.hudControl
+
+ # hud_v_cruise = hud_control.setSpeed
+ # if hud_v_cruise > 70:
+ # hud_v_cruise = 0
+
+ # steering torque
+ new_steer = int(round(actuators.steer * self.params.STEER_MAX))
+ apply_steer = apply_driver_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, self.params)
+
+ # >90 degree steering fault prevention
+ self.angle_limit_counter, apply_steer_req = common_fault_avoidance(abs(CS.out.steeringAngleDeg) >= MAX_ANGLE, CC.latActive,
+ self.angle_limit_counter, MAX_ANGLE_FRAMES,
+ MAX_ANGLE_CONSECUTIVE_FRAMES)
+
+ if not CC.latActive:
+ apply_steer = 0
+
+ # Hold torque with induced temporary fault when cutting the actuation bit
+ torque_fault = CC.latActive and not apply_steer_req
+
+ self.apply_steer_last = apply_steer
+
+ # accel + longitudinal
+ if sport_plus:
+ accel = clip(actuators.accel, CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX_PLUS)
+ else:
+ accel = clip(actuators.accel, CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX)
+ stopping = actuators.longControlState == LongCtrlState.stopping
+ set_speed_in_units = hud_control.setSpeed * (CV.MS_TO_KPH if CS.is_metric else CV.MS_TO_MPH)
+
+ # HUD messages
+ sys_warning, sys_state, left_lane_warning, right_lane_warning = process_hud_alert(CC.enabled, self.car_fingerprint,
+ hud_control)
+ can_sends = []
+
+ # *** common hyundai stuff ***
+
+ # tester present - w/ no response (keeps relevant ECU disabled)
+ if self.frame % 100 == 0 and not (self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC.value) and self.CP.openpilotLongitudinalControl:
+ # for longitudinal control, either radar or ADAS driving ECU
+ addr, bus = 0x7d0, 0
+ if self.CP.flags & HyundaiFlags.CANFD_HDA2.value:
+ addr, bus = 0x730, self.CAN.ECAN
+ can_sends.append([addr, 0, b"\x02\x3E\x80\x00\x00\x00\x00\x00", bus])
+
+ # for blinkers
+ if self.CP.flags & HyundaiFlags.ENABLE_BLINKERS:
+ can_sends.append([0x7b1, 0, b"\x02\x3E\x80\x00\x00\x00\x00\x00", self.CAN.ECAN])
+
+ # CAN-FD platforms
+ if self.CP.carFingerprint in CANFD_CAR:
+ hda2 = self.CP.flags & HyundaiFlags.CANFD_HDA2
+ hda2_long = hda2 and self.CP.openpilotLongitudinalControl
+
+ # steering control
+ can_sends.extend(hyundaicanfd.create_steering_messages(self.packer, self.CP, self.CAN, CC.enabled, apply_steer_req, apply_steer))
+
+ # MODIFIED BBOT
+ if self.frame % 5 == 0 and hda2:
+ can_sends.append(hyundaicanfd.create_suppress_lfa(self.packer, self.CAN, CS.hda2_lfa_block_msg,
+ self.CP.flags & HyundaiFlags.CANFD_HDA2_ALT_STEERING))
+
+ # MODIFIED BBOT
+ # LFA and HDA icons
+ if self.frame % 5 == 0 and (not hda2 or hda2_long):
+ can_sends.append(hyundaicanfd.create_lfahda_cluster(self.packer, self.CAN, CC.enabled))
+
+ # blinkers
+ if hda2 and self.CP.flags & HyundaiFlags.ENABLE_BLINKERS:
+ can_sends.extend(hyundaicanfd.create_spas_messages(self.packer, self.CAN, self.frame, CC.leftBlinker, CC.rightBlinker))
+
+ # can_sends.append(hyundaicanfd.create_misc_messages(self.packer, self.CAN, self.frame))
+
+ if self.CP.openpilotLongitudinalControl:
+ if hda2:
+ can_sends.extend(hyundaicanfd.create_adrv_messages(self.packer, self.CAN, self.frame))
+ if self.frame % 2 == 0:
+ can_sends.append(hyundaicanfd.create_acc_control(self.packer, self.CAN, CC.enabled, self.accel_last, accel, stopping, CC.cruiseControl.override,
+ set_speed_in_units, CS.personality_profile))
+ self.accel_last = accel
+ else:
+ # button presses
+ can_sends.extend(self.create_button_messages(CC, CS, use_clu11=False, set_speed_in_units = None))
+ else:
+ can_sends.append(hyundaican.create_lkas11(self.packer, self.frame, self.car_fingerprint, apply_steer, apply_steer_req,
+ torque_fault, CS.lkas11, sys_warning, sys_state, CC.enabled,
+ hud_control.leftLaneVisible, hud_control.rightLaneVisible,
+ left_lane_warning, right_lane_warning))
+
+ if not self.CP.openpilotLongitudinalControl:
+ can_sends.extend(self.create_button_messages(CC, CS, use_clu11=True))
+
+ if self.frame % 2 == 0 and self.CP.openpilotLongitudinalControl:
+ # TODO: unclear if this is needed
+ jerk = 3.0 if actuators.longControlState == LongCtrlState.pid else 1.0
+ use_fca = self.CP.flags & HyundaiFlags.USE_FCA.value
+ can_sends.extend(hyundaican.create_acc_commands(self.packer, CC.enabled, accel, jerk, int(self.frame / 2),
+ hud_control.leadVisible, set_speed_in_units, stopping,
+ CC.cruiseControl.override, use_fca, CS.out.cruiseState.available, CS.personality_profile))
+
+ # 20 Hz LFA MFA message
+ if self.frame % 5 == 0 and self.CP.flags & HyundaiFlags.SEND_LFA.value:
+ can_sends.append(hyundaican.create_lfahda_mfc(self.packer, CC.enabled))
+
+ # 5 Hz ACC options
+ if self.frame % 20 == 0 and self.CP.openpilotLongitudinalControl:
+ can_sends.extend(hyundaican.create_acc_opt(self.packer))
+
+ # 2 Hz front radar options
+ if self.frame % 50 == 0 and self.CP.openpilotLongitudinalControl:
+ can_sends.append(hyundaican.create_frt_radar_opt(self.packer))
+
+ # CSLC
+ # if not self.CP.openpilotLongitudinalControl and CS.cruiseState.available and not CS.out.gasPressed and CS.cruise_buttons == Buttons.NONE:
+ # if False and not self.CP.openpilotLongitudinalControl and CC.enabled and CC.experimental_mode and CS.cruiseState.available and not CS.out.gasPressed and CS.cruise_buttons == Buttons.NONE:
+ # # cslcSetSpeed = get_set_speed(self, hud_v_cruise)
+ # cslcSetSpeed = set_speed_in_units
+ # self.cruise_button = get_cslc_button(self, cslcSetSpeed, CS)
+ # if self.cruise_button != Buttons.NONE:
+ # # if self.CP.carFingerprint in LEGACY_SAFETY_MODE_CAR:
+ # # send_freq = 1
+ # # # send resume at a max freq of 10Hz
+ # # if (self.frame - self.last_button_frame) * DT_CTRL > 0.1 * send_freq:
+ # # # send 25 messages at a time to increases the likelihood of cruise buttons being accepted
+ # # can_sends.extend([hyundaican.create_clu11(self.packer, self.frame, CS.clu11, self.cruise_button, self.CP.carFingerprint)] * 25)
+ # # if (self.frame - self.last_button_frame) * DT_CTRL >= 0.15 * send_freq:
+ # # self.last_button_frame = self.frame
+ # if self.frame % 2 == 0:
+ # if self.CP.carFingerprint in CANFD_CAR:
+ # can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, ((self.frame // 2) + 1) % 0x10, self.cruise_button))
+ # else:
+ # can_sends.extend([hyundaican.create_clu11(self.packer, (self.frame // 2) + 1, CS.clu11, self.cruise_button, self.CP.carFingerprint)] * 25)
+
+ # Test - Works???
+ # if CS.cruise_buttons == Buttons.NONE and CS.cruiseState.enabled:
+ # can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, ((self.frame // 2) + 1) % 0x10, Buttons.SET_DECEL))
+
+ new_actuators = actuators.copy()
+ new_actuators.steer = apply_steer / self.params.STEER_MAX
+ new_actuators.steerOutputCan = apply_steer
+ new_actuators.accel = accel
+
+ Watcher.log_watch("hyundai_carcontroller_update_CC", CC)
+ Watcher.log_watch("hyundai_carcontroller_update_CS", CS)
+ Watcher.log_watch("hyundai_carcontroller_update_self", self)
+
+ self.frame += 1
+ return new_actuators, can_sends
+
+ def create_button_messages(self, CC: car.CarControl, CS: car.CarState, use_clu11: bool, set_speed_in_units = None):
+ can_sends = []
+
+ # Test me.
+ # can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, 1, Buttons.RES_ACCEL))
+ # if self.CP.openpilotLongitudinalControl:
+ # CC.cruiseControl.resume = True
+ # self.CP.openpilotLongitudinalControl = False
+ # else:
+ # CC.cruiseControl.cancel = True
+ # self.CP.openpilotLongitudinalControl = True
+
+ if use_clu11:
+ if CC.cruiseControl.cancel:
+ can_sends.append(hyundaican.create_clu11(self.packer, self.frame, CS.clu11, Buttons.CANCEL, self.CP.carFingerprint))
+ 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 likeli M,hood of resume being accepted
+ can_sends.extend([hyundaican.create_clu11(self.packer, self.frame, CS.clu11, Buttons.RES_ACCEL, self.CP.carFingerprint)] * 25)
+ if (self.frame - self.last_button_frame) * DT_CTRL >= 0.15:
+ self.last_button_frame = self.frame
+ else:
+ if (self.frame - self.last_button_frame) * DT_CTRL > 0.25:
+ # if (self.frame - self.last_button_frame) * DT_CTRL > 3:
+ # if self.last_resume_frame = self.frame
+
+ if CS.oscar_lane_center_btn_pressed:
+ CS.oscar_lane_center_btn_pressed = False
+ # CC.cruiseControl.resume = True
+ CC.cruiseControl.cancel = True
+ # Test this...
+ # Also try create_acc_commands
+ # This attempts to set the speed to
+ # stopping = CC.actuators.longControlState == LongCtrlState.stopping
+ # can_sends.append(hyundaicanfd.create_acc_control(self.packer, self.CAN, CC.enabled, self.accel_last, CC.actuators.accel, stopping, CC.cruiseControl.override,
+ # 40, CS.personality_profile))
+
+ # cruise cancel
+ if CC.cruiseControl.cancel:
+ if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS:
+ can_sends.append(hyundaicanfd.create_acc_cancel(self.packer, self.CP, self.CAN, CS.cruise_info))
+ self.last_button_frame = self.frame
+ else:
+ for _ in range(20):
+ can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, CS.buttons_counter+1, Buttons.CANCEL))
+ self.last_button_frame = self.frame
+
+ # cruise standstill resume
+ elif CC.cruiseControl.resume:
+ if (self.frame - self.last_button_frame) * DT_CTRL > 4:
+ if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS:
+ # for _ in range(20):
+ nothing = 0
+ # Nothing for now --?
+ # oscar - test me
+ # can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, CS.buttons_counter+1, Buttons.CANCEL))
+ # can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, CS.buttons_counter+1, Buttons.RES_ACCEL))
+ else:
+ for _ in range(20):
+ can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, CS.buttons_counter+1, Buttons.RES_ACCEL))
+ self.last_button_frame = self.frame
+ self.last_resume_frame = self.frame
+
+ elif set_speed_in_units is not None and not self.CP.openpilotLongitudinalControl and CS.cruiseState.enabled and not CS.out.gasPressed and CS.cruise_buttons == Buttons.NONE:
+ # if False and not self.CP.openpilotLongitudinalControl and CC.enabled and CC.experimental_mode and CS.cruiseState.available and not CS.out.gasPressed and CS.cruise_buttons == Buttons.NONE:
+ # # cslcSetSpeed = get_set_speed(self, hud_v_cruise)
+ cslcSetSpeed = set_speed_in_units
+ self.cruise_button = get_cslc_button(self, cslcSetSpeed, CS)
+ if self.cruise_button != Buttons.NONE:
+ # if self.CP.carFingerprint in LEGACY_SAFETY_MODE_CAR:
+ # send_freq = 1
+ # # send resume at a max freq of 10Hz
+ # if (self.frame - self.last_button_frame) * DT_CTRL > 0.1 * send_freq:
+ # # send 25 messages at a time to increases the likelihood of cruise buttons being accepted
+ # can_sends.extend([hyundaican.create_clu11(self.packer, self.frame, CS.clu11, self.cruise_button, self.CP.carFingerprint)] * 25)
+ # if (self.frame - self.last_button_frame) * DT_CTRL >= 0.15 * send_freq:
+ # self.last_button_frame = self.frame
+ if self.frame % 2 == 0:
+ for _ in range(20):
+ if self.CP.carFingerprint in CANFD_CAR:
+ can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, ((self.frame // 2) + 1) % 0x10, self.cruise_button))
+ else:
+ can_sends.extend([hyundaican.create_clu11(self.packer, (self.frame // 2) + 1, CS.clu11, self.cruise_button, self.CP.carFingerprint)] * 25)
+ self.last_button_frame = self.frame
+
+
+ # can_sends.extend([hyundaican.create_clu11(self.packer, self.frame, CS.clu11, Buttons.SET_DECEL, self.CP.carFingerprint)] * 25)
+
+ return can_sends
+
+def get_set_speed(self, hud_v_cruise):
+ v_cruise_kph = min(hud_v_cruise * CV.MS_TO_KPH, V_CRUISE_MAX)
+ v_cruise = int(round(v_cruise_kph * CV.KPH_TO_MPH))
+
+ v_cruise_slc: int = 0
+ # v_cruise_slc = params_memory.get_int("CSLCSpeed")
+
+ if v_cruise_slc > 0:
+ v_cruise = v_cruise_slc
+ return v_cruise
+
+def get_cslc_button(self, cslcSetSpeed, CS, CC):
+ cruiseBtn = Buttons.NONE
+ speedSetPoint = int(round(CS.out.cruiseState.speed * CV.MS_TO_MPH))
+
+ if cslcSetSpeed < speedSetPoint and speedSetPoint > 25 and CC.enabled and CC.experimental_mode:
+ cruiseBtn = Buttons.SET_DECEL
+ elif cslcSetSpeed > speedSetPoint and speedSetPoint < 85 and CC.enabled:
+ cruiseBtn = Buttons.RES_ACCEL
+ else:
+ cruiseBtn = Buttons.SET_DECEL
+ # cruiseBtn = Buttons.NONE
+ return cruiseBtn
diff --git a/selfdrive/car/hyundai/carcontroller.py b/selfdrive/car/hyundai/carcontroller.py
index 0366489..72f3eca 100644
--- a/selfdrive/car/hyundai/carcontroller.py
+++ b/selfdrive/car/hyundai/carcontroller.py
@@ -12,6 +12,18 @@ from openpilot.common.params import Params
from openpilot.common.watcher import Watcher
+# DEVELOPOMENT TODO
+
+# - Write a loop that runs and does nothing.
+# - Load as many inputs in possible into state variables.
+# - Make a state variable tester. It should be a web server running async.
+# - Make a button tester, also on web server, to test engaging each button.
+# - Write basic interface refactor
+# - Write experimental mode speed controller
+# - Write resume from stop controller
+# - Implement as many extra features as possible (auto hvac, auto sunroof, suggest a break, remind headlights)
+
+
VisualAlert = car.CarControl.HUDControl.VisualAlert
LongCtrlState = car.CarControl.Actuators.LongControlState
@@ -23,7 +35,148 @@ MAX_ANGLE = 85
MAX_ANGLE_FRAMES = 89
MAX_ANGLE_CONSECUTIVE_FRAMES = 2
+# Constants for state arrays.
+ENGAGED = 'engaged'
+STANDBY = 'standby'
+OFF = 'off'
+# Input
+# Current state of openpilot and its desired commands
+openpilot_state = {
+ 'openpilot_ready': False, # Openpilot is enabled in settings
+ 'lateral_active': False, # Lateral control is engaged either full or always on lateral
+ 'openpilot_engaged': False, # Openpilot is full engaged (lateral + cruise control)
+ 'always_on_lateral_active': False, # Cruise control disengaged but lateral still engaged
+ 'experimental_active': False, # Frogpilot has engaged experimental control, so we need to adjust speed and possibly apply brakes (if this is possible)
+ 'experimental_desired_speed': 0, # The speed experimental control wants to set long to
+ 'curviture_angle': 0, # Detected current curviture (ideally within the next 3 or 4 seconds) for taking over LKAS and possibly LONG
+ 'lane_change_enabled': False, # The lane change assist feature is active
+ 'lane_change_active': False, # Executing a lane change assist
+ 'connected_to_internet': False,
+ 'rate_limited_internet': False
+}
+
+# Input
+# Esoteric things related to the car that support other features than driving. Will be shown in debugger.
+car_state = {
+ 'location_lat': 0,
+ 'location_long': 0,
+ 'drive_distance_this_trip': 0,
+ 'drive_distance_today': 0,
+ 'compass_direction': 'N', # Unclear if I will use this
+ 'fuel': 1, # 0-1 fuel tank level
+ 'windows_down': False, # True if any windows / sunroof is open
+ 'climate_control': False,
+ 'climate_control_set_temp': 72,
+ 'cabin_temprature': 50,
+ 'heated_seat_driver_on': False,
+ 'heated_seat_passenger_on': False,
+ 'heated_steering_wheel_on': False,
+ 'fan_seat_driver_on': False,
+ 'fan_seat_passenger_on': False,
+ 'info_panel_item_showing': 0, # If we can capture what instrument panel info is showing, we can change it to speed
+ 'daytime': False,
+ 'headlights': False, # Would be cool to remind to have the headlights turned on if moving
+}
+
+# Input
+# The current status of cruise control activation
+cruise_control_state = {
+ 'set_speed': 0, # Cruise control set speed
+ 'actual_speed': 0, # Spedometer reading
+ 'speed_limit': 0, # Speed limit as reported by car's dashboard
+ 'cruise_control_status': OFF, # or ENGAGED or STANDBY
+ 'brake_pressed': False
+}
+
+# Input
+# The current state of the car in front of us, if cruise control is engaged but the car is not moving
+stationary_state = {
+ 'stationary': False, # When speed reaches 0 we are stationary
+ 'stationary_since': 0, # At what time stationary was achieved
+ 'stationary_has_lead': False, # At the time of becoming stationary, was there a lead veichele?
+ 'stationary_has_lead_distance': 0, # At the time of becoming stationary, what was the distance to the lead veichele?
+ 'current_lead_car_distance': 0, # What is the distance to the lead veichele now?
+ 'lead_vehicle_moving_away': False, # Has logic decided that the current veichele is moving away?
+ 'oem_lanes_detected': False # Is the car reporting it can see lanes? I would like to experiment with engaging stock LKAS.
+}
+
+# Input
+# What buttons the user is pressing. Can be None, BUTTON_SHORT, or BUTTON_LONG (held for 1/2 second)
+cruise_control_buttons_input = {
+ 'engage_cruise_control': None,
+ 'cruise_control_speed_up': None,
+ 'cruise_control_speed_down': None,
+ 'pause_resume_cruise_control': None,
+ 'lane_keep_assist_button': None,
+ 'lane_follow_assist_button': None
+}
+
+# Output
+# What buttons we wish to simulate pressing.
+cruise_control_buttons_output = {
+ 'engage_cruise_control': False,
+ 'cruise_control_speed_up': False,
+ 'cruise_control_speed_down': False,
+ 'pause_resume_cruise_control': False,
+ 'lane_keep_assist_button': False,
+ 'lane_follow_assist_button': False,
+}
+
+# Output
+# What buttons we wish to simulate pressing.
+# I don't know if I will have access to these.
+other_buttons_output = {
+ 'info_category': False,
+ 'info_section': False,
+ 'heated_seat_driver': False,
+ 'heated_seat_passenger': False,
+ 'heated_steering_wheel': False,
+ 'fan_seat_driver': False,
+ 'fan_seat_passenger': False,
+ 'sunroof': False,
+ 'hvac_power': False,
+ 'hvac_sync': False,
+ 'hvac_up': False,
+ 'hvac_down': False
+}
+
+# What to display on the instrument panel. Sent every frame.
+instrument_panel_outputs = {
+ 'lane_keeping_assist_active': False,
+ 'forward_collision_warning_active': False,
+ 'high_beam_assist_active': False,
+ 'forward_collision_avoidance_assist_active': False,
+ 'blind_spot_collision_warning_active': False,
+ 'lane_following_assist_active': False,
+ 'driver_attention_warning_active': False,
+ 'lane_departure_warning_active': False
+}
+
+# State
+# Variables to save what oscarpilot is doing - behaviors will change depending
+# on current state
+oscarpilot_state = [
+ 'set_speed': 0, # Current desired cruise speed
+ 'speed_override': False, # Set if moving away from set speed due to experimental
+ 'speed_restore': False, # Set if moving twoards set speed due to reengagement or change speed to speed limit
+ 'lkas_oem': False, # Set if allowing the car oem software to control LKAS
+ 'daytime': False, # Set if it is daytime. Car is more judgmental at night.
+]
+
+# Output
+# These are messages to the user, and get set to false when processed by openpilot
+# Ideally we can set these in the infotainment area as well, like carplay audio selection
+oscarpilot_alerts = {
+ 'detected_stop_sign_or_light': False, # Openpilot has seen a stoplight or stopsign
+ 'very_sharp_curve': False, # The upcoming curve is probably too sharp to be handled automatically
+ 'lane_confidence_low': False, # The confidence level that openpilot knows what its doing is low
+ 'heavy_traffic_ahead': False, # Mapping data indicates heavy traffic within 2 miles
+ 'weather_ahead': False, # Mapping data indicates precipitation within 5 miles
+ 'suggest_a_break': False, # Variable will be used to suggest a break (3 hours at day, 1.5 hours at night)
+}
+
+# Where is this called? Public? Private? Should we refactor?
def process_hud_alert(enabled, fingerprint, hud_control):
sys_warning = (hud_control.visualAlert in (VisualAlert.steerRequired, VisualAlert.ldw))
@@ -47,7 +200,6 @@ def process_hud_alert(enabled, fingerprint, hud_control):
return sys_warning, sys_state, left_lane_warning, right_lane_warning
-
class CarController:
def __init__(self, dbc_name, CP, VM):
self.CP = CP
@@ -64,28 +216,90 @@ class CarController:
self.last_resume_frame = 0
self.last_debug_frame = 0
+ self._CC = None
+ # self._CC.actuators
+ # self._CC.hudControl
+ self._CS = None
+ self._now_nanos = None
+ self._sport_plus = None
+ self._actuators = None
+ self._hud_control = None
+
def update(self, CC, CS, now_nanos, sport_plus):
- actuators = CC.actuators
- hud_control = CC.hudControl
+ self._CC = CC
+ self._CS = CS
+ self._now_nanos = now_nanos
+ self._sport_plus = sport_plus
- # hud_v_cruise = hud_control.setSpeed
- # if hud_v_cruise > 70:
- # hud_v_cruise = 0
+ self._apply_steer = None
+ self._accel = None
+ can_sends = []
+
+ # CAN-FD car logic
+ if self.CP.carFingerprint in CANFD_CAR:
+ # Steering control for CAN FD
+ # can_sends.extend(self._create_common_messages())
+ can_sends.extend(self._create_steering_messages())
+ can_sends.extend(self._create_instrument_messages())
+ can_sends.extend(self._create_button_messages())
+
+ new_actuators = actuators.copy()
+ new_actuators.steer = apply_steer / self.params.STEER_MAX
+ new_actuators.steerOutputCan = apply_steer
+ new_actuators.accel = accel
+
+ self.frame += 1
+ return new_actuators, can_sends
+
+# def _create_common_messages():
+ # *** common hyundai stuff ***
+
+ def _unprocessed():
+
+ # HUD messages
+ sys_warning, sys_state, left_lane_warning, right_lane_warning = process_hud_alert(CC.enabled, self.car_fingerprint,
+ hud_control)
+
+ can_sends = []
+
+
+ # CAN-FD platforms
+ # if self.CP.carFingerprint in CANFD_CAR:
+
+ # # LFA and HDA icons
+ # if self.frame % 5 == 0 and (not hda2 or hda2_long):
+ # can_sends.append(hyundaicanfd.create_lfahda_cluster(self.packer, self.CAN, CC.enabled))
+
+
+ # if self.CP.openpilotLongitudinalControl:
+ # if hda2:
+ # can_sends.extend(hyundaicanfd.create_adrv_messages(self.packer, self.CAN, self.frame))
+ # if self.frame % 2 == 0:
+ # can_sends.append(hyundaicanfd.create_acc_control(self.packer, self.CAN, CC.enabled, self.accel_last, accel, stopping, CC.cruiseControl.override,
+ # set_speed_in_units, CS.personality_profile))
+ # self.accel_last = accel
+ # else:
+ # # button presses
+ # can_sends.extend(self.create_button_messages(CC, CS, use_clu11=False))
+
+ # Mostly unchanged from frogpilot.
+ def _create_steering_messages():
+ can_sends = []
+
# steering torque
new_steer = int(round(actuators.steer * self.params.STEER_MAX))
- apply_steer = apply_driver_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, self.params)
+ apply_steer = apply_driver_steer_torque_limits(new_steer, self.apply_steer_last, self._CS.out.steeringTorque, self.params)
# >90 degree steering fault prevention
- self.angle_limit_counter, apply_steer_req = common_fault_avoidance(abs(CS.out.steeringAngleDeg) >= MAX_ANGLE, CC.latActive,
+ self.angle_limit_counter, apply_steer_req = common_fault_avoidance(abs(self._CS.out.steeringAngleDeg) >= MAX_ANGLE, self._CC.latActive,
self.angle_limit_counter, MAX_ANGLE_FRAMES,
MAX_ANGLE_CONSECUTIVE_FRAMES)
-
if not CC.latActive:
apply_steer = 0
# Hold torque with induced temporary fault when cutting the actuation bit
- torque_fault = CC.latActive and not apply_steer_req
+ torque_fault = self._CC.latActive and not apply_steer_req
self.apply_steer_last = apply_steer
@@ -94,240 +308,70 @@ class CarController:
accel = clip(actuators.accel, CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX_PLUS)
else:
accel = clip(actuators.accel, CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX)
+
stopping = actuators.longControlState == LongCtrlState.stopping
set_speed_in_units = hud_control.setSpeed * (CV.MS_TO_KPH if CS.is_metric else CV.MS_TO_MPH)
- # HUD messages
- sys_warning, sys_state, left_lane_warning, right_lane_warning = process_hud_alert(CC.enabled, self.car_fingerprint,
- hud_control)
+ hda2 = self.CP.flags & HyundaiFlags.CANFD_HDA2
- can_sends = []
+ # steering control
+ can_sends.extend(hyundaicanfd.create_steering_messages(self.packer, self.CP, self.CAN, CC.enabled, apply_steer_req, apply_steer))
- # *** common hyundai stuff ***
-
- # tester present - w/ no response (keeps relevant ECU disabled)
- if self.frame % 100 == 0 and not (self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC.value) and self.CP.openpilotLongitudinalControl:
- # for longitudinal control, either radar or ADAS driving ECU
- addr, bus = 0x7d0, 0
- if self.CP.flags & HyundaiFlags.CANFD_HDA2.value:
- addr, bus = 0x730, self.CAN.ECAN
- can_sends.append([addr, 0, b"\x02\x3E\x80\x00\x00\x00\x00\x00", bus])
-
- # for blinkers
- if self.CP.flags & HyundaiFlags.ENABLE_BLINKERS:
- can_sends.append([0x7b1, 0, b"\x02\x3E\x80\x00\x00\x00\x00\x00", self.CAN.ECAN])
-
- # CAN-FD platforms
- if self.CP.carFingerprint in CANFD_CAR:
- hda2 = self.CP.flags & HyundaiFlags.CANFD_HDA2
- hda2_long = hda2 and self.CP.openpilotLongitudinalControl
-
- # steering control
- can_sends.extend(hyundaicanfd.create_steering_messages(self.packer, self.CP, self.CAN, CC.enabled, apply_steer_req, apply_steer))
-
- # MODIFIED BBOT
- if self.frame % 5 == 0 and hda2:
- can_sends.append(hyundaicanfd.create_suppress_lfa(self.packer, self.CAN, CS.hda2_lfa_block_msg,
+ # prevent LFA from activating on HDA2 by sending "no lane lines detected" to ADAS ECU
+ if self.frame % 5 == 0 and hda2:
+ can_sends.append(hyundaicanfd.create_suppress_lfa(self.packer, self.CAN, CS.hda2_lfa_block_msg,
self.CP.flags & HyundaiFlags.CANFD_HDA2_ALT_STEERING))
-
- # MODIFIED BBOT
- # LFA and HDA icons
- if self.frame % 5 == 0 and (not hda2 or hda2_long):
- can_sends.append(hyundaicanfd.create_lfahda_cluster(self.packer, self.CAN, CC.enabled))
-
- # blinkers
- if hda2 and self.CP.flags & HyundaiFlags.ENABLE_BLINKERS:
- can_sends.extend(hyundaicanfd.create_spas_messages(self.packer, self.CAN, self.frame, CC.leftBlinker, CC.rightBlinker))
-
- # can_sends.append(hyundaicanfd.create_misc_messages(self.packer, self.CAN, self.frame))
-
- if self.CP.openpilotLongitudinalControl:
- if hda2:
- can_sends.extend(hyundaicanfd.create_adrv_messages(self.packer, self.CAN, self.frame))
- if self.frame % 2 == 0:
- can_sends.append(hyundaicanfd.create_acc_control(self.packer, self.CAN, CC.enabled, self.accel_last, accel, stopping, CC.cruiseControl.override,
- set_speed_in_units, CS.personality_profile))
- self.accel_last = accel
- else:
- # button presses
- can_sends.extend(self.create_button_messages(CC, CS, use_clu11=False, set_speed_in_units = None))
- else:
- can_sends.append(hyundaican.create_lkas11(self.packer, self.frame, self.car_fingerprint, apply_steer, apply_steer_req,
- torque_fault, CS.lkas11, sys_warning, sys_state, CC.enabled,
- hud_control.leftLaneVisible, hud_control.rightLaneVisible,
- left_lane_warning, right_lane_warning))
-
- if not self.CP.openpilotLongitudinalControl:
- can_sends.extend(self.create_button_messages(CC, CS, use_clu11=True))
-
- if self.frame % 2 == 0 and self.CP.openpilotLongitudinalControl:
- # TODO: unclear if this is needed
- jerk = 3.0 if actuators.longControlState == LongCtrlState.pid else 1.0
- use_fca = self.CP.flags & HyundaiFlags.USE_FCA.value
- can_sends.extend(hyundaican.create_acc_commands(self.packer, CC.enabled, accel, jerk, int(self.frame / 2),
- hud_control.leadVisible, set_speed_in_units, stopping,
- CC.cruiseControl.override, use_fca, CS.out.cruiseState.available, CS.personality_profile))
-
- # 20 Hz LFA MFA message
- if self.frame % 5 == 0 and self.CP.flags & HyundaiFlags.SEND_LFA.value:
- can_sends.append(hyundaican.create_lfahda_mfc(self.packer, CC.enabled))
-
- # 5 Hz ACC options
- if self.frame % 20 == 0 and self.CP.openpilotLongitudinalControl:
- can_sends.extend(hyundaican.create_acc_opt(self.packer))
-
- # 2 Hz front radar options
- if self.frame % 50 == 0 and self.CP.openpilotLongitudinalControl:
- can_sends.append(hyundaican.create_frt_radar_opt(self.packer))
-
- # CSLC
- # if not self.CP.openpilotLongitudinalControl and CS.cruiseState.available and not CS.out.gasPressed and CS.cruise_buttons == Buttons.NONE:
- # if False and not self.CP.openpilotLongitudinalControl and CC.enabled and CC.experimental_mode and CS.cruiseState.available and not CS.out.gasPressed and CS.cruise_buttons == Buttons.NONE:
- # # cslcSetSpeed = get_set_speed(self, hud_v_cruise)
- # cslcSetSpeed = set_speed_in_units
- # self.cruise_button = get_cslc_button(self, cslcSetSpeed, CS)
- # if self.cruise_button != Buttons.NONE:
- # # if self.CP.carFingerprint in LEGACY_SAFETY_MODE_CAR:
- # # send_freq = 1
- # # # send resume at a max freq of 10Hz
- # # if (self.frame - self.last_button_frame) * DT_CTRL > 0.1 * send_freq:
- # # # send 25 messages at a time to increases the likelihood of cruise buttons being accepted
- # # can_sends.extend([hyundaican.create_clu11(self.packer, self.frame, CS.clu11, self.cruise_button, self.CP.carFingerprint)] * 25)
- # # if (self.frame - self.last_button_frame) * DT_CTRL >= 0.15 * send_freq:
- # # self.last_button_frame = self.frame
- # if self.frame % 2 == 0:
- # if self.CP.carFingerprint in CANFD_CAR:
- # can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, ((self.frame // 2) + 1) % 0x10, self.cruise_button))
- # else:
- # can_sends.extend([hyundaican.create_clu11(self.packer, (self.frame // 2) + 1, CS.clu11, self.cruise_button, self.CP.carFingerprint)] * 25)
-
- # Test - Works???
- # if CS.cruise_buttons == Buttons.NONE and CS.cruiseState.enabled:
- # can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, ((self.frame // 2) + 1) % 0x10, Buttons.SET_DECEL))
-
- new_actuators = actuators.copy()
- new_actuators.steer = apply_steer / self.params.STEER_MAX
- new_actuators.steerOutputCan = apply_steer
- new_actuators.accel = accel
-
- Watcher.log_watch("hyundai_carcontroller_update_CC", CC)
- Watcher.log_watch("hyundai_carcontroller_update_CS", CS)
- Watcher.log_watch("hyundai_carcontroller_update_self", self)
-
- self.frame += 1
- return new_actuators, can_sends
-
- def create_button_messages(self, CC: car.CarControl, CS: car.CarState, use_clu11: bool, set_speed_in_units = None):
- can_sends = []
-
- # Test me.
- # can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, 1, Buttons.RES_ACCEL))
- # if self.CP.openpilotLongitudinalControl:
- # CC.cruiseControl.resume = True
- # self.CP.openpilotLongitudinalControl = False
- # else:
- # CC.cruiseControl.cancel = True
- # self.CP.openpilotLongitudinalControl = True
-
- if use_clu11:
- if CC.cruiseControl.cancel:
- can_sends.append(hyundaican.create_clu11(self.packer, self.frame, CS.clu11, Buttons.CANCEL, self.CP.carFingerprint))
- 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 likeli M,hood of resume being accepted
- can_sends.extend([hyundaican.create_clu11(self.packer, self.frame, CS.clu11, Buttons.RES_ACCEL, self.CP.carFingerprint)] * 25)
- if (self.frame - self.last_button_frame) * DT_CTRL >= 0.15:
- self.last_button_frame = self.frame
- else:
- if (self.frame - self.last_button_frame) * DT_CTRL > 0.25:
- # if (self.frame - self.last_button_frame) * DT_CTRL > 3:
- # if self.last_resume_frame = self.frame
-
- if CS.oscar_lane_center_btn_pressed:
- CS.oscar_lane_center_btn_pressed = False
- # CC.cruiseControl.resume = True
- CC.cruiseControl.cancel = True
- # Test this...
- # Also try create_acc_commands
- # This attempts to set the speed to
- # stopping = CC.actuators.longControlState == LongCtrlState.stopping
- # can_sends.append(hyundaicanfd.create_acc_control(self.packer, self.CAN, CC.enabled, self.accel_last, CC.actuators.accel, stopping, CC.cruiseControl.override,
- # 40, CS.personality_profile))
-
- # cruise cancel
- if CC.cruiseControl.cancel:
- if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS:
- can_sends.append(hyundaicanfd.create_acc_cancel(self.packer, self.CP, self.CAN, CS.cruise_info))
- self.last_button_frame = self.frame
- else:
- for _ in range(20):
- can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, CS.buttons_counter+1, Buttons.CANCEL))
- self.last_button_frame = self.frame
-
- # cruise standstill resume
- elif CC.cruiseControl.resume:
- if (self.frame - self.last_button_frame) * DT_CTRL > 4:
- if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS:
- # for _ in range(20):
- nothing = 0
- # Nothing for now --?
- # oscar - test me
- # can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, CS.buttons_counter+1, Buttons.CANCEL))
- # can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, CS.buttons_counter+1, Buttons.RES_ACCEL))
- else:
- for _ in range(20):
- can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, CS.buttons_counter+1, Buttons.RES_ACCEL))
- self.last_button_frame = self.frame
- self.last_resume_frame = self.frame
-
- elif set_speed_in_units is not None and not self.CP.openpilotLongitudinalControl and CS.cruiseState.enabled and not CS.out.gasPressed and CS.cruise_buttons == Buttons.NONE:
- # if False and not self.CP.openpilotLongitudinalControl and CC.enabled and CC.experimental_mode and CS.cruiseState.available and not CS.out.gasPressed and CS.cruise_buttons == Buttons.NONE:
- # # cslcSetSpeed = get_set_speed(self, hud_v_cruise)
- cslcSetSpeed = set_speed_in_units
- self.cruise_button = get_cslc_button(self, cslcSetSpeed, CS)
- if self.cruise_button != Buttons.NONE:
- # if self.CP.carFingerprint in LEGACY_SAFETY_MODE_CAR:
- # send_freq = 1
- # # send resume at a max freq of 10Hz
- # if (self.frame - self.last_button_frame) * DT_CTRL > 0.1 * send_freq:
- # # send 25 messages at a time to increases the likelihood of cruise buttons being accepted
- # can_sends.extend([hyundaican.create_clu11(self.packer, self.frame, CS.clu11, self.cruise_button, self.CP.carFingerprint)] * 25)
- # if (self.frame - self.last_button_frame) * DT_CTRL >= 0.15 * send_freq:
- # self.last_button_frame = self.frame
- if self.frame % 2 == 0:
- for _ in range(20):
- if self.CP.carFingerprint in CANFD_CAR:
- can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, ((self.frame // 2) + 1) % 0x10, self.cruise_button))
- else:
- can_sends.extend([hyundaican.create_clu11(self.packer, (self.frame // 2) + 1, CS.clu11, self.cruise_button, self.CP.carFingerprint)] * 25)
- self.last_button_frame = self.frame
-
-
- # can_sends.extend([hyundaican.create_clu11(self.packer, self.frame, CS.clu11, Buttons.SET_DECEL, self.CP.carFingerprint)] * 25)
+ # blinkers
+ # if hda2 and self.CP.flags & HyundaiFlags.ENABLE_BLINKERS:
+ # can_sends.extend(hyundaicanfd.create_spas_messages(self.packer, self.CAN, self.frame, CC.leftBlinker, CC.rightBlinker))
+ self._apply_steer = apply_steer
+ self._accel = accel
return can_sends
+
+ # Placeholder for potential instrument panel processing
+ def _create_instrument_messages(instrument_panel_state):
+ can_sends = []
+# Assume default values or read the initial state
+ lfa_icon_state = 0
+ hda_active = 0
+ hda_icon_state = 0
+ hda_set_speed = 0 # This would likely need to be more dynamic based on context
+
+ # Assign values based on instrument_panel_outputs states
+ for output in instrument_panel_outputs:
+ if output['name'] == 'lane_keeping_assist_active':
+ lfa_icon_state = 2 if output['value'] else 0
+ elif output['name'] == 'hda_active': # Hypothetical key for example
+ hda_active = 1 if output['value'] else 0
+ elif output['name'] == 'hda_icon_state': # Also hypothetical
+ hda_icon_state = 2 if output['value'] else 0
+ # Add other conditions based on the actual data structure you expect
+
+ # Assume we can bundle all these states into one message as in your example
+ values = {
+ "LFA_Icon_State": lfa_icon_state,
+ "HDA_Active": hda_active,
+ "HDA_Icon_State": hda_icon_state,
+ "HDA_VSetReq": hda_set_speed, # This example assumes static speed; adjust if dynamic
+ }
+
+ can_sends.append(packer.make_can_msg("LFAHDA_MFC", 0, values))
-def get_set_speed(self, hud_v_cruise):
- v_cruise_kph = min(hud_v_cruise * CV.MS_TO_KPH, V_CRUISE_MAX)
- v_cruise = int(round(v_cruise_kph * CV.KPH_TO_MPH))
+ return can_sends
- v_cruise_slc: int = 0
- # v_cruise_slc = params_memory.get_int("CSLCSpeed")
+ # Placeholder for potential button press processing
+ def _create_button_messages(button_presses):
+ can_sends = []
- if v_cruise_slc > 0:
- v_cruise = v_cruise_slc
- return v_cruise
+ for button in cruise_control_buttons:
+ if button['value']:
+ # Resetting button state to prevent repeated presses
+ button['value'] = False
-def get_cslc_button(self, cslcSetSpeed, CS, CC):
- cruiseBtn = Buttons.NONE
- speedSetPoint = int(round(CS.out.cruiseState.speed * CV.MS_TO_MPH))
+ if button['name'] in button_map:
+ # Mapping each button to a specific CAN message
+ btn_value = button_map[button['name']]
+ can_sends.append(create_buttons(packer, CP, CAN, 0, btn_value)) # Counter is example, replace with actual logic if necessary
- if cslcSetSpeed < speedSetPoint and speedSetPoint > 25 and CC.enabled and CC.experimental_mode:
- cruiseBtn = Buttons.SET_DECEL
- elif cslcSetSpeed > speedSetPoint and speedSetPoint < 85 and CC.enabled:
- cruiseBtn = Buttons.RES_ACCEL
- else:
- cruiseBtn = Buttons.SET_DECEL
- # cruiseBtn = Buttons.NONE
- return cruiseBtn
+ return can_sends
\ No newline at end of file
diff --git a/selfdrive/car/hyundai/carstate.org b/selfdrive/car/hyundai/carstate.org
new file mode 100644
index 0000000..ee4c3a1
--- /dev/null
+++ b/selfdrive/car/hyundai/carstate.org
@@ -0,0 +1,500 @@
+from collections import deque
+import copy
+import math
+
+from cereal import car
+from openpilot.common.conversions import Conversions as CV
+from opendbc.can.parser import CANParser
+from opendbc.can.can_define import CANDefine
+from openpilot.selfdrive.car.hyundai.hyundaicanfd import CanBus
+from openpilot.selfdrive.car.hyundai.values import HyundaiFlags, CAR, DBC, CAN_GEARS, CAMERA_SCC_CAR, \
+ CANFD_CAR, EV_CAR, HYBRID_CAR, Buttons, CarControllerParams
+from openpilot.selfdrive.car.interfaces import CarStateBase
+from openpilot.selfdrive.frogpilot.functions.speed_limit_controller import SpeedLimitController
+
+from openpilot.common.watcher import Watcher
+
+PREV_BUTTON_SAMPLES = 8
+CLUSTER_SAMPLE_RATE = 20 # frames
+STANDSTILL_THRESHOLD = 12 * 0.03125 * CV.KPH_TO_MS
+
+
+class CarState(CarStateBase):
+ def __init__(self, CP):
+ super().__init__(CP)
+ can_define = CANDefine(DBC[CP.carFingerprint]["pt"])
+
+ self.cruise_buttons = deque([Buttons.NONE] * PREV_BUTTON_SAMPLES, maxlen=PREV_BUTTON_SAMPLES)
+ self.main_buttons = deque([Buttons.NONE] * PREV_BUTTON_SAMPLES, maxlen=PREV_BUTTON_SAMPLES)
+
+ 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:
+ 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"]
+ elif self.CP.carFingerprint in CAN_GEARS["use_tcu_gears"]:
+ self.shifter_values = can_define.dv["TCU12"]["CUR_GR"]
+ else: # preferred and elect gear methods use same definition
+ self.shifter_values = can_define.dv["LVR12"]["CF_Lvr_Gear"]
+
+ self.accelerator_msg_canfd = "ACCELERATOR" if CP.carFingerprint in EV_CAR else \
+ "ACCELERATOR_ALT" if CP.carFingerprint in HYBRID_CAR else \
+ "ACCELERATOR_BRAKE_ALT"
+ self.cruise_btns_msg_canfd = "CRUISE_BUTTONS_ALT" if CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS else \
+ "CRUISE_BUTTONS"
+ self.is_metric = False
+ self.buttons_counter = 0
+
+ self.cruise_info = {}
+
+ # On some cars, CLU15->CF_Clu_VehicleSpeed can oscillate faster than the dash updates. Sample at 5 Hz
+ self.cluster_speed = 0
+ self.cluster_speed_counter = CLUSTER_SAMPLE_RATE
+
+ self.params = CarControllerParams(CP)
+
+ def update(self, cp, cp_cam):
+ Watcher.log_watch("hyundai_carstate_update_cp", cp)
+ Watcher.log_watch("hyundai_carstate_update_cp_cam", cp_cam)
+
+ if self.CP.carFingerprint in CANFD_CAR:
+ return self.update_canfd(cp, cp_cam)
+
+ ret = car.CarState.new_message()
+ cp_cruise = cp_cam if self.CP.carFingerprint in CAMERA_SCC_CAR else cp
+ self.is_metric = cp.vl["CLU11"]["CF_Clu_SPEED_UNIT"] == 0
+ speed_conv = CV.KPH_TO_MS if self.is_metric else CV.MPH_TO_MS
+
+ ret.doorOpen = any([cp.vl["CGW1"]["CF_Gway_DrvDrSw"], cp.vl["CGW1"]["CF_Gway_AstDrSw"],
+ cp.vl["CGW2"]["CF_Gway_RLDrSw"], cp.vl["CGW2"]["CF_Gway_RRDrSw"]])
+
+ ret.seatbeltUnlatched = cp.vl["CGW1"]["CF_Gway_DrvSeatBeltSw"] == 0
+
+ ret.wheelSpeeds = self.get_wheel_speeds(
+ cp.vl["WHL_SPD11"]["WHL_SPD_FL"],
+ cp.vl["WHL_SPD11"]["WHL_SPD_FR"],
+ cp.vl["WHL_SPD11"]["WHL_SPD_RL"],
+ cp.vl["WHL_SPD11"]["WHL_SPD_RR"],
+ )
+ ret.vEgoRaw = (ret.wheelSpeeds.fl + ret.wheelSpeeds.fr + ret.wheelSpeeds.rl + ret.wheelSpeeds.rr) / 4.
+ ret.vEgo, ret.aEgo = self.update_speed_kf(ret.vEgoRaw)
+ ret.standstill = ret.wheelSpeeds.fl <= STANDSTILL_THRESHOLD and ret.wheelSpeeds.rr <= STANDSTILL_THRESHOLD
+
+ self.cluster_speed_counter += 1
+ if self.cluster_speed_counter > CLUSTER_SAMPLE_RATE:
+ self.cluster_speed = cp.vl["CLU15"]["CF_Clu_VehicleSpeed"]
+ self.cluster_speed_counter = 0
+
+ # Mimic how dash converts to imperial.
+ # Sorento is the only platform where CF_Clu_VehicleSpeed is already imperial when not is_metric
+ # TODO: CGW_USM1->CF_Gway_DrLockSoundRValue may describe this
+ if not self.is_metric and self.CP.carFingerprint not in (CAR.KIA_SORENTO,):
+ self.cluster_speed = math.floor(self.cluster_speed * CV.KPH_TO_MPH + CV.KPH_TO_MPH)
+
+ ret.vEgoCluster = self.cluster_speed * speed_conv
+
+ ret.steeringAngleDeg = cp.vl["SAS11"]["SAS_Angle"]
+ ret.steeringRateDeg = cp.vl["SAS11"]["SAS_Speed"]
+ ret.yawRate = cp.vl["ESP12"]["YAW_RATE"]
+ ret.leftBlinker, ret.rightBlinker = self.update_blinker_from_lamp(
+ 50, cp.vl["CGW1"]["CF_Gway_TurnSigLh"], cp.vl["CGW1"]["CF_Gway_TurnSigRh"])
+ ret.steeringTorque = cp.vl["MDPS12"]["CR_Mdps_StrColTq"]
+ ret.steeringTorqueEps = cp.vl["MDPS12"]["CR_Mdps_OutTq"]
+ ret.steeringPressed = self.update_steering_pressed(abs(ret.steeringTorque) > self.params.STEER_THRESHOLD, 5)
+ ret.steerFaultTemporary = cp.vl["MDPS12"]["CF_Mdps_ToiUnavail"] != 0 or cp.vl["MDPS12"]["CF_Mdps_ToiFlt"] != 0
+
+ # cruise state
+ if self.CP.openpilotLongitudinalControl:
+ # These are not used for engage/disengage since openpilot keeps track of state using the buttons
+ ret.cruiseState.available = self.main_enabled
+ ret.cruiseState.enabled = cp.vl["TCS13"]["ACC_REQ"] == 1
+ ret.cruiseState.standstill = False
+ ret.cruiseState.nonAdaptive = False
+ else:
+ ret.cruiseState.available = cp_cruise.vl["SCC11"]["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
+
+ # TODO: Find brake pressure
+ ret.brake = 0
+ ret.brakePressed = cp.vl["TCS13"]["DriverOverride"] == 2 # 2 includes regen braking by user on HEV/EV
+ ret.brakeHoldActive = cp.vl["TCS15"]["AVH_LAMP"] == 2 # 0 OFF, 1 ERROR, 2 ACTIVE, 3 READY
+ ret.parkingBrake = cp.vl["TCS13"]["PBRAKE_ACT"] == 1
+ ret.accFaulted = cp.vl["TCS13"]["ACCEnable"] != 0 # 0 ACC CONTROL ENABLED, 1-3 ACC CONTROL DISABLED
+
+ if self.CP.carFingerprint in (HYBRID_CAR | EV_CAR):
+ if self.CP.carFingerprint in HYBRID_CAR:
+ ret.gas = cp.vl["E_EMS11"]["CR_Vcu_AccPedDep_Pos"] / 254.
+ else:
+ ret.gas = cp.vl["E_EMS11"]["Accel_Pedal_Pos"] / 254.
+ ret.gasPressed = ret.gas > 0
+ else:
+ ret.gas = cp.vl["EMS12"]["PV_AV_CAN"] / 100.
+ ret.gasPressed = bool(cp.vl["EMS16"]["CF_Ems_AclAct"])
+
+ # Gear Selection via Cluster - For those Kia/Hyundai which are not fully discovered, we can use the Cluster Indicator for Gear Selection,
+ # as this seems to be standard over all cars, but is not the preferred method.
+ if self.CP.carFingerprint in (HYBRID_CAR | EV_CAR):
+ gear = cp.vl["ELECT_GEAR"]["Elect_Gear_Shifter"]
+ elif self.CP.carFingerprint in CAN_GEARS["use_cluster_gears"]:
+ gear = cp.vl["CLU15"]["CF_Clu_Gear"]
+ elif self.CP.carFingerprint in CAN_GEARS["use_tcu_gears"]:
+ gear = cp.vl["TCU12"]["CUR_GR"]
+ else:
+ gear = cp.vl["LVR12"]["CF_Lvr_Gear"]
+
+ ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(gear))
+
+ if not self.CP.openpilotLongitudinalControl:
+ 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
+ scc_warning = cp_cruise.vl["SCC12"]["TakeOverReq"] == 1 # sometimes only SCC system shows an FCW
+ aeb_braking = cp_cruise.vl[aeb_src]["CF_VSM_DecCmdAct"] != 0 or cp_cruise.vl[aeb_src][aeb_sig] != 0
+ ret.stockFcw = (aeb_warning or scc_warning) and not aeb_braking
+ ret.stockAeb = aeb_warning and aeb_braking
+
+ if self.CP.enableBsm:
+ ret.leftBlindspot = cp.vl["LCA11"]["CF_Lca_IndLeft"] != 0
+ ret.rightBlindspot = cp.vl["LCA11"]["CF_Lca_IndRight"] != 0
+
+ # save the entire LKAS11 and CLU11
+ 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
+ self.prev_cruise_buttons = self.cruise_buttons[-1]
+ self.cruise_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwState"])
+ self.prev_main_buttons = self.main_buttons[-1]
+ self.main_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwMain"])
+ if self.prev_main_buttons == 0 and self.main_buttons[-1] != 0:
+ self.main_enabled = not self.main_enabled
+
+ # BBot functions for lfa and gap buttons - test speed up / down
+ self.oscar_lane_center_btn_pressed= False
+ self.oscar_slc_decel = False
+ self.oscar_slc_accel = False
+
+ self.param_memory.put("oscar_debug", "Hello World")
+
+ # if self.cruise_buttons[-1] == Buttons.GAP_DIST and self.prev_cruise_buttons == 0:
+ # self.oscar_lane_center_btn_pressed= True
+
+ # lkas_pressed = cp.vl["BCM_PO_11"]["LFA_Pressed"]
+ # if lkas_pressed and not self.lkas_previously_pressed:
+ # self.custom_speed_up = True
+ # self.lkas_previously_pressed = lkas_pressed
+
+ # Driving personalities function
+ # if self.personalities_via_wheel and ret.cruiseState.available:
+ # # Sync with the onroad UI button
+ # if self.param_memory.get_bool("PersonalityChangedViaUI"):
+ # self.personality_profile = self.param.get_int("LongitudinalPersonality")
+ # self.param_memory.put_bool("PersonalityChangedViaUI", False)
+
+ # # Change personality upon steering wheel button press
+ # if self.cruise_buttons[-1] == Buttons.GAP_DIST and self.prev_cruise_buttons == 0:
+ # self.param_memory.put_bool("PersonalityChangedViaWheel", True)
+ # self.personality_profile = (self.previous_personality_profile + 2) % 3
+
+ # if self.personality_profile != self.previous_personality_profile and self.personality_profile >= 0:
+ # self.param.put_int("LongitudinalPersonality", self.personality_profile)
+ # self.previous_personality_profile = self.personality_profile
+
+ # # Toggle Experimental Mode from steering wheel function
+ # if self.experimental_mode_via_lkas and ret.cruiseState.available:
+ # lkas_pressed = cp.vl["BCM_PO_11"]["LFA_Pressed"]
+ # if lkas_pressed and not self.lkas_previously_pressed:
+ # if self.conditional_experimental_mode:
+ # # Set "CEStatus" to work with "Conditional Experimental Mode"
+ # conditional_status = self.param_memory.get_int("CEStatus")
+ # override_value = 0 if conditional_status in (1, 2, 3, 4) else 1 if conditional_status >= 5 else 2
+ # self.param_memory.put_int("CEStatus", override_value)
+ # else:
+ # experimental_mode = self.param.get_bool("ExperimentalMode")
+ # # Invert the value of "ExperimentalMode"
+ # put_bool_nonblocking("ExperimentalMode", not experimental_mode)
+ # self.lkas_previously_pressed = lkas_pressed
+
+ Watcher.log_watch("hyundai_carstate_update_self", self)
+ return ret
+
+ def update_canfd(self, cp, cp_cam):
+ Watcher.log_watch("hyundai_carstate_update_canfd_cp", cp)
+ Watcher.log_watch("hyundai_carstate_update_canfd_cp_cam", cp_cam)
+
+ ret = car.CarState.new_message()
+
+ self.is_metric = cp.vl["CRUISE_BUTTONS_ALT"]["DISTANCE_UNIT"] != 1
+ speed_factor = CV.KPH_TO_MS if self.is_metric else CV.MPH_TO_MS
+
+ if self.CP.carFingerprint in (EV_CAR | HYBRID_CAR):
+ offset = 255. if self.CP.carFingerprint in EV_CAR else 1023.
+ ret.gas = cp.vl[self.accelerator_msg_canfd]["ACCELERATOR_PEDAL"] / offset
+ ret.gasPressed = ret.gas > 1e-5
+ else:
+ ret.gasPressed = bool(cp.vl[self.accelerator_msg_canfd]["ACCELERATOR_PEDAL_PRESSED"])
+
+ ret.brakePressed = cp.vl["TCS"]["DriverBraking"] == 1
+
+ ret.doorOpen = cp.vl["DOORS_SEATBELTS"]["DRIVER_DOOR"] == 1
+ ret.seatbeltUnlatched = cp.vl["DOORS_SEATBELTS"]["DRIVER_SEATBELT"] == 0
+
+ gear = cp.vl[self.gear_msg_canfd]["GEAR"]
+ ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(gear))
+
+ # TODO: figure out positions
+ ret.wheelSpeeds = self.get_wheel_speeds(
+ cp.vl["WHEEL_SPEEDS"]["WHEEL_SPEED_1"],
+ cp.vl["WHEEL_SPEEDS"]["WHEEL_SPEED_2"],
+ cp.vl["WHEEL_SPEEDS"]["WHEEL_SPEED_3"],
+ cp.vl["WHEEL_SPEEDS"]["WHEEL_SPEED_4"],
+ )
+ ret.vEgoRaw = (ret.wheelSpeeds.fl + ret.wheelSpeeds.fr + ret.wheelSpeeds.rl + ret.wheelSpeeds.rr) / 4.
+ ret.vEgo, ret.aEgo = self.update_speed_kf(ret.vEgoRaw)
+ ret.standstill = ret.wheelSpeeds.fl <= STANDSTILL_THRESHOLD and ret.wheelSpeeds.rr <= STANDSTILL_THRESHOLD
+
+ ret.steeringRateDeg = cp.vl["STEERING_SENSORS"]["STEERING_RATE"]
+ ret.steeringAngleDeg = cp.vl["STEERING_SENSORS"]["STEERING_ANGLE"] * -1
+ ret.steeringTorque = cp.vl["MDPS"]["STEERING_COL_TORQUE"]
+ ret.steeringTorqueEps = cp.vl["MDPS"]["STEERING_OUT_TORQUE"]
+ ret.steeringPressed = self.update_steering_pressed(abs(ret.steeringTorque) > self.params.STEER_THRESHOLD, 5)
+ ret.steerFaultTemporary = cp.vl["MDPS"]["LKA_FAULT"] != 0
+
+ # TODO: alt signal usage may be described by cp.vl['BLINKERS']['USE_ALT_LAMP']
+ left_blinker_sig, right_blinker_sig = "LEFT_LAMP", "RIGHT_LAMP"
+ if self.CP.carFingerprint == CAR.KONA_EV_2ND_GEN:
+ left_blinker_sig, right_blinker_sig = "LEFT_LAMP_ALT", "RIGHT_LAMP_ALT"
+ ret.leftBlinker, ret.rightBlinker = self.update_blinker_from_lamp(50, cp.vl["BLINKERS"][left_blinker_sig],
+ cp.vl["BLINKERS"][right_blinker_sig])
+ if self.CP.enableBsm:
+ ret.leftBlindspot = cp.vl["BLINDSPOTS_REAR_CORNERS"]["FL_INDICATOR"] != 0
+ ret.rightBlindspot = cp.vl["BLINDSPOTS_REAR_CORNERS"]["FR_INDICATOR"] != 0
+
+ # cruise state
+ # CAN FD cars enable on main button press, set available if no TCS faults preventing engagement
+ ret.cruiseState.available = self.main_enabled
+ if self.CP.openpilotLongitudinalControl:
+ # These are not used for engage/disengage since openpilot keeps track of state using the buttons
+ ret.cruiseState.enabled = cp.vl["TCS"]["ACC_REQ"] == 1
+ ret.cruiseState.standstill = False
+ else:
+ cp_cruise_info = cp_cam if self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC else cp
+ ret.cruiseState.enabled = cp_cruise_info.vl["SCC_CONTROL"]["ACCMode"] in (1, 2)
+ ret.cruiseState.standstill = cp_cruise_info.vl["SCC_CONTROL"]["CRUISE_STANDSTILL"] == 1
+ ret.cruiseState.speed = cp_cruise_info.vl["SCC_CONTROL"]["VSetDis"] * speed_factor
+ self.cruise_info = copy.copy(cp_cruise_info.vl["SCC_CONTROL"])
+
+ # Manual Speed Limit Assist is a feature that replaces non-adaptive cruise control on EV CAN FD platforms.
+ # It limits the vehicle speed, overridable by pressing the accelerator past a certain point.
+ # The car will brake, but does not respect positive acceleration commands in this mode
+ # TODO: find this message on ICE & HYBRID cars + cruise control signals (if exists)
+ if self.CP.carFingerprint in EV_CAR:
+ ret.cruiseState.nonAdaptive = cp.vl["MANUAL_SPEED_LIMIT_ASSIST"]["MSLA_ENABLED"] == 1
+
+ self.prev_cruise_buttons = self.cruise_buttons[-1]
+ self.cruise_buttons.extend(cp.vl_all[self.cruise_btns_msg_canfd]["CRUISE_BUTTONS"])
+ self.prev_main_buttons = self.main_buttons[-1]
+ self.main_buttons.extend(cp.vl_all[self.cruise_btns_msg_canfd]["ADAPTIVE_CRUISE_MAIN_BTN"])
+ if self.prev_main_buttons == 0 and self.main_buttons[-1] != 0:
+ self.main_enabled = not self.main_enabled
+ self.buttons_counter = cp.vl[self.cruise_btns_msg_canfd]["COUNTER"]
+ ret.accFaulted = cp.vl["TCS"]["ACCEnable"] != 0 # 0 ACC CONTROL ENABLED, 1-3 ACC CONTROL DISABLED
+
+ if self.CP.flags & HyundaiFlags.CANFD_HDA2:
+ self.hda2_lfa_block_msg = copy.copy(cp_cam.vl["CAM_0x362"] if self.CP.flags & HyundaiFlags.CANFD_HDA2_ALT_STEERING
+ else cp_cam.vl["CAM_0x2a4"])
+
+ SpeedLimitController.load_state()
+ SpeedLimitController.car_speed_limit = self.calculate_speed_limit_canfd(self.CP, cp, cp_cam) * speed_factor
+ SpeedLimitController.write_car_state()
+
+ # self.custom_speed_up = False
+ self.oscar_lane_center_btn_pressed = False
+
+ if ret.cruiseState.available:
+
+ if self.cruise_buttons[-1] == Buttons.GAP_DIST and self.prev_cruise_buttons == 0:
+ self.oscar_lane_center_btn_pressed = True
+
+ lkas_pressed = False
+ try:
+ lkas_pressed = cp.vl[self.cruise_btns_msg_canfd]["LKAS_BTN"]
+ except:
+ nothing = 0
+
+ # intentionally cause a failure
+ if lkas_pressed:
+ floog=norpdywoop
+ # if self.cruise_buttons[-1] == Buttons.GAP_DIST and self.prev_cruise_buttons == 0:
+ # self.oscar_lane_center_btn_pressed= True
+
+ # Driving personalities function
+ # if self.personalities_via_wheel and ret.cruiseState.available:
+ # # Sync with the onroad UI button
+ # if self.param_memory.get_bool("PersonalityChangedViaUI"):
+ # self.personality_profile = self.param.get_int("LongitudinalPersonality")
+ # self.param_memory.put_bool("PersonalityChangedViaUI", False)
+
+ # # Change personality upon steering wheel button press
+ # if self.cruise_buttons[-1] == Buttons.GAP_DIST and self.prev_cruise_buttons == 0:
+ # self.param_memory.put_bool("PersonalityChangedViaWheel", True)
+ # self.personality_profile = (self.previous_personality_profile + 2) % 3
+
+ # if self.personality_profile != self.previous_personality_profile and self.personality_profile >= 0:
+ # self.param.put_int("LongitudinalPersonality", self.personality_profile)
+ # self.previous_personality_profile = self.personality_profile
+
+ # # Toggle Experimental Mode from steering wheel function
+ # if self.experimental_mode_via_lkas and ret.cruiseState.available:
+ # lkas_pressed = cp.vl[self.cruise_btns_msg_canfd]["LKAS_BTN"]
+ # if lkas_pressed and not self.lkas_previously_pressed:
+ # if self.conditional_experimental_mode:
+ # # Set "CEStatus" to work with "Conditional Experimental Mode"
+ # conditional_status = self.param_memory.get_int("CEStatus")
+ # override_value = 0 if conditional_status in (1, 2, 3, 4) else 1 if conditional_status >= 5 else 2
+ # self.param_memory.put_int("CEStatus", override_value)
+ # else:
+ # experimental_mode = self.param.get_bool("ExperimentalMode")
+ # # Invert the value of "ExperimentalMode"
+ # put_bool_nonblocking("ExperimentalMode", not experimental_mode)
+ # self.lkas_previously_pressed = lkas_pressed
+
+ Watcher.log_watch("hyundai_carstate_update_canfd_self", self)
+
+ return ret
+
+ # BBOT does not work
+ def calculate_speed_limit_canfd(self, CP, cp, cp_cam):
+ try:
+ self._speed_limit_clu = cp.vl["CLUSTER_SPEED_LIMIT"]["SPEED_LIMIT_1"]
+ return self._speed_limit_clu if self._speed_limit_clu not in (0, 255) else 0
+ except:
+ return 0
+
+ def get_can_parser(self, CP):
+ if CP.carFingerprint in CANFD_CAR:
+ return self.get_can_parser_canfd(CP)
+
+ messages = [
+ # address, frequency
+ ("MDPS12", 50),
+ ("TCS13", 50),
+ ("TCS15", 10),
+ ("CLU11", 50),
+ ("CLU15", 5),
+ ("ESP12", 100),
+ ("CGW1", 10),
+ ("CGW2", 5),
+ ("CGW4", 5),
+ ("WHL_SPD11", 50),
+ ("SAS11", 100),
+ ]
+
+ if not CP.openpilotLongitudinalControl and CP.carFingerprint not in CAMERA_SCC_CAR:
+ messages += [
+ ("SCC11", 50),
+ ("SCC12", 50),
+ ]
+ if CP.flags & HyundaiFlags.USE_FCA.value:
+ messages.append(("FCA11", 50))
+
+ if CP.enableBsm:
+ messages.append(("LCA11", 50))
+
+ if CP.carFingerprint in (HYBRID_CAR | EV_CAR):
+ messages.append(("E_EMS11", 50))
+ else:
+ messages += [
+ ("EMS12", 100),
+ ("EMS16", 100),
+ ]
+
+ if CP.carFingerprint in (HYBRID_CAR | EV_CAR):
+ messages.append(("ELECT_GEAR", 20))
+ elif CP.carFingerprint in CAN_GEARS["use_cluster_gears"]:
+ pass
+ elif CP.carFingerprint in CAN_GEARS["use_tcu_gears"]:
+ messages.append(("TCU12", 100))
+ else:
+ messages.append(("LVR12", 100))
+
+ messages.append(("BCM_PO_11", 50))
+
+ return CANParser(DBC[CP.carFingerprint]["pt"], messages, 0)
+
+ @staticmethod
+ def get_cam_can_parser(CP):
+ if CP.carFingerprint in CANFD_CAR:
+ return CarState.get_cam_can_parser_canfd(CP)
+
+ messages = [
+ ("LKAS11", 100)
+ ]
+
+ if not CP.openpilotLongitudinalControl and CP.carFingerprint in CAMERA_SCC_CAR:
+ messages += [
+ ("SCC11", 50),
+ ("SCC12", 50),
+ ]
+
+ if CP.flags & HyundaiFlags.USE_FCA.value:
+ messages.append(("FCA11", 50))
+
+ return CANParser(DBC[CP.carFingerprint]["pt"], messages, 2)
+
+ def get_can_parser_canfd(self, CP):
+ messages = [
+ (self.gear_msg_canfd, 100),
+ (self.accelerator_msg_canfd, 100),
+ ("WHEEL_SPEEDS", 100),
+ ("STEERING_SENSORS", 100),
+ ("MDPS", 100),
+ ("TCS", 50),
+ ("CRUISE_BUTTONS_ALT", 50),
+ ("BLINKERS", 4),
+ ("DOORS_SEATBELTS", 4),
+ ]
+
+ if CP.carFingerprint in EV_CAR:
+ messages += [
+ ("MANUAL_SPEED_LIMIT_ASSIST", 10),
+ ]
+
+ if not (CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS):
+ messages += [
+ ("CRUISE_BUTTONS", 50)
+ ]
+
+ if CP.enableBsm:
+ messages += [
+ ("BLINDSPOTS_REAR_CORNERS", 20),
+ ]
+
+ # if CP.nav_msg:
+ # messages.append(("CLUSTER_SPEED_LIMIT", 10))
+
+ if not (CP.flags & HyundaiFlags.CANFD_CAMERA_SCC.value) and not CP.openpilotLongitudinalControl:
+ messages += [
+ ("SCC_CONTROL", 50),
+ ]
+
+ return CANParser(DBC[CP.carFingerprint]["pt"], messages, CanBus(CP).ECAN)
+
+ @staticmethod
+ def get_cam_can_parser_canfd(CP):
+ messages = []
+ if CP.flags & HyundaiFlags.CANFD_HDA2:
+ block_lfa_msg = "CAM_0x362" if CP.flags & HyundaiFlags.CANFD_HDA2_ALT_STEERING else "CAM_0x2a4"
+ messages += [(block_lfa_msg, 20)]
+ elif CP.flags & HyundaiFlags.CANFD_CAMERA_SCC:
+ messages += [
+ ("SCC_CONTROL", 50),
+ ]
+
+
+
+ return CANParser(DBC[CP.carFingerprint]["pt"], messages, CanBus(CP).CAM)
diff --git a/selfdrive/car/hyundai/carstate.py b/selfdrive/car/hyundai/carstate.py
index 20d6967..bb8720e 100644
--- a/selfdrive/car/hyundai/carstate.py
+++ b/selfdrive/car/hyundai/carstate.py
@@ -27,32 +27,6 @@ class CarState(CarStateBase):
self.cruise_buttons = deque([Buttons.NONE] * PREV_BUTTON_SAMPLES, maxlen=PREV_BUTTON_SAMPLES)
self.main_buttons = deque([Buttons.NONE] * PREV_BUTTON_SAMPLES, maxlen=PREV_BUTTON_SAMPLES)
- 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:
- 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"]
- elif self.CP.carFingerprint in CAN_GEARS["use_tcu_gears"]:
- self.shifter_values = can_define.dv["TCU12"]["CUR_GR"]
- else: # preferred and elect gear methods use same definition
- self.shifter_values = can_define.dv["LVR12"]["CF_Lvr_Gear"]
-
- self.accelerator_msg_canfd = "ACCELERATOR" if CP.carFingerprint in EV_CAR else \
- "ACCELERATOR_ALT" if CP.carFingerprint in HYBRID_CAR else \
- "ACCELERATOR_BRAKE_ALT"
- self.cruise_btns_msg_canfd = "CRUISE_BUTTONS_ALT" if CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS else \
- "CRUISE_BUTTONS"
- self.is_metric = False
- self.buttons_counter = 0
-
- self.cruise_info = {}
-
- # On some cars, CLU15->CF_Clu_VehicleSpeed can oscillate faster than the dash updates. Sample at 5 Hz
- self.cluster_speed = 0
- self.cluster_speed_counter = CLUSTER_SAMPLE_RATE
-
self.params = CarControllerParams(CP)
def update(self, cp, cp_cam):
@@ -62,391 +36,15 @@ class CarState(CarStateBase):
if self.CP.carFingerprint in CANFD_CAR:
return self.update_canfd(cp, cp_cam)
- ret = car.CarState.new_message()
- cp_cruise = cp_cam if self.CP.carFingerprint in CAMERA_SCC_CAR else cp
- self.is_metric = cp.vl["CLU11"]["CF_Clu_SPEED_UNIT"] == 0
- speed_conv = CV.KPH_TO_MS if self.is_metric else CV.MPH_TO_MS
-
- ret.doorOpen = any([cp.vl["CGW1"]["CF_Gway_DrvDrSw"], cp.vl["CGW1"]["CF_Gway_AstDrSw"],
- cp.vl["CGW2"]["CF_Gway_RLDrSw"], cp.vl["CGW2"]["CF_Gway_RRDrSw"]])
-
- ret.seatbeltUnlatched = cp.vl["CGW1"]["CF_Gway_DrvSeatBeltSw"] == 0
-
- ret.wheelSpeeds = self.get_wheel_speeds(
- cp.vl["WHL_SPD11"]["WHL_SPD_FL"],
- cp.vl["WHL_SPD11"]["WHL_SPD_FR"],
- cp.vl["WHL_SPD11"]["WHL_SPD_RL"],
- cp.vl["WHL_SPD11"]["WHL_SPD_RR"],
- )
- ret.vEgoRaw = (ret.wheelSpeeds.fl + ret.wheelSpeeds.fr + ret.wheelSpeeds.rl + ret.wheelSpeeds.rr) / 4.
- ret.vEgo, ret.aEgo = self.update_speed_kf(ret.vEgoRaw)
- ret.standstill = ret.wheelSpeeds.fl <= STANDSTILL_THRESHOLD and ret.wheelSpeeds.rr <= STANDSTILL_THRESHOLD
-
- self.cluster_speed_counter += 1
- if self.cluster_speed_counter > CLUSTER_SAMPLE_RATE:
- self.cluster_speed = cp.vl["CLU15"]["CF_Clu_VehicleSpeed"]
- self.cluster_speed_counter = 0
-
- # Mimic how dash converts to imperial.
- # Sorento is the only platform where CF_Clu_VehicleSpeed is already imperial when not is_metric
- # TODO: CGW_USM1->CF_Gway_DrLockSoundRValue may describe this
- if not self.is_metric and self.CP.carFingerprint not in (CAR.KIA_SORENTO,):
- self.cluster_speed = math.floor(self.cluster_speed * CV.KPH_TO_MPH + CV.KPH_TO_MPH)
-
- ret.vEgoCluster = self.cluster_speed * speed_conv
-
- ret.steeringAngleDeg = cp.vl["SAS11"]["SAS_Angle"]
- ret.steeringRateDeg = cp.vl["SAS11"]["SAS_Speed"]
- ret.yawRate = cp.vl["ESP12"]["YAW_RATE"]
- ret.leftBlinker, ret.rightBlinker = self.update_blinker_from_lamp(
- 50, cp.vl["CGW1"]["CF_Gway_TurnSigLh"], cp.vl["CGW1"]["CF_Gway_TurnSigRh"])
- ret.steeringTorque = cp.vl["MDPS12"]["CR_Mdps_StrColTq"]
- ret.steeringTorqueEps = cp.vl["MDPS12"]["CR_Mdps_OutTq"]
- ret.steeringPressed = self.update_steering_pressed(abs(ret.steeringTorque) > self.params.STEER_THRESHOLD, 5)
- ret.steerFaultTemporary = cp.vl["MDPS12"]["CF_Mdps_ToiUnavail"] != 0 or cp.vl["MDPS12"]["CF_Mdps_ToiFlt"] != 0
-
- # cruise state
- if self.CP.openpilotLongitudinalControl:
- # These are not used for engage/disengage since openpilot keeps track of state using the buttons
- ret.cruiseState.available = self.main_enabled
- ret.cruiseState.enabled = cp.vl["TCS13"]["ACC_REQ"] == 1
- ret.cruiseState.standstill = False
- ret.cruiseState.nonAdaptive = False
- else:
- ret.cruiseState.available = cp_cruise.vl["SCC11"]["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
-
- # TODO: Find brake pressure
- ret.brake = 0
- ret.brakePressed = cp.vl["TCS13"]["DriverOverride"] == 2 # 2 includes regen braking by user on HEV/EV
- ret.brakeHoldActive = cp.vl["TCS15"]["AVH_LAMP"] == 2 # 0 OFF, 1 ERROR, 2 ACTIVE, 3 READY
- ret.parkingBrake = cp.vl["TCS13"]["PBRAKE_ACT"] == 1
- ret.accFaulted = cp.vl["TCS13"]["ACCEnable"] != 0 # 0 ACC CONTROL ENABLED, 1-3 ACC CONTROL DISABLED
-
- if self.CP.carFingerprint in (HYBRID_CAR | EV_CAR):
- if self.CP.carFingerprint in HYBRID_CAR:
- ret.gas = cp.vl["E_EMS11"]["CR_Vcu_AccPedDep_Pos"] / 254.
- else:
- ret.gas = cp.vl["E_EMS11"]["Accel_Pedal_Pos"] / 254.
- ret.gasPressed = ret.gas > 0
- else:
- ret.gas = cp.vl["EMS12"]["PV_AV_CAN"] / 100.
- ret.gasPressed = bool(cp.vl["EMS16"]["CF_Ems_AclAct"])
-
- # Gear Selection via Cluster - For those Kia/Hyundai which are not fully discovered, we can use the Cluster Indicator for Gear Selection,
- # as this seems to be standard over all cars, but is not the preferred method.
- if self.CP.carFingerprint in (HYBRID_CAR | EV_CAR):
- gear = cp.vl["ELECT_GEAR"]["Elect_Gear_Shifter"]
- elif self.CP.carFingerprint in CAN_GEARS["use_cluster_gears"]:
- gear = cp.vl["CLU15"]["CF_Clu_Gear"]
- elif self.CP.carFingerprint in CAN_GEARS["use_tcu_gears"]:
- gear = cp.vl["TCU12"]["CUR_GR"]
- else:
- gear = cp.vl["LVR12"]["CF_Lvr_Gear"]
-
- ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(gear))
-
- if not self.CP.openpilotLongitudinalControl:
- 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
- scc_warning = cp_cruise.vl["SCC12"]["TakeOverReq"] == 1 # sometimes only SCC system shows an FCW
- aeb_braking = cp_cruise.vl[aeb_src]["CF_VSM_DecCmdAct"] != 0 or cp_cruise.vl[aeb_src][aeb_sig] != 0
- ret.stockFcw = (aeb_warning or scc_warning) and not aeb_braking
- ret.stockAeb = aeb_warning and aeb_braking
-
- if self.CP.enableBsm:
- ret.leftBlindspot = cp.vl["LCA11"]["CF_Lca_IndLeft"] != 0
- ret.rightBlindspot = cp.vl["LCA11"]["CF_Lca_IndRight"] != 0
-
- # save the entire LKAS11 and CLU11
- 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
- self.prev_cruise_buttons = self.cruise_buttons[-1]
- self.cruise_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwState"])
- self.prev_main_buttons = self.main_buttons[-1]
- self.main_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwMain"])
- if self.prev_main_buttons == 0 and self.main_buttons[-1] != 0:
- self.main_enabled = not self.main_enabled
-
- # BBot functions for lfa and gap buttons - test speed up / down
- self.oscar_lane_center_btn_pressed= False
- self.oscar_slc_decel = False
- self.oscar_slc_accel = False
-
- self.param_memory.put("oscar_debug", "Hello World")
-
- # if self.cruise_buttons[-1] == Buttons.GAP_DIST and self.prev_cruise_buttons == 0:
- # self.oscar_lane_center_btn_pressed= True
-
- # lkas_pressed = cp.vl["BCM_PO_11"]["LFA_Pressed"]
- # if lkas_pressed and not self.lkas_previously_pressed:
- # self.custom_speed_up = True
- # self.lkas_previously_pressed = lkas_pressed
-
- # Driving personalities function
- # if self.personalities_via_wheel and ret.cruiseState.available:
- # # Sync with the onroad UI button
- # if self.param_memory.get_bool("PersonalityChangedViaUI"):
- # self.personality_profile = self.param.get_int("LongitudinalPersonality")
- # self.param_memory.put_bool("PersonalityChangedViaUI", False)
-
- # # Change personality upon steering wheel button press
- # if self.cruise_buttons[-1] == Buttons.GAP_DIST and self.prev_cruise_buttons == 0:
- # self.param_memory.put_bool("PersonalityChangedViaWheel", True)
- # self.personality_profile = (self.previous_personality_profile + 2) % 3
-
- # if self.personality_profile != self.previous_personality_profile and self.personality_profile >= 0:
- # self.param.put_int("LongitudinalPersonality", self.personality_profile)
- # self.previous_personality_profile = self.personality_profile
-
- # # Toggle Experimental Mode from steering wheel function
- # if self.experimental_mode_via_lkas and ret.cruiseState.available:
- # lkas_pressed = cp.vl["BCM_PO_11"]["LFA_Pressed"]
- # if lkas_pressed and not self.lkas_previously_pressed:
- # if self.conditional_experimental_mode:
- # # Set "CEStatus" to work with "Conditional Experimental Mode"
- # conditional_status = self.param_memory.get_int("CEStatus")
- # override_value = 0 if conditional_status in (1, 2, 3, 4) else 1 if conditional_status >= 5 else 2
- # self.param_memory.put_int("CEStatus", override_value)
- # else:
- # experimental_mode = self.param.get_bool("ExperimentalMode")
- # # Invert the value of "ExperimentalMode"
- # put_bool_nonblocking("ExperimentalMode", not experimental_mode)
- # self.lkas_previously_pressed = lkas_pressed
-
Watcher.log_watch("hyundai_carstate_update_self", self)
return ret
def update_canfd(self, cp, cp_cam):
Watcher.log_watch("hyundai_carstate_update_canfd_cp", cp)
Watcher.log_watch("hyundai_carstate_update_canfd_cp_cam", cp_cam)
-
- ret = car.CarState.new_message()
-
- self.is_metric = cp.vl["CRUISE_BUTTONS_ALT"]["DISTANCE_UNIT"] != 1
- speed_factor = CV.KPH_TO_MS if self.is_metric else CV.MPH_TO_MS
-
- if self.CP.carFingerprint in (EV_CAR | HYBRID_CAR):
- offset = 255. if self.CP.carFingerprint in EV_CAR else 1023.
- ret.gas = cp.vl[self.accelerator_msg_canfd]["ACCELERATOR_PEDAL"] / offset
- ret.gasPressed = ret.gas > 1e-5
- else:
- ret.gasPressed = bool(cp.vl[self.accelerator_msg_canfd]["ACCELERATOR_PEDAL_PRESSED"])
-
- ret.brakePressed = cp.vl["TCS"]["DriverBraking"] == 1
-
- ret.doorOpen = cp.vl["DOORS_SEATBELTS"]["DRIVER_DOOR"] == 1
- ret.seatbeltUnlatched = cp.vl["DOORS_SEATBELTS"]["DRIVER_SEATBELT"] == 0
-
- gear = cp.vl[self.gear_msg_canfd]["GEAR"]
- ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(gear))
-
- # TODO: figure out positions
- ret.wheelSpeeds = self.get_wheel_speeds(
- cp.vl["WHEEL_SPEEDS"]["WHEEL_SPEED_1"],
- cp.vl["WHEEL_SPEEDS"]["WHEEL_SPEED_2"],
- cp.vl["WHEEL_SPEEDS"]["WHEEL_SPEED_3"],
- cp.vl["WHEEL_SPEEDS"]["WHEEL_SPEED_4"],
- )
- ret.vEgoRaw = (ret.wheelSpeeds.fl + ret.wheelSpeeds.fr + ret.wheelSpeeds.rl + ret.wheelSpeeds.rr) / 4.
- ret.vEgo, ret.aEgo = self.update_speed_kf(ret.vEgoRaw)
- ret.standstill = ret.wheelSpeeds.fl <= STANDSTILL_THRESHOLD and ret.wheelSpeeds.rr <= STANDSTILL_THRESHOLD
-
- ret.steeringRateDeg = cp.vl["STEERING_SENSORS"]["STEERING_RATE"]
- ret.steeringAngleDeg = cp.vl["STEERING_SENSORS"]["STEERING_ANGLE"] * -1
- ret.steeringTorque = cp.vl["MDPS"]["STEERING_COL_TORQUE"]
- ret.steeringTorqueEps = cp.vl["MDPS"]["STEERING_OUT_TORQUE"]
- ret.steeringPressed = self.update_steering_pressed(abs(ret.steeringTorque) > self.params.STEER_THRESHOLD, 5)
- ret.steerFaultTemporary = cp.vl["MDPS"]["LKA_FAULT"] != 0
-
- # TODO: alt signal usage may be described by cp.vl['BLINKERS']['USE_ALT_LAMP']
- left_blinker_sig, right_blinker_sig = "LEFT_LAMP", "RIGHT_LAMP"
- if self.CP.carFingerprint == CAR.KONA_EV_2ND_GEN:
- left_blinker_sig, right_blinker_sig = "LEFT_LAMP_ALT", "RIGHT_LAMP_ALT"
- ret.leftBlinker, ret.rightBlinker = self.update_blinker_from_lamp(50, cp.vl["BLINKERS"][left_blinker_sig],
- cp.vl["BLINKERS"][right_blinker_sig])
- if self.CP.enableBsm:
- ret.leftBlindspot = cp.vl["BLINDSPOTS_REAR_CORNERS"]["FL_INDICATOR"] != 0
- ret.rightBlindspot = cp.vl["BLINDSPOTS_REAR_CORNERS"]["FR_INDICATOR"] != 0
-
- # cruise state
- # CAN FD cars enable on main button press, set available if no TCS faults preventing engagement
- ret.cruiseState.available = self.main_enabled
- if self.CP.openpilotLongitudinalControl:
- # These are not used for engage/disengage since openpilot keeps track of state using the buttons
- ret.cruiseState.enabled = cp.vl["TCS"]["ACC_REQ"] == 1
- ret.cruiseState.standstill = False
- else:
- cp_cruise_info = cp_cam if self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC else cp
- ret.cruiseState.enabled = cp_cruise_info.vl["SCC_CONTROL"]["ACCMode"] in (1, 2)
- ret.cruiseState.standstill = cp_cruise_info.vl["SCC_CONTROL"]["CRUISE_STANDSTILL"] == 1
- ret.cruiseState.speed = cp_cruise_info.vl["SCC_CONTROL"]["VSetDis"] * speed_factor
- self.cruise_info = copy.copy(cp_cruise_info.vl["SCC_CONTROL"])
-
- # Manual Speed Limit Assist is a feature that replaces non-adaptive cruise control on EV CAN FD platforms.
- # It limits the vehicle speed, overridable by pressing the accelerator past a certain point.
- # The car will brake, but does not respect positive acceleration commands in this mode
- # TODO: find this message on ICE & HYBRID cars + cruise control signals (if exists)
- if self.CP.carFingerprint in EV_CAR:
- ret.cruiseState.nonAdaptive = cp.vl["MANUAL_SPEED_LIMIT_ASSIST"]["MSLA_ENABLED"] == 1
-
- self.prev_cruise_buttons = self.cruise_buttons[-1]
- self.cruise_buttons.extend(cp.vl_all[self.cruise_btns_msg_canfd]["CRUISE_BUTTONS"])
- self.prev_main_buttons = self.main_buttons[-1]
- self.main_buttons.extend(cp.vl_all[self.cruise_btns_msg_canfd]["ADAPTIVE_CRUISE_MAIN_BTN"])
- if self.prev_main_buttons == 0 and self.main_buttons[-1] != 0:
- self.main_enabled = not self.main_enabled
- self.buttons_counter = cp.vl[self.cruise_btns_msg_canfd]["COUNTER"]
- ret.accFaulted = cp.vl["TCS"]["ACCEnable"] != 0 # 0 ACC CONTROL ENABLED, 1-3 ACC CONTROL DISABLED
-
- if self.CP.flags & HyundaiFlags.CANFD_HDA2:
- self.hda2_lfa_block_msg = copy.copy(cp_cam.vl["CAM_0x362"] if self.CP.flags & HyundaiFlags.CANFD_HDA2_ALT_STEERING
- else cp_cam.vl["CAM_0x2a4"])
-
- SpeedLimitController.load_state()
- SpeedLimitController.car_speed_limit = self.calculate_speed_limit_canfd(self.CP, cp, cp_cam) * speed_factor
- SpeedLimitController.write_car_state()
-
- # self.custom_speed_up = False
- self.oscar_lane_center_btn_pressed = False
-
- if ret.cruiseState.available:
-
- if self.cruise_buttons[-1] == Buttons.GAP_DIST and self.prev_cruise_buttons == 0:
- self.oscar_lane_center_btn_pressed = True
-
- lkas_pressed = False
- try:
- lkas_pressed = cp.vl[self.cruise_btns_msg_canfd]["LKAS_BTN"]
- except:
- nothing = 0
-
- # intentionally cause a failure
- if lkas_pressed:
- floog=norpdywoop
- # if self.cruise_buttons[-1] == Buttons.GAP_DIST and self.prev_cruise_buttons == 0:
- # self.oscar_lane_center_btn_pressed= True
-
- # Driving personalities function
- # if self.personalities_via_wheel and ret.cruiseState.available:
- # # Sync with the onroad UI button
- # if self.param_memory.get_bool("PersonalityChangedViaUI"):
- # self.personality_profile = self.param.get_int("LongitudinalPersonality")
- # self.param_memory.put_bool("PersonalityChangedViaUI", False)
-
- # # Change personality upon steering wheel button press
- # if self.cruise_buttons[-1] == Buttons.GAP_DIST and self.prev_cruise_buttons == 0:
- # self.param_memory.put_bool("PersonalityChangedViaWheel", True)
- # self.personality_profile = (self.previous_personality_profile + 2) % 3
-
- # if self.personality_profile != self.previous_personality_profile and self.personality_profile >= 0:
- # self.param.put_int("LongitudinalPersonality", self.personality_profile)
- # self.previous_personality_profile = self.personality_profile
-
- # # Toggle Experimental Mode from steering wheel function
- # if self.experimental_mode_via_lkas and ret.cruiseState.available:
- # lkas_pressed = cp.vl[self.cruise_btns_msg_canfd]["LKAS_BTN"]
- # if lkas_pressed and not self.lkas_previously_pressed:
- # if self.conditional_experimental_mode:
- # # Set "CEStatus" to work with "Conditional Experimental Mode"
- # conditional_status = self.param_memory.get_int("CEStatus")
- # override_value = 0 if conditional_status in (1, 2, 3, 4) else 1 if conditional_status >= 5 else 2
- # self.param_memory.put_int("CEStatus", override_value)
- # else:
- # experimental_mode = self.param.get_bool("ExperimentalMode")
- # # Invert the value of "ExperimentalMode"
- # put_bool_nonblocking("ExperimentalMode", not experimental_mode)
- # self.lkas_previously_pressed = lkas_pressed
-
- Watcher.log_watch("hyundai_carstate_update_canfd_self", self)
-
return ret
-
- # BBOT does not work
- def calculate_speed_limit_canfd(self, CP, cp, cp_cam):
- try:
- self._speed_limit_clu = cp.vl["CLUSTER_SPEED_LIMIT"]["SPEED_LIMIT_1"]
- return self._speed_limit_clu if self._speed_limit_clu not in (0, 255) else 0
- except:
- return 0
-
+
def get_can_parser(self, CP):
- if CP.carFingerprint in CANFD_CAR:
- return self.get_can_parser_canfd(CP)
-
- messages = [
- # address, frequency
- ("MDPS12", 50),
- ("TCS13", 50),
- ("TCS15", 10),
- ("CLU11", 50),
- ("CLU15", 5),
- ("ESP12", 100),
- ("CGW1", 10),
- ("CGW2", 5),
- ("CGW4", 5),
- ("WHL_SPD11", 50),
- ("SAS11", 100),
- ]
-
- if not CP.openpilotLongitudinalControl and CP.carFingerprint not in CAMERA_SCC_CAR:
- messages += [
- ("SCC11", 50),
- ("SCC12", 50),
- ]
- if CP.flags & HyundaiFlags.USE_FCA.value:
- messages.append(("FCA11", 50))
-
- if CP.enableBsm:
- messages.append(("LCA11", 50))
-
- if CP.carFingerprint in (HYBRID_CAR | EV_CAR):
- messages.append(("E_EMS11", 50))
- else:
- messages += [
- ("EMS12", 100),
- ("EMS16", 100),
- ]
-
- if CP.carFingerprint in (HYBRID_CAR | EV_CAR):
- messages.append(("ELECT_GEAR", 20))
- elif CP.carFingerprint in CAN_GEARS["use_cluster_gears"]:
- pass
- elif CP.carFingerprint in CAN_GEARS["use_tcu_gears"]:
- messages.append(("TCU12", 100))
- else:
- messages.append(("LVR12", 100))
-
- messages.append(("BCM_PO_11", 50))
-
- return CANParser(DBC[CP.carFingerprint]["pt"], messages, 0)
-
- @staticmethod
- def get_cam_can_parser(CP):
- if CP.carFingerprint in CANFD_CAR:
- return CarState.get_cam_can_parser_canfd(CP)
-
- messages = [
- ("LKAS11", 100)
- ]
-
- if not CP.openpilotLongitudinalControl and CP.carFingerprint in CAMERA_SCC_CAR:
- messages += [
- ("SCC11", 50),
- ("SCC12", 50),
- ]
-
- if CP.flags & HyundaiFlags.USE_FCA.value:
- messages.append(("FCA11", 50))
-
- return CANParser(DBC[CP.carFingerprint]["pt"], messages, 2)
-
- def get_can_parser_canfd(self, CP):
messages = [
(self.gear_msg_canfd, 100),
(self.accelerator_msg_canfd, 100),
@@ -485,7 +83,7 @@ class CarState(CarStateBase):
return CANParser(DBC[CP.carFingerprint]["pt"], messages, CanBus(CP).ECAN)
@staticmethod
- def get_cam_can_parser_canfd(CP):
+ def get_cam_can_parser(CP):
messages = []
if CP.flags & HyundaiFlags.CANFD_HDA2:
block_lfa_msg = "CAM_0x362" if CP.flags & HyundaiFlags.CANFD_HDA2_ALT_STEERING else "CAM_0x2a4"
@@ -495,6 +93,4 @@ class CarState(CarStateBase):
("SCC_CONTROL", 50),
]
-
-
return CANParser(DBC[CP.carFingerprint]["pt"], messages, CanBus(CP).CAM)
diff --git a/selfdrive/car/hyundai/hyundaicanfd.org b/selfdrive/car/hyundai/hyundaicanfd.org
new file mode 100644
index 0000000..15668ca
--- /dev/null
+++ b/selfdrive/car/hyundai/hyundaicanfd.org
@@ -0,0 +1,224 @@
+from openpilot.common.numpy_fast import clip
+from openpilot.selfdrive.car import CanBusBase
+from openpilot.selfdrive.car.hyundai.values import HyundaiFlags
+
+
+class CanBus(CanBusBase):
+ def __init__(self, CP, hda2=None, fingerprint=None) -> None:
+ super().__init__(CP, fingerprint)
+
+ if hda2 is None:
+ assert CP is not None
+ hda2 = CP.flags & HyundaiFlags.CANFD_HDA2.value
+
+ # On the CAN-FD platforms, the LKAS camera is on both A-CAN and E-CAN. HDA2 cars
+ # have a different harness than the HDA1 and non-HDA variants in order to split
+ # a different bus, since the steering is done by different ECUs.
+ self._a, self._e = 1, 0
+ if hda2:
+ self._a, self._e = 0, 1
+
+ self._a += self.offset
+ self._e += self.offset
+ self._cam = 2 + self.offset
+
+ @property
+ def ECAN(self):
+ return self._e
+
+ @property
+ def ACAN(self):
+ return self._a
+
+ @property
+ def CAM(self):
+ return self._cam
+
+
+def create_steering_messages(packer, CP, CAN, enabled, lat_active, apply_steer):
+
+ ret = []
+
+ values = {
+ "LKA_MODE": 2,
+ "LKA_ICON": 2 if enabled else 1 if lat_active else 0,
+ "TORQUE_REQUEST": apply_steer,
+ "LKA_ASSIST": 0,
+ "STEER_REQ": 1 if lat_active else 0,
+ "STEER_MODE": 0,
+ "HAS_LANE_SAFETY": 0, # hide LKAS settings
+ "NEW_SIGNAL_1": 0,
+ "NEW_SIGNAL_2": 0,
+ }
+
+ if CP.flags & HyundaiFlags.CANFD_HDA2:
+ hda2_lkas_msg = "LKAS_ALT" if CP.flags & HyundaiFlags.CANFD_HDA2_ALT_STEERING else "LKAS"
+ if CP.openpilotLongitudinalControl:
+ ret.append(packer.make_can_msg("LFA", CAN.ECAN, values))
+ ret.append(packer.make_can_msg(hda2_lkas_msg, CAN.ACAN, values))
+ else:
+ ret.append(packer.make_can_msg("LFA", CAN.ECAN, values))
+
+ return ret
+
+def create_suppress_lfa(packer, CAN, hda2_lfa_block_msg, hda2_alt_steering):
+ suppress_msg = "CAM_0x362" if hda2_alt_steering else "CAM_0x2a4"
+ msg_bytes = 32 if hda2_alt_steering else 24
+
+ values = {f"BYTE{i}": hda2_lfa_block_msg[f"BYTE{i}"] for i in range(3, msg_bytes) if i != 7}
+ values["COUNTER"] = hda2_lfa_block_msg["COUNTER"]
+ values["SET_ME_0"] = 0
+ values["SET_ME_0_2"] = 0
+ values["LEFT_LANE_LINE"] = 0
+ values["RIGHT_LANE_LINE"] = 0
+ return packer.make_can_msg(suppress_msg, CAN.ACAN, values)
+
+def create_buttons(packer, CP, CAN, cnt, btn):
+ values = {
+ "COUNTER": cnt,
+ "SET_ME_1": 1,
+ "CRUISE_BUTTONS": btn,
+ }
+
+ bus = CAN.ECAN if CP.flags & HyundaiFlags.CANFD_HDA2 else CAN.CAM
+ return packer.make_can_msg("CRUISE_BUTTONS", bus, values)
+
+def create_acc_cancel(packer, CP, CAN, cruise_info_copy):
+ # TODO: why do we copy different values here?
+ if CP.flags & HyundaiFlags.CANFD_CAMERA_SCC.value:
+ values = {s: cruise_info_copy[s] for s in [
+ "COUNTER",
+ "CHECKSUM",
+ "NEW_SIGNAL_1",
+ "MainMode_ACC",
+ "ACCMode",
+ "ZEROS_9",
+ "CRUISE_STANDSTILL",
+ "ZEROS_5",
+ "DISTANCE_SETTING",
+ "VSetDis",
+ ]}
+ else:
+ values = {s: cruise_info_copy[s] for s in [
+ "COUNTER",
+ "CHECKSUM",
+ "ACCMode",
+ "VSetDis",
+ "CRUISE_STANDSTILL",
+ ]}
+ values.update({
+ "ACCMode": 4,
+ "aReqRaw": 0.0,
+ "aReqValue": 0.0,
+ })
+ return packer.make_can_msg("SCC_CONTROL", CAN.ECAN, values)
+
+def create_lfahda_cluster(packer, CAN, enabled):
+ values = {
+ "HDA_ICON": 1 if enabled else 0,
+ # 0 off, 1 gray, 2 green, 3 blinking (wheel icon)
+ "LFA_ICON": 0 if enabled else 0, # was green before i think in 2? 3 should be flashing?
+ # "LFA_ICON": 2 if enabled else 0,
+ }
+ return packer.make_can_msg("LFAHDA_CLUSTER", CAN.ECAN, values)
+
+
+def create_acc_control(packer, CAN, enabled, accel_last, accel, stopping, gas_override, set_speed, personality):
+ jerk = 5
+ jn = jerk / 50
+ if not enabled or gas_override:
+ a_val, a_raw = 0, 0
+ else:
+ a_raw = accel
+ a_val = clip(accel, accel_last - jn, accel_last + jn)
+
+ values = {
+ "ACCMode": 0 if not enabled else (2 if gas_override else 1),
+ "MainMode_ACC": 1,
+ "StopReq": 1 if stopping else 0,
+ "aReqValue": a_val,
+ "aReqRaw": a_raw,
+ "VSetDis": set_speed,
+ "JerkLowerLimit": jerk if enabled else 1,
+ "JerkUpperLimit": 3.0,
+
+ "ACC_ObjDist": 1,
+ "ObjValid": 0,
+ "OBJ_STATUS": 2,
+ "SET_ME_2": 0x4,
+ "SET_ME_3": 0x3,
+ "SET_ME_TMP_64": 0x64,
+ "DISTANCE_SETTING": personality + 1,
+ }
+
+ return packer.make_can_msg("SCC_CONTROL", CAN.ECAN, values)
+
+def create_spas_messages(packer, CAN, frame, left_blink, right_blink):
+ ret = []
+
+ values = {
+ }
+ ret.append(packer.make_can_msg("SPAS1", CAN.ECAN, values))
+
+ blink = 0
+ if left_blink:
+ blink = 3
+ elif right_blink:
+ blink = 4
+ values = {
+ "BLINKER_CONTROL": blink,
+ }
+ ret.append(packer.make_can_msg("SPAS2", CAN.ECAN, values))
+
+ return ret
+
+
+def create_adrv_messages(packer, CAN, frame):
+ # messages needed to car happy after disabling
+ # the ADAS Driving ECU to do longitudinal control
+
+ ret = []
+
+ values = {
+ }
+ ret.append(packer.make_can_msg("ADRV_0x51", CAN.ACAN, values))
+
+ if frame % 2 == 0:
+ values = {
+ 'AEB_SETTING': 0x1, # show AEB disabled icon
+ 'SET_ME_2': 0x2,
+ 'SET_ME_FF': 0xff,
+ 'SET_ME_FC': 0xfc,
+ 'SET_ME_9': 0x9,
+ }
+ ret.append(packer.make_can_msg("ADRV_0x160", CAN.ECAN, values))
+
+ if frame % 5 == 0:
+ values = {
+ 'SET_ME_1C': 0x1c,
+ 'SET_ME_FF': 0xff,
+ 'SET_ME_TMP_F': 0xf,
+ 'SET_ME_TMP_F_2': 0xf,
+ }
+ ret.append(packer.make_can_msg("ADRV_0x1ea", CAN.ECAN, values))
+
+ values = {
+ 'SET_ME_E1': 0xe1,
+ 'SET_ME_3A': 0x3a,
+ }
+ ret.append(packer.make_can_msg("ADRV_0x200", CAN.ECAN, values))
+
+ if frame % 20 == 0:
+ values = {
+ 'SET_ME_15': 0x15,
+ }
+ ret.append(packer.make_can_msg("ADRV_0x345", CAN.ECAN, values))
+
+ if frame % 100 == 0:
+ values = {
+ 'SET_ME_22': 0x22,
+ 'SET_ME_41': 0x41,
+ }
+ ret.append(packer.make_can_msg("ADRV_0x1da", CAN.ECAN, values))
+
+ return ret
diff --git a/selfdrive/oscarpilot/settings/basic.cc b/selfdrive/oscarpilot/settings/basic.cc
index c27fc86..75174f1 100644
--- a/selfdrive/oscarpilot/settings/basic.cc
+++ b/selfdrive/oscarpilot/settings/basic.cc
@@ -21,11 +21,10 @@ OscarPilotBasicPanel::OscarPilotBasicPanel(OscarSettingsWindow *parent) : FrogPi
// "Engages 'experimental mode' when a curve is detected, temporairly reducing max speed.", "../frogpilot/assets/toggle_icons/icon_conditional.png"
// },
// Alert on stopsign / stoplight
-
+ {"LaneChangeAssist", "Lane Change Assist", "Automatically change lanes on turn signal and wheel nudge at highway speeds.", "../frogpilot/assets/toggle_icons/icon_lane.png"},
{"FireTheBabysitter", "Custom Driver Monitoring", "Customize the driver awareness alert timeouts.", ""},
// - Hands On Wheel: Always / At Dusk / 2+ hrs driving
- {"LaneChangeAssist", "Lane Change Assist", "Automatically change lanes on turn signal and wheel nudge at highway speeds.", "../frogpilot/assets/toggle_icons/icon_lane.png"},
{"DashCam", "Dash Cam Recording", "Record video and gps data for all drives automatically.", ""}
};
diff --git a/selfdrive/oscarpilot/settings/notes b/selfdrive/oscarpilot/settings/notes
index c5abc07..132b28a 100644
--- a/selfdrive/oscarpilot/settings/notes
+++ b/selfdrive/oscarpilot/settings/notes
@@ -1 +1,20 @@
-Need a reset to defaults option
\ No newline at end of file
+Goals:
+
+- slow down on experimental mode
+- LKAS button - should toggle between drive, weather, weather radar. Hold for screen off
+- car dashboard should have enough indicators that it is able to represent drive state without screen on
+- set speed limit on engage cruise control
+
+qol:
+- customize babysitter - driver awareness timeouts daytime, nighttime, require steering wheel
+- set climate on start, roll up windows on stop
+- upload park location on stop
+- low bandwidth / high bandwidth wifi, upload recordings on high bandwidth
+- list drives w/ image on stop
+ - stop light / stop sign warning alert
+
+ release:
+ - reenable training screen
+ - - disregard for my device id
+ - cleanup code
+ - rename to diamondpilot
\ No newline at end of file