openpilot is an open source driver assistance system. openpilot performs the functions of Automated Lane Centering and Adaptive Cruise Control for over 200 supported car makes and models.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

386 lines
15 KiB

#pragma once
#include "opendbc/safety/safety_declarations.h"
#include "opendbc/safety/modes/hyundai_common.h"
#define HYUNDAI_CANFD_CRUISE_BUTTON_TX_MSGS(bus) \
{0x1CF, bus, 8, .check_relay = false}, /* CRUISE_BUTTON */ \
#define HYUNDAI_CANFD_LKA_STEERING_COMMON_TX_MSGS(a_can, e_can) \
HYUNDAI_CANFD_CRUISE_BUTTON_TX_MSGS(e_can) \
{0x50, a_can, 16, .check_relay = (a_can) == 0}, /* LKAS */ \
{0x2A4, a_can, 24, .check_relay = (a_can) == 0}, /* CAM_0x2A4 */ \
#define HYUNDAI_CANFD_LKA_STEERING_ALT_COMMON_TX_MSGS(a_can, e_can) \
HYUNDAI_CANFD_CRUISE_BUTTON_TX_MSGS(e_can) \
{0x110, a_can, 32, .check_relay = (a_can) == 0}, /* LKAS_ALT */ \
{0x362, a_can, 32, .check_relay = (a_can) == 0}, /* CAM_0x362 */ \
#define HYUNDAI_CANFD_LFA_STEERING_COMMON_TX_MSGS(e_can) \
{0x12A, e_can, 16, .check_relay = (e_can) == 0}, /* LFA */ \
{0x1E0, e_can, 16, .check_relay = (e_can) == 0}, /* LFAHDA_CLUSTER */ \
#define HYUNDAI_CANFD_SCC_CONTROL_COMMON_TX_MSGS(e_can, longitudinal) \
{0x1A0, e_can, 32, .check_relay = (longitudinal)}, /* SCC_CONTROL */ \
// *** Addresses checked in rx hook ***
// EV, ICE, HYBRID: ACCELERATOR (0x35), ACCELERATOR_BRAKE_ALT (0x100), ACCELERATOR_ALT (0x105)
#define HYUNDAI_CANFD_COMMON_RX_CHECKS(pt_bus) \
{.msg = {{0x35, (pt_bus), 32, .max_counter = 0xffU, .ignore_quality_flag = true, .frequency = 100U}, \
{0x100, (pt_bus), 32, .max_counter = 0xffU, .ignore_quality_flag = true, .frequency = 100U}, \
{0x105, (pt_bus), 32, .max_counter = 0xffU, .ignore_quality_flag = true, .frequency = 100U}}}, \
{.msg = {{0x175, (pt_bus), 24, .max_counter = 0xffU, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}}, \
{.msg = {{0xa0, (pt_bus), 24, .max_counter = 0xffU, .ignore_quality_flag = true, .frequency = 100U}, { 0 }, { 0 }}}, \
{.msg = {{0xea, (pt_bus), 24, .max_counter = 0xffU, .ignore_quality_flag = true, .frequency = 100U}, { 0 }, { 0 }}}, \
#define HYUNDAI_CANFD_STD_BUTTONS_RX_CHECKS(pt_bus) \
HYUNDAI_CANFD_COMMON_RX_CHECKS(pt_bus) \
{.msg = {{0x1cf, (pt_bus), 8, .ignore_checksum = true, .max_counter = 0xfU, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}}, \
#define HYUNDAI_CANFD_ALT_BUTTONS_RX_CHECKS(pt_bus) \
HYUNDAI_CANFD_COMMON_RX_CHECKS(pt_bus) \
{.msg = {{0x1aa, (pt_bus), 16, .ignore_checksum = true, .max_counter = 0xffU, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}}, \
// SCC_CONTROL (from ADAS unit or camera)
#define HYUNDAI_CANFD_SCC_ADDR_CHECK(scc_bus) \
{.msg = {{0x1a0, (scc_bus), 32, .max_counter = 0xffU, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}}, \
static bool hyundai_canfd_alt_buttons = false;
static bool hyundai_canfd_lka_steering_alt = false;
static int hyundai_canfd_get_lka_addr(void) {
return hyundai_canfd_lka_steering_alt ? 0x110 : 0x50;
}
static uint8_t hyundai_canfd_get_counter(const CANPacket_t *to_push) {
uint8_t ret = 0;
if (GET_LEN(to_push) == 8U) {
ret = GET_BYTE(to_push, 1) >> 4;
} else {
ret = GET_BYTE(to_push, 2);
}
return ret;
}
static uint32_t hyundai_canfd_get_checksum(const CANPacket_t *to_push) {
uint32_t chksum = GET_BYTE(to_push, 0) | (GET_BYTE(to_push, 1) << 8);
return chksum;
}
static void hyundai_canfd_rx_hook(const CANPacket_t *to_push) {
int bus = GET_BUS(to_push);
int addr = GET_ADDR(to_push);
const int pt_bus = hyundai_canfd_lka_steering ? 1 : 0;
const int scc_bus = hyundai_camera_scc ? 2 : pt_bus;
if (bus == pt_bus) {
// driver torque
if (addr == 0xea) {
int torque_driver_new = ((GET_BYTE(to_push, 11) & 0x1fU) << 8U) | GET_BYTE(to_push, 10);
torque_driver_new -= 4095;
update_sample(&torque_driver, torque_driver_new);
}
// cruise buttons
const int button_addr = hyundai_canfd_alt_buttons ? 0x1aa : 0x1cf;
if (addr == button_addr) {
bool main_button = false;
int cruise_button = 0;
if (addr == 0x1cf) {
cruise_button = GET_BYTE(to_push, 2) & 0x7U;
main_button = GET_BIT(to_push, 19U);
} else {
cruise_button = (GET_BYTE(to_push, 4) >> 4) & 0x7U;
main_button = GET_BIT(to_push, 34U);
}
hyundai_common_cruise_buttons_check(cruise_button, main_button);
}
// gas press, different for EV, hybrid, and ICE models
if ((addr == 0x35) && hyundai_ev_gas_signal) {
gas_pressed = GET_BYTE(to_push, 5) != 0U;
} else if ((addr == 0x105) && hyundai_hybrid_gas_signal) {
gas_pressed = GET_BIT(to_push, 103U) || (GET_BYTE(to_push, 13) != 0U) || GET_BIT(to_push, 112U);
} else if ((addr == 0x100) && !hyundai_ev_gas_signal && !hyundai_hybrid_gas_signal) {
gas_pressed = GET_BIT(to_push, 176U);
} else {
}
// brake press
if (addr == 0x175) {
brake_pressed = GET_BIT(to_push, 81U);
}
// vehicle moving
if (addr == 0xa0) {
uint32_t fl = (GET_BYTES(to_push, 8, 2)) & 0x3FFFU;
uint32_t fr = (GET_BYTES(to_push, 10, 2)) & 0x3FFFU;
uint32_t rl = (GET_BYTES(to_push, 12, 2)) & 0x3FFFU;
uint32_t rr = (GET_BYTES(to_push, 14, 2)) & 0x3FFFU;
vehicle_moving = (fl > HYUNDAI_STANDSTILL_THRSLD) || (fr > HYUNDAI_STANDSTILL_THRSLD) ||
(rl > HYUNDAI_STANDSTILL_THRSLD) || (rr > HYUNDAI_STANDSTILL_THRSLD);
// average of all 4 wheel speeds. Conversion: raw * 0.03125 / 3.6 = m/s
UPDATE_VEHICLE_SPEED((fr + rr + rl + fl) / 4.0 * 0.03125 * KPH_TO_MS);
}
}
if (bus == scc_bus) {
// cruise state
if ((addr == 0x1a0) && !hyundai_longitudinal) {
// 1=enabled, 2=driver override
int cruise_status = ((GET_BYTE(to_push, 8) >> 4) & 0x7U);
bool cruise_engaged = (cruise_status == 1) || (cruise_status == 2);
hyundai_common_cruise_state_check(cruise_engaged);
}
}
}
static bool hyundai_canfd_tx_hook(const CANPacket_t *to_send) {
const TorqueSteeringLimits HYUNDAI_CANFD_STEERING_LIMITS = {
.max_torque = 270,
.max_rt_delta = 112,
.max_rate_up = 2,
.max_rate_down = 3,
.driver_torque_allowance = 250,
.driver_torque_multiplier = 2,
.type = TorqueDriverLimited,
// the EPS faults when the steering angle is above a certain threshold for too long. to prevent this,
// we allow setting torque actuation bit to 0 while maintaining the requested torque value for two consecutive frames
.min_valid_request_frames = 89,
.max_invalid_request_frames = 2,
.min_valid_request_rt_interval = 810000, // 810ms; a ~10% buffer on cutting every 90 frames
.has_steer_req_tolerance = true,
};
bool tx = true;
int addr = GET_ADDR(to_send);
// steering
const int steer_addr = (hyundai_canfd_lka_steering && !hyundai_longitudinal) ? hyundai_canfd_get_lka_addr() : 0x12a;
if (addr == steer_addr) {
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_CANFD_STEERING_LIMITS)) {
tx = false;
}
}
// cruise buttons check
if (addr == 0x1cf) {
int button = GET_BYTE(to_send, 2) & 0x7U;
bool is_cancel = (button == HYUNDAI_BTN_CANCEL);
bool is_resume = (button == HYUNDAI_BTN_RESUME);
bool allowed = (is_cancel && cruise_engaged_prev) || (is_resume && controls_allowed);
if (!allowed) {
tx = false;
}
}
// UDS: only tester present ("\x02\x3E\x80\x00\x00\x00\x00\x00") allowed on diagnostics address
if (((addr == 0x730) && hyundai_canfd_lka_steering) || ((addr == 0x7D0) && !hyundai_camera_scc)) {
if ((GET_BYTES(to_send, 0, 4) != 0x00803E02U) || (GET_BYTES(to_send, 4, 4) != 0x0U)) {
tx = false;
}
}
// ACCEL: safety check
if (addr == 0x1a0) {
int desired_accel_raw = (((GET_BYTE(to_send, 17) & 0x7U) << 8) | GET_BYTE(to_send, 16)) - 1023U;
int desired_accel_val = ((GET_BYTE(to_send, 18) << 4) | (GET_BYTE(to_send, 17) >> 4)) - 1023U;
bool violation = false;
if (hyundai_longitudinal) {
violation |= longitudinal_accel_checks(desired_accel_raw, HYUNDAI_LONG_LIMITS);
violation |= longitudinal_accel_checks(desired_accel_val, HYUNDAI_LONG_LIMITS);
} else {
// only used to cancel on here
const int acc_mode = (GET_BYTE(to_send, 8) >> 4) & 0x7U;
if (acc_mode != 4) {
violation = true;
}
if ((desired_accel_raw != 0) || (desired_accel_val != 0)) {
violation = true;
}
}
if (violation) {
tx = false;
}
}
return tx;
}
static safety_config hyundai_canfd_init(uint16_t param) {
const int HYUNDAI_PARAM_CANFD_LKA_STEERING_ALT = 128;
const int HYUNDAI_PARAM_CANFD_ALT_BUTTONS = 32;
static const CanMsg HYUNDAI_CANFD_LKA_STEERING_TX_MSGS[] = {
HYUNDAI_CANFD_LKA_STEERING_COMMON_TX_MSGS(0, 1)
};
static const CanMsg HYUNDAI_CANFD_LKA_STEERING_ALT_TX_MSGS[] = {
HYUNDAI_CANFD_LKA_STEERING_ALT_COMMON_TX_MSGS(0, 1)
};
static const CanMsg HYUNDAI_CANFD_LKA_STEERING_LONG_TX_MSGS[] = {
HYUNDAI_CANFD_LKA_STEERING_COMMON_TX_MSGS(0, 1)
HYUNDAI_CANFD_LFA_STEERING_COMMON_TX_MSGS(1)
HYUNDAI_CANFD_SCC_CONTROL_COMMON_TX_MSGS(1, true)
{0x51, 0, 32, .check_relay = false}, // ADRV_0x51
{0x730, 1, 8, .check_relay = false}, // tester present for ADAS ECU disable
{0x160, 1, 16, .check_relay = false}, // ADRV_0x160
{0x1EA, 1, 32, .check_relay = false}, // ADRV_0x1ea
{0x200, 1, 8, .check_relay = false}, // ADRV_0x200
{0x345, 1, 8, .check_relay = false}, // ADRV_0x345
{0x1DA, 1, 32, .check_relay = false}, // ADRV_0x1da
};
static const CanMsg HYUNDAI_CANFD_LFA_STEERING_TX_MSGS[] = {
HYUNDAI_CANFD_CRUISE_BUTTON_TX_MSGS(2)
HYUNDAI_CANFD_LFA_STEERING_COMMON_TX_MSGS(0)
HYUNDAI_CANFD_SCC_CONTROL_COMMON_TX_MSGS(0, false)
};
// ADRV_0x160 is checked for radar liveness
static const CanMsg HYUNDAI_CANFD_LFA_STEERING_LONG_TX_MSGS[] = {
HYUNDAI_CANFD_CRUISE_BUTTON_TX_MSGS(2)
HYUNDAI_CANFD_LFA_STEERING_COMMON_TX_MSGS(0)
HYUNDAI_CANFD_SCC_CONTROL_COMMON_TX_MSGS(0, true)
{0x160, 0, 16, .check_relay = true}, // ADRV_0x160
{0x7D0, 0, 8, .check_relay = false}, // tester present for radar ECU disable
};
// ADRV_0x160 is checked for relay malfunction
#define HYUNDAI_CANFD_LFA_STEERING_CAMERA_SCC_TX_MSGS(longitudinal) \
HYUNDAI_CANFD_CRUISE_BUTTON_TX_MSGS(2) \
HYUNDAI_CANFD_LFA_STEERING_COMMON_TX_MSGS(0) \
HYUNDAI_CANFD_SCC_CONTROL_COMMON_TX_MSGS(0, (longitudinal)) \
{0x160, 0, 16, .check_relay = (longitudinal)}, /* ADRV_0x160 */ \
hyundai_common_init(param);
gen_crc_lookup_table_16(0x1021, hyundai_canfd_crc_lut);
hyundai_canfd_alt_buttons = GET_FLAG(param, HYUNDAI_PARAM_CANFD_ALT_BUTTONS);
hyundai_canfd_lka_steering_alt = GET_FLAG(param, HYUNDAI_PARAM_CANFD_LKA_STEERING_ALT);
safety_config ret;
if (hyundai_longitudinal) {
if (hyundai_canfd_lka_steering) {
static RxCheck hyundai_canfd_lka_steering_long_rx_checks[] = {
HYUNDAI_CANFD_STD_BUTTONS_RX_CHECKS(1)
};
ret = BUILD_SAFETY_CFG(hyundai_canfd_lka_steering_long_rx_checks, HYUNDAI_CANFD_LKA_STEERING_LONG_TX_MSGS);
} else {
// Longitudinal checks for LFA steering
static RxCheck hyundai_canfd_long_rx_checks[] = {
HYUNDAI_CANFD_STD_BUTTONS_RX_CHECKS(0)
};
static RxCheck hyundai_canfd_alt_buttons_long_rx_checks[] = {
HYUNDAI_CANFD_ALT_BUTTONS_RX_CHECKS(0)
};
static CanMsg hyundai_canfd_lfa_steering_camera_scc_tx_msgs[] = {
HYUNDAI_CANFD_LFA_STEERING_CAMERA_SCC_TX_MSGS(true)
};
if (hyundai_canfd_alt_buttons) {
SET_RX_CHECKS(hyundai_canfd_alt_buttons_long_rx_checks, ret);
} else {
SET_RX_CHECKS(hyundai_canfd_long_rx_checks, ret);
}
if (hyundai_camera_scc) {
SET_TX_MSGS(hyundai_canfd_lfa_steering_camera_scc_tx_msgs, ret);
} else {
SET_TX_MSGS(HYUNDAI_CANFD_LFA_STEERING_LONG_TX_MSGS, ret);
}
}
} else {
if (hyundai_canfd_lka_steering) {
// *** LKA steering checks ***
// E-CAN is on bus 1, SCC messages are sent on cars with ADRV ECU.
// Does not use the alt buttons message
static RxCheck hyundai_canfd_lka_steering_rx_checks[] = {
HYUNDAI_CANFD_STD_BUTTONS_RX_CHECKS(1)
HYUNDAI_CANFD_SCC_ADDR_CHECK(1)
};
SET_RX_CHECKS(hyundai_canfd_lka_steering_rx_checks, ret);
if (hyundai_canfd_lka_steering_alt) {
SET_TX_MSGS(HYUNDAI_CANFD_LKA_STEERING_ALT_TX_MSGS, ret);
} else {
SET_TX_MSGS(HYUNDAI_CANFD_LKA_STEERING_TX_MSGS, ret);
}
} else if (!hyundai_camera_scc) {
// Radar sends SCC messages on these cars instead of camera
static RxCheck hyundai_canfd_radar_scc_rx_checks[] = {
HYUNDAI_CANFD_STD_BUTTONS_RX_CHECKS(0)
HYUNDAI_CANFD_SCC_ADDR_CHECK(0)
};
static RxCheck hyundai_canfd_alt_buttons_radar_scc_rx_checks[] = {
HYUNDAI_CANFD_ALT_BUTTONS_RX_CHECKS(0)
HYUNDAI_CANFD_SCC_ADDR_CHECK(0)
};
SET_TX_MSGS(HYUNDAI_CANFD_LFA_STEERING_TX_MSGS, ret);
if (hyundai_canfd_alt_buttons) {
SET_RX_CHECKS(hyundai_canfd_alt_buttons_radar_scc_rx_checks, ret);
} else {
SET_RX_CHECKS(hyundai_canfd_radar_scc_rx_checks, ret);
}
} else {
// *** LFA steering checks ***
// Camera sends SCC messages on LFA steering cars.
// Both button messages exist on some platforms, so we ensure we track the correct one using flag
static RxCheck hyundai_canfd_rx_checks[] = {
HYUNDAI_CANFD_STD_BUTTONS_RX_CHECKS(0)
HYUNDAI_CANFD_SCC_ADDR_CHECK(2)
};
static RxCheck hyundai_canfd_alt_buttons_rx_checks[] = {
HYUNDAI_CANFD_ALT_BUTTONS_RX_CHECKS(0)
HYUNDAI_CANFD_SCC_ADDR_CHECK(2)
};
static CanMsg hyundai_canfd_lfa_steering_camera_scc_tx_msgs[] = {
HYUNDAI_CANFD_LFA_STEERING_CAMERA_SCC_TX_MSGS(false)
};
SET_TX_MSGS(hyundai_canfd_lfa_steering_camera_scc_tx_msgs, ret);
if (hyundai_canfd_alt_buttons) {
SET_RX_CHECKS(hyundai_canfd_alt_buttons_rx_checks, ret);
} else {
SET_RX_CHECKS(hyundai_canfd_rx_checks, ret);
}
}
}
return ret;
}
const safety_hooks hyundai_canfd_hooks = {
.init = hyundai_canfd_init,
.rx = hyundai_canfd_rx_hook,
.tx = hyundai_canfd_tx_hook,
.get_counter = hyundai_canfd_get_counter,
.get_checksum = hyundai_canfd_get_checksum,
.compute_checksum = hyundai_common_canfd_compute_checksum,
};