From 055b09e3a67fd7b9027bf86f6626ff0b6c2ca920 Mon Sep 17 00:00:00 2001 From: Greg Hogan Date: Sat, 2 Dec 2023 11:25:27 -0800 Subject: [PATCH] chrysler longitudinal --- board/safety/safety_chrysler.h | 213 ++++++++++++++++++++++++++------- python/__init__.py | 1 + tests/safety/common.py | 5 + tests/safety/test_chrysler.py | 134 ++++++++++++++++++++- 4 files changed, 308 insertions(+), 45 deletions(-) diff --git a/board/safety/safety_chrysler.h b/board/safety/safety_chrysler.h index 7fb237c9255..f103642e71f 100644 --- a/board/safety/safety_chrysler.h +++ b/board/safety/safety_chrysler.h @@ -28,12 +28,38 @@ const SteeringLimits CHRYSLER_RAM_HD_STEERING_LIMITS = { .type = TorqueMotorLimited, }; +const LongitudinalLimits CHRYSLER_LONG_LIMITS = { + // acceleration cmd limits (used for brakes) + // Signal: ACC_DECEL + .max_accel = 3685, // 3685 x 0.004885 - 16 = 2.0 m/s^2 + .min_accel = 2558, // 2558 x 0.004885 - 16 = -3.5 m/s^2 + .inactive_accel = 4094, // 4094 x 0.004885 - 16 = 4.0 m/s^2 + + // gas cmd limits + // Signal: ENGINE_TORQUE_REQUEST + .max_gas = 4000, // 4000 x .25 - 500 = 500.0 Nm + .min_gas = 0, // 0 x .25 - 500 = -500.0 Nm + .inactive_gas = 2000, // 2000 x .25 - 500 = 0.0 Nm +}; + +enum { + CHRYSLER_BTN_NONE = 0, + CHRYSLER_BTN_CANCEL = 1, + CHRYSLER_BTN_ACCEL = 4, + CHRYSLER_BTN_DECEL = 8, + CHRYSLER_BTN_RESUME = 16, +}; + +bool chrysler_longitudinal = false; + typedef struct { const int EPS_2; const int ESP_1; const int ESP_8; const int ECM_5; const int DAS_3; + const int DAS_4; + const int DAS_5; const int DAS_6; const int LKAS_COMMAND; const int CRUISE_BUTTONS; @@ -45,7 +71,9 @@ const ChryslerAddrs CHRYSLER_ADDRS = { .ESP_1 = 0x140, // Brake pedal and vehicle speed .ESP_8 = 0x11C, // Brake pedal and vehicle speed .ECM_5 = 0x22F, // Throttle position sensor - .DAS_3 = 0x1F4, // ACC engagement states from DASM + .DAS_3 = 0x1F4, // ACC state and control from DASM + .DAS_4 = 0x1F5, // ACC and FCW dispaly and config from DASM + .DAS_5 = 0x271, // ACC and FCW dispaly and config from DASM .DAS_6 = 0x2A6, // LKAS HUD and auto headlight control from DASM .LKAS_COMMAND = 0x292, // LKAS controls from DASM .CRUISE_BUTTONS = 0x23B, // Cruise control buttons @@ -57,7 +85,9 @@ const ChryslerAddrs CHRYSLER_RAM_DT_ADDRS = { .ESP_1 = 0x83, // Brake pedal and vehicle speed .ESP_8 = 0x79, // Brake pedal and vehicle speed .ECM_5 = 0x9D, // Throttle position sensor - .DAS_3 = 0x99, // ACC engagement states from DASM + .DAS_3 = 0x99, // ACC state and control from DASM + .DAS_4 = 0xE8, // ACC and FCW dispaly and config from DASM + .DAS_5 = 0xA3, // ACC and FCW dispaly and config from DASM .DAS_6 = 0xFA, // LKAS HUD and auto headlight control from DASM .LKAS_COMMAND = 0xA6, // LKAS controls from DASM .CRUISE_BUTTONS = 0xB1, // Cruise control buttons @@ -69,59 +99,108 @@ const ChryslerAddrs CHRYSLER_RAM_HD_ADDRS = { .ESP_1 = 0x140, // Brake pedal and vehicle speed .ESP_8 = 0x11C, // Brake pedal and vehicle speed .ECM_5 = 0x22F, // Throttle position sensor - .DAS_3 = 0x1F4, // ACC engagement states from DASM + .DAS_3 = 0x1F4, // ACC state and control from DASM + .DAS_4 = 0x1F5, // ACC and FCW dispaly and config from DASM + .DAS_5 = 0x271, // ACC and FCW dispaly and config from DASM .DAS_6 = 0x275, // LKAS HUD and auto headlight control from DASM .LKAS_COMMAND = 0x276, // LKAS controls from DASM .CRUISE_BUTTONS = 0x23A, // Cruise control buttons }; +#define CHRYSLER_COMMON_TX_MSGS(addrs, cruise_buttons_bus, lkas_cmd_len) \ + {(addrs).CRUISE_BUTTONS, (cruise_buttons_bus), 3}, \ + {(addrs).LKAS_COMMAND, 0, (lkas_cmd_len)}, \ + {(addrs).DAS_6, 0, 8}, \ + +#define CHRYSLER_COMMON_LONG_TX_MSGS(addrs) \ + {(addrs).DAS_3, 0, 8}, \ + {(addrs).DAS_4, 0, 8}, \ + {(addrs).DAS_5, 0, 8}, \ + const CanMsg CHRYSLER_TX_MSGS[] = { - {CHRYSLER_ADDRS.CRUISE_BUTTONS, 0, 3}, - {CHRYSLER_ADDRS.LKAS_COMMAND, 0, 6}, - {CHRYSLER_ADDRS.DAS_6, 0, 8}, + CHRYSLER_COMMON_TX_MSGS(CHRYSLER_ADDRS, 0, 6) +}; + +const CanMsg CHRYSLER_LONG_TX_MSGS[] = { + CHRYSLER_COMMON_TX_MSGS(CHRYSLER_ADDRS, 0, 6) + CHRYSLER_COMMON_LONG_TX_MSGS(CHRYSLER_ADDRS) }; const CanMsg CHRYSLER_RAM_DT_TX_MSGS[] = { - {CHRYSLER_RAM_DT_ADDRS.CRUISE_BUTTONS, 2, 3}, - {CHRYSLER_RAM_DT_ADDRS.LKAS_COMMAND, 0, 8}, - {CHRYSLER_RAM_DT_ADDRS.DAS_6, 0, 8}, + CHRYSLER_COMMON_TX_MSGS(CHRYSLER_RAM_DT_ADDRS, 2, 8) +}; + +const CanMsg CHRYSLER_RAM_DT_LONG_TX_MSGS[] = { + CHRYSLER_COMMON_TX_MSGS(CHRYSLER_RAM_DT_ADDRS, 2, 8) + CHRYSLER_COMMON_LONG_TX_MSGS(CHRYSLER_RAM_DT_ADDRS) }; const CanMsg CHRYSLER_RAM_HD_TX_MSGS[] = { - {CHRYSLER_RAM_HD_ADDRS.CRUISE_BUTTONS, 2, 3}, - {CHRYSLER_RAM_HD_ADDRS.LKAS_COMMAND, 0, 8}, - {CHRYSLER_RAM_HD_ADDRS.DAS_6, 0, 8}, + CHRYSLER_COMMON_TX_MSGS(CHRYSLER_RAM_HD_ADDRS, 2, 8) +}; + +const CanMsg CHRYSLER_RAM_HD_LONG_TX_MSGS[] = { + CHRYSLER_COMMON_TX_MSGS(CHRYSLER_RAM_HD_ADDRS, 2, 8) + CHRYSLER_COMMON_LONG_TX_MSGS(CHRYSLER_RAM_HD_ADDRS) }; +#define CHRYSLER_COMMON_RX_CHECKS(addrs) \ + {.msg = {{(addrs).EPS_2, 0, 8, .check_checksum = true, .max_counter = 15U, .frequency = 100U}, { 0 }, { 0 }}}, \ + {.msg = {{(addrs).ESP_1, 0, 8, .check_checksum = true, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}}, \ + {.msg = {{(addrs).ECM_5, 0, 8, .check_checksum = true, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}}, \ + +// TODO: use the same message for both (see vehicle_moving below) +#define CHRYSLER_COMMON_ALT_RX_CHECKS() \ + {.msg = {{514, 0, 8, .check_checksum = false, .max_counter = 0U, .frequency = 100U}, { 0 }, { 0 }}}, \ + +#define CHRYSLER_COMMON_RAM_RX_CHECKS(addrs) \ + {.msg = {{(addrs).ESP_8, 0, 8, .check_checksum = true, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}}, \ + +#define CHRYSLER_COMMON_ACC_RX_CHECKS(addrs, das_3_bus) \ + {.msg = {{(addrs).DAS_3, (das_3_bus), 8, .check_checksum = true, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}}, \ + +#define CHRYSLER_COMMON_BUTTONS_RX_CHECKS(addrs) \ + {.msg = {{(addrs).CRUISE_BUTTONS, 0, 3, .check_checksum = true, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}}, \ + RxCheck chrysler_rx_checks[] = { - {.msg = {{CHRYSLER_ADDRS.EPS_2, 0, 8, .check_checksum = true, .max_counter = 15U, .frequency = 100U}, { 0 }, { 0 }}}, - {.msg = {{CHRYSLER_ADDRS.ESP_1, 0, 8, .check_checksum = true, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}}, - //{.msg = {{ESP_8, 0, 8, .check_checksum = true, .max_counter = 15U, .frequency = 50U}}}, - {.msg = {{514, 0, 8, .check_checksum = false, .max_counter = 0U, .frequency = 100U}, { 0 }, { 0 }}}, - {.msg = {{CHRYSLER_ADDRS.ECM_5, 0, 8, .check_checksum = true, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}}, - {.msg = {{CHRYSLER_ADDRS.DAS_3, 0, 8, .check_checksum = true, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}}, + CHRYSLER_COMMON_RX_CHECKS(CHRYSLER_ADDRS) + CHRYSLER_COMMON_ALT_RX_CHECKS() + CHRYSLER_COMMON_ACC_RX_CHECKS(CHRYSLER_ADDRS, 0) +}; + +RxCheck chrysler_long_rx_checks[] = { + CHRYSLER_COMMON_RX_CHECKS(CHRYSLER_ADDRS) + CHRYSLER_COMMON_ALT_RX_CHECKS() + CHRYSLER_COMMON_BUTTONS_RX_CHECKS(CHRYSLER_ADDRS) }; RxCheck chrysler_ram_dt_rx_checks[] = { - {.msg = {{CHRYSLER_RAM_DT_ADDRS.EPS_2, 0, 8, .check_checksum = true, .max_counter = 15U, .frequency = 100U}, { 0 }, { 0 }}}, - {.msg = {{CHRYSLER_RAM_DT_ADDRS.ESP_1, 0, 8, .check_checksum = true, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}}, - {.msg = {{CHRYSLER_RAM_DT_ADDRS.ESP_8, 0, 8, .check_checksum = true, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}}, - {.msg = {{CHRYSLER_RAM_DT_ADDRS.ECM_5, 0, 8, .check_checksum = true, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}}, - {.msg = {{CHRYSLER_RAM_DT_ADDRS.DAS_3, 2, 8, .check_checksum = true, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}}, + CHRYSLER_COMMON_RX_CHECKS(CHRYSLER_RAM_DT_ADDRS) + CHRYSLER_COMMON_RAM_RX_CHECKS(CHRYSLER_RAM_DT_ADDRS) + CHRYSLER_COMMON_ACC_RX_CHECKS(CHRYSLER_RAM_DT_ADDRS, 2) }; -RxCheck chrysler_ram_hd_rx_checks[] = { - {.msg = {{CHRYSLER_RAM_HD_ADDRS.EPS_2, 0, 8, .check_checksum = true, .max_counter = 15U, .frequency = 100U}, { 0 }, { 0 }}}, - {.msg = {{CHRYSLER_RAM_HD_ADDRS.ESP_1, 0, 8, .check_checksum = true, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}}, - {.msg = {{CHRYSLER_RAM_HD_ADDRS.ESP_8, 0, 8, .check_checksum = true, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}}, - {.msg = {{CHRYSLER_RAM_HD_ADDRS.ECM_5, 0, 8, .check_checksum = true, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}}, - {.msg = {{CHRYSLER_RAM_HD_ADDRS.DAS_3, 2, 8, .check_checksum = true, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}}, +RxCheck chrysler_ram_dt_long_rx_checks[] = { + CHRYSLER_COMMON_RX_CHECKS(CHRYSLER_RAM_DT_ADDRS) + CHRYSLER_COMMON_RAM_RX_CHECKS(CHRYSLER_RAM_DT_ADDRS) + CHRYSLER_COMMON_BUTTONS_RX_CHECKS(CHRYSLER_RAM_DT_ADDRS) }; +RxCheck chrysler_ram_hd_rx_checks[] = { + CHRYSLER_COMMON_RX_CHECKS(CHRYSLER_RAM_HD_ADDRS) + CHRYSLER_COMMON_RAM_RX_CHECKS(CHRYSLER_RAM_HD_ADDRS) + CHRYSLER_COMMON_ACC_RX_CHECKS(CHRYSLER_RAM_HD_ADDRS, 2) +}; +RxCheck chrysler_ram_hd_long_rx_checks[] = { + CHRYSLER_COMMON_RX_CHECKS(CHRYSLER_RAM_HD_ADDRS) + CHRYSLER_COMMON_RAM_RX_CHECKS(CHRYSLER_RAM_HD_ADDRS) + CHRYSLER_COMMON_BUTTONS_RX_CHECKS(CHRYSLER_RAM_HD_ADDRS) +}; const uint32_t CHRYSLER_PARAM_RAM_DT = 1U; // set for Ram DT platform const uint32_t CHRYSLER_PARAM_RAM_HD = 2U; // set for Ram HD platform +const uint32_t CHRYSLER_PARAM_LONGITUDINAL = 4U; enum { CHRYSLER_RAM_DT, @@ -169,24 +248,52 @@ static uint32_t chrysler_compute_checksum(CANPacket_t *to_push) { } static uint8_t chrysler_get_counter(CANPacket_t *to_push) { - return (uint8_t)(GET_BYTE(to_push, 6) >> 4); + int counter_byte = GET_LEN(to_push) - 2U; + return (uint8_t)(GET_BYTE(to_push, counter_byte) >> 4); } static void chrysler_rx_hook(CANPacket_t *to_push) { const int bus = GET_BUS(to_push); const int addr = GET_ADDR(to_push); + if ((bus == 0) && (addr == chrysler_addrs->CRUISE_BUTTONS) && chrysler_longitudinal) { + int cruise_button = GET_BIT(to_push, 0U); // cancel button + // ensure cancel overrides any multi-button pressed state + if (!cruise_button) { + cruise_button |= GET_BIT(to_push, 2U) << 2U; // accel button + cruise_button |= GET_BIT(to_push, 3U) << 3U; // decel button + cruise_button |= GET_BIT(to_push, 4U) << 4U; // resume button + } + + // enter controls on falling edge of accel/decel/resume + bool accel = (cruise_button != CHRYSLER_BTN_ACCEL) && (cruise_button_prev == CHRYSLER_BTN_ACCEL); + bool decel = (cruise_button != CHRYSLER_BTN_DECEL) && (cruise_button_prev == CHRYSLER_BTN_DECEL); + bool resume = (cruise_button != CHRYSLER_BTN_RESUME) && (cruise_button_prev == CHRYSLER_BTN_RESUME); + if (accel || decel || resume) { + controls_allowed = true; + } + + // exit controls on cancel press + if (cruise_button == CHRYSLER_BTN_CANCEL) { + controls_allowed = false; + } + + cruise_button_prev = cruise_button; + } + // Measured EPS torque if ((bus == 0) && (addr == chrysler_addrs->EPS_2)) { int torque_meas_new = ((GET_BYTE(to_push, 4) & 0x7U) << 8) + GET_BYTE(to_push, 5) - 1024U; update_sample(&torque_meas, torque_meas_new); } - // enter controls on rising edge of ACC, exit controls on ACC off - const int das_3_bus = (chrysler_platform == CHRYSLER_PACIFICA) ? 0 : 2; - if ((bus == das_3_bus) && (addr == chrysler_addrs->DAS_3)) { - bool cruise_engaged = GET_BIT(to_push, 21U) == 1U; - pcm_cruise_check(cruise_engaged); + if (!chrysler_longitudinal) { + // enter controls on rising edge of ACC, exit controls on ACC off + const int das_3_bus = (chrysler_platform == CHRYSLER_PACIFICA) ? 0 : 2; + if ((bus == das_3_bus) && (addr == chrysler_addrs->DAS_3)) { + bool cruise_engaged = GET_BIT(to_push, 21U) == 1U; + pcm_cruise_check(cruise_engaged); + } } // TODO: use the same message for both @@ -232,8 +339,24 @@ static bool chrysler_tx_hook(CANPacket_t *to_send) { } } + // ACCEL + if (tx && (addr == chrysler_addrs->DAS_3)) { + // Signal: ENGINE_TORQUE_REQUEST + int gas = (((GET_BYTE(to_send, 0) & 0x1FU) << 8) | GET_BYTE(to_send, 1)); + // Signal: ACC_DECEL + int accel = (((GET_BYTE(to_send, 2) & 0xFU) << 8) | GET_BYTE(to_send, 3)); + + bool violation = false; + violation |= longitudinal_accel_checks(accel, CHRYSLER_LONG_LIMITS); + violation |= longitudinal_gas_checks(gas, CHRYSLER_LONG_LIMITS); + + if (violation) { + tx = 0; + } + } + // FORCE CANCEL: only the cancel button press is allowed - if (addr == chrysler_addrs->CRUISE_BUTTONS) { + if ((addr == chrysler_addrs->CRUISE_BUTTONS) && !chrysler_longitudinal) { const bool is_cancel = GET_BYTE(to_send, 0) == 1U; const bool is_resume = GET_BYTE(to_send, 0) == 0x10U; const bool allowed = is_cancel || (is_resume && controls_allowed); @@ -249,13 +372,15 @@ static int chrysler_fwd_hook(int bus_num, int addr) { int bus_fwd = -1; // forward to camera - if (bus_num == 0) { + const bool is_buttons = (addr == chrysler_addrs->CRUISE_BUTTONS); + if ((bus_num == 0) && (!chrysler_longitudinal || !is_buttons)) { bus_fwd = 2; } // forward all messages from camera except LKAS messages const bool is_lkas = ((addr == chrysler_addrs->LKAS_COMMAND) || (addr == chrysler_addrs->DAS_6)); - if ((bus_num == 2) && !is_lkas){ + const bool is_acc = ((addr == chrysler_addrs->DAS_3) || (addr == chrysler_addrs->DAS_4) || (addr == chrysler_addrs->DAS_5)); + if ((bus_num == 2) && !is_lkas && (!chrysler_longitudinal || !is_acc)){ bus_fwd = 0; } @@ -263,21 +388,27 @@ static int chrysler_fwd_hook(int bus_num, int addr) { } static safety_config chrysler_init(uint16_t param) { +#ifdef ALLOW_DEBUG + chrysler_longitudinal = GET_FLAG(param, CHRYSLER_PARAM_LONGITUDINAL); +#else + chrysler_longitudinal = false; +#endif + safety_config ret; if (GET_FLAG(param, CHRYSLER_PARAM_RAM_DT)) { chrysler_platform = CHRYSLER_RAM_DT; chrysler_addrs = &CHRYSLER_RAM_DT_ADDRS; - ret = BUILD_SAFETY_CFG(chrysler_ram_dt_rx_checks, CHRYSLER_RAM_DT_TX_MSGS); + ret = chrysler_longitudinal ? BUILD_SAFETY_CFG(chrysler_ram_dt_long_rx_checks, CHRYSLER_RAM_DT_LONG_TX_MSGS) : BUILD_SAFETY_CFG(chrysler_ram_dt_rx_checks, CHRYSLER_RAM_DT_TX_MSGS); #ifdef ALLOW_DEBUG } else if (GET_FLAG(param, CHRYSLER_PARAM_RAM_HD)) { chrysler_platform = CHRYSLER_RAM_HD; chrysler_addrs = &CHRYSLER_RAM_HD_ADDRS; - ret = BUILD_SAFETY_CFG(chrysler_ram_hd_rx_checks, CHRYSLER_RAM_HD_TX_MSGS); + ret = chrysler_longitudinal ? BUILD_SAFETY_CFG(chrysler_ram_hd_long_rx_checks, CHRYSLER_RAM_HD_LONG_TX_MSGS) : BUILD_SAFETY_CFG(chrysler_ram_hd_rx_checks, CHRYSLER_RAM_HD_TX_MSGS); #endif } else { chrysler_platform = CHRYSLER_PACIFICA; chrysler_addrs = &CHRYSLER_ADDRS; - ret = BUILD_SAFETY_CFG(chrysler_rx_checks, CHRYSLER_TX_MSGS); + ret = chrysler_longitudinal ? BUILD_SAFETY_CFG(chrysler_long_rx_checks, CHRYSLER_LONG_TX_MSGS) : BUILD_SAFETY_CFG(chrysler_rx_checks, CHRYSLER_TX_MSGS); } return ret; } diff --git a/python/__init__.py b/python/__init__.py index 274e7dbe4d4..3e791dee359 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -215,6 +215,7 @@ class Panda: FLAG_CHRYSLER_RAM_DT = 1 FLAG_CHRYSLER_RAM_HD = 2 + FLAG_CHRYSLER_LONG = 4 FLAG_SUBARU_GEN2 = 1 FLAG_SUBARU_LONG = 2 diff --git a/tests/safety/common.py b/tests/safety/common.py index 5aa96364320..d5f86a4110a 100644 --- a/tests/safety/common.py +++ b/tests/safety/common.py @@ -841,6 +841,11 @@ def test_tx_hook_on_wrong_safety_mode(self): continue if {attr, current_test}.issubset({'TestVolkswagenMqbSafety', 'TestVolkswagenMqbStockSafety', 'TestVolkswagenMqbLongSafety'}): continue + if attr.startswith('TestChryslerRamDT') and current_test.startswith('TestChryslerRamDT'): + continue + if {attr, current_test}.issubset({'TestChryslerSafety', 'TestChryslerLongitudinalSafety', + 'TestChryslerRamHDSafety', 'TestChryslerRamHDLongitudinalSafety'}): + continue # overlapping TX addrs, but they're not actuating messages for either car if attr == 'TestHyundaiCanfdHDA2LongEV' and current_test.startswith('TestToyota'): diff --git a/tests/safety/test_chrysler.py b/tests/safety/test_chrysler.py index 5bbb6dd1030..d3123ff35a0 100755 --- a/tests/safety/test_chrysler.py +++ b/tests/safety/test_chrysler.py @@ -1,11 +1,12 @@ #!/usr/bin/env python3 import unittest +import itertools + from panda import Panda from panda.tests.libpanda import libpanda_py import panda.tests.safety.common as common from panda.tests.safety.common import CANPackerPanda - class TestChryslerSafety(common.PandaCarSafetyTest, common.MotorTorqueSteeringSafetyTest): TX_MSGS = [[0x23B, 0], [0x292, 0], [0x2A6, 0]] STANDSTILL_THRESHOLD = 0 @@ -24,14 +25,17 @@ class TestChryslerSafety(common.PandaCarSafetyTest, common.MotorTorqueSteeringSa DAS_BUS = 0 + cnt_button = 0 + def setUp(self): self.packer = CANPackerPanda("chrysler_pacifica_2017_hybrid_generated") self.safety = libpanda_py.libpanda self.safety.set_safety_hooks(Panda.SAFETY_CHRYSLER, 0) self.safety.init_tests() - def _button_msg(self, cancel=False, resume=False): - values = {"ACC_Cancel": cancel, "ACC_Resume": resume} + def _button_msg(self, cancel=False, resume=False, accel=False, decel=False): + values = {"ACC_Cancel": cancel, "ACC_Resume": resume, "ACC_Accel": accel, "ACC_Decel": decel, "COUNTER": self.cnt_button} + self.__class__.cnt_button += 1 return self.packer.make_can_msg_panda("CRUISE_BUTTONS", self.DAS_BUS, values) def _pcm_status_msg(self, enable): @@ -96,8 +100,9 @@ def _speed_msg(self, speed): values = {"Vehicle_Speed": speed} return self.packer.make_can_msg_panda("ESP_8", 0, values) + class TestChryslerRamHDSafety(TestChryslerSafety): - TX_MSGS = [[0x275, 0], [0x276, 0], [0x23A, 2]] + TX_MSGS = [[0x23A, 2], [0x275, 0], [0x276, 0]] RELAY_MALFUNCTION_ADDRS = {0: (0x276,)} FWD_BLACKLISTED_ADDRS = {2: [0x275, 0x276]} @@ -121,5 +126,126 @@ def _speed_msg(self, speed): return self.packer.make_can_msg_panda("ESP_8", 0, values) +class ChryslerLongitudinalBase(common.PandaSafetyTestBase): + # pylint: disable=no-member,abstract-method + + DAS_BUS = 0 + + MIN_ENGINE_TORQUE = -500 + MAX_ENGINE_TORQUE = 500 + INACTIVE_ENGINE_TORQUE = 0 + MIN_POSSIBLE_ENGINE_TORQUE = -500 + MAX_POSSIBLE_ENGINE_TORQUE = 1548 + + MIN_ACCEL = -3.5 + MAX_ACCEL = 2.0 + INACTIVE_ACCEL = 4.0 + MIN_POSSIBLE_ACCEL = -16.0 + MAX_POSSIBLE_ACCEL = 4.0 + + @classmethod + def setUpClass(cls): + if cls.__name__ == "ChryslerLongitudinalBase": + cls.safety = None + raise unittest.SkipTest + + # override these tests from PandaCarSafetyTest, chrysler longitudinal uses button enable + def test_disable_control_allowed_from_cruise(self): + pass + + def test_enable_control_allowed_from_cruise(self): + pass + + def test_sampling_cruise_buttons(self): + pass + + def test_cruise_engaged_prev(self): + pass + + def test_button_sends(self): + pass + + def _pcm_status_msg(self, enable): + raise Exception + + def _send_torque_accel_msg(self, enable, torque_active, torque, accel_active, accel): + values = { + "ACC_AVAILABLE": 1, + "ACC_ACTIVE": enable, + "ENGINE_TORQUE_REQUEST": torque, + "ENGINE_TORQUE_REQUEST_MAX": torque_active, + "ACC_DECEL": accel, + "ACC_DECEL_REQ": accel_active, + } + return self.packer.make_can_msg_panda("DAS_3", self.DAS_BUS, values) + + def _send_accel_msg(self, accel): + return self._send_torque_accel_msg(1, 0, self.INACTIVE_ENGINE_TORQUE, 1, accel) + + def _send_torque_msg(self, torque): + return self._send_torque_accel_msg(1, 1, torque, 0, self.INACTIVE_ACCEL) + + def test_accel_torque_safety_check(self): + self._generic_limit_safety_check(self._send_accel_msg, + self.MIN_ACCEL, self.MAX_ACCEL, + self.MIN_POSSIBLE_ACCEL, self.MAX_POSSIBLE_ACCEL, + test_delta=0.1, inactive_value=self.INACTIVE_ACCEL) + self._generic_limit_safety_check(self._send_torque_msg, + self.MIN_ENGINE_TORQUE, self.MAX_ENGINE_TORQUE, + self.MIN_POSSIBLE_ENGINE_TORQUE, self.MAX_POSSIBLE_ENGINE_TORQUE, + test_delta=10, inactive_value=self.INACTIVE_ENGINE_TORQUE) + + def test_buttons(self): + enable_buttons = {1 << 2: "resume", 1 << 3: "accel", 1 << 4: "decel"} + for cancel_cur, resume_cur, accel_cur, decel_cur in itertools.product([0, 1], repeat=4): + for cancel_prev, resume_prev, accel_prev, decel_prev in itertools.product([0, 1], repeat=4): + self._rx(self._button_msg(cancel=False, resume=False, accel=False, decel=False)) + self.safety.set_controls_allowed(0) + for _ in range(10): + self._rx(self._button_msg(cancel_prev, resume_prev, accel_prev, decel_prev)) + self.assertFalse(self.safety.get_controls_allowed()) + + # should enter controls allowed on falling edge and not transitioning to cancel + button_cur = enable_buttons.get(cancel_cur if cancel_cur else (resume_cur << 2) | (accel_cur << 3) | (decel_cur << 4)) + button_prev = enable_buttons.get(cancel_prev if cancel_prev else (resume_prev << 2) | (accel_prev << 3) | (decel_prev << 4)) + should_enable = not cancel_cur and not cancel_prev and button_prev is not None and button_prev != button_cur + + self._rx(self._button_msg(cancel_cur, resume_cur, accel_cur, decel_cur)) + self.assertEqual(should_enable, self.safety.get_controls_allowed()) + + +class TestChryslerLongitudinalSafety(ChryslerLongitudinalBase, TestChryslerSafety): + TX_MSGS = [[0x23B, 0], [0x292, 0], [0x2A6, 0], [0x1F4, 0], [0x1F5, 0], [0x271, 0]] + FWD_BLACKLISTED_ADDRS = {0: [0x23B], 2: [0x292, 0x2A6, 0x1F4, 0x1F5, 0x271]} + + def setUp(self): + self.packer = CANPackerPanda("chrysler_pacifica_2017_hybrid_generated") + self.safety = libpanda_py.libpanda + self.safety.set_safety_hooks(Panda.SAFETY_CHRYSLER, Panda.FLAG_CHRYSLER_LONG) + self.safety.init_tests() + + +class TestChryslerRamDTLongitudinalSafety(ChryslerLongitudinalBase, TestChryslerRamDTSafety): + TX_MSGS = [[0xB1, 0], [0xA6, 0], [0xFA, 0], [0x99, 0], [0xE8, 0], [0xA3, 0]] + FWD_BLACKLISTED_ADDRS = {0: [0xB1], 2: [0xA6, 0xFA, 0x99, 0xE8, 0xA3]} + + def setUp(self): + self.packer = CANPackerPanda("chrysler_ram_dt_generated") + self.safety = libpanda_py.libpanda + self.safety.set_safety_hooks(Panda.SAFETY_CHRYSLER, Panda.FLAG_CHRYSLER_RAM_DT | Panda.FLAG_CHRYSLER_LONG) + self.safety.init_tests() + + +class TestChryslerRamHDLongitudinalSafety(ChryslerLongitudinalBase, TestChryslerRamHDSafety): + TX_MSGS = [[0x23A, 0], [0x275, 0], [0x276, 0], [0x1F4, 0], [0x1F5, 0], [0x271, 0]] + FWD_BLACKLISTED_ADDRS = {0: [0x23A], 2: [0x275, 0x276, 0x1F4, 0x1F5, 0x271]} + + def setUp(self): + self.packer = CANPackerPanda("chrysler_ram_hd_generated") + self.safety = libpanda_py.libpanda + self.safety.set_safety_hooks(Panda.SAFETY_CHRYSLER, Panda.FLAG_CHRYSLER_RAM_HD | Panda.FLAG_CHRYSLER_LONG) + self.safety.init_tests() + + if __name__ == "__main__": unittest.main()