Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HKG: Car Port for Hyundai Palisade 2023 and Kia Telluride 2023 (HDA2) #1243

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ RUN pip3 install --break-system-packages --no-cache-dir $PYTHONPATH/panda/[dev]

# TODO: this should be a "pip install" or not even in this repo at all
RUN git config --global --add safe.directory $PYTHONPATH/panda
ENV OPENDBC_REF="5ed7a834a4e0e24c3968dd1e98ceb4b9d5f9791a"
ENV OPENDBC_REF="7099534b54cd3527fbfd5a45fe7067652fa1ee7b"
RUN cd /tmp/ && \
git clone --depth 1 https://github.com/commaai/opendbc opendbc_repo && \
git clone --depth 1 https://github.com/sunnypilot/opendbc opendbc_repo && \
cd opendbc_repo && git fetch origin $OPENDBC_REF && git checkout FETCH_HEAD && rm -rf .git/ && \
pip3 install --break-system-packages --no-cache-dir Cython numpy && \
scons -j8 --minimal opendbc/ && \
Expand Down
110 changes: 75 additions & 35 deletions board/safety/safety_hyundai.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
#include "safety_declarations.h"
#include "safety_hyundai_common.h"

#define HYUNDAI_LIMITS(steer, rate_up, rate_down) { \
#define HYUNDAI_LIMITS(steer, rate_up, rate_down, drv_trq_alloweance) { \
.max_steer = (steer), \
.max_rate_up = (rate_up), \
.max_rate_down = (rate_down), \
.max_rt_delta = 112, \
.max_rt_interval = 250000, \
.driver_torque_allowance = 50, \
.driver_torque_allowance = (drv_trq_alloweance), \
.driver_torque_factor = 2, \
.type = TorqueDriverLimited, \
/* the EPS faults when the steering angle is above a certain threshold for too long. to prevent this, */ \
Expand All @@ -32,14 +32,14 @@ static const CanMsg HYUNDAI_TX_MSGS[] = {
{0x485, 0, 4}, // LFAHDA_MFC Bus 0
};

#define HYUNDAI_COMMON_RX_CHECKS(legacy) \
{.msg = {{0x260, 0, 8, .check_checksum = true, .max_counter = 3U, .frequency = 100U}, \
{0x371, 0, 8, .frequency = 100U}, { 0 }}}, \
{.msg = {{0x386, 0, 8, .check_checksum = !(legacy), .max_counter = (legacy) ? 0U : 15U, .frequency = 100U}, { 0 }, { 0 }}}, \
{.msg = {{0x394, 0, 8, .check_checksum = !(legacy), .max_counter = (legacy) ? 0U : 7U, .frequency = 100U}, { 0 }, { 0 }}}, \
#define HYUNDAI_COMMON_RX_CHECKS(pt_bus, can_canfd_hybrid, legacy) \
{.msg = {{0x260, pt_bus, 8, .check_checksum = true, .max_counter = 3U, .frequency = 100U}, \
{0x371, 0, 8, .frequency = 100U}, { 0 }}}, \
{.msg = {{0x386, pt_bus, 8, .check_checksum = !(legacy), .max_counter = (legacy) ? 0U : 15U, .frequency = (can_canfd_hybrid) ? 50U : 100U}, { 0 }, { 0 }}}, \
{.msg = {{0x394, pt_bus, 8, .check_checksum = !(legacy), .max_counter = (legacy) ? 0U : 7U, .frequency = (can_canfd_hybrid) ? 50U : 100U}, { 0 }, { 0 }}}, \

#define HYUNDAI_SCC12_ADDR_CHECK(scc_bus) \
{.msg = {{0x421, (scc_bus), 8, .check_checksum = true, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}}, \
#define HYUNDAI_SCC12_ADDR_CHECK(scc_bus, can_canfd_hybrid) \
{.msg = {{0x421, (scc_bus), 8, .check_checksum = !(can_canfd_hybrid), .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}}, \

static bool hyundai_legacy = false;

Expand All @@ -54,7 +54,8 @@ static uint8_t hyundai_get_counter(const CANPacket_t *to_push) {
} else if (addr == 0x394) {
cnt = (GET_BYTE(to_push, 1) >> 5) & 0x7U;
} else if (addr == 0x421) {
cnt = GET_BYTE(to_push, 7) & 0xFU;
uint8_t byte_421 = hyundai_can_canfd_hybrid ? (GET_BYTE(to_push, 1) >> 4) : GET_BYTE(to_push, 7);
cnt = byte_421 & 0xFU;
} else if (addr == 0x4F1) {
cnt = (GET_BYTE(to_push, 3) >> 4) & 0xFU;
} else {
Expand All @@ -73,7 +74,7 @@ static uint32_t hyundai_get_checksum(const CANPacket_t *to_push) {
} else if (addr == 0x394) {
chksum = GET_BYTE(to_push, 6) & 0xFU;
} else if (addr == 0x421) {
chksum = GET_BYTE(to_push, 7) >> 4;
chksum = hyundai_can_canfd_hybrid ? GET_BYTE(to_push, 0) : GET_BYTE(to_push, 7) >> 4;
} else {
}
return chksum;
Expand Down Expand Up @@ -109,7 +110,7 @@ static uint32_t hyundai_compute_checksum(const CANPacket_t *to_push) {
}
chksum += (b % 16U) + (b / 16U);
}
chksum = (16U - (chksum % 16U)) % 16U;
chksum = (16U - (chksum % 16U)) % 16U;
}

return chksum;
Expand All @@ -119,14 +120,18 @@ static void hyundai_rx_hook(const CANPacket_t *to_push) {
int bus = GET_BUS(to_push);
int addr = GET_ADDR(to_push);

const int pt_bus = hyundai_can_canfd_hybrid ? 1 : 0;
const int non_cam_scc_bus = hyundai_can_canfd_hybrid ? 1 : 0;
const int scc_bus = hyundai_camera_scc ? 2 : non_cam_scc_bus;

// SCC12 is on bus 2 for camera-based SCC cars, bus 0 on all others
if ((addr == 0x421) && (((bus == 0) && !hyundai_camera_scc) || ((bus == 2) && hyundai_camera_scc))) {
// 2 bits: 13-14
int cruise_engaged = (GET_BYTES(to_push, 0, 4) >> 13) & 0x3U;
if ((addr == 0x421) && (bus == scc_bus)) {
uint8_t cruise_byte = hyundai_can_canfd_hybrid ? (GET_BYTE(to_push, 3) >> 4) : (GET_BYTES(to_push, 0, 4) >> 13);
bool cruise_engaged = (cruise_byte & 0x3U) != 0U;
hyundai_common_cruise_state_check(cruise_engaged);
}

if (bus == 0) {
if (bus == pt_bus) {
if (addr == 0x251) {
int torque_driver_new = (GET_BYTES(to_push, 0, 2) & 0x7ffU) - 1024U;
// update array of samples
Expand Down Expand Up @@ -160,21 +165,23 @@ static void hyundai_rx_hook(const CANPacket_t *to_push) {
if (addr == 0x394) {
brake_pressed = ((GET_BYTE(to_push, 5) >> 5U) & 0x3U) == 0x2U;
}
}

bool stock_ecu_detected = (addr == 0x340);
const int steer_addr = hyundai_canfd_hda2 ? 0x50 : 0x340;
bool stock_ecu_detected = (addr == steer_addr) && (bus == 0);

// If openpilot is controlling longitudinal we need to ensure the radar is turned off
// Enforce by checking we don't see SCC12
if (hyundai_longitudinal && (addr == 0x421)) {
stock_ecu_detected = true;
}
generic_rx_checks(stock_ecu_detected);
// If openpilot is controlling longitudinal we need to ensure the radar is turned off
// Enforce by checking we don't see SCC12
if (hyundai_longitudinal) {
stock_ecu_detected = stock_ecu_detected || ((addr == 0x421) && (bus == 0));
}
generic_rx_checks(stock_ecu_detected);
}

static bool hyundai_tx_hook(const CANPacket_t *to_send) {
const SteeringLimits HYUNDAI_STEERING_LIMITS = HYUNDAI_LIMITS(384, 3, 7);
const SteeringLimits HYUNDAI_STEERING_LIMITS_ALT = HYUNDAI_LIMITS(270, 2, 3);
const SteeringLimits HYUNDAI_STEERING_LIMITS = HYUNDAI_LIMITS(384, 3, 7, 50);
const SteeringLimits HYUNDAI_STEERING_LIMITS_ALT = HYUNDAI_LIMITS(270, 2, 3, 50);
const SteeringLimits HYUNDAI_STEERING_LIMITS_CAN_CANFD_HYBRID = HYUNDAI_LIMITS(384, 2, 3, 250);

bool tx = true;
int addr = GET_ADDR(to_send);
Expand Down Expand Up @@ -221,6 +228,16 @@ static bool hyundai_tx_hook(const CANPacket_t *to_send) {
}
}

// CAN CAN-FD Hybrid steering
if (addr == 0x50) {
int desired_torque = (((GET_BYTE(to_send, 6) & 0xFU) << 7U) | (GET_BYTE(to_send, 5) >> 1U)) - 1024U;
bool steer_req = GET_BIT(to_send, 52U);

if (steer_torque_cmd_checks(desired_torque, steer_req, HYUNDAI_STEERING_LIMITS_CAN_CANFD_HYBRID)) {
tx = false;
}
}

// UDS: Only tester present ("\x02\x3E\x80\x00\x00\x00\x00\x00") allowed on diagnostics address
if (addr == 0x7D0) {
if ((GET_BYTES(to_send, 0, 4) != 0x00803E02U) || (GET_BYTES(to_send, 4, 4) != 0x0U)) {
Expand Down Expand Up @@ -250,8 +267,18 @@ static int hyundai_fwd_hook(int bus_num, int addr) {
if (bus_num == 0) {
bus_fwd = 2;
}
if ((bus_num == 2) && (addr != 0x340) && (addr != 0x485)) {
bus_fwd = 0;
if (bus_num == 2) {
// LKAS11 for CAN, LKAS for CAN/CAN-FD
bool is_lkas11_msg = (addr == 0x340) && !hyundai_canfd_hda2;
bool is_lkas_msg = ((addr == 0x50) || (addr == 0x2a4)) && hyundai_canfd_hda2;

// LFAHDA_MFC for CAN
bool is_lfahda_msg = (addr == 0x485) && !hyundai_canfd_hda2;

bool block_msg = is_lkas11_msg || is_lkas_msg || is_lfahda_msg;
if (!block_msg) {
bus_fwd = 0;
}
}

return bus_fwd;
Expand All @@ -278,33 +305,46 @@ static safety_config hyundai_init(uint16_t param) {
{0x485, 0, 4}, // LFAHDA_MFC Bus 0
};

static const CanMsg HYUNDAI_CAN_CANFD_HYBRID_HDA2_TX_MSGS[] = {
{0x50, 0, 16},
{0x4F1, 1, 4},
{0x2A4, 0, 24},
};

hyundai_common_init(param);
hyundai_legacy = false;

if (hyundai_camera_scc) {
if (hyundai_camera_scc || hyundai_can_canfd_hybrid) {
hyundai_longitudinal = false;
}

safety_config ret;
if (hyundai_longitudinal) {
static RxCheck hyundai_long_rx_checks[] = {
HYUNDAI_COMMON_RX_CHECKS(false)
HYUNDAI_COMMON_RX_CHECKS(0, false, false)
// Use CLU11 (buttons) to manage controls allowed instead of SCC cruise state
{.msg = {{0x4F1, 0, 4, .check_checksum = false, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}},
};

ret = BUILD_SAFETY_CFG(hyundai_long_rx_checks, HYUNDAI_LONG_TX_MSGS);
} else if (hyundai_camera_scc) {
static RxCheck hyundai_cam_scc_rx_checks[] = {
HYUNDAI_COMMON_RX_CHECKS(false)
HYUNDAI_SCC12_ADDR_CHECK(2)
HYUNDAI_COMMON_RX_CHECKS(0, false, false)
HYUNDAI_SCC12_ADDR_CHECK(2, false)
};

ret = BUILD_SAFETY_CFG(hyundai_cam_scc_rx_checks, HYUNDAI_CAMERA_SCC_TX_MSGS);
} else if (hyundai_can_canfd_hybrid) {
static RxCheck hyundai_can_canfd_hda2_rx_checks[] = {
HYUNDAI_COMMON_RX_CHECKS(1, true, false)
HYUNDAI_SCC12_ADDR_CHECK(1, true)
};

ret = BUILD_SAFETY_CFG(hyundai_can_canfd_hda2_rx_checks, HYUNDAI_CAN_CANFD_HYBRID_HDA2_TX_MSGS);
} else {
static RxCheck hyundai_rx_checks[] = {
HYUNDAI_COMMON_RX_CHECKS(false)
HYUNDAI_SCC12_ADDR_CHECK(0)
HYUNDAI_COMMON_RX_CHECKS(0, false, false)
HYUNDAI_SCC12_ADDR_CHECK(0, false)
};

ret = BUILD_SAFETY_CFG(hyundai_rx_checks, HYUNDAI_TX_MSGS);
Expand All @@ -315,8 +355,8 @@ static safety_config hyundai_init(uint16_t param) {
static safety_config hyundai_legacy_init(uint16_t param) {
// older hyundai models have less checks due to missing counters and checksums
static RxCheck hyundai_legacy_rx_checks[] = {
HYUNDAI_COMMON_RX_CHECKS(true)
HYUNDAI_SCC12_ADDR_CHECK(0)
HYUNDAI_COMMON_RX_CHECKS(0, false, true)
HYUNDAI_SCC12_ADDR_CHECK(0, false)
};

hyundai_common_init(param);
Expand Down
5 changes: 5 additions & 0 deletions board/safety/safety_hyundai_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ bool hyundai_canfd_hda2 = false;
extern bool hyundai_alt_limits;
bool hyundai_alt_limits = false;

extern bool hyundai_can_canfd_hybrid;
bool hyundai_can_canfd_hybrid = false;

static uint8_t hyundai_last_button_interaction; // button messages since the user pressed an enable button

void hyundai_common_init(uint16_t param) {
Expand All @@ -44,12 +47,14 @@ void hyundai_common_init(uint16_t param) {
const int HYUNDAI_PARAM_CAMERA_SCC = 8;
const int HYUNDAI_PARAM_CANFD_HDA2 = 16;
const int HYUNDAI_PARAM_ALT_LIMITS = 64; // TODO: shift this down with the rest of the common flags
const int HYUNDAI_PARAM_CAN_CANFD_HYBRID = 256;

hyundai_ev_gas_signal = GET_FLAG(param, HYUNDAI_PARAM_EV_GAS);
hyundai_hybrid_gas_signal = !hyundai_ev_gas_signal && GET_FLAG(param, HYUNDAI_PARAM_HYBRID_GAS);
hyundai_camera_scc = GET_FLAG(param, HYUNDAI_PARAM_CAMERA_SCC);
hyundai_canfd_hda2 = GET_FLAG(param, HYUNDAI_PARAM_CANFD_HDA2);
hyundai_alt_limits = GET_FLAG(param, HYUNDAI_PARAM_ALT_LIMITS);
hyundai_can_canfd_hybrid = GET_FLAG(param, HYUNDAI_PARAM_CAN_CANFD_HYBRID);

hyundai_last_button_interaction = HYUNDAI_PREV_BUTTON_SAMPLES;

Expand Down
1 change: 1 addition & 0 deletions python/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ class Panda:
FLAG_HYUNDAI_CANFD_ALT_BUTTONS = 32
FLAG_HYUNDAI_ALT_LIMITS = 64
FLAG_HYUNDAI_CANFD_HDA2_ALT_STEERING = 128
FLAG_HYUNDAI_CAN_CANFD_HYBRID = 256

FLAG_TESLA_POWERTRAIN = 1
FLAG_TESLA_LONG_CONTROL = 2
Expand Down
47 changes: 41 additions & 6 deletions tests/safety/test_hyundai.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ class TestHyundaiSafety(HyundaiButtonBase, common.PandaCarSafetyTest, common.Dri
MAX_INVALID_STEERING_FRAMES = 2
MIN_VALID_STEERING_RT_INTERVAL = 810000 # a ~10% buffer, can send steer up to 110Hz

PT_BUS = 0
STEER_BUS = 0

cnt_gas = 0
cnt_speed = 0
cnt_brake = 0
Expand All @@ -75,29 +78,31 @@ def setUp(self):
self.safety.set_safety_hooks(Panda.SAFETY_HYUNDAI, 0)
self.safety.init_tests()

def _button_msg(self, buttons, main_button=0, bus=0):
def _button_msg(self, buttons, main_button=0, bus=None):
if bus is None:
bus = self.PT_BUS
values = {"CF_Clu_CruiseSwState": buttons, "CF_Clu_CruiseSwMain": main_button, "CF_Clu_AliveCnt1": self.cnt_button}
self.__class__.cnt_button += 1
return self.packer.make_can_msg_panda("CLU11", bus, values)

def _user_gas_msg(self, gas):
values = {"CF_Ems_AclAct": gas, "AliveCounter": self.cnt_gas % 4}
self.__class__.cnt_gas += 1
return self.packer.make_can_msg_panda("EMS16", 0, values, fix_checksum=checksum)
return self.packer.make_can_msg_panda("EMS16", self.PT_BUS, values, fix_checksum=checksum)

def _user_brake_msg(self, brake):
values = {"DriverOverride": 2 if brake else random.choice((0, 1, 3)),
"AliveCounterTCS": self.cnt_brake % 8}
self.__class__.cnt_brake += 1
return self.packer.make_can_msg_panda("TCS13", 0, values, fix_checksum=checksum)
return self.packer.make_can_msg_panda("TCS13", self.PT_BUS, values, fix_checksum=checksum)

def _speed_msg(self, speed):
# panda safety doesn't scale, so undo the scaling
values = {"WHL_SPD_%s" % s: speed * 0.03125 for s in ["FL", "FR", "RL", "RR"]}
values["WHL_SPD_AliveCounter_LSB"] = (self.cnt_speed % 16) & 0x3
values["WHL_SPD_AliveCounter_MSB"] = (self.cnt_speed % 16) >> 2
self.__class__.cnt_speed += 1
return self.packer.make_can_msg_panda("WHL_SPD11", 0, values, fix_checksum=checksum)
return self.packer.make_can_msg_panda("WHL_SPD11", self.PT_BUS, values, fix_checksum=checksum)

def _pcm_status_msg(self, enable):
values = {"ACCMode": enable, "CR_VSM_Alive": self.cnt_cruise % 16}
Expand All @@ -106,11 +111,11 @@ def _pcm_status_msg(self, enable):

def _torque_driver_msg(self, torque):
values = {"CR_Mdps_StrColTq": torque}
return self.packer.make_can_msg_panda("MDPS12", 0, values)
return self.packer.make_can_msg_panda("MDPS12", self.PT_BUS, values)

def _torque_cmd_msg(self, torque, steer_req=1):
values = {"CR_Lkas_StrToqReq": torque, "CF_Lkas_ActToi": steer_req}
return self.packer.make_can_msg_panda("LKAS11", 0, values)
return self.packer.make_can_msg_panda("LKAS11", self.STEER_BUS, values)


class TestHyundaiSafetyAltLimits(TestHyundaiSafety):
Expand Down Expand Up @@ -167,6 +172,36 @@ def _user_gas_msg(self, gas):
values = {"CR_Vcu_AccPedDep_Pos": gas}
return self.packer.make_can_msg_panda("E_EMS11", 0, values, fix_checksum=checksum)


class TestHyundaiCanCanfdHybridHda2Safety(TestHyundaiSafety):
TX_MSGS = [[0x50, 0], [0x4F1, 1], [0x2A4, 0]]
RELAY_MALFUNCTION_ADDRS = {0: (0x50, )} # LKAS
FWD_BLACKLISTED_ADDRS = {2: [0x50, 0x2A4]} # LKAS, CAM_0x2a4

MAX_RATE_UP = 2
MAX_RATE_DOWN = 3
DRIVER_TORQUE_ALLOWANCE = 250

PT_BUS = 1
BUTTONS_TX_BUS = 1
SCC_BUS = 1

def setUp(self):
self.packer = CANPackerPanda("hyundai_palisade_2023_generated")
self.safety = libpanda_py.libpanda
self.safety.set_safety_hooks(Panda.SAFETY_HYUNDAI, Panda.FLAG_HYUNDAI_CAN_CANFD_HYBRID | Panda.FLAG_HYUNDAI_CANFD_HDA2)
self.safety.init_tests()

def _torque_cmd_msg(self, torque, steer_req=1):
values = {"TORQUE_REQUEST": torque, "STEER_REQ": steer_req}
return self.packer.make_can_msg_panda("LKAS", self.STEER_BUS, values)

def _pcm_status_msg(self, enable):
values = {"ACCMode": enable, "CR_VSM_Alive": self.cnt_cruise % 16}
self.__class__.cnt_cruise += 1
return self.packer.make_can_msg_panda("SCC12", self.SCC_BUS, values)


class TestHyundaiLongitudinalSafety(HyundaiLongitudinalBase, TestHyundaiSafety):
TX_MSGS = [[0x340, 0], [0x4F1, 0], [0x485, 0], [0x420, 0], [0x421, 0], [0x50A, 0], [0x389, 0], [0x4A2, 0], [0x38D, 0], [0x483, 0], [0x7D0, 0]]

Expand Down
Loading