from cereal import car
from panda import Panda
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
Ecu = car . CarParams . Ecu
ButtonType = car . CarState . ButtonEvent . Type
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 }
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
# 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 if car is hybrid
if 0x105 in fingerprint [ CAN . ECAN ] :
ret . flags | = HyundaiFlags . HYBRID . value
elif candidate in EV_CAR :
ret . flags | = HyundaiFlags . EV . value
# detect HDA2 with ADAS Driving ECU
if hda2 :
ret . flags | = HyundaiFlags . CANFD_HDA2 . value
if 0x110 in fingerprint [ CAN . CAM ] :
ret . flags | = HyundaiFlags . CANFD_HDA2_ALT_STEERING . value
else :
# 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 :
# TODO: detect EV and hybrid
if candidate in HYBRID_CAR :
ret . flags | = HyundaiFlags . HYBRID . value
elif candidate in EV_CAR :
ret . flags | = HyundaiFlags . EV . value
# 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 == CAR . KIA_OPTIMA_G4_FL :
ret . steerActuatorDelay = 0.2
# *** longitudinal control ***
if candidate in CANFD_CAR :
ret . experimentalLongitudinalAvailable = candidate not in ( CANFD_UNSUPPORTED_LONGITUDINAL_CAR | CANFD_RADAR_SCC_CAR )
else :
ret . experimentalLongitudinalAvailable = candidate not in ( UNSUPPORTED_LONGITUDINAL_CAR | CAMERA_SCC_CAR )
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 . longitudinalActuatorDelay = 0.5
# *** feature detection ***
if candidate in CANFD_CAR :
ret . enableBsm = 0x1e5 in fingerprint [ CAN . ECAN ]
else :
ret . enableBsm = 0x58b in fingerprint [ 0 ]
# *** panda safety config ***
if candidate in CANFD_CAR :
cfgs = [ get_safety_config ( car . CarParams . SafetyModel . hyundaiCanfd ) , ]
if CAN . ECAN > = 4 :
cfgs . insert ( 0 , get_safety_config ( car . CarParams . SafetyModel . noOutput ) )
ret . safetyConfigs = cfgs
if ret . flags & HyundaiFlags . CANFD_HDA2 :
ret . safetyConfigs [ - 1 ] . safetyParam | = Panda . FLAG_HYUNDAI_CANFD_HDA2
if ret . flags & HyundaiFlags . CANFD_HDA2_ALT_STEERING :
ret . safetyConfigs [ - 1 ] . safetyParam | = Panda . FLAG_HYUNDAI_CANFD_HDA2_ALT_STEERING
if ret . flags & HyundaiFlags . CANFD_ALT_BUTTONS :
ret . safetyConfigs [ - 1 ] . safetyParam | = Panda . FLAG_HYUNDAI_CANFD_ALT_BUTTONS
if ret . flags & HyundaiFlags . CANFD_CAMERA_SCC :
ret . safetyConfigs [ - 1 ] . safetyParam | = Panda . FLAG_HYUNDAI_CAMERA_SCC
else :
if candidate in LEGACY_SAFETY_MODE_CAR :
# these cars require a special panda safety mode due to missing counters and checksums in the messages
ret . safetyConfigs = [ get_safety_config ( car . CarParams . SafetyModel . hyundaiLegacy ) ]
else :
ret . safetyConfigs = [ get_safety_config ( car . CarParams . SafetyModel . hyundai , 0 ) ]
if candidate in CAMERA_SCC_CAR :
ret . safetyConfigs [ 0 ] . safetyParam | = Panda . FLAG_HYUNDAI_CAMERA_SCC
if ret . openpilotLongitudinalControl :
ret . safetyConfigs [ - 1 ] . safetyParam | = Panda . FLAG_HYUNDAI_LONG
if ret . flags & HyundaiFlags . HYBRID :
ret . safetyConfigs [ - 1 ] . safetyParam | = Panda . FLAG_HYUNDAI_HYBRID_GAS
elif ret . flags & HyundaiFlags . EV :
ret . safetyConfigs [ - 1 ] . safetyParam | = Panda . FLAG_HYUNDAI_EV_GAS
if candidate in ( CAR . HYUNDAI_KONA , CAR . HYUNDAI_KONA_EV , CAR . HYUNDAI_KONA_HEV , CAR . HYUNDAI_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 , can_recv , can_send ) :
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 ( can_recv , can_send , bus = bus , addr = addr , com_cont_req = b ' \x28 \x83 \x01 ' )
# for blinkers
if CP . flags & HyundaiFlags . ENABLE_BLINKERS :
disable_ecu ( can_recv , can_send , bus = CanBus ( CP ) . ECAN , addr = 0x7B1 , com_cont_req = b ' \x28 \x83 \x01 ' )
def _update ( self ) :
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 )
return ret