Hyundai CAN-FD: Tucson Hybrid 2022 support (#999)

* Hyundai: Car Port for Tucson Hybrid 2022

* Remove test comments

* Fix fwd_hook

* Allow tx on 0x1a0

* Fix byte counts

* Send LFA and HDA icons based on engageability

* Add FLAG_HYUNDAI_CANFD_HDA2 flag

* Update __init__.py

* Allow tx with CRUISE_INACTIVE

* Panda safety cleanup

* Include bus 0 in rx checks

* Missed one

* Remove redundant check

* Add comments

* start cleanup

* little more

* more cleanup

* tests

* one more test case

* rename

Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com>
This commit is contained in:
Jason Wen
2022-08-19 22:43:58 -04:00
committed by GitHub
parent abaa9f8968
commit 9d6496ece8
6 changed files with 170 additions and 40 deletions

View File

@@ -48,7 +48,7 @@ ENV PATH="/root/.pyenv/bin:/root/.pyenv/shims:${PATH}"
ENV PANDA_PATH=/tmp/openpilot/panda
ENV OPENPILOT_REF="96e8d5c9fe1a8084dfa5d97c78d4ea2037272420"
ENV OPENDBC_REF="488568517162194fbb2aa45d3dba4c6af663a883"
ENV OPENDBC_REF="3270c931c07bd3a47839a1a84c109eb2a7d295a6"
COPY requirements.txt /tmp/
RUN pyenv install 3.8.10 && \

View File

@@ -11,19 +11,33 @@ const SteeringLimits HYUNDAI_CANFD_STEERING_LIMITS = {
const uint32_t HYUNDAI_CANFD_STANDSTILL_THRSLD = 30; // ~1kph
const CanMsg HYUNDAI_CANFD_TX_MSGS[] = {
{0x50, 0, 16},
{0x1CF, 1, 8},
{0x2A4, 0, 24},
const CanMsg HYUNDAI_CANFD_HDA2_TX_MSGS[] = {
{0x50, 0, 16}, // LKAS
{0x1CF, 1, 8}, // CRUISE_BUTTON
{0x2A4, 0, 24}, // CAM_0x2A4
};
const CanMsg HYUNDAI_CANFD_HDA1_TX_MSGS[] = {
{0x12A, 0, 16}, // LFA
{0x1A0, 0, 32}, // CRUISE_INFO
{0x1CF, 0, 8}, // CRUISE_BUTTON
{0x1E0, 0, 16}, // LFAHDA_CLUSTER
};
AddrCheckStruct hyundai_canfd_addr_checks[] = {
{.msg = {{0x35, 1, 32, .check_checksum = true, .max_counter = 0xffU, .expected_timestep = 10000U}, { 0 }, { 0 }}},
{.msg = {{0x65, 1, 32, .check_checksum = true, .max_counter = 0xffU, .expected_timestep = 10000U}, { 0 }, { 0 }}},
{.msg = {{0xa0, 1, 24, .check_checksum = true, .max_counter = 0xffU, .expected_timestep = 10000U}, { 0 }, { 0 }}},
{.msg = {{0xea, 1, 24, .check_checksum = true, .max_counter = 0xffU, .expected_timestep = 10000U}, { 0 }, { 0 }}},
{.msg = {{0x175, 1, 24, .check_checksum = true, .max_counter = 0xffU, .expected_timestep = 10000U}, { 0 }, { 0 }}},
{.msg = {{0x1cf, 1, 8, .check_checksum = false, .max_counter = 0xfU, .expected_timestep = 20000U}, { 0 }, { 0 }}},
{.msg = {{0x35, 1, 32, .check_checksum = true, .max_counter = 0xffU, .expected_timestep = 10000U},
{0x105, 0, 32, .check_checksum = true, .max_counter = 0xffU, .expected_timestep = 10000U}, { 0 }}},
{.msg = {{0x65, 1, 32, .check_checksum = true, .max_counter = 0xffU, .expected_timestep = 10000U},
{0x65, 0, 32, .check_checksum = true, .max_counter = 0xffU, .expected_timestep = 10000U}, { 0 }}},
{.msg = {{0xa0, 1, 24, .check_checksum = true, .max_counter = 0xffU, .expected_timestep = 10000U},
{0xa0, 0, 24, .check_checksum = true, .max_counter = 0xffU, .expected_timestep = 10000U}, { 0 }}},
{.msg = {{0xea, 1, 24, .check_checksum = true, .max_counter = 0xffU, .expected_timestep = 10000U},
{0xea, 0, 24, .check_checksum = true, .max_counter = 0xffU, .expected_timestep = 10000U}, { 0 }}},
{.msg = {{0x175, 1, 24, .check_checksum = true, .max_counter = 0xffU, .expected_timestep = 10000U},
{0x175, 0, 24, .check_checksum = true, .max_counter = 0xffU, .expected_timestep = 10000U}, { 0 }}},
{.msg = {{0x1cf, 1, 8, .check_checksum = false, .max_counter = 0xfU, .expected_timestep = 20000U},
{0x1cf, 0, 8, .check_checksum = false, .max_counter = 0xfU, .expected_timestep = 20000U},
{0x1aa, 0, 16, .check_checksum = false, .max_counter = 0xffU, .expected_timestep = 20000U}}},
};
#define HYUNDAI_CANFD_ADDR_CHECK_LEN (sizeof(hyundai_canfd_addr_checks) / sizeof(hyundai_canfd_addr_checks[0]))
@@ -32,6 +46,13 @@ addr_checks hyundai_canfd_rx_checks = {hyundai_canfd_addr_checks, HYUNDAI_CANFD_
uint16_t hyundai_canfd_crc_lut[256];
const int HYUNDAI_PARAM_CANFD_HDA2 = 1;
const int HYUNDAI_PARAM_CANFD_ALT_BUTTONS = 2;
bool hyundai_canfd_hda2 = false;
bool hyundai_canfd_alt_buttons = false;
static uint8_t hyundai_canfd_get_counter(CANPacket_t *to_push) {
uint8_t ret = 0;
if (GET_LEN(to_push) == 8U) {
@@ -84,8 +105,9 @@ static int hyundai_canfd_rx_hook(CANPacket_t *to_push) {
int bus = GET_BUS(to_push);
int addr = GET_ADDR(to_push);
if (valid && (bus == 1)) {
const int pt_bus = hyundai_canfd_hda2 ? 1 : 0;
if (valid && (bus == pt_bus)) {
// driver torque
if (addr == 0xea) {
int torque_driver_new = ((GET_BYTE(to_push, 11) & 0x1fU) << 8U) | GET_BYTE(to_push, 10);
@@ -94,9 +116,17 @@ static int hyundai_canfd_rx_hook(CANPacket_t *to_push) {
}
// cruise buttons
if (addr == 0x1cf) {
int cruise_button = GET_BYTE(to_push, 2) & 0x7U;
int main_button = GET_BIT(to_push, 19U);
const int button_addr = hyundai_canfd_alt_buttons ? 0x1aa : 0x1cf;
if (addr == button_addr) {
int main_button = 0;
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);
}
if ((cruise_button == HYUNDAI_BTN_RESUME) || (cruise_button == HYUNDAI_BTN_SET) || (cruise_button == HYUNDAI_BTN_CANCEL) || (main_button != 0)) {
hyundai_last_button_interaction = 0U;
@@ -119,8 +149,11 @@ static int hyundai_canfd_rx_hook(CANPacket_t *to_push) {
}
// gas press
if (addr == 0x35) {
if ((addr == 0x35) && hyundai_canfd_hda2) {
gas_pressed = GET_BYTE(to_push, 5) != 0U;
} else if ((addr == 0x105) && !hyundai_canfd_hda2) {
gas_pressed = (GET_BIT(to_push, 103U) != 0U) || (GET_BYTE(to_push, 13) != 0U) || (GET_BIT(to_push, 112U) != 0U);
} else {
}
// brake press
@@ -138,7 +171,8 @@ static int hyundai_canfd_rx_hook(CANPacket_t *to_push) {
}
}
generic_rx_checks((addr == 0x50) && (bus == 0));
const int steer_addr = hyundai_canfd_hda2 ? 0x50 : 0x12a;
generic_rx_checks((addr == steer_addr) && (bus == 0));
return valid;
}
@@ -146,12 +180,19 @@ static int hyundai_canfd_rx_hook(CANPacket_t *to_push) {
static int hyundai_canfd_tx_hook(CANPacket_t *to_send, bool longitudinal_allowed) {
UNUSED(longitudinal_allowed);
int tx = msg_allowed(to_send, HYUNDAI_CANFD_TX_MSGS, sizeof(HYUNDAI_CANFD_TX_MSGS)/sizeof(HYUNDAI_CANFD_TX_MSGS[0]));
int tx = 0;
int addr = GET_ADDR(to_send);
int bus = GET_BUS(to_send);
if (hyundai_canfd_hda2) {
tx = msg_allowed(to_send, HYUNDAI_CANFD_HDA2_TX_MSGS, sizeof(HYUNDAI_CANFD_HDA2_TX_MSGS)/sizeof(HYUNDAI_CANFD_HDA2_TX_MSGS[0]));
} else {
tx = msg_allowed(to_send, HYUNDAI_CANFD_HDA1_TX_MSGS, sizeof(HYUNDAI_CANFD_HDA1_TX_MSGS)/sizeof(HYUNDAI_CANFD_HDA1_TX_MSGS[0]));
}
// steering
if ((addr == 0x50) && (bus == 0)) {
const int steer_addr = hyundai_canfd_hda2 ? 0x50 : 0x12a;
if ((addr == steer_addr) && (bus == 0)) {
int desired_torque = ((GET_BYTE(to_send, 6) & 0xFU) << 7U) | (GET_BYTE(to_send, 5) >> 1U);
desired_torque -= 1024;
@@ -161,9 +202,12 @@ static int hyundai_canfd_tx_hook(CANPacket_t *to_send, bool longitudinal_allowed
}
// cruise buttons check
if ((addr == 0x1cf) && (bus == 1)) {
bool is_cancel = GET_BYTE(to_send, 2) == 4U;
bool is_resume = GET_BYTE(to_send, 2) == 1U;
const int buttons_bus = hyundai_canfd_hda2 ? 1 : 0;
if ((addr == 0x1cf) && (bus == buttons_bus)) {
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 = 0;
@@ -181,17 +225,29 @@ static int hyundai_canfd_fwd_hook(int bus_num, CANPacket_t *to_fwd) {
if (bus_num == 0) {
bus_fwd = 2;
}
if ((bus_num == 2) && (addr != 0x50) && (addr != 0x2a4)) {
bus_fwd = 0;
if (bus_num == 2) {
// LKAS for HDA2, LFA for HDA1
int is_lkas_msg = (((addr == 0x50) || (addr == 0x2a4)) && hyundai_canfd_hda2);
int is_lfa_msg = ((addr == 0x12a) && !hyundai_canfd_hda2);
// HUD icons
int is_lfahda_msg = ((addr == 0x1e0) && !hyundai_canfd_hda2);
int block_msg = is_lkas_msg || is_lfa_msg || is_lfahda_msg;
if (!block_msg) {
bus_fwd = 0;
}
}
return bus_fwd;
}
static const addr_checks* hyundai_canfd_init(uint16_t param) {
UNUSED(param);
gen_crc_lookup_table_16(0x1021, hyundai_canfd_crc_lut);
hyundai_last_button_interaction = HYUNDAI_PREV_BUTTON_SAMPLES;
hyundai_canfd_hda2 = GET_FLAG(param, HYUNDAI_PARAM_CANFD_HDA2);
hyundai_canfd_alt_buttons = GET_FLAG(param, HYUNDAI_PARAM_CANFD_ALT_BUTTONS);
return &hyundai_canfd_rx_checks;
}

View File

@@ -197,6 +197,9 @@ class Panda:
FLAG_HYUNDAI_LONG = 4
FLAG_HYUNDAI_CAMERA_SCC = 8
FLAG_HYUNDAI_CANFD_HDA2 = 1
FLAG_HYUNDAI_CANFD_ALT_BUTTONS = 2
FLAG_TESLA_POWERTRAIN = 1
FLAG_TESLA_LONG_CONTROL = 2

View File

@@ -568,6 +568,8 @@ class PandaSafetyTest(PandaSafetyTestBase):
continue
if {attr, current_test}.issubset({'TestVolkswagenPqSafety', 'TestVolkswagenPqStockSafety', 'TestVolkswagenPqLongSafety'}):
continue
if attr.startswith('TestHyundaiCanfd') and current_test.startswith('TestHyundaiCanfd'):
continue
# TODO: Temporary, should be fixed in panda firmware, safety_honda.h
if attr.startswith('TestHonda'):
# exceptions for common msgs across different hondas

View File

@@ -61,7 +61,7 @@ class HyundaiButtonBase: #(common.PandaSafetyTest):
BUTTONS_BUS = 0 # tx on this bus, rx on 0. added to all `self._tx(self._button_msg(...))`
SCC_BUS = 0 # rx on this bus
def test_buttons(self):
def test_button_sends(self):
"""
Only RES and CANCEL buttons are allowed
- RES allowed while controls allowed
@@ -259,7 +259,7 @@ class TestHyundaiLongitudinalSafety(TestHyundaiSafety):
def test_cruise_engaged_prev(self):
pass
def test_buttons(self):
def test_button_sends(self):
pass
def _pcm_status_msg(self, enable):

View File

@@ -6,7 +6,7 @@ import panda.tests.safety.common as common
from panda.tests.safety.common import CANPackerPanda
from panda.tests.safety.test_hyundai import HyundaiButtonBase
class TestHyundaiCanfd(HyundaiButtonBase, common.PandaSafetyTest, common.DriverTorqueSteeringSafetyTest):
class TestHyundaiCanfdBase(HyundaiButtonBase, common.PandaSafetyTest, common.DriverTorqueSteeringSafetyTest):
TX_MSGS = [[0x50, 0], [0x1CF, 1], [0x2A4, 0]]
STANDSTILL_THRESHOLD = 30 # ~1kph
@@ -25,42 +25,111 @@ class TestHyundaiCanfd(HyundaiButtonBase, common.PandaSafetyTest, common.DriverT
DRIVER_TORQUE_ALLOWANCE = 250
DRIVER_TORQUE_FACTOR = 2
def setUp(self):
self.packer = CANPackerPanda("kia_ev6")
self.safety = libpandasafety_py.libpandasafety
self.safety.set_safety_hooks(Panda.SAFETY_HYUNDAI_CANFD, 0)
self.safety.init_tests()
PT_BUS = 0
STEER_MSG = ""
@classmethod
def setUpClass(cls):
if cls.__name__ == "TestHyundaiCanfdBase":
cls.packer = None
cls.safety = None
raise unittest.SkipTest
def _torque_driver_msg(self, torque):
values = {"STEERING_COL_TORQUE": torque}
return self.packer.make_can_msg_panda("MDPS", 1, values)
return self.packer.make_can_msg_panda("MDPS", self.PT_BUS, values)
def _torque_cmd_msg(self, torque, steer_req=1):
values = {"TORQUE_REQUEST": torque}
return self.packer.make_can_msg_panda("LKAS", 0, values)
return self.packer.make_can_msg_panda(self.STEER_MSG, 0, values)
def _speed_msg(self, speed):
values = {f"WHEEL_SPEED_{i}": speed * 0.03125 for i in range(1, 5)}
return self.packer.make_can_msg_panda("WHEEL_SPEEDS", 1, values)
return self.packer.make_can_msg_panda("WHEEL_SPEEDS", self.PT_BUS, values)
def _user_brake_msg(self, brake):
values = {"BRAKE_PRESSED": brake}
return self.packer.make_can_msg_panda("BRAKE", 1, values)
return self.packer.make_can_msg_panda("BRAKE", self.PT_BUS, values)
def _user_gas_msg(self, gas):
values = {"ACCELERATOR_PEDAL": gas}
return self.packer.make_can_msg_panda("ACCELERATOR", 1, values)
return self.packer.make_can_msg_panda("ACCELERATOR", self.PT_BUS, values)
def _pcm_status_msg(self, enable):
values = {"CRUISE_ACTIVE": enable}
return self.packer.make_can_msg_panda("SCC1", 1, values)
return self.packer.make_can_msg_panda("SCC1", self.PT_BUS, values)
def _button_msg(self, buttons, main_button=0, bus=1):
values = {
"CRUISE_BUTTONS": buttons,
"ADAPTIVE_CRUISE_MAIN_BTN": main_button,
}
return self.packer.make_can_msg_panda("CRUISE_BUTTONS", 1, values)
return self.packer.make_can_msg_panda("CRUISE_BUTTONS", self.PT_BUS, values)
class TestHyundaiCanfdHDA1(TestHyundaiCanfdBase):
TX_MSGS = [[0x12A, 0], [0x1A0, 1], [0x1CF, 0], [0x1E0, 0]]
RELAY_MALFUNCTION_ADDR = 0x12A
RELAY_MALFUNCTION_BUS = 0
FWD_BLACKLISTED_ADDRS = {2: [0x12A, 0x1E0]}
FWD_BUS_LOOKUP = {0: 2, 2: 0}
STEER_MSG = "LFA"
def setUp(self):
self.packer = CANPackerPanda("hyundai_canfd")
self.safety = libpandasafety_py.libpandasafety
self.safety.set_safety_hooks(Panda.SAFETY_HYUNDAI_CANFD, 0)
self.safety.init_tests()
def _user_gas_msg(self, gas):
values = {"ACCELERATOR_PEDAL": gas}
return self.packer.make_can_msg_panda("ACCELERATOR_ALT", self.PT_BUS, values)
class TestHyundaiCanfdHDA1AltButtons(TestHyundaiCanfdHDA1):
def setUp(self):
self.packer = CANPackerPanda("hyundai_canfd")
self.safety = libpandasafety_py.libpandasafety
self.safety.set_safety_hooks(Panda.SAFETY_HYUNDAI_CANFD, Panda.FLAG_HYUNDAI_CANFD_ALT_BUTTONS)
self.safety.init_tests()
def _button_msg(self, buttons, main_button=0, bus=1):
values = {
"CRUISE_BUTTONS": buttons,
"ADAPTIVE_CRUISE_MAIN_BTN": main_button,
}
return self.packer.make_can_msg_panda("CRUISE_BUTTONS_ALT", self.PT_BUS, values)
def test_button_sends(self):
"""
No button send allowed with alt buttons.
"""
for enabled in (True, False):
for btn in range(8):
self.safety.set_controls_allowed(enabled)
self.assertFalse(self._tx(self._button_msg(btn)))
class TestHyundaiCanfdHDA2(TestHyundaiCanfdBase):
TX_MSGS = [[0x50, 0], [0x1CF, 1], [0x2A4, 0]]
RELAY_MALFUNCTION_ADDR = 0x50
RELAY_MALFUNCTION_BUS = 0
FWD_BLACKLISTED_ADDRS = {2: [0x50, 0x2a4]}
FWD_BUS_LOOKUP = {0: 2, 2: 0}
PT_BUS = 1
STEER_MSG = "LKAS"
def setUp(self):
self.packer = CANPackerPanda("hyundai_canfd")
self.safety = libpandasafety_py.libpandasafety
self.safety.set_safety_hooks(Panda.SAFETY_HYUNDAI_CANFD, Panda.FLAG_HYUNDAI_CANFD_HDA2)
self.safety.init_tests()
if __name__ == "__main__":