From 317b2da151aaebe3774eefa3bc2867a23e7316ec Mon Sep 17 00:00:00 2001 From: Jason Young Date: Mon, 21 Mar 2022 03:46:31 -0400 Subject: [PATCH 01/26] FAW: Barebones vehicle port --- board/safety.h | 3 + board/safety/safety_faw.h | 221 ++++++++++++++++++++++++++++++ python/__init__.py | 3 + tests/safety/test_faw.py | 280 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 507 insertions(+) create mode 100644 board/safety/safety_faw.h create mode 100755 tests/safety/test_faw.py diff --git a/board/safety.h b/board/safety.h index 28f629bea4..0b29a5f480 100644 --- a/board/safety.h +++ b/board/safety.h @@ -14,6 +14,7 @@ #include "safety/safety_nissan.h" #include "safety/safety_volkswagen_mqb.h" #include "safety/safety_volkswagen_pq.h" +#include "safety/safety_faw.h" #include "safety/safety_elm327.h" // from cereal.car.CarParams.SafetyModel @@ -40,6 +41,7 @@ #define SAFETY_HYUNDAI_LEGACY 23U #define SAFETY_HYUNDAI_COMMUNITY 24U #define SAFETY_STELLANTIS 25U +#define SAFETY_FAW 26U uint16_t current_safety_mode = SAFETY_SILENT; int16_t current_safety_param = 0; @@ -255,6 +257,7 @@ const safety_hook_config safety_hook_registry[] = { {SAFETY_TESLA, &tesla_hooks}, {SAFETY_SUBARU_LEGACY, &subaru_legacy_hooks}, {SAFETY_VOLKSWAGEN_PQ, &volkswagen_pq_hooks}, + {SAFETY_FAW, &faw_hooks}, {SAFETY_ALLOUTPUT, &alloutput_hooks}, {SAFETY_FORD, &ford_hooks}, #endif diff --git a/board/safety/safety_faw.h b/board/safety/safety_faw.h new file mode 100644 index 0000000000..af5728ebd2 --- /dev/null +++ b/board/safety/safety_faw.h @@ -0,0 +1,221 @@ +const int FAW_MAX_STEER = 300; // As-yet unknown fault boundary, guessing 300 / 3.0Nm for now +const int FAW_MAX_RT_DELTA = 56; // 3 max rate up * 50Hz send rate * 250000 RT interval / 1000000 = 37.5 ; 50 * 1.5 for safety pad = 56.25 +const uint32_t FAW_RT_INTERVAL = 250000; // 250ms between real time checks +const int FAW_MAX_RATE_UP = 3; // 3 unit/sec observed from factory LKAS, fault boundary unknown +const int FAW_MAX_RATE_DOWN = 3; // 3 unit/sec observed from factory LKAS, fault boundary unknown +const int FAW_DRIVER_TORQUE_ALLOWANCE = 25; +const int FAW_DRIVER_TORQUE_FACTOR = 3; + +#define MSG_ECM_1 0x92 // RX from ABS, for brake pressures +#define MSG_ABS_1 0xC0 // RX from ABS, for wheel speeds +#define MSG_ABS_2 0xC2 // RX from ABS, for wheel speeds and braking +#define MSG_ACC 0x110 // RX from ACC, for ACC engagement state +#define MSG_LKAS 0x112 // TX from openpilot, for LKAS torque +#define MSG_EPS_2 0x150 // RX from EPS, torque inputs and outputs + +// Transmit of GRA_ACC_01 is allowed on bus 0 and 2 to keep compatibility with gateway and camera integration +const CanMsg FAW_TX_MSGS[] = {{MSG_LKAS, 0, 8}}; +#define FAW_TX_MSGS_LEN (sizeof(FAW_TX_MSGS) / sizeof(FAW_TX_MSGS[0])) + +AddrCheckStruct faw_addr_checks[] = { + {.msg = {{MSG_ECM_1, 0, 8, .check_checksum = true, .max_counter = 15U, .expected_timestep = 10000U}, { 0 }, { 0 }}}, + {.msg = {{MSG_ABS_1, 0, 8, .check_checksum = true, .max_counter = 15U, .expected_timestep = 10000U}, { 0 }, { 0 }}}, + {.msg = {{MSG_ABS_2, 0, 8, .check_checksum = true, .max_counter = 15U, .expected_timestep = 10000U}, { 0 }, { 0 }}}, + {.msg = {{MSG_ACC, 0, 8, .check_checksum = true, .max_counter = 15U, .expected_timestep = 20000U}, { 0 }, { 0 }}}, + {.msg = {{MSG_EPS_2, 0, 8, .check_checksum = true, .max_counter = 15U, .expected_timestep = 20000U}, { 0 }, { 0 }}}, +}; +#define FAW_ADDR_CHECKS_LEN (sizeof(faw_addr_checks) / sizeof(faw_addr_checks[0])) +addr_checks faw_rx_checks = {faw_addr_checks, FAW_ADDR_CHECKS_LEN}; + + +static uint8_t faw_get_checksum(CANPacket_t *to_push) { + return (uint8_t)GET_BYTE(to_push, 0); +} + +static uint8_t faw_get_counter(CANPacket_t *to_push) { + return ((uint8_t)GET_BYTE(to_push, 7) >> 4) & 0xFU; +} + +static uint8_t faw_compute_checksum(CANPacket_t *to_push) { + int len = GET_LEN(to_push); + int checksum = 0; + + for(int i = 1; i < len; i++) { + checksum ^= (uint8_t)GET_BYTE(to_push, i); + } + + return checksum; +} + +static const addr_checks* faw_init(int16_t param) { + UNUSED(param); + + controls_allowed = false; + relay_malfunction_reset(); + return &faw_rx_checks; +} + +static int faw_rx_hook(CANPacket_t *to_push) { + + bool valid = addr_safety_check(to_push, &faw_rx_checks, faw_get_checksum, faw_compute_checksum, faw_get_counter); + + if (valid && (GET_BUS(to_push) == 0U)) { + int addr = GET_ADDR(to_push); + + // Update in-motion state by sampling front wheel speeds + // Signal: ABS_1.FRONT_LEFT in scaled km/h + // Signal: ABS_1.FRONT_RIGHT in scaled km/h + if (addr == MSG_ABS_1) { + int wheel_speed_fl = GET_BYTE(to_push, 1) | (GET_BYTE(to_push, 2) << 8); + int wheel_speed_fr = GET_BYTE(to_push, 3) | (GET_BYTE(to_push, 4) << 8); + // Check for average front speed in excess of 0.3m/s, 1.08km/h + // DBC speed scale 0.01: 0.3m/s = 108, sum both wheels to compare + vehicle_moving = (wheel_speed_fl + wheel_speed_fr) > 216; + } + + // Update driver input torque samples + // Signal: EPS_2.DRIVER_INPUT_TORQUE (absolute torque) + // Signal: EPS_2.EPS_TORQUE_DIRECTION (direction) (FIXME: may not be the correct direction signal) + if (addr == MSG_EPS_2) { + int torque_driver_new = GET_BYTE(to_push, 4); + int sign = (GET_BYTE(to_push, 2) & 0x4U) >> 2; + if (sign == 1) { + torque_driver_new *= -1; + } + update_sample(&torque_driver, torque_driver_new); + } + + // Enter controls on rising edge of stock ACC, exit controls if stock ACC disengages + // Signal: ACC.STATUS + if (addr == MSG_ACC) { + int acc_status = (GET_BYTE(to_push, 4) & 0x7CU) >> 2; + int cruise_engaged = acc_status == 20; + if (cruise_engaged && !cruise_engaged_prev) { + controls_allowed = 1; + } + if (!cruise_engaged) { + controls_allowed = 0; + } + cruise_engaged_prev = cruise_engaged; + } + + // Signal: ECM_1.DRIVER_THROTTLE + if (addr == MSG_ECM_1) { + gas_pressed = GET_BYTE(to_push, 5) != 0; + } + + // Signal: ABS_2.BRAKE_PRESSURE + if (addr == MSG_ABS_2) { + brake_pressed = GET_BYTE(to_push, 5) != 0; + } + + generic_rx_checks((addr == MSG_LKAS)); + } + return valid; +} + +static int faw_tx_hook(CANPacket_t *to_send) { + int addr = GET_ADDR(to_send); + int tx = 1; + + if (!msg_allowed(to_send, FAW_TX_MSGS, FAW_TX_MSGS_LEN)) { + tx = 0; + } + + // Safety check for LKAS torque + // Signal: LKAS.LKAS_TORQUE + // Signal: LKAS.LKAS_TORQUE_DIRECTION + if (addr == MSG_LKAS) { + int desired_torque = GET_BYTE(to_send, 1) | ((GET_BYTE(to_send, 2) & 0x3U) << 8); + int sign = (GET_BYTE(to_send, 2) & 0x4U) >> 2; + if (sign == 1) { + desired_torque *= -1; + } + + bool violation = false; + uint32_t ts = microsecond_timer_get(); + + if (controls_allowed) { + // *** global torque limit check *** + violation |= max_limit_check(desired_torque, FAW_MAX_STEER, -FAW_MAX_STEER); + + // *** torque rate limit check *** + violation |= driver_limit_check(desired_torque, desired_torque_last, &torque_driver, + FAW_MAX_STEER, FAW_MAX_RATE_UP, FAW_MAX_RATE_DOWN, + FAW_DRIVER_TORQUE_ALLOWANCE, FAW_DRIVER_TORQUE_FACTOR); + desired_torque_last = desired_torque; + + // *** torque real time rate limit check *** + violation |= rt_rate_limit_check(desired_torque, rt_torque_last, FAW_MAX_RT_DELTA); + + // every RT_INTERVAL set the new limits + uint32_t ts_elapsed = get_ts_elapsed(ts, ts_last); + if (ts_elapsed > FAW_RT_INTERVAL) { + rt_torque_last = desired_torque; + ts_last = ts; + } + } + + // no torque if controls is not allowed + if (!controls_allowed && (desired_torque != 0)) { + violation = true; + } + + // reset to 0 if either controls is not allowed or there's a violation + if (violation || !controls_allowed) { + desired_torque_last = 0; + rt_torque_last = 0; + ts_last = ts; + } + + if (violation) { + tx = 0; + } + } + + // FORCE CANCEL: ensuring that only the cancel button press is sent when controls are off. + // This avoids unintended engagements while still allowing resume spam + // TODO: implement this + //if ((addr == MSG_GRA_ACC_01) && !controls_allowed) { + // // disallow resume and set: bits 16 and 19 + // if ((GET_BYTE(to_send, 2) & 0x9U) != 0U) { + // tx = 0; + // } + //} + + // 1 allows the message through + return tx; +} + +static int faw_fwd_hook(int bus_num, CANPacket_t *to_fwd) { + int addr = GET_ADDR(to_fwd); + int bus_fwd = -1; + + switch (bus_num) { + case 0: + bus_fwd = 2; + break; + case 2: + if (addr == MSG_LKAS) { + // OP takes control of the LKAS messages from the camera + bus_fwd = -1; + } else { + bus_fwd = 0; + } + break; + default: + // No other buses should be in use; fallback to do-not-forward + bus_fwd = -1; + break; + } + + return bus_fwd; +} + +const safety_hooks faw_hooks = { + .init = faw_init, + .rx = faw_rx_hook, + .tx = faw_tx_hook, + .tx_lin = nooutput_tx_lin_hook, + .fwd = faw_fwd_hook, +}; diff --git a/python/__init__.py b/python/__init__.py index 0daab85df9..4100809d1c 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -138,6 +138,9 @@ class Panda(object): SAFETY_VOLKSWAGEN_PQ = 21 SAFETY_SUBARU_LEGACY = 22 SAFETY_HYUNDAI_LEGACY = 23 + SAFETY_HYUNDAI_COMMUNITY = 24 + SAFETY_STELLANTIS = 25 + SAFETY_FAW = 26 SERIAL_DEBUG = 0 SERIAL_ESP = 1 diff --git a/tests/safety/test_faw.py b/tests/safety/test_faw.py new file mode 100755 index 0000000000..31f824ffcb --- /dev/null +++ b/tests/safety/test_faw.py @@ -0,0 +1,280 @@ +#!/usr/bin/env python3 +import unittest +import numpy as np +from panda import Panda +from panda.tests.safety import libpandasafety_py +import panda.tests.safety.common as common +from panda.tests.safety.common import CANPackerPanda, MAX_WRONG_COUNTERS + +MAX_RATE_UP = 3 +MAX_RATE_DOWN = 3 +MAX_STEER = 300 +MAX_RT_DELTA = 56 +RT_INTERVAL = 250000 + +DRIVER_TORQUE_ALLOWANCE = 25 +DRIVER_TORQUE_FACTOR = 3 + +MSG_ECM_1 = 0x92 # RX from ECM, for gas pedal +MSG_ABS_1 = 0xC0 # RX from ABS, for wheel speeds +MSG_ABS_2 = 0xC2 # RX from ABS, for wheel speeds and braking +MSG_ACC = 0x110 # RX from ACC, for ACC engagement state +MSG_LKAS = 0x112 # TX from openpilot, for LKAS torque +MSG_EPS_2 = 0x150 # RX from EPS, torque inputs and outputs + + +class TestFawSafety(common.PandaSafetyTest): + cnt_ecm_1 = 0 + cnt_abs_1 = 0 + cnt_abs_2 = 0 + cnt_acc = 0 + cnt_lkas = 0 + cnt_eps_2 = 0 + + STANDSTILL_THRESHOLD = 1 + RELAY_MALFUNCTION_ADDR = MSG_LKAS + RELAY_MALFUNCTION_BUS = 0 + + @classmethod + def setUpClass(cls): + if cls.__name__ == "TestFawSafety": + cls.packer = None + cls.safety = None + raise unittest.SkipTest + + def _set_prev_torque(self, t): + self.safety.set_desired_torque_last(t) + self.safety.set_rt_torque_last(t) + + # Wheel speeds + def _speed_msg(self, speed): + values = {"FRONT_LEFT": speed, "FRONT_RIGHT": speed, "COUNTER": self.cnt_abs_1 % 16} + self.__class__.cnt_abs_1 += 1 + return self.packer.make_can_msg_panda("ABS_1", 0, values) + + # Brake pressed + def _brake_msg(self, brake): + values = {"BRAKE_PRESSURE": brake, "COUNTER": self.cnt_abs_2 % 16} + self.__class__.cnt_abs_2 += 1 + return self.packer.make_can_msg_panda("ABS_2", 0, values) + + # Driver throttle input + def _gas_msg(self, gas): + values = {"DRIVER_THROTTLE": gas, "COUNTER": self.cnt_ecm_1 % 16} + self.__class__.cnt_ecm_1 += 1 + return self.packer.make_can_msg_panda("ECM_1", 0, values) + + # ACC engagement status + def _pcm_status_msg(self, enable): + values = {"STATUS": 20 if enable else 11, "COUNTER": self.cnt_acc % 16} + self.__class__.cnt_acc += 1 + return self.packer.make_can_msg_panda("ACC", 0, values) + + # Driver steering input torque + def _eps_2_msg(self, torque): + values = {"DRIVER_INPUT_TORQUE": abs(torque), "EPS_TORQUE_DIRECTION": torque < 0, + "COUNTER": self.cnt_eps_2 % 16} + self.__class__.cnt_eps_2 += 1 + return self.packer.make_can_msg_panda("EPS_2", 0, values) + + # openpilot steering output torque + def _lkas_msg(self, torque): + values = {"LKAS_TORQUE": abs(torque), "LKAS_TORQUE_DIRECTION": torque < 0, + "COUNTER": self.cnt_lkas % 16} + self.__class__.cnt_lkas += 1 + return self.packer.make_can_msg_panda("LKAS", 0, values) + + # Cruise control buttons + # TODO: implement this + #def _gra_acc_01_msg(self, cancel=0, resume=0, _set=0): + # values = {"GRA_Abbrechen": cancel, "GRA_Tip_Setzen": _set, + # "GRA_Tip_Wiederaufnahme": resume, "COUNTER": self.cnt_gra_acc_01 % 16} + # self.__class__.cnt_gra_acc_01 += 1 + # return self.packer.make_can_msg_panda("GRA_ACC_01", 0, values) + + def test_steer_safety_check(self): + for enabled in [0, 1]: + for t in range(-500, 500): + self.safety.set_controls_allowed(enabled) + self._set_prev_torque(t) + if abs(t) > MAX_STEER or (not enabled and abs(t) > 0): + self.assertFalse(self._tx(self._lkas_msg(t))) + else: + self.assertTrue(self._tx(self._lkas_msg(t))) + + def test_non_realtime_limit_up(self): + self.safety.set_torque_driver(0, 0) + self.safety.set_controls_allowed(True) + + self._set_prev_torque(0) + self.assertTrue(self._tx(self._lkas_msg(MAX_RATE_UP))) + self._set_prev_torque(0) + self.assertTrue(self._tx(self._lkas_msg(-MAX_RATE_UP))) + + self._set_prev_torque(0) + self.assertFalse(self._tx(self._lkas_msg(MAX_RATE_UP + 1))) + self.safety.set_controls_allowed(True) + self._set_prev_torque(0) + self.assertFalse(self._tx(self._lkas_msg(-MAX_RATE_UP - 1))) + + def test_non_realtime_limit_down(self): + self.safety.set_torque_driver(0, 0) + self.safety.set_controls_allowed(True) + + def test_against_torque_driver(self): + self.safety.set_controls_allowed(True) + + for sign in [-1, 1]: + for t in np.arange(0, DRIVER_TORQUE_ALLOWANCE + 1, 1): + t *= -sign + self.safety.set_torque_driver(t, t) + self._set_prev_torque(MAX_STEER * sign) + self.assertTrue(self._tx(self._lkas_msg(MAX_STEER * sign))) + + self.safety.set_torque_driver(DRIVER_TORQUE_ALLOWANCE + 1, DRIVER_TORQUE_ALLOWANCE + 1) + self.assertFalse(self._tx(self._lkas_msg(-MAX_STEER))) + + # spot check some individual cases + for sign in [-1, 1]: + driver_torque = (DRIVER_TORQUE_ALLOWANCE + 10) * sign + torque_desired = (MAX_STEER - 10 * DRIVER_TORQUE_FACTOR) * sign + delta = 1 * sign + self._set_prev_torque(torque_desired) + self.safety.set_torque_driver(-driver_torque, -driver_torque) + self.assertTrue(self._tx(self._lkas_msg(torque_desired))) + self._set_prev_torque(torque_desired + delta) + self.safety.set_torque_driver(-driver_torque, -driver_torque) + self.assertFalse(self._tx(self._lkas_msg(torque_desired + delta))) + + self._set_prev_torque(MAX_STEER * sign) + self.safety.set_torque_driver(-MAX_STEER * sign, -MAX_STEER * sign) + self.assertTrue(self._tx(self._lkas_msg((MAX_STEER - MAX_RATE_DOWN) * sign))) + self._set_prev_torque(MAX_STEER * sign) + self.safety.set_torque_driver(-MAX_STEER * sign, -MAX_STEER * sign) + self.assertTrue(self._tx(self._lkas_msg(0))) + self._set_prev_torque(MAX_STEER * sign) + self.safety.set_torque_driver(-MAX_STEER * sign, -MAX_STEER * sign) + self.assertFalse(self._tx(self._lkas_msg((MAX_STEER - MAX_RATE_DOWN + 1) * sign))) + + def test_realtime_limits(self): + self.safety.set_controls_allowed(True) + + for sign in [-1, 1]: + self.safety.init_tests() + self._set_prev_torque(0) + self.safety.set_torque_driver(0, 0) + for t in np.arange(0, MAX_RT_DELTA, 1): + t *= sign + self.assertTrue(self._tx(self._lkas_msg(t))) + self.assertFalse(self._tx(self._lkas_msg(sign * (MAX_RT_DELTA + 1)))) + + self._set_prev_torque(0) + for t in np.arange(0, MAX_RT_DELTA, 1): + t *= sign + self.assertTrue(self._tx(self._lkas_msg(t))) + + # Increase timer to update rt_torque_last + self.safety.set_timer(RT_INTERVAL + 1) + self.assertTrue(self._tx(self._lkas_msg(sign * (MAX_RT_DELTA - 1)))) + self.assertTrue(self._tx(self._lkas_msg(sign * (MAX_RT_DELTA + 1)))) + + def test_torque_measurements(self): + self._rx(self._eps_2_msg(50)) + self._rx(self._eps_2_msg(-50)) + self._rx(self._eps_2_msg(0)) + self._rx(self._eps_2_msg(0)) + self._rx(self._eps_2_msg(0)) + self._rx(self._eps_2_msg(0)) + + self.assertEqual(-50, self.safety.get_torque_driver_min()) + self.assertEqual(50, self.safety.get_torque_driver_max()) + + self._rx(self._eps_2_msg(0)) + self.assertEqual(0, self.safety.get_torque_driver_max()) + self.assertEqual(-50, self.safety.get_torque_driver_min()) + + self._rx(self._eps_2_msg(0)) + self.assertEqual(0, self.safety.get_torque_driver_max()) + self.assertEqual(0, self.safety.get_torque_driver_min()) + + def test_rx_hook(self): + # checksum checks + # TODO: Would be ideal to check ESP_19 as well, but it has no checksum + # or counter, and I'm not sure if we can easily validate Panda's simple + # temporal reception-rate check here. + # TODO: add gas message to this list + for msg in [MSG_EPS_2, MSG_ABS_2, MSG_ACC, MSG_ECM_1, MSG_ABS_1]: + self.safety.set_controls_allowed(1) + if msg == MSG_EPS_2: + to_push = self._eps_2_msg(0) + if msg == MSG_ABS_2: + to_push = self._brake_msg(False) + if msg == MSG_ACC: + to_push = self._pcm_status_msg(True) + if msg == MSG_ECM_1: + to_push = self._gas_msg(0) + if msg == MSG_ABS_1: + to_push = self._speed_msg(0) + self.assertTrue(self._rx(to_push)) + to_push[0].data[4] ^= 0xFF + self.assertFalse(self._rx(to_push)) + self.assertFalse(self.safety.get_controls_allowed()) + + # counter + # reset wrong_counters to zero by sending valid messages + for i in range(MAX_WRONG_COUNTERS + 1): + self.__class__.cnt_eps_2 += 1 + self.__class__.cnt_abs_2 += 1 + self.__class__.cnt_acc += 1 + self.__class__.cnt_ecm_1 += 1 + self.__class__.cnt_abs_1 += 1 + if i < MAX_WRONG_COUNTERS: + self.safety.set_controls_allowed(1) + self._rx(self._eps_2_msg(0)) + self._rx(self._brake_msg(False)) + self._rx(self._pcm_status_msg(True)) + self._rx(self._gas_msg(0)) + self._rx(self._speed_msg(0)) + else: + self.assertFalse(self._rx(self._eps_2_msg(0))) + self.assertFalse(self._rx(self._brake_msg(False))) + self.assertFalse(self._rx(self._pcm_status_msg(True))) + self.assertFalse(self._rx(self._gas_msg(0))) + self.assertFalse(self._rx(self._speed_msg(0))) + self.assertFalse(self.safety.get_controls_allowed()) + + # restore counters for future tests with a couple of good messages + for i in range(2): + self.safety.set_controls_allowed(1) + self._rx(self._eps_2_msg(0)) + self._rx(self._brake_msg(False)) + self._rx(self._pcm_status_msg(True)) + self._rx(self._gas_msg(0)) + self._rx(self._speed_msg(0)) + self.assertTrue(self.safety.get_controls_allowed()) + + +class TestFawStockSafety(TestFawSafety): + TX_MSGS = [[MSG_LKAS, 0]] + FWD_BLACKLISTED_ADDRS = {2: [MSG_LKAS]} + FWD_BUS_LOOKUP = {0: 2, 2: 0} + + def setUp(self): + self.packer = CANPackerPanda("faw") + self.safety = libpandasafety_py.libpandasafety + self.safety.set_safety_hooks(Panda.SAFETY_FAW, 0) + self.safety.init_tests() + + # TODO: implement + #def test_spam_cancel_safety_check(self): + # self.safety.set_controls_allowed(0) + # self.assertTrue(self._tx(self._gra_acc_01_msg(cancel=1))) + # self.assertFalse(self._tx(self._gra_acc_01_msg(resume=1))) + # self.assertFalse(self._tx(self._gra_acc_01_msg(_set=1))) + # # do not block resume if we are engaged already + # self.safety.set_controls_allowed(1) + # self.assertTrue(self._tx(self._gra_acc_01_msg(resume=1))) + + +if __name__ == "__main__": + unittest.main() From 415a3d8e23a65ce8c75604afb4fc360b55d5c977 Mon Sep 17 00:00:00 2001 From: Jason Young Date: Mon, 21 Mar 2022 05:01:24 -0400 Subject: [PATCH 02/26] GC old comment --- board/safety/safety_faw.h | 1 - 1 file changed, 1 deletion(-) diff --git a/board/safety/safety_faw.h b/board/safety/safety_faw.h index af5728ebd2..6eb5a69006 100644 --- a/board/safety/safety_faw.h +++ b/board/safety/safety_faw.h @@ -13,7 +13,6 @@ const int FAW_DRIVER_TORQUE_FACTOR = 3; #define MSG_LKAS 0x112 // TX from openpilot, for LKAS torque #define MSG_EPS_2 0x150 // RX from EPS, torque inputs and outputs -// Transmit of GRA_ACC_01 is allowed on bus 0 and 2 to keep compatibility with gateway and camera integration const CanMsg FAW_TX_MSGS[] = {{MSG_LKAS, 0, 8}}; #define FAW_TX_MSGS_LEN (sizeof(FAW_TX_MSGS) / sizeof(FAW_TX_MSGS[0])) From 9b831f4ac40f93040f9f38053650028e9b70ba9f Mon Sep 17 00:00:00 2001 From: Jason Young Date: Mon, 21 Mar 2022 05:04:36 -0400 Subject: [PATCH 03/26] GC old comment --- tests/safety/test_faw.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/safety/test_faw.py b/tests/safety/test_faw.py index 31f824ffcb..ecc3076986 100755 --- a/tests/safety/test_faw.py +++ b/tests/safety/test_faw.py @@ -199,10 +199,6 @@ def test_torque_measurements(self): def test_rx_hook(self): # checksum checks - # TODO: Would be ideal to check ESP_19 as well, but it has no checksum - # or counter, and I'm not sure if we can easily validate Panda's simple - # temporal reception-rate check here. - # TODO: add gas message to this list for msg in [MSG_EPS_2, MSG_ABS_2, MSG_ACC, MSG_ECM_1, MSG_ABS_1]: self.safety.set_controls_allowed(1) if msg == MSG_EPS_2: From 2c795f3d72b5d5b2cfff883288325abc2a271077 Mon Sep 17 00:00:00 2001 From: Jason Young Date: Mon, 21 Mar 2022 05:33:54 -0400 Subject: [PATCH 04/26] MISRA letting me off easy today --- board/safety/safety_faw.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/board/safety/safety_faw.h b/board/safety/safety_faw.h index 6eb5a69006..927f05cbb3 100644 --- a/board/safety/safety_faw.h +++ b/board/safety/safety_faw.h @@ -100,12 +100,12 @@ static int faw_rx_hook(CANPacket_t *to_push) { // Signal: ECM_1.DRIVER_THROTTLE if (addr == MSG_ECM_1) { - gas_pressed = GET_BYTE(to_push, 5) != 0; + gas_pressed = (GET_BYTE(to_push, 5) != 0); } // Signal: ABS_2.BRAKE_PRESSURE if (addr == MSG_ABS_2) { - brake_pressed = GET_BYTE(to_push, 5) != 0; + brake_pressed = (GET_BYTE(to_push, 5) != 0); } generic_rx_checks((addr == MSG_LKAS)); From e57d1bc1d2aa31e4d8826b24d8eb476dde5b14bb Mon Sep 17 00:00:00 2001 From: Jason Young Date: Wed, 23 Mar 2022 02:38:33 -0400 Subject: [PATCH 05/26] blind test --- board/safety/safety_faw.h | 37 ++++++++++++++++++++----------------- tests/safety/test_faw.py | 2 +- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/board/safety/safety_faw.h b/board/safety/safety_faw.h index 927f05cbb3..07590a6fb3 100644 --- a/board/safety/safety_faw.h +++ b/board/safety/safety_faw.h @@ -20,7 +20,7 @@ AddrCheckStruct faw_addr_checks[] = { {.msg = {{MSG_ECM_1, 0, 8, .check_checksum = true, .max_counter = 15U, .expected_timestep = 10000U}, { 0 }, { 0 }}}, {.msg = {{MSG_ABS_1, 0, 8, .check_checksum = true, .max_counter = 15U, .expected_timestep = 10000U}, { 0 }, { 0 }}}, {.msg = {{MSG_ABS_2, 0, 8, .check_checksum = true, .max_counter = 15U, .expected_timestep = 10000U}, { 0 }, { 0 }}}, - {.msg = {{MSG_ACC, 0, 8, .check_checksum = true, .max_counter = 15U, .expected_timestep = 20000U}, { 0 }, { 0 }}}, + {.msg = {{MSG_ACC, 2, 8, .check_checksum = true, .max_counter = 15U, .expected_timestep = 20000U}, { 0 }, { 0 }}}, {.msg = {{MSG_EPS_2, 0, 8, .check_checksum = true, .max_counter = 15U, .expected_timestep = 20000U}, { 0 }, { 0 }}}, }; #define FAW_ADDR_CHECKS_LEN (sizeof(faw_addr_checks) / sizeof(faw_addr_checks[0])) @@ -57,10 +57,26 @@ static const addr_checks* faw_init(int16_t param) { static int faw_rx_hook(CANPacket_t *to_push) { bool valid = addr_safety_check(to_push, &faw_rx_checks, faw_get_checksum, faw_compute_checksum, faw_get_counter); + int bus = GET_BUS(to_push); + int addr = GET_ADDR(to_push); - if (valid && (GET_BUS(to_push) == 0U)) { - int addr = GET_ADDR(to_push); + if (valid && (bus == 2U)) { + // Enter controls on rising edge of stock ACC, exit controls if stock ACC disengages + // Signal: ACC.STATUS + if (addr == MSG_ACC) { + int acc_status = (GET_BYTE(to_push, 4) & 0x7CU) >> 2; + int cruise_engaged = acc_status == 20; + if (cruise_engaged && !cruise_engaged_prev) { + controls_allowed = 1; + } + if (!cruise_engaged) { + controls_allowed = 0; + } + cruise_engaged_prev = cruise_engaged; + } + } + if (valid && (bus == 0U)) { // Update in-motion state by sampling front wheel speeds // Signal: ABS_1.FRONT_LEFT in scaled km/h // Signal: ABS_1.FRONT_RIGHT in scaled km/h @@ -84,20 +100,6 @@ static int faw_rx_hook(CANPacket_t *to_push) { update_sample(&torque_driver, torque_driver_new); } - // Enter controls on rising edge of stock ACC, exit controls if stock ACC disengages - // Signal: ACC.STATUS - if (addr == MSG_ACC) { - int acc_status = (GET_BYTE(to_push, 4) & 0x7CU) >> 2; - int cruise_engaged = acc_status == 20; - if (cruise_engaged && !cruise_engaged_prev) { - controls_allowed = 1; - } - if (!cruise_engaged) { - controls_allowed = 0; - } - cruise_engaged_prev = cruise_engaged; - } - // Signal: ECM_1.DRIVER_THROTTLE if (addr == MSG_ECM_1) { gas_pressed = (GET_BYTE(to_push, 5) != 0); @@ -110,6 +112,7 @@ static int faw_rx_hook(CANPacket_t *to_push) { generic_rx_checks((addr == MSG_LKAS)); } + return valid; } diff --git a/tests/safety/test_faw.py b/tests/safety/test_faw.py index ecc3076986..619779ae18 100755 --- a/tests/safety/test_faw.py +++ b/tests/safety/test_faw.py @@ -68,7 +68,7 @@ def _gas_msg(self, gas): def _pcm_status_msg(self, enable): values = {"STATUS": 20 if enable else 11, "COUNTER": self.cnt_acc % 16} self.__class__.cnt_acc += 1 - return self.packer.make_can_msg_panda("ACC", 0, values) + return self.packer.make_can_msg_panda("ACC", 2, values) # Driver steering input torque def _eps_2_msg(self, torque): From e171095c1bda342215ff8a19a9e6c11cf36c10bd Mon Sep 17 00:00:00 2001 From: Jason Young Date: Fri, 5 Aug 2022 22:18:21 -0400 Subject: [PATCH 06/26] follow refactoring --- board/safety/safety_faw.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/board/safety/safety_faw.h b/board/safety/safety_faw.h index 07590a6fb3..6a98bdf43a 100644 --- a/board/safety/safety_faw.h +++ b/board/safety/safety_faw.h @@ -27,7 +27,7 @@ AddrCheckStruct faw_addr_checks[] = { addr_checks faw_rx_checks = {faw_addr_checks, FAW_ADDR_CHECKS_LEN}; -static uint8_t faw_get_checksum(CANPacket_t *to_push) { +static uint32_t faw_get_checksum(CANPacket_t *to_push) { return (uint8_t)GET_BYTE(to_push, 0); } @@ -35,7 +35,7 @@ static uint8_t faw_get_counter(CANPacket_t *to_push) { return ((uint8_t)GET_BYTE(to_push, 7) >> 4) & 0xFU; } -static uint8_t faw_compute_checksum(CANPacket_t *to_push) { +static uint32_t faw_compute_checksum(CANPacket_t *to_push) { int len = GET_LEN(to_push); int checksum = 0; @@ -46,11 +46,9 @@ static uint8_t faw_compute_checksum(CANPacket_t *to_push) { return checksum; } -static const addr_checks* faw_init(int16_t param) { +static const addr_checks* faw_init(uint16_t param) { UNUSED(param); - controls_allowed = false; - relay_malfunction_reset(); return &faw_rx_checks; } @@ -116,7 +114,9 @@ static int faw_rx_hook(CANPacket_t *to_push) { return valid; } -static int faw_tx_hook(CANPacket_t *to_send) { +static int faw_tx_hook(CANPacket_t *to_send, bool longitudinal_allowed) { + UNUSED(longitudinal_allowed); + int addr = GET_ADDR(to_send); int tx = 1; From 4b7925768d6f079d74248a572f0c14dd129aa498 Mon Sep 17 00:00:00 2001 From: Jason Young Date: Fri, 5 Aug 2022 23:19:18 -0400 Subject: [PATCH 07/26] clean up commonized tests --- tests/safety/test_faw.py | 115 ++++----------------------------------- 1 file changed, 12 insertions(+), 103 deletions(-) diff --git a/tests/safety/test_faw.py b/tests/safety/test_faw.py index 619779ae18..9ef21225cb 100755 --- a/tests/safety/test_faw.py +++ b/tests/safety/test_faw.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 import unittest -import numpy as np from panda import Panda from panda.tests.safety import libpandasafety_py import panda.tests.safety.common as common @@ -23,7 +22,7 @@ MSG_EPS_2 = 0x150 # RX from EPS, torque inputs and outputs -class TestFawSafety(common.PandaSafetyTest): +class TestFawSafety(common.PandaSafetyTest, common.DriverTorqueSteeringSafetyTest): cnt_ecm_1 = 0 cnt_abs_1 = 0 cnt_abs_2 = 0 @@ -42,10 +41,6 @@ def setUpClass(cls): cls.safety = None raise unittest.SkipTest - def _set_prev_torque(self, t): - self.safety.set_desired_torque_last(t) - self.safety.set_rt_torque_last(t) - # Wheel speeds def _speed_msg(self, speed): values = {"FRONT_LEFT": speed, "FRONT_RIGHT": speed, "COUNTER": self.cnt_abs_1 % 16} @@ -53,13 +48,13 @@ def _speed_msg(self, speed): return self.packer.make_can_msg_panda("ABS_1", 0, values) # Brake pressed - def _brake_msg(self, brake): + def _user_brake_msg(self, brake): values = {"BRAKE_PRESSURE": brake, "COUNTER": self.cnt_abs_2 % 16} self.__class__.cnt_abs_2 += 1 return self.packer.make_can_msg_panda("ABS_2", 0, values) # Driver throttle input - def _gas_msg(self, gas): + def _user_gas_msg(self, gas): values = {"DRIVER_THROTTLE": gas, "COUNTER": self.cnt_ecm_1 % 16} self.__class__.cnt_ecm_1 += 1 return self.packer.make_can_msg_panda("ECM_1", 0, values) @@ -78,7 +73,7 @@ def _eps_2_msg(self, torque): return self.packer.make_can_msg_panda("EPS_2", 0, values) # openpilot steering output torque - def _lkas_msg(self, torque): + def _torque_cmd_msg(self, torque, steer_req=1): values = {"LKAS_TORQUE": abs(torque), "LKAS_TORQUE_DIRECTION": torque < 0, "COUNTER": self.cnt_lkas % 16} self.__class__.cnt_lkas += 1 @@ -92,92 +87,6 @@ def _lkas_msg(self, torque): # self.__class__.cnt_gra_acc_01 += 1 # return self.packer.make_can_msg_panda("GRA_ACC_01", 0, values) - def test_steer_safety_check(self): - for enabled in [0, 1]: - for t in range(-500, 500): - self.safety.set_controls_allowed(enabled) - self._set_prev_torque(t) - if abs(t) > MAX_STEER or (not enabled and abs(t) > 0): - self.assertFalse(self._tx(self._lkas_msg(t))) - else: - self.assertTrue(self._tx(self._lkas_msg(t))) - - def test_non_realtime_limit_up(self): - self.safety.set_torque_driver(0, 0) - self.safety.set_controls_allowed(True) - - self._set_prev_torque(0) - self.assertTrue(self._tx(self._lkas_msg(MAX_RATE_UP))) - self._set_prev_torque(0) - self.assertTrue(self._tx(self._lkas_msg(-MAX_RATE_UP))) - - self._set_prev_torque(0) - self.assertFalse(self._tx(self._lkas_msg(MAX_RATE_UP + 1))) - self.safety.set_controls_allowed(True) - self._set_prev_torque(0) - self.assertFalse(self._tx(self._lkas_msg(-MAX_RATE_UP - 1))) - - def test_non_realtime_limit_down(self): - self.safety.set_torque_driver(0, 0) - self.safety.set_controls_allowed(True) - - def test_against_torque_driver(self): - self.safety.set_controls_allowed(True) - - for sign in [-1, 1]: - for t in np.arange(0, DRIVER_TORQUE_ALLOWANCE + 1, 1): - t *= -sign - self.safety.set_torque_driver(t, t) - self._set_prev_torque(MAX_STEER * sign) - self.assertTrue(self._tx(self._lkas_msg(MAX_STEER * sign))) - - self.safety.set_torque_driver(DRIVER_TORQUE_ALLOWANCE + 1, DRIVER_TORQUE_ALLOWANCE + 1) - self.assertFalse(self._tx(self._lkas_msg(-MAX_STEER))) - - # spot check some individual cases - for sign in [-1, 1]: - driver_torque = (DRIVER_TORQUE_ALLOWANCE + 10) * sign - torque_desired = (MAX_STEER - 10 * DRIVER_TORQUE_FACTOR) * sign - delta = 1 * sign - self._set_prev_torque(torque_desired) - self.safety.set_torque_driver(-driver_torque, -driver_torque) - self.assertTrue(self._tx(self._lkas_msg(torque_desired))) - self._set_prev_torque(torque_desired + delta) - self.safety.set_torque_driver(-driver_torque, -driver_torque) - self.assertFalse(self._tx(self._lkas_msg(torque_desired + delta))) - - self._set_prev_torque(MAX_STEER * sign) - self.safety.set_torque_driver(-MAX_STEER * sign, -MAX_STEER * sign) - self.assertTrue(self._tx(self._lkas_msg((MAX_STEER - MAX_RATE_DOWN) * sign))) - self._set_prev_torque(MAX_STEER * sign) - self.safety.set_torque_driver(-MAX_STEER * sign, -MAX_STEER * sign) - self.assertTrue(self._tx(self._lkas_msg(0))) - self._set_prev_torque(MAX_STEER * sign) - self.safety.set_torque_driver(-MAX_STEER * sign, -MAX_STEER * sign) - self.assertFalse(self._tx(self._lkas_msg((MAX_STEER - MAX_RATE_DOWN + 1) * sign))) - - def test_realtime_limits(self): - self.safety.set_controls_allowed(True) - - for sign in [-1, 1]: - self.safety.init_tests() - self._set_prev_torque(0) - self.safety.set_torque_driver(0, 0) - for t in np.arange(0, MAX_RT_DELTA, 1): - t *= sign - self.assertTrue(self._tx(self._lkas_msg(t))) - self.assertFalse(self._tx(self._lkas_msg(sign * (MAX_RT_DELTA + 1)))) - - self._set_prev_torque(0) - for t in np.arange(0, MAX_RT_DELTA, 1): - t *= sign - self.assertTrue(self._tx(self._lkas_msg(t))) - - # Increase timer to update rt_torque_last - self.safety.set_timer(RT_INTERVAL + 1) - self.assertTrue(self._tx(self._lkas_msg(sign * (MAX_RT_DELTA - 1)))) - self.assertTrue(self._tx(self._lkas_msg(sign * (MAX_RT_DELTA + 1)))) - def test_torque_measurements(self): self._rx(self._eps_2_msg(50)) self._rx(self._eps_2_msg(-50)) @@ -204,11 +113,11 @@ def test_rx_hook(self): if msg == MSG_EPS_2: to_push = self._eps_2_msg(0) if msg == MSG_ABS_2: - to_push = self._brake_msg(False) + to_push = self._user_brake_msg(False) if msg == MSG_ACC: to_push = self._pcm_status_msg(True) if msg == MSG_ECM_1: - to_push = self._gas_msg(0) + to_push = self._user_gas_msg(0) if msg == MSG_ABS_1: to_push = self._speed_msg(0) self.assertTrue(self._rx(to_push)) @@ -227,15 +136,15 @@ def test_rx_hook(self): if i < MAX_WRONG_COUNTERS: self.safety.set_controls_allowed(1) self._rx(self._eps_2_msg(0)) - self._rx(self._brake_msg(False)) + self._rx(self._user_brake_msg(False)) self._rx(self._pcm_status_msg(True)) - self._rx(self._gas_msg(0)) + self._rx(self._user_gas_msg(0)) self._rx(self._speed_msg(0)) else: self.assertFalse(self._rx(self._eps_2_msg(0))) - self.assertFalse(self._rx(self._brake_msg(False))) + self.assertFalse(self._rx(self._user_brake_msg(False))) self.assertFalse(self._rx(self._pcm_status_msg(True))) - self.assertFalse(self._rx(self._gas_msg(0))) + self.assertFalse(self._rx(self._user_gas_msg(0))) self.assertFalse(self._rx(self._speed_msg(0))) self.assertFalse(self.safety.get_controls_allowed()) @@ -243,9 +152,9 @@ def test_rx_hook(self): for i in range(2): self.safety.set_controls_allowed(1) self._rx(self._eps_2_msg(0)) - self._rx(self._brake_msg(False)) + self._rx(self._user_brake_msg(False)) self._rx(self._pcm_status_msg(True)) - self._rx(self._gas_msg(0)) + self._rx(self._user_gas_msg(0)) self._rx(self._speed_msg(0)) self.assertTrue(self.safety.get_controls_allowed()) From 20cf44b8af68ad88a8ff5c2b1b061fcfa981c1d4 Mon Sep 17 00:00:00 2001 From: Jason Young Date: Sat, 6 Aug 2022 00:19:10 -0400 Subject: [PATCH 08/26] more commonized tests, GET_BIT usage --- board/safety/safety_faw.h | 2 +- tests/safety/test_faw.py | 44 +++++++++++++++++++-------------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/board/safety/safety_faw.h b/board/safety/safety_faw.h index 6a98bdf43a..fca91a3a4e 100644 --- a/board/safety/safety_faw.h +++ b/board/safety/safety_faw.h @@ -91,7 +91,7 @@ static int faw_rx_hook(CANPacket_t *to_push) { // Signal: EPS_2.EPS_TORQUE_DIRECTION (direction) (FIXME: may not be the correct direction signal) if (addr == MSG_EPS_2) { int torque_driver_new = GET_BYTE(to_push, 4); - int sign = (GET_BYTE(to_push, 2) & 0x4U) >> 2; + int sign = GET_BIT(to_push, 18); if (sign == 1) { torque_driver_new *= -1; } diff --git a/tests/safety/test_faw.py b/tests/safety/test_faw.py index 9ef21225cb..13c0aebd8c 100755 --- a/tests/safety/test_faw.py +++ b/tests/safety/test_faw.py @@ -5,15 +5,6 @@ import panda.tests.safety.common as common from panda.tests.safety.common import CANPackerPanda, MAX_WRONG_COUNTERS -MAX_RATE_UP = 3 -MAX_RATE_DOWN = 3 -MAX_STEER = 300 -MAX_RT_DELTA = 56 -RT_INTERVAL = 250000 - -DRIVER_TORQUE_ALLOWANCE = 25 -DRIVER_TORQUE_FACTOR = 3 - MSG_ECM_1 = 0x92 # RX from ECM, for gas pedal MSG_ABS_1 = 0xC0 # RX from ABS, for wheel speeds MSG_ABS_2 = 0xC2 # RX from ABS, for wheel speeds and braking @@ -34,6 +25,15 @@ class TestFawSafety(common.PandaSafetyTest, common.DriverTorqueSteeringSafetyTes RELAY_MALFUNCTION_ADDR = MSG_LKAS RELAY_MALFUNCTION_BUS = 0 + MAX_RATE_UP = 3 + MAX_RATE_DOWN = 3 + MAX_TORQUE = 300 + MAX_RT_DELTA = 56 + RT_INTERVAL = 250000 + + DRIVER_TORQUE_ALLOWANCE = 25 + DRIVER_TORQUE_FACTOR = 3 + @classmethod def setUpClass(cls): if cls.__name__ == "TestFawSafety": @@ -66,7 +66,7 @@ def _pcm_status_msg(self, enable): return self.packer.make_can_msg_panda("ACC", 2, values) # Driver steering input torque - def _eps_2_msg(self, torque): + def _torque_driver_msg(self, torque): values = {"DRIVER_INPUT_TORQUE": abs(torque), "EPS_TORQUE_DIRECTION": torque < 0, "COUNTER": self.cnt_eps_2 % 16} self.__class__.cnt_eps_2 += 1 @@ -88,21 +88,21 @@ def _torque_cmd_msg(self, torque, steer_req=1): # return self.packer.make_can_msg_panda("GRA_ACC_01", 0, values) def test_torque_measurements(self): - self._rx(self._eps_2_msg(50)) - self._rx(self._eps_2_msg(-50)) - self._rx(self._eps_2_msg(0)) - self._rx(self._eps_2_msg(0)) - self._rx(self._eps_2_msg(0)) - self._rx(self._eps_2_msg(0)) + self._rx(self._torque_driver_msg(50)) + self._rx(self._torque_driver_msg(-50)) + self._rx(self._torque_driver_msg(0)) + self._rx(self._torque_driver_msg(0)) + self._rx(self._torque_driver_msg(0)) + self._rx(self._torque_driver_msg(0)) self.assertEqual(-50, self.safety.get_torque_driver_min()) self.assertEqual(50, self.safety.get_torque_driver_max()) - self._rx(self._eps_2_msg(0)) + self._rx(self._torque_driver_msg(0)) self.assertEqual(0, self.safety.get_torque_driver_max()) self.assertEqual(-50, self.safety.get_torque_driver_min()) - self._rx(self._eps_2_msg(0)) + self._rx(self._torque_driver_msg(0)) self.assertEqual(0, self.safety.get_torque_driver_max()) self.assertEqual(0, self.safety.get_torque_driver_min()) @@ -111,7 +111,7 @@ def test_rx_hook(self): for msg in [MSG_EPS_2, MSG_ABS_2, MSG_ACC, MSG_ECM_1, MSG_ABS_1]: self.safety.set_controls_allowed(1) if msg == MSG_EPS_2: - to_push = self._eps_2_msg(0) + to_push = self._torque_driver_msg(0) if msg == MSG_ABS_2: to_push = self._user_brake_msg(False) if msg == MSG_ACC: @@ -135,13 +135,13 @@ def test_rx_hook(self): self.__class__.cnt_abs_1 += 1 if i < MAX_WRONG_COUNTERS: self.safety.set_controls_allowed(1) - self._rx(self._eps_2_msg(0)) + self._rx(self._torque_driver_msg(0)) self._rx(self._user_brake_msg(False)) self._rx(self._pcm_status_msg(True)) self._rx(self._user_gas_msg(0)) self._rx(self._speed_msg(0)) else: - self.assertFalse(self._rx(self._eps_2_msg(0))) + self.assertFalse(self._rx(self._torque_driver_msg(0))) self.assertFalse(self._rx(self._user_brake_msg(False))) self.assertFalse(self._rx(self._pcm_status_msg(True))) self.assertFalse(self._rx(self._user_gas_msg(0))) @@ -151,7 +151,7 @@ def test_rx_hook(self): # restore counters for future tests with a couple of good messages for i in range(2): self.safety.set_controls_allowed(1) - self._rx(self._eps_2_msg(0)) + self._rx(self._torque_driver_msg(0)) self._rx(self._user_brake_msg(False)) self._rx(self._pcm_status_msg(True)) self._rx(self._user_gas_msg(0)) From 0484fce0d14fb9a1b784efb00899af0de1e8cb74 Mon Sep 17 00:00:00 2001 From: Jason Young Date: Sat, 6 Aug 2022 00:27:59 -0400 Subject: [PATCH 09/26] MISRA --- board/safety/safety_faw.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/board/safety/safety_faw.h b/board/safety/safety_faw.h index fca91a3a4e..6bf006bb23 100644 --- a/board/safety/safety_faw.h +++ b/board/safety/safety_faw.h @@ -55,8 +55,8 @@ static const addr_checks* faw_init(uint16_t param) { static int faw_rx_hook(CANPacket_t *to_push) { bool valid = addr_safety_check(to_push, &faw_rx_checks, faw_get_checksum, faw_compute_checksum, faw_get_counter); - int bus = GET_BUS(to_push); - int addr = GET_ADDR(to_push); + unsigned int bus = GET_BUS(to_push); + unsigned int addr = GET_ADDR(to_push); if (valid && (bus == 2U)) { // Enter controls on rising edge of stock ACC, exit controls if stock ACC disengages @@ -91,7 +91,7 @@ static int faw_rx_hook(CANPacket_t *to_push) { // Signal: EPS_2.EPS_TORQUE_DIRECTION (direction) (FIXME: may not be the correct direction signal) if (addr == MSG_EPS_2) { int torque_driver_new = GET_BYTE(to_push, 4); - int sign = GET_BIT(to_push, 18); + int sign = GET_BIT(to_push, 18U); if (sign == 1) { torque_driver_new *= -1; } @@ -100,12 +100,12 @@ static int faw_rx_hook(CANPacket_t *to_push) { // Signal: ECM_1.DRIVER_THROTTLE if (addr == MSG_ECM_1) { - gas_pressed = (GET_BYTE(to_push, 5) != 0); + gas_pressed = (GET_BYTE(to_push, 5) != 0U); } // Signal: ABS_2.BRAKE_PRESSURE if (addr == MSG_ABS_2) { - brake_pressed = (GET_BYTE(to_push, 5) != 0); + brake_pressed = (GET_BYTE(to_push, 5) != 0U); } generic_rx_checks((addr == MSG_LKAS)); From 349a20d113e5cff07932407f51997fa44740d26f Mon Sep 17 00:00:00 2001 From: Jason Young Date: Sat, 6 Aug 2022 00:29:12 -0400 Subject: [PATCH 10/26] bump opendbc ref --- Dockerfile.panda | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile.panda b/Dockerfile.panda index 3c12dcdcbf..4f7a323271 100644 --- a/Dockerfile.panda +++ b/Dockerfile.panda @@ -46,7 +46,7 @@ ENV LC_ALL en_US.UTF-8 RUN curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash ENV PATH="/root/.pyenv/bin:/root/.pyenv/shims:${PATH}" ENV OPENPILOT_REF="1b0167ce24afb037b36464c40f9c5e0d657e77d9" -ENV OPENDBC_REF="387dcf9628cdbcc975caece2e8b0ae1dce5e546d" +ENV OPENDBC_REF="eac83669993a6e495f46661661a2228bc1847c0d" COPY requirements.txt /tmp/ RUN pyenv install 3.8.10 && \ From 188be5a446687434c7555477532b1ebe3ddd9fe7 Mon Sep 17 00:00:00 2001 From: Jason Young Date: Sat, 6 Aug 2022 00:41:11 -0400 Subject: [PATCH 11/26] living my best submodule life --- Dockerfile.panda | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Dockerfile.panda b/Dockerfile.panda index 4f7a323271..c68b932424 100644 --- a/Dockerfile.panda +++ b/Dockerfile.panda @@ -67,7 +67,8 @@ RUN cd /tmp && \ git fetch && \ git checkout $OPENPILOT_REF && \ git submodule update --init cereal opendbc rednose_repo && \ - git -C opendbc fetch && \ + git -C opendbc remote add jyoung8607 https://github.com/jyoung8607/opendbc.git + git -C opendbc fetch jyoung8607 && \ git -C opendbc checkout $OPENDBC_REF && \ git -C opendbc reset --hard HEAD && \ git -C opendbc clean -xfd && \ From 0d78410c225b2a301b179304caaacc93852b84b5 Mon Sep 17 00:00:00 2001 From: Jason Young Date: Sat, 6 Aug 2022 00:45:20 -0400 Subject: [PATCH 12/26] detail oriented --- Dockerfile.panda | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile.panda b/Dockerfile.panda index c68b932424..e7504a6034 100644 --- a/Dockerfile.panda +++ b/Dockerfile.panda @@ -67,7 +67,7 @@ RUN cd /tmp && \ git fetch && \ git checkout $OPENPILOT_REF && \ git submodule update --init cereal opendbc rednose_repo && \ - git -C opendbc remote add jyoung8607 https://github.com/jyoung8607/opendbc.git + git -C opendbc remote add jyoung8607 https://github.com/jyoung8607/opendbc.git && \ git -C opendbc fetch jyoung8607 && \ git -C opendbc checkout $OPENDBC_REF && \ git -C opendbc reset --hard HEAD && \ From 7b66219410991c72a67f69d6279afbde5f54e5a0 Mon Sep 17 00:00:00 2001 From: Jason Young Date: Sat, 6 Aug 2022 00:59:40 -0400 Subject: [PATCH 13/26] different MISRA --- board/safety/safety_faw.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/board/safety/safety_faw.h b/board/safety/safety_faw.h index 6bf006bb23..10105f8fcd 100644 --- a/board/safety/safety_faw.h +++ b/board/safety/safety_faw.h @@ -55,10 +55,10 @@ static const addr_checks* faw_init(uint16_t param) { static int faw_rx_hook(CANPacket_t *to_push) { bool valid = addr_safety_check(to_push, &faw_rx_checks, faw_get_checksum, faw_compute_checksum, faw_get_counter); - unsigned int bus = GET_BUS(to_push); - unsigned int addr = GET_ADDR(to_push); + int bus = GET_BUS(to_push); + int addr = GET_ADDR(to_push); - if (valid && (bus == 2U)) { + if (valid && (bus == 2)) { // Enter controls on rising edge of stock ACC, exit controls if stock ACC disengages // Signal: ACC.STATUS if (addr == MSG_ACC) { @@ -74,7 +74,7 @@ static int faw_rx_hook(CANPacket_t *to_push) { } } - if (valid && (bus == 0U)) { + if (valid && (bus == 0)) { // Update in-motion state by sampling front wheel speeds // Signal: ABS_1.FRONT_LEFT in scaled km/h // Signal: ABS_1.FRONT_RIGHT in scaled km/h From cd67ef2447739a9b1ecf2c801ca9543e8157c33b Mon Sep 17 00:00:00 2001 From: Jason Young Date: Mon, 8 Aug 2022 02:41:38 -0400 Subject: [PATCH 14/26] allow magic torque value for steering disabled --- board/safety/safety_faw.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/board/safety/safety_faw.h b/board/safety/safety_faw.h index 10105f8fcd..07e10add6b 100644 --- a/board/safety/safety_faw.h +++ b/board/safety/safety_faw.h @@ -130,6 +130,10 @@ static int faw_tx_hook(CANPacket_t *to_send, bool longitudinal_allowed) { if (addr == MSG_LKAS) { int desired_torque = GET_BYTE(to_send, 1) | ((GET_BYTE(to_send, 2) & 0x3U) << 8); int sign = (GET_BYTE(to_send, 2) & 0x4U) >> 2; + // FAW sends 1022 when steering is inactive + if (desired_torque == 1022) { + desired_torque = 0; + } if (sign == 1) { desired_torque *= -1; } From db3d9a6fb90b316cbb2e61eda8953504218d6592 Mon Sep 17 00:00:00 2001 From: Jason Young Date: Mon, 8 Aug 2022 18:16:09 -0400 Subject: [PATCH 15/26] signal and counter refactor --- board/safety/safety_faw.h | 14 +++---- tests/safety/test_faw.py | 85 +++++---------------------------------- 2 files changed, 16 insertions(+), 83 deletions(-) diff --git a/board/safety/safety_faw.h b/board/safety/safety_faw.h index 07e10add6b..939b341b33 100644 --- a/board/safety/safety_faw.h +++ b/board/safety/safety_faw.h @@ -8,7 +8,7 @@ const int FAW_DRIVER_TORQUE_FACTOR = 3; #define MSG_ECM_1 0x92 // RX from ABS, for brake pressures #define MSG_ABS_1 0xC0 // RX from ABS, for wheel speeds -#define MSG_ABS_2 0xC2 // RX from ABS, for wheel speeds and braking +#define MSG_MAYBE_ABS 0x94 // RX from ABS? has brake-pressed and other signals #define MSG_ACC 0x110 // RX from ACC, for ACC engagement state #define MSG_LKAS 0x112 // TX from openpilot, for LKAS torque #define MSG_EPS_2 0x150 // RX from EPS, torque inputs and outputs @@ -19,7 +19,7 @@ const CanMsg FAW_TX_MSGS[] = {{MSG_LKAS, 0, 8}}; AddrCheckStruct faw_addr_checks[] = { {.msg = {{MSG_ECM_1, 0, 8, .check_checksum = true, .max_counter = 15U, .expected_timestep = 10000U}, { 0 }, { 0 }}}, {.msg = {{MSG_ABS_1, 0, 8, .check_checksum = true, .max_counter = 15U, .expected_timestep = 10000U}, { 0 }, { 0 }}}, - {.msg = {{MSG_ABS_2, 0, 8, .check_checksum = true, .max_counter = 15U, .expected_timestep = 10000U}, { 0 }, { 0 }}}, + {.msg = {{MSG_MAYBE_ABS, 0, 8, .check_checksum = true, .max_counter = 15U, .expected_timestep = 10000U}, { 0 }, { 0 }}}, {.msg = {{MSG_ACC, 2, 8, .check_checksum = true, .max_counter = 15U, .expected_timestep = 20000U}, { 0 }, { 0 }}}, {.msg = {{MSG_EPS_2, 0, 8, .check_checksum = true, .max_counter = 15U, .expected_timestep = 20000U}, { 0 }, { 0 }}}, }; @@ -62,8 +62,8 @@ static int faw_rx_hook(CANPacket_t *to_push) { // Enter controls on rising edge of stock ACC, exit controls if stock ACC disengages // Signal: ACC.STATUS if (addr == MSG_ACC) { - int acc_status = (GET_BYTE(to_push, 4) & 0x7CU) >> 2; - int cruise_engaged = acc_status == 20; + int acc_status = (GET_BYTE(to_push, 4) & 0xF0U) >> 4; + int cruise_engaged = (acc_status == 5); if (cruise_engaged && !cruise_engaged_prev) { controls_allowed = 1; } @@ -103,9 +103,9 @@ static int faw_rx_hook(CANPacket_t *to_push) { gas_pressed = (GET_BYTE(to_push, 5) != 0U); } - // Signal: ABS_2.BRAKE_PRESSURE - if (addr == MSG_ABS_2) { - brake_pressed = (GET_BYTE(to_push, 5) != 0U); + // Signal: MAYBE_ABS.BRAKE_PRESSED + if (addr == MSG_MAYBE_ABS) { + brake_pressed = GET_BIT(to_push, 35U); } generic_rx_checks((addr == MSG_LKAS)); diff --git a/tests/safety/test_faw.py b/tests/safety/test_faw.py index 13c0aebd8c..d47ed9d064 100755 --- a/tests/safety/test_faw.py +++ b/tests/safety/test_faw.py @@ -3,24 +3,17 @@ from panda import Panda from panda.tests.safety import libpandasafety_py import panda.tests.safety.common as common -from panda.tests.safety.common import CANPackerPanda, MAX_WRONG_COUNTERS +from panda.tests.safety.common import CANPackerPanda MSG_ECM_1 = 0x92 # RX from ECM, for gas pedal MSG_ABS_1 = 0xC0 # RX from ABS, for wheel speeds -MSG_ABS_2 = 0xC2 # RX from ABS, for wheel speeds and braking +MSG_MAYBE_ABS = 0x94 # RX from ABS? for brake pressed state MSG_ACC = 0x110 # RX from ACC, for ACC engagement state MSG_LKAS = 0x112 # TX from openpilot, for LKAS torque MSG_EPS_2 = 0x150 # RX from EPS, torque inputs and outputs class TestFawSafety(common.PandaSafetyTest, common.DriverTorqueSteeringSafetyTest): - cnt_ecm_1 = 0 - cnt_abs_1 = 0 - cnt_abs_2 = 0 - cnt_acc = 0 - cnt_lkas = 0 - cnt_eps_2 = 0 - STANDSTILL_THRESHOLD = 1 RELAY_MALFUNCTION_ADDR = MSG_LKAS RELAY_MALFUNCTION_BUS = 0 @@ -43,40 +36,32 @@ def setUpClass(cls): # Wheel speeds def _speed_msg(self, speed): - values = {"FRONT_LEFT": speed, "FRONT_RIGHT": speed, "COUNTER": self.cnt_abs_1 % 16} - self.__class__.cnt_abs_1 += 1 + values = {"FRONT_LEFT": speed, "FRONT_RIGHT": speed} return self.packer.make_can_msg_panda("ABS_1", 0, values) # Brake pressed def _user_brake_msg(self, brake): - values = {"BRAKE_PRESSURE": brake, "COUNTER": self.cnt_abs_2 % 16} - self.__class__.cnt_abs_2 += 1 - return self.packer.make_can_msg_panda("ABS_2", 0, values) + values = {"BRAKE_PRESSED": brake} + return self.packer.make_can_msg_panda("MAYBE_ABS", 0, values) # Driver throttle input def _user_gas_msg(self, gas): - values = {"DRIVER_THROTTLE": gas, "COUNTER": self.cnt_ecm_1 % 16} - self.__class__.cnt_ecm_1 += 1 + values = {"DRIVER_THROTTLE": gas} return self.packer.make_can_msg_panda("ECM_1", 0, values) # ACC engagement status def _pcm_status_msg(self, enable): - values = {"STATUS": 20 if enable else 11, "COUNTER": self.cnt_acc % 16} - self.__class__.cnt_acc += 1 + values = {"STATUS": 5 if enable else 2} return self.packer.make_can_msg_panda("ACC", 2, values) # Driver steering input torque def _torque_driver_msg(self, torque): - values = {"DRIVER_INPUT_TORQUE": abs(torque), "EPS_TORQUE_DIRECTION": torque < 0, - "COUNTER": self.cnt_eps_2 % 16} - self.__class__.cnt_eps_2 += 1 + values = {"DRIVER_INPUT_TORQUE": abs(torque), "EPS_TORQUE_DIRECTION": torque < 0} return self.packer.make_can_msg_panda("EPS_2", 0, values) # openpilot steering output torque def _torque_cmd_msg(self, torque, steer_req=1): - values = {"LKAS_TORQUE": abs(torque), "LKAS_TORQUE_DIRECTION": torque < 0, - "COUNTER": self.cnt_lkas % 16} - self.__class__.cnt_lkas += 1 + values = {"LKAS_TORQUE": abs(torque), "LKAS_TORQUE_DIRECTION": torque < 0} return self.packer.make_can_msg_panda("LKAS", 0, values) # Cruise control buttons @@ -106,58 +91,6 @@ def test_torque_measurements(self): self.assertEqual(0, self.safety.get_torque_driver_max()) self.assertEqual(0, self.safety.get_torque_driver_min()) - def test_rx_hook(self): - # checksum checks - for msg in [MSG_EPS_2, MSG_ABS_2, MSG_ACC, MSG_ECM_1, MSG_ABS_1]: - self.safety.set_controls_allowed(1) - if msg == MSG_EPS_2: - to_push = self._torque_driver_msg(0) - if msg == MSG_ABS_2: - to_push = self._user_brake_msg(False) - if msg == MSG_ACC: - to_push = self._pcm_status_msg(True) - if msg == MSG_ECM_1: - to_push = self._user_gas_msg(0) - if msg == MSG_ABS_1: - to_push = self._speed_msg(0) - self.assertTrue(self._rx(to_push)) - to_push[0].data[4] ^= 0xFF - self.assertFalse(self._rx(to_push)) - self.assertFalse(self.safety.get_controls_allowed()) - - # counter - # reset wrong_counters to zero by sending valid messages - for i in range(MAX_WRONG_COUNTERS + 1): - self.__class__.cnt_eps_2 += 1 - self.__class__.cnt_abs_2 += 1 - self.__class__.cnt_acc += 1 - self.__class__.cnt_ecm_1 += 1 - self.__class__.cnt_abs_1 += 1 - if i < MAX_WRONG_COUNTERS: - self.safety.set_controls_allowed(1) - self._rx(self._torque_driver_msg(0)) - self._rx(self._user_brake_msg(False)) - self._rx(self._pcm_status_msg(True)) - self._rx(self._user_gas_msg(0)) - self._rx(self._speed_msg(0)) - else: - self.assertFalse(self._rx(self._torque_driver_msg(0))) - self.assertFalse(self._rx(self._user_brake_msg(False))) - self.assertFalse(self._rx(self._pcm_status_msg(True))) - self.assertFalse(self._rx(self._user_gas_msg(0))) - self.assertFalse(self._rx(self._speed_msg(0))) - self.assertFalse(self.safety.get_controls_allowed()) - - # restore counters for future tests with a couple of good messages - for i in range(2): - self.safety.set_controls_allowed(1) - self._rx(self._torque_driver_msg(0)) - self._rx(self._user_brake_msg(False)) - self._rx(self._pcm_status_msg(True)) - self._rx(self._user_gas_msg(0)) - self._rx(self._speed_msg(0)) - self.assertTrue(self.safety.get_controls_allowed()) - class TestFawStockSafety(TestFawSafety): TX_MSGS = [[MSG_LKAS, 0]] From 2b8ccf4fd4a16e0d24624c3d06d0df50f7faf015 Mon Sep 17 00:00:00 2001 From: Jason Young Date: Tue, 9 Aug 2022 12:37:09 -0400 Subject: [PATCH 16/26] check all engaged states --- board/safety/safety_faw.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/board/safety/safety_faw.h b/board/safety/safety_faw.h index 939b341b33..c2ea979828 100644 --- a/board/safety/safety_faw.h +++ b/board/safety/safety_faw.h @@ -63,7 +63,7 @@ static int faw_rx_hook(CANPacket_t *to_push) { // Signal: ACC.STATUS if (addr == MSG_ACC) { int acc_status = (GET_BYTE(to_push, 4) & 0xF0U) >> 4; - int cruise_engaged = (acc_status == 5); + int cruise_engaged = ((acc_status == 4) || (acc_status == 5) || (acc_status == 6) || (acc_status == 7)); if (cruise_engaged && !cruise_engaged_prev) { controls_allowed = 1; } From 5f9fb7777939b0faab041cdf2d0c33b7fd69573f Mon Sep 17 00:00:00 2001 From: Jason Young Date: Tue, 9 Aug 2022 16:46:55 -0400 Subject: [PATCH 17/26] adjust ramp-rates and driver torque allowance --- board/safety/safety_faw.h | 8 ++++---- tests/safety/test_faw.py | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/board/safety/safety_faw.h b/board/safety/safety_faw.h index c2ea979828..4da01c2e25 100644 --- a/board/safety/safety_faw.h +++ b/board/safety/safety_faw.h @@ -1,9 +1,9 @@ const int FAW_MAX_STEER = 300; // As-yet unknown fault boundary, guessing 300 / 3.0Nm for now -const int FAW_MAX_RT_DELTA = 56; // 3 max rate up * 50Hz send rate * 250000 RT interval / 1000000 = 37.5 ; 50 * 1.5 for safety pad = 56.25 +const int FAW_MAX_RT_DELTA = 113; // 6 max rate up * 50Hz send rate * 250000 RT interval / 1000000 = 75 ; 50 * 1.5 for safety pad = 113 const uint32_t FAW_RT_INTERVAL = 250000; // 250ms between real time checks -const int FAW_MAX_RATE_UP = 3; // 3 unit/sec observed from factory LKAS, fault boundary unknown -const int FAW_MAX_RATE_DOWN = 3; // 3 unit/sec observed from factory LKAS, fault boundary unknown -const int FAW_DRIVER_TORQUE_ALLOWANCE = 25; +const int FAW_MAX_RATE_UP = 6; // 10 unit/sec observed from factory LKAS, fault boundary unknown +const int FAW_MAX_RATE_DOWN = 10; // 10 unit/sec observed from factory LKAS, fault boundary unknown +const int FAW_DRIVER_TORQUE_ALLOWANCE = 50; const int FAW_DRIVER_TORQUE_FACTOR = 3; #define MSG_ECM_1 0x92 // RX from ABS, for brake pressures diff --git a/tests/safety/test_faw.py b/tests/safety/test_faw.py index d47ed9d064..918ead06ee 100755 --- a/tests/safety/test_faw.py +++ b/tests/safety/test_faw.py @@ -18,13 +18,13 @@ class TestFawSafety(common.PandaSafetyTest, common.DriverTorqueSteeringSafetyTes RELAY_MALFUNCTION_ADDR = MSG_LKAS RELAY_MALFUNCTION_BUS = 0 - MAX_RATE_UP = 3 - MAX_RATE_DOWN = 3 + MAX_RATE_UP = 6 + MAX_RATE_DOWN = 10 MAX_TORQUE = 300 - MAX_RT_DELTA = 56 + MAX_RT_DELTA = 113 RT_INTERVAL = 250000 - DRIVER_TORQUE_ALLOWANCE = 25 + DRIVER_TORQUE_ALLOWANCE = 50 DRIVER_TORQUE_FACTOR = 3 @classmethod From f6a02bb9cef145eb28e129cc50b0402356efc79f Mon Sep 17 00:00:00 2001 From: Jason Young Date: Wed, 24 Aug 2022 14:25:53 -0400 Subject: [PATCH 18/26] faw -> hongqi --- board/safety.h | 6 +++--- board/safety/{safety_faw.h => safety_hongqi.h} | 0 tests/safety/{test_faw.py => test_hongqi.py} | 0 3 files changed, 3 insertions(+), 3 deletions(-) rename board/safety/{safety_faw.h => safety_hongqi.h} (100%) rename tests/safety/{test_faw.py => test_hongqi.py} (100%) diff --git a/board/safety.h b/board/safety.h index 4d435f553d..1751efdc56 100644 --- a/board/safety.h +++ b/board/safety.h @@ -15,7 +15,7 @@ #include "safety/safety_nissan.h" #include "safety/safety_volkswagen_mqb.h" #include "safety/safety_volkswagen_pq.h" -#include "safety/safety_faw.h" +#include "safety/safety_hongqi.h" #include "safety/safety_elm327.h" #include "safety/safety_body.h" @@ -52,7 +52,7 @@ #define SAFETY_HYUNDAI_LEGACY 23U #define SAFETY_HYUNDAI_COMMUNITY 24U #define SAFETY_STELLANTIS 25U -#define SAFETY_FAW 26U +#define SAFETY_HONGQI 26U #define SAFETY_BODY 27U #define SAFETY_HYUNDAI_CANFD 28U @@ -295,7 +295,7 @@ const safety_hook_config safety_hook_registry[] = { {SAFETY_TESLA, &tesla_hooks}, {SAFETY_SUBARU_LEGACY, &subaru_legacy_hooks}, {SAFETY_VOLKSWAGEN_PQ, &volkswagen_pq_hooks}, - {SAFETY_FAW, &faw_hooks}, + {SAFETY_HONGQI, &faw_hooks}, {SAFETY_ALLOUTPUT, &alloutput_hooks}, {SAFETY_FORD, &ford_hooks}, #endif diff --git a/board/safety/safety_faw.h b/board/safety/safety_hongqi.h similarity index 100% rename from board/safety/safety_faw.h rename to board/safety/safety_hongqi.h diff --git a/tests/safety/test_faw.py b/tests/safety/test_hongqi.py similarity index 100% rename from tests/safety/test_faw.py rename to tests/safety/test_hongqi.py From 7c633b066024c7d8573fd6b22c4884d89a80fb48 Mon Sep 17 00:00:00 2001 From: Jason Young Date: Wed, 24 Aug 2022 14:50:03 -0400 Subject: [PATCH 19/26] more renaming --- board/safety.h | 2 +- board/safety/safety_hongqi.h | 66 ++++++++++++++++++------------------ python/__init__.py | 2 +- tests/safety/test_hongqi.py | 10 +++--- 4 files changed, 40 insertions(+), 40 deletions(-) diff --git a/board/safety.h b/board/safety.h index 1751efdc56..c9a721f1b9 100644 --- a/board/safety.h +++ b/board/safety.h @@ -295,7 +295,7 @@ const safety_hook_config safety_hook_registry[] = { {SAFETY_TESLA, &tesla_hooks}, {SAFETY_SUBARU_LEGACY, &subaru_legacy_hooks}, {SAFETY_VOLKSWAGEN_PQ, &volkswagen_pq_hooks}, - {SAFETY_HONGQI, &faw_hooks}, + {SAFETY_HONGQI, &hongqi_hooks}, {SAFETY_ALLOUTPUT, &alloutput_hooks}, {SAFETY_FORD, &ford_hooks}, #endif diff --git a/board/safety/safety_hongqi.h b/board/safety/safety_hongqi.h index 4da01c2e25..38cb02824f 100644 --- a/board/safety/safety_hongqi.h +++ b/board/safety/safety_hongqi.h @@ -1,10 +1,10 @@ -const int FAW_MAX_STEER = 300; // As-yet unknown fault boundary, guessing 300 / 3.0Nm for now -const int FAW_MAX_RT_DELTA = 113; // 6 max rate up * 50Hz send rate * 250000 RT interval / 1000000 = 75 ; 50 * 1.5 for safety pad = 113 -const uint32_t FAW_RT_INTERVAL = 250000; // 250ms between real time checks -const int FAW_MAX_RATE_UP = 6; // 10 unit/sec observed from factory LKAS, fault boundary unknown -const int FAW_MAX_RATE_DOWN = 10; // 10 unit/sec observed from factory LKAS, fault boundary unknown -const int FAW_DRIVER_TORQUE_ALLOWANCE = 50; -const int FAW_DRIVER_TORQUE_FACTOR = 3; +const int HONGQI_MAX_STEER = 300; // As-yet unknown fault boundary, guessing 300 / 3.0Nm for now +const int HONGQI_MAX_RT_DELTA = 113; // 6 max rate up * 50Hz send rate * 250000 RT interval / 1000000 = 75 ; 50 * 1.5 for safety pad = 113 +const uint32_t HONGQI_RT_INTERVAL = 250000; // 250ms between real time checks +const int HONGQI_MAX_RATE_UP = 6; // 10 unit/sec observed from factory LKAS, fault boundary unknown +const int HONGQI_MAX_RATE_DOWN = 10; // 10 unit/sec observed from factory LKAS, fault boundary unknown +const int HONGQI_DRIVER_TORQUE_ALLOWANCE = 50; +const int HONGQI_DRIVER_TORQUE_FACTOR = 3; #define MSG_ECM_1 0x92 // RX from ABS, for brake pressures #define MSG_ABS_1 0xC0 // RX from ABS, for wheel speeds @@ -13,29 +13,29 @@ const int FAW_DRIVER_TORQUE_FACTOR = 3; #define MSG_LKAS 0x112 // TX from openpilot, for LKAS torque #define MSG_EPS_2 0x150 // RX from EPS, torque inputs and outputs -const CanMsg FAW_TX_MSGS[] = {{MSG_LKAS, 0, 8}}; -#define FAW_TX_MSGS_LEN (sizeof(FAW_TX_MSGS) / sizeof(FAW_TX_MSGS[0])) +const CanMsg HONGQI_TX_MSGS[] = {{MSG_LKAS, 0, 8}}; +#define HONGQI_TX_MSGS_LEN (sizeof(HONGQI_TX_MSGS) / sizeof(HONGQI_TX_MSGS[0])) -AddrCheckStruct faw_addr_checks[] = { +AddrCheckStruct hongqi_addr_checks[] = { {.msg = {{MSG_ECM_1, 0, 8, .check_checksum = true, .max_counter = 15U, .expected_timestep = 10000U}, { 0 }, { 0 }}}, {.msg = {{MSG_ABS_1, 0, 8, .check_checksum = true, .max_counter = 15U, .expected_timestep = 10000U}, { 0 }, { 0 }}}, {.msg = {{MSG_MAYBE_ABS, 0, 8, .check_checksum = true, .max_counter = 15U, .expected_timestep = 10000U}, { 0 }, { 0 }}}, {.msg = {{MSG_ACC, 2, 8, .check_checksum = true, .max_counter = 15U, .expected_timestep = 20000U}, { 0 }, { 0 }}}, {.msg = {{MSG_EPS_2, 0, 8, .check_checksum = true, .max_counter = 15U, .expected_timestep = 20000U}, { 0 }, { 0 }}}, }; -#define FAW_ADDR_CHECKS_LEN (sizeof(faw_addr_checks) / sizeof(faw_addr_checks[0])) -addr_checks faw_rx_checks = {faw_addr_checks, FAW_ADDR_CHECKS_LEN}; +#define HONGQI_ADDR_CHECKS_LEN (sizeof(hongqi_addr_checks) / sizeof(hongqi_addr_checks[0])) +addr_checks hongqi_rx_checks = {hongqi_addr_checks, HONGQI_ADDR_CHECKS_LEN}; -static uint32_t faw_get_checksum(CANPacket_t *to_push) { +static uint32_t hongqi_get_checksum(CANPacket_t *to_push) { return (uint8_t)GET_BYTE(to_push, 0); } -static uint8_t faw_get_counter(CANPacket_t *to_push) { +static uint8_t hongqi_get_counter(CANPacket_t *to_push) { return ((uint8_t)GET_BYTE(to_push, 7) >> 4) & 0xFU; } -static uint32_t faw_compute_checksum(CANPacket_t *to_push) { +static uint32_t hongqi_compute_checksum(CANPacket_t *to_push) { int len = GET_LEN(to_push); int checksum = 0; @@ -46,15 +46,15 @@ static uint32_t faw_compute_checksum(CANPacket_t *to_push) { return checksum; } -static const addr_checks* faw_init(uint16_t param) { +static const addr_checks* hongqi_init(uint16_t param) { UNUSED(param); - return &faw_rx_checks; + return &hongqi_rx_checks; } -static int faw_rx_hook(CANPacket_t *to_push) { +static int hongqi_rx_hook(CANPacket_t *to_push) { - bool valid = addr_safety_check(to_push, &faw_rx_checks, faw_get_checksum, faw_compute_checksum, faw_get_counter); + bool valid = addr_safety_check(to_push, &hongqi_rx_checks, hongqi_get_checksum, hongqi_compute_checksum, hongqi_get_counter); int bus = GET_BUS(to_push); int addr = GET_ADDR(to_push); @@ -114,13 +114,13 @@ static int faw_rx_hook(CANPacket_t *to_push) { return valid; } -static int faw_tx_hook(CANPacket_t *to_send, bool longitudinal_allowed) { +static int hongqi_tx_hook(CANPacket_t *to_send, bool longitudinal_allowed) { UNUSED(longitudinal_allowed); int addr = GET_ADDR(to_send); int tx = 1; - if (!msg_allowed(to_send, FAW_TX_MSGS, FAW_TX_MSGS_LEN)) { + if (!msg_allowed(to_send, HONGQI_TX_MSGS, HONGQI_TX_MSGS_LEN)) { tx = 0; } @@ -130,7 +130,7 @@ static int faw_tx_hook(CANPacket_t *to_send, bool longitudinal_allowed) { if (addr == MSG_LKAS) { int desired_torque = GET_BYTE(to_send, 1) | ((GET_BYTE(to_send, 2) & 0x3U) << 8); int sign = (GET_BYTE(to_send, 2) & 0x4U) >> 2; - // FAW sends 1022 when steering is inactive + // Hongqi sends 1022 when steering is inactive if (desired_torque == 1022) { desired_torque = 0; } @@ -143,20 +143,20 @@ static int faw_tx_hook(CANPacket_t *to_send, bool longitudinal_allowed) { if (controls_allowed) { // *** global torque limit check *** - violation |= max_limit_check(desired_torque, FAW_MAX_STEER, -FAW_MAX_STEER); + violation |= max_limit_check(desired_torque, HONGQI_MAX_STEER, -HONGQI_MAX_STEER); // *** torque rate limit check *** violation |= driver_limit_check(desired_torque, desired_torque_last, &torque_driver, - FAW_MAX_STEER, FAW_MAX_RATE_UP, FAW_MAX_RATE_DOWN, - FAW_DRIVER_TORQUE_ALLOWANCE, FAW_DRIVER_TORQUE_FACTOR); + HONGQI_MAX_STEER, HONGQI_MAX_RATE_UP, HONGQI_MAX_RATE_DOWN, + HONGQI_DRIVER_TORQUE_ALLOWANCE, HONGQI_DRIVER_TORQUE_FACTOR); desired_torque_last = desired_torque; // *** torque real time rate limit check *** - violation |= rt_rate_limit_check(desired_torque, rt_torque_last, FAW_MAX_RT_DELTA); + violation |= rt_rate_limit_check(desired_torque, rt_torque_last, HONGQI_MAX_RT_DELTA); // every RT_INTERVAL set the new limits uint32_t ts_elapsed = get_ts_elapsed(ts, ts_last); - if (ts_elapsed > FAW_RT_INTERVAL) { + if (ts_elapsed > HONGQI_RT_INTERVAL) { rt_torque_last = desired_torque; ts_last = ts; } @@ -193,7 +193,7 @@ static int faw_tx_hook(CANPacket_t *to_send, bool longitudinal_allowed) { return tx; } -static int faw_fwd_hook(int bus_num, CANPacket_t *to_fwd) { +static int hongqi_fwd_hook(int bus_num, CANPacket_t *to_fwd) { int addr = GET_ADDR(to_fwd); int bus_fwd = -1; @@ -218,10 +218,10 @@ static int faw_fwd_hook(int bus_num, CANPacket_t *to_fwd) { return bus_fwd; } -const safety_hooks faw_hooks = { - .init = faw_init, - .rx = faw_rx_hook, - .tx = faw_tx_hook, +const safety_hooks hongqi_hooks = { + .init = hongqi_init, + .rx = hongqi_rx_hook, + .tx = hongqi_tx_hook, .tx_lin = nooutput_tx_lin_hook, - .fwd = faw_fwd_hook, + .fwd = hongqi_fwd_hook, }; diff --git a/python/__init__.py b/python/__init__.py index de382f3841..9d3ecb7e26 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -148,7 +148,7 @@ class Panda: SAFETY_HYUNDAI_LEGACY = 23 SAFETY_HYUNDAI_COMMUNITY = 24 SAFETY_STELLANTIS = 25 - SAFETY_FAW = 26 + SAFETY_HONGQI = 26 SAFETY_BODY = 27 SAFETY_HYUNDAI_CANFD = 28 diff --git a/tests/safety/test_hongqi.py b/tests/safety/test_hongqi.py index 918ead06ee..bae80c70bd 100755 --- a/tests/safety/test_hongqi.py +++ b/tests/safety/test_hongqi.py @@ -13,7 +13,7 @@ MSG_EPS_2 = 0x150 # RX from EPS, torque inputs and outputs -class TestFawSafety(common.PandaSafetyTest, common.DriverTorqueSteeringSafetyTest): +class TestHongqiSafety(common.PandaSafetyTest, common.DriverTorqueSteeringSafetyTest): STANDSTILL_THRESHOLD = 1 RELAY_MALFUNCTION_ADDR = MSG_LKAS RELAY_MALFUNCTION_BUS = 0 @@ -29,7 +29,7 @@ class TestFawSafety(common.PandaSafetyTest, common.DriverTorqueSteeringSafetyTes @classmethod def setUpClass(cls): - if cls.__name__ == "TestFawSafety": + if cls.__name__ == "TestHongqiSafety": cls.packer = None cls.safety = None raise unittest.SkipTest @@ -92,15 +92,15 @@ def test_torque_measurements(self): self.assertEqual(0, self.safety.get_torque_driver_min()) -class TestFawStockSafety(TestFawSafety): +class TestHongqiStockSafety(TestHongqiSafety): TX_MSGS = [[MSG_LKAS, 0]] FWD_BLACKLISTED_ADDRS = {2: [MSG_LKAS]} FWD_BUS_LOOKUP = {0: 2, 2: 0} def setUp(self): - self.packer = CANPackerPanda("faw") + self.packer = CANPackerPanda("hongqi_hs5") self.safety = libpandasafety_py.libpandasafety - self.safety.set_safety_hooks(Panda.SAFETY_FAW, 0) + self.safety.set_safety_hooks(Panda.SAFETY_HONGQI, 0) self.safety.init_tests() # TODO: implement From 7ff1f31d0584c9b8af1265391c08d2787576b3c1 Mon Sep 17 00:00:00 2001 From: Jason Young Date: Fri, 26 Aug 2022 15:55:12 -0400 Subject: [PATCH 20/26] follow torque rate control refactor --- board/safety/safety_hongqi.h | 56 ++++++++---------------------------- 1 file changed, 12 insertions(+), 44 deletions(-) diff --git a/board/safety/safety_hongqi.h b/board/safety/safety_hongqi.h index 38cb02824f..282ffe9bb7 100644 --- a/board/safety/safety_hongqi.h +++ b/board/safety/safety_hongqi.h @@ -1,10 +1,14 @@ -const int HONGQI_MAX_STEER = 300; // As-yet unknown fault boundary, guessing 300 / 3.0Nm for now -const int HONGQI_MAX_RT_DELTA = 113; // 6 max rate up * 50Hz send rate * 250000 RT interval / 1000000 = 75 ; 50 * 1.5 for safety pad = 113 -const uint32_t HONGQI_RT_INTERVAL = 250000; // 250ms between real time checks -const int HONGQI_MAX_RATE_UP = 6; // 10 unit/sec observed from factory LKAS, fault boundary unknown -const int HONGQI_MAX_RATE_DOWN = 10; // 10 unit/sec observed from factory LKAS, fault boundary unknown -const int HONGQI_DRIVER_TORQUE_ALLOWANCE = 50; -const int HONGQI_DRIVER_TORQUE_FACTOR = 3; +// lateral limits +const SteeringLimits HONGQI_STEERING_LIMITS = { + .max_steer = 300, // As-yet unknown fault boundary, guessing 300 / 3.0Nm for now + .max_rt_delta = 113, // 6 max rate up * 50Hz send rate * 250000 RT interval / 1000000 = 75 ; 50 * 1.5 for safety pad = 113 + .max_rt_interval = 250000, // 250ms between real time checks + .max_rate_up = 6, // 10 unit/sec observed from factory LKAS, fault boundary unknown + .max_rate_down = 10, // 10 unit/sec observed from factory LKAS, fault boundary unknown + .driver_torque_allowance = 50, + .driver_torque_factor = 3, + .type = TorqueDriverLimited, +}; #define MSG_ECM_1 0x92 // RX from ABS, for brake pressures #define MSG_ABS_1 0xC0 // RX from ABS, for wheel speeds @@ -138,43 +142,7 @@ static int hongqi_tx_hook(CANPacket_t *to_send, bool longitudinal_allowed) { desired_torque *= -1; } - bool violation = false; - uint32_t ts = microsecond_timer_get(); - - if (controls_allowed) { - // *** global torque limit check *** - violation |= max_limit_check(desired_torque, HONGQI_MAX_STEER, -HONGQI_MAX_STEER); - - // *** torque rate limit check *** - violation |= driver_limit_check(desired_torque, desired_torque_last, &torque_driver, - HONGQI_MAX_STEER, HONGQI_MAX_RATE_UP, HONGQI_MAX_RATE_DOWN, - HONGQI_DRIVER_TORQUE_ALLOWANCE, HONGQI_DRIVER_TORQUE_FACTOR); - desired_torque_last = desired_torque; - - // *** torque real time rate limit check *** - violation |= rt_rate_limit_check(desired_torque, rt_torque_last, HONGQI_MAX_RT_DELTA); - - // every RT_INTERVAL set the new limits - uint32_t ts_elapsed = get_ts_elapsed(ts, ts_last); - if (ts_elapsed > HONGQI_RT_INTERVAL) { - rt_torque_last = desired_torque; - ts_last = ts; - } - } - - // no torque if controls is not allowed - if (!controls_allowed && (desired_torque != 0)) { - violation = true; - } - - // reset to 0 if either controls is not allowed or there's a violation - if (violation || !controls_allowed) { - desired_torque_last = 0; - rt_torque_last = 0; - ts_last = ts; - } - - if (violation) { + if (steer_torque_cmd_checks(desired_torque, -1, HONGQI_STEERING_LIMITS)) { tx = 0; } } From aaa6806cfdeee1498ec8315a0e657d571ea4d1fd Mon Sep 17 00:00:00 2001 From: Jason Young Date: Sat, 22 Oct 2022 18:27:00 -0400 Subject: [PATCH 21/26] follow pcm_cruise_check refactor --- board/safety/safety_hongqi.h | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/board/safety/safety_hongqi.h b/board/safety/safety_hongqi.h index 282ffe9bb7..739aa09fac 100644 --- a/board/safety/safety_hongqi.h +++ b/board/safety/safety_hongqi.h @@ -67,14 +67,8 @@ static int hongqi_rx_hook(CANPacket_t *to_push) { // Signal: ACC.STATUS if (addr == MSG_ACC) { int acc_status = (GET_BYTE(to_push, 4) & 0xF0U) >> 4; - int cruise_engaged = ((acc_status == 4) || (acc_status == 5) || (acc_status == 6) || (acc_status == 7)); - if (cruise_engaged && !cruise_engaged_prev) { - controls_allowed = 1; - } - if (!cruise_engaged) { - controls_allowed = 0; - } - cruise_engaged_prev = cruise_engaged; + bool cruise_engaged = ((acc_status == 4) || (acc_status == 5) || (acc_status == 6) || (acc_status == 7)); + pcm_cruise_check(cruise_engaged); } } From de5559acdab041ded1a71b087dc0cd06ebda43d4 Mon Sep 17 00:00:00 2001 From: Jason Young Date: Sat, 22 Oct 2022 18:27:13 -0400 Subject: [PATCH 22/26] temp hack out other safeties to build on H7 --- board/safety.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/board/safety.h b/board/safety.h index 12416c484a..7435561a9a 100644 --- a/board/safety.h +++ b/board/safety.h @@ -3,11 +3,11 @@ // include the safety policies. #include "safety/safety_defaults.h" #include "safety/safety_honda.h" -#include "safety/safety_toyota.h" +//#include "safety/safety_toyota.h" #include "safety/safety_tesla.h" #include "safety/safety_gm.h" #include "safety/safety_ford.h" -#include "safety/safety_hyundai.h" +//#include "safety/safety_hyundai.h" #include "safety/safety_chrysler.h" #include "safety/safety_subaru.h" #include "safety/safety_subaru_legacy.h" @@ -25,7 +25,7 @@ // CAN-FD only safety modes #ifdef CANFD -#include "safety/safety_hyundai_canfd.h" +//#include "safety/safety_hyundai_canfd.h" #endif // from cereal.car.CarParams.SafetyModel @@ -288,21 +288,21 @@ typedef struct { const safety_hook_config safety_hook_registry[] = { {SAFETY_SILENT, &nooutput_hooks}, {SAFETY_HONDA_NIDEC, &honda_nidec_hooks}, - {SAFETY_TOYOTA, &toyota_hooks}, +// {SAFETY_TOYOTA, &toyota_hooks}, {SAFETY_ELM327, &elm327_hooks}, {SAFETY_GM, &gm_hooks}, {SAFETY_HONDA_BOSCH, &honda_bosch_hooks}, - {SAFETY_HYUNDAI, &hyundai_hooks}, +// {SAFETY_HYUNDAI, &hyundai_hooks}, {SAFETY_CHRYSLER, &chrysler_hooks}, {SAFETY_SUBARU, &subaru_hooks}, {SAFETY_VOLKSWAGEN_MQB, &volkswagen_mqb_hooks}, {SAFETY_NISSAN, &nissan_hooks}, {SAFETY_NOOUTPUT, &nooutput_hooks}, - {SAFETY_HYUNDAI_LEGACY, &hyundai_legacy_hooks}, +// {SAFETY_HYUNDAI_LEGACY, &hyundai_legacy_hooks}, {SAFETY_MAZDA, &mazda_hooks}, {SAFETY_BODY, &body_hooks}, #ifdef CANFD - {SAFETY_HYUNDAI_CANFD, &hyundai_canfd_hooks}, +// {SAFETY_HYUNDAI_CANFD, &hyundai_canfd_hooks}, #endif #ifdef ALLOW_DEBUG {SAFETY_TESLA, &tesla_hooks}, From 804cae5c66ea3a946e833390f13968bbd8915e45 Mon Sep 17 00:00:00 2001 From: Jason Young Date: Sat, 22 Oct 2022 18:42:31 -0400 Subject: [PATCH 23/26] more temp hack outs --- tests/safety/test_hyundai.py | 203 --------------------- tests/safety/test_hyundai_canfd.py | 172 ------------------ tests/safety/test_toyota.py | 206 ---------------------- tests/safety_replay/test_safety_replay.py | 5 +- 4 files changed, 1 insertion(+), 585 deletions(-) delete mode 100755 tests/safety/test_hyundai.py delete mode 100755 tests/safety/test_hyundai_canfd.py delete mode 100755 tests/safety/test_toyota.py diff --git a/tests/safety/test_hyundai.py b/tests/safety/test_hyundai.py deleted file mode 100755 index 6c35e874d8..0000000000 --- a/tests/safety/test_hyundai.py +++ /dev/null @@ -1,203 +0,0 @@ -#!/usr/bin/env python3 -import unittest -from panda import Panda -from panda.tests.safety import libpandasafety_py -import panda.tests.safety.common as common -from panda.tests.safety.common import CANPackerPanda -from panda.tests.safety.hyundai_common import HyundaiButtonBase, HyundaiLongitudinalBase - - -# 4 bit checkusm used in some hyundai messages -# lives outside the can packer because we never send this msg -def checksum(msg): - addr, t, dat, bus = msg - - chksum = 0 - if addr == 902: - for i, b in enumerate(dat): - for j in range(8): - # exclude checksum and counter bits - if (i != 1 or j < 6) and (i != 3 or j < 6) and (i != 5 or j < 6) and (i != 7 or j < 6): - bit = (b >> j) & 1 - else: - bit = 0 - chksum += bit - chksum = (chksum ^ 9) & 0xF - ret = bytearray(dat) - ret[5] |= (chksum & 0x3) << 6 - ret[7] |= (chksum & 0xc) << 4 - else: - for i, b in enumerate(dat): - if addr in [608, 1057] and i == 7: - b &= 0x0F if addr == 1057 else 0xF0 - elif addr == 916 and i == 6: - b &= 0xF0 - elif addr == 916 and i == 7: - continue - chksum += sum(divmod(b, 16)) - chksum = (16 - chksum) % 16 - ret = bytearray(dat) - ret[6 if addr == 916 else 7] |= chksum << (4 if addr == 1057 else 0) - - return addr, t, ret, bus - - -class TestHyundaiSafety(HyundaiButtonBase, common.PandaSafetyTest, common.DriverTorqueSteeringSafetyTest): - TX_MSGS = [[832, 0], [1265, 0], [1157, 0]] - STANDSTILL_THRESHOLD = 30 # ~1kph - RELAY_MALFUNCTION_ADDR = 832 - RELAY_MALFUNCTION_BUS = 0 - FWD_BLACKLISTED_ADDRS = {2: [832, 1157]} - FWD_BUS_LOOKUP = {0: 2, 2: 0} - - MAX_RATE_UP = 3 - MAX_RATE_DOWN = 7 - MAX_TORQUE = 384 - MAX_RT_DELTA = 112 - RT_INTERVAL = 250000 - DRIVER_TORQUE_ALLOWANCE = 50 - DRIVER_TORQUE_FACTOR = 2 - - # Safety around steering req bit - MIN_VALID_STEERING_FRAMES = 89 - MAX_INVALID_STEERING_FRAMES = 2 - MIN_VALID_STEERING_RT_INTERVAL = 810000 # a ~10% buffer, can send steer up to 110Hz - - cnt_gas = 0 - cnt_speed = 0 - cnt_brake = 0 - cnt_cruise = 0 - cnt_button = 0 - - def setUp(self): - self.packer = CANPackerPanda("hyundai_kia_generic") - self.safety = libpandasafety_py.libpandasafety - self.safety.set_safety_hooks(Panda.SAFETY_HYUNDAI, 0) - self.safety.init_tests() - - def _button_msg(self, buttons, main_button=0, bus=0): - 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) - - def _user_brake_msg(self, brake): - values = {"DriverBraking": brake, "AliveCounterTCS": self.cnt_brake % 8} - self.__class__.cnt_brake += 1 - return self.packer.make_can_msg_panda("TCS13", 0, 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) - - 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, fix_checksum=checksum) - - # TODO: this is unused - def _torque_driver_msg(self, torque): - values = {"CR_Mdps_StrColTq": torque} - return self.packer.make_can_msg_panda("MDPS12", 0, 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) - - -class TestHyundaiSafetyCameraSCC(TestHyundaiSafety): - BUTTONS_TX_BUS = 2 # tx on 2, rx on 0 - SCC_BUS = 2 # rx on 2 - - def setUp(self): - self.packer = CANPackerPanda("hyundai_kia_generic") - self.safety = libpandasafety_py.libpandasafety - self.safety.set_safety_hooks(Panda.SAFETY_HYUNDAI, Panda.FLAG_HYUNDAI_CAMERA_SCC) - self.safety.init_tests() - - -class TestHyundaiLegacySafety(TestHyundaiSafety): - def setUp(self): - self.packer = CANPackerPanda("hyundai_kia_generic") - self.safety = libpandasafety_py.libpandasafety - self.safety.set_safety_hooks(Panda.SAFETY_HYUNDAI_LEGACY, 0) - self.safety.init_tests() - - -class TestHyundaiLegacySafetyEV(TestHyundaiSafety): - def setUp(self): - self.packer = CANPackerPanda("hyundai_kia_generic") - self.safety = libpandasafety_py.libpandasafety - self.safety.set_safety_hooks(Panda.SAFETY_HYUNDAI_LEGACY, 1) - self.safety.init_tests() - - def _user_gas_msg(self, gas): - values = {"Accel_Pedal_Pos": gas} - return self.packer.make_can_msg_panda("E_EMS11", 0, values, fix_checksum=checksum) - - -class TestHyundaiLegacySafetyHEV(TestHyundaiSafety): - def setUp(self): - self.packer = CANPackerPanda("hyundai_kia_generic") - self.safety = libpandasafety_py.libpandasafety - self.safety.set_safety_hooks(Panda.SAFETY_HYUNDAI_LEGACY, 2) - self.safety.init_tests() - - 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 TestHyundaiLongitudinalSafety(HyundaiLongitudinalBase, TestHyundaiSafety): - TX_MSGS = [[832, 0], [1265, 0], [1157, 0], [1056, 0], [1057, 0], [1290, 0], [905, 0], [1186, 0], [909, 0], [1155, 0], [2000, 0]] - - - DISABLED_ECU_UDS_MSG = (2000, 0) - DISABLED_ECU_ACTUATION_MSG = (1057, 0) - - def setUp(self): - self.packer = CANPackerPanda("hyundai_kia_generic") - self.safety = libpandasafety_py.libpandasafety - self.safety.set_safety_hooks(Panda.SAFETY_HYUNDAI, Panda.FLAG_HYUNDAI_LONG) - self.safety.init_tests() - - def _accel_msg(self, accel, aeb_req=False, aeb_decel=0): - values = { - "aReqRaw": accel, - "aReqValue": accel, - "AEB_CmdAct": int(aeb_req), - "CR_VSM_DecCmd": aeb_decel, - } - return self.packer.make_can_msg_panda("SCC12", self.SCC_BUS, values) - - def _fca11_msg(self, idx=0, vsm_aeb_req=False, fca_aeb_req=False, aeb_decel=0): - values = { - "CR_FCA_Alive": idx % 0xF, - "FCA_Status": 2, - "CR_VSM_DecCmd": aeb_decel, - "CF_VSM_DecCmdAct": int(vsm_aeb_req), - "FCA_CmdAct": int(fca_aeb_req), - } - return self.packer.make_can_msg_panda("FCA11", 0, values) - - def test_no_aeb_fca11(self): - self.assertTrue(self._tx(self._fca11_msg())) - self.assertFalse(self._tx(self._fca11_msg(vsm_aeb_req=True))) - self.assertFalse(self._tx(self._fca11_msg(fca_aeb_req=True))) - self.assertFalse(self._tx(self._fca11_msg(aeb_decel=1.0))) - - def test_no_aeb_scc12(self): - self.assertTrue(self._tx(self._accel_msg(0))) - self.assertFalse(self._tx(self._accel_msg(0, aeb_req=True))) - self.assertFalse(self._tx(self._accel_msg(0, aeb_decel=1.0))) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/safety/test_hyundai_canfd.py b/tests/safety/test_hyundai_canfd.py deleted file mode 100755 index 4219277265..0000000000 --- a/tests/safety/test_hyundai_canfd.py +++ /dev/null @@ -1,172 +0,0 @@ -#!/usr/bin/env python3 -import unittest -from panda import Panda -from panda.tests.safety import libpandasafety_py -import panda.tests.safety.common as common -from panda.tests.safety.common import CANPackerPanda -from panda.tests.safety.hyundai_common import HyundaiButtonBase, HyundaiLongitudinalBase - -class TestHyundaiCanfdBase(HyundaiButtonBase, common.PandaSafetyTest, common.DriverTorqueSteeringSafetyTest): - - TX_MSGS = [[0x50, 0], [0x1CF, 1], [0x2A4, 0]] - STANDSTILL_THRESHOLD = 30 # ~1kph - RELAY_MALFUNCTION_ADDR = 0x50 - RELAY_MALFUNCTION_BUS = 0 - FWD_BLACKLISTED_ADDRS = {2: [0x50, 0x2a4]} - FWD_BUS_LOOKUP = {0: 2, 2: 0} - - MAX_RATE_UP = 2 - MAX_RATE_DOWN = 3 - MAX_TORQUE = 270 - - MAX_RT_DELTA = 112 - RT_INTERVAL = 250000 - - DRIVER_TORQUE_ALLOWANCE = 250 - DRIVER_TORQUE_FACTOR = 2 - - # Safety around steering req bit - MIN_VALID_STEERING_FRAMES = 89 - MAX_INVALID_STEERING_FRAMES = 2 - MIN_VALID_STEERING_RT_INTERVAL = 810000 # a ~10% buffer, can send steer up to 110Hz - - PT_BUS = 0 - SCC_BUS = 2 - STEER_BUS = 0 - STEER_MSG = "" - BUTTONS_TX_BUS = 1 - - @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", self.PT_BUS, values) - - def _torque_cmd_msg(self, torque, steer_req=1): - values = {"TORQUE_REQUEST": torque, "STEER_REQ": steer_req} - return self.packer.make_can_msg_panda(self.STEER_MSG, self.STEER_BUS, 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", self.PT_BUS, values) - - def _user_brake_msg(self, brake): - values = {"DriverBraking": brake} - return self.packer.make_can_msg_panda("TCS", self.PT_BUS, values) - - def _user_gas_msg(self, gas): - values = {"ACCELERATOR_PEDAL": gas} - return self.packer.make_can_msg_panda("ACCELERATOR", self.PT_BUS, values) - - def _pcm_status_msg(self, enable): - values = {"CRUISE_STATUS": 3 if enable else 0} - return self.packer.make_can_msg_panda("CRUISE_INFO", self.SCC_BUS, values) - - def _button_msg(self, buttons, main_button=0, bus=None): - if bus is None: - bus = self.PT_BUS - values = { - "CRUISE_BUTTONS": buttons, - "ADAPTIVE_CRUISE_MAIN_BTN": main_button, - } - return self.packer.make_can_msg_panda("CRUISE_BUTTONS", 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" - BUTTONS_TX_BUS = 2 - - 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_HYBRID_GAS) - 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_HYBRID_GAS | 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 - SCC_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 | Panda.FLAG_HYUNDAI_EV_GAS) - self.safety.init_tests() - - -class TestHyundaiCanfdHDA2Long(HyundaiLongitudinalBase, TestHyundaiCanfdHDA2): - - TX_MSGS = [[0x50, 0], [0x1CF, 1], [0x2A4, 0], [0x51, 0], [0x730, 1], [0x12a, 1], [0x160, 1], - [0x1e0, 1], [0x1a0, 1], [0x1ea, 1], [0x200, 1], [0x345, 1], [0x1da, 1]] - - DISABLED_ECU_UDS_MSG = (0x730, 1) - DISABLED_ECU_ACTUATION_MSG = (0x1a0, 1) - - STEER_MSG = "LFA" - STEER_BUS = 1 - - 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 | Panda.FLAG_HYUNDAI_LONG | Panda.FLAG_HYUNDAI_EV_GAS) - self.safety.init_tests() - - def _accel_msg(self, accel, aeb_req=False, aeb_decel=0): - values = { - "ACCEL_REQ": accel, - "ACCEL_REQ2": accel, - } - return self.packer.make_can_msg_panda("CRUISE_INFO", 1, values) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/safety/test_toyota.py b/tests/safety/test_toyota.py deleted file mode 100755 index e758d7d233..0000000000 --- a/tests/safety/test_toyota.py +++ /dev/null @@ -1,206 +0,0 @@ -#!/usr/bin/env python3 -import numpy as np -import random -import unittest - -from panda import Panda -from panda.tests.safety import libpandasafety_py -import panda.tests.safety.common as common -from panda.tests.safety.common import CANPackerPanda, make_msg, ALTERNATIVE_EXPERIENCE - -MAX_ACCEL = 2.0 -MIN_ACCEL = -3.5 - - -def interceptor_msg(gas, addr): - to_send = make_msg(0, addr, 6) - to_send[0].data[0] = (gas & 0xFF00) >> 8 - to_send[0].data[1] = gas & 0xFF - to_send[0].data[2] = (gas & 0xFF00) >> 8 - to_send[0].data[3] = gas & 0xFF - return to_send - - -class TestToyotaSafety(common.PandaSafetyTest, common.InterceptorSafetyTest, - common.MotorTorqueSteeringSafetyTest): - - TX_MSGS = [[0x283, 0], [0x2E6, 0], [0x2E7, 0], [0x33E, 0], [0x344, 0], [0x365, 0], [0x366, 0], [0x4CB, 0], # DSU bus 0 - [0x128, 1], [0x141, 1], [0x160, 1], [0x161, 1], [0x470, 1], # DSU bus 1 - [0x2E4, 0], [0x191, 0], [0x411, 0], [0x412, 0], [0x343, 0], [0x1D2, 0], # LKAS + ACC - [0x200, 0], [0x750, 0]] # interceptor + blindspot monitor - STANDSTILL_THRESHOLD = 0 # kph - RELAY_MALFUNCTION_ADDR = 0x2E4 - RELAY_MALFUNCTION_BUS = 0 - FWD_BLACKLISTED_ADDRS = {2: [0x2E4, 0x412, 0x191, 0x343]} - FWD_BUS_LOOKUP = {0: 2, 2: 0} - INTERCEPTOR_THRESHOLD = 805 - - MAX_RATE_UP = 15 - MAX_RATE_DOWN = 25 - MAX_TORQUE = 1500 - MAX_RT_DELTA = 450 - RT_INTERVAL = 250000 - MAX_TORQUE_ERROR = 350 - TORQUE_MEAS_TOLERANCE = 1 # toyota safety adds one to be conservative for rounding - EPS_SCALE = 73 - - # Safety around steering req bit - MIN_VALID_STEERING_FRAMES = 18 - MAX_INVALID_STEERING_FRAMES = 1 - MIN_VALID_STEERING_RT_INTERVAL = 170000 # a ~10% buffer, can send steer up to 110Hz - - def setUp(self): - self.packer = CANPackerPanda("toyota_nodsu_pt_generated") - self.safety = libpandasafety_py.libpandasafety - self.safety.set_safety_hooks(Panda.SAFETY_TOYOTA, self.EPS_SCALE) - self.safety.init_tests() - - def _torque_meas_msg(self, torque): - values = {"STEER_TORQUE_EPS": (torque / self.EPS_SCALE) * 100.} - return self.packer.make_can_msg_panda("STEER_TORQUE_SENSOR", 0, values) - - def _torque_cmd_msg(self, torque, steer_req=1): - values = {"STEER_TORQUE_CMD": torque, "STEER_REQUEST": steer_req} - return self.packer.make_can_msg_panda("STEERING_LKA", 0, values) - - def _lta_msg(self, req, req2, angle_cmd): - values = {"STEER_REQUEST": req, "STEER_REQUEST_2": req2, "STEER_ANGLE_CMD": angle_cmd} - return self.packer.make_can_msg_panda("STEERING_LTA", 0, values) - - def _accel_msg(self, accel, cancel_req=0): - values = {"ACCEL_CMD": accel, "CANCEL_REQ": cancel_req} - return self.packer.make_can_msg_panda("ACC_CONTROL", 0, values) - - def _speed_msg(self, speed): - values = {("WHEEL_SPEED_%s" % n): speed for n in ["FR", "FL", "RR", "RL"]} - return self.packer.make_can_msg_panda("WHEEL_SPEEDS", 0, values) - - def _user_brake_msg(self, brake): - values = {"BRAKE_PRESSED": brake} - return self.packer.make_can_msg_panda("BRAKE_MODULE", 0, values) - - def _user_gas_msg(self, gas): - cruise_active = self.safety.get_controls_allowed() - values = {"GAS_RELEASED": not gas, "CRUISE_ACTIVE": cruise_active} - return self.packer.make_can_msg_panda("PCM_CRUISE", 0, values) - - def _pcm_status_msg(self, enable): - values = {"CRUISE_ACTIVE": enable} - return self.packer.make_can_msg_panda("PCM_CRUISE", 0, values) - - def _interceptor_gas_cmd(self, gas): - return interceptor_msg(gas, 0x200) - - def _interceptor_user_gas(self, gas): - return interceptor_msg(gas, 0x201) - - def test_block_aeb(self): - for controls_allowed in (True, False): - for bad in (True, False): - for _ in range(10): - self.safety.set_controls_allowed(controls_allowed) - dat = [random.randint(1, 255) for _ in range(7)] - if not bad: - dat = [0]*6 + dat[-1:] - msg = common.package_can_msg([0x283, 0, bytes(dat), 0]) - self.assertEqual(not bad, self._tx(msg)) - - def test_accel_actuation_limits(self, stock_longitudinal=False): - limits = ((MIN_ACCEL, MAX_ACCEL, ALTERNATIVE_EXPERIENCE.DEFAULT), - (MIN_ACCEL, MAX_ACCEL, ALTERNATIVE_EXPERIENCE.RAISE_LONGITUDINAL_LIMITS_TO_ISO_MAX)) - - for min_accel, max_accel, alternative_experience in limits: - for accel in np.arange(min_accel - 1, max_accel + 1, 0.1): - for controls_allowed in [True, False]: - self.safety.set_controls_allowed(controls_allowed) - self.safety.set_alternative_experience(alternative_experience) - if stock_longitudinal: - should_tx = False - elif controls_allowed: - should_tx = int(min_accel * 1000) <= int(accel * 1000) <= int(max_accel * 1000) - else: - should_tx = np.isclose(accel, 0, atol=0.0001) - self.assertEqual(should_tx, self._tx(self._accel_msg(accel))) - - # Only allow LTA msgs with no actuation - def test_lta_steer_cmd(self): - for engaged in [True, False]: - self.safety.set_controls_allowed(engaged) - - # good msg - self.assertTrue(self._tx(self._lta_msg(0, 0, 0))) - - # bad msgs - self.assertFalse(self._tx(self._lta_msg(1, 0, 0))) - self.assertFalse(self._tx(self._lta_msg(0, 1, 0))) - self.assertFalse(self._tx(self._lta_msg(0, 0, 1))) - - for _ in range(20): - req = random.choice([0, 1]) - req2 = random.choice([0, 1]) - angle = random.randint(-50, 50) - should_tx = not req and not req2 and angle == 0 - self.assertEqual(should_tx, self._tx(self._lta_msg(req, req2, angle))) - - def test_rx_hook(self): - # checksum checks - for msg in ["trq", "pcm"]: - self.safety.set_controls_allowed(1) - if msg == "trq": - to_push = self._torque_meas_msg(0) - if msg == "pcm": - to_push = self._pcm_status_msg(True) - self.assertTrue(self._rx(to_push)) - to_push[0].data[4] = 0 - to_push[0].data[5] = 0 - to_push[0].data[6] = 0 - to_push[0].data[7] = 0 - self.assertFalse(self._rx(to_push)) - self.assertFalse(self.safety.get_controls_allowed()) - - -class TestToyotaAltBrakeSafety(TestToyotaSafety): - def setUp(self): - self.packer = CANPackerPanda("toyota_new_mc_pt_generated") - self.safety = libpandasafety_py.libpandasafety - self.safety.set_safety_hooks(Panda.SAFETY_TOYOTA, self.EPS_SCALE | Panda.FLAG_TOYOTA_ALT_BRAKE) - self.safety.init_tests() - - def _user_brake_msg(self, brake): - values = {"BRAKE_PRESSED": brake} - return self.packer.make_can_msg_panda("BRAKE_MODULE", 0, values) - - # No LTA on these cars - def test_lta_steer_cmd(self): - pass - - -class TestToyotaStockLongitudinal(TestToyotaSafety): - def setUp(self): - self.packer = CANPackerPanda("toyota_nodsu_pt_generated") - self.safety = libpandasafety_py.libpandasafety - self.safety.set_safety_hooks(Panda.SAFETY_TOYOTA, self.EPS_SCALE | Panda.FLAG_TOYOTA_STOCK_LONGITUDINAL) - self.safety.init_tests() - - def test_accel_actuation_limits(self, stock_longitudinal=True): - super().test_accel_actuation_limits(stock_longitudinal=stock_longitudinal) - - def test_acc_cancel(self): - """ - Regardless of controls allowed, never allow ACC_CONTROL if cancel bit isn't set - """ - for controls_allowed in [True, False]: - self.safety.set_controls_allowed(controls_allowed) - for accel in np.arange(MIN_ACCEL - 1, MAX_ACCEL + 1, 0.1): - self.assertFalse(self._tx(self._accel_msg(accel))) - should_tx = np.isclose(accel, 0, atol=0.0001) - self.assertEqual(should_tx, self._tx(self._accel_msg(accel, cancel_req=1))) - - def test_fwd_hook(self): - # forward ACC_CONTROL - self.FWD_BLACKLISTED_ADDRS[2].remove(0x343) - super().test_fwd_hook() - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/safety_replay/test_safety_replay.py b/tests/safety_replay/test_safety_replay.py index 8478e6f6b6..9b85fc2d5a 100755 --- a/tests/safety_replay/test_safety_replay.py +++ b/tests/safety_replay/test_safety_replay.py @@ -14,7 +14,6 @@ logs = [ ReplayRoute("2425568437959f9d|2019-12-22--16-24-37.bz2", Panda.SAFETY_HONDA_NIDEC), # HONDA.CIVIC (fcw presents: 0x1FA blocked as expected) - ReplayRoute("38bfd238edecbcd7|2019-06-07--10-15-25.bz2", Panda.SAFETY_TOYOTA, 66), # TOYOTA.PRIUS ReplayRoute("f89c604cf653e2bf|2018-09-29--13-46-50.bz2", Panda.SAFETY_GM), # GM.VOLT ReplayRoute("6fb4948a7ebe670e|2019-11-12--00-35-53.bz2", Panda.SAFETY_CHRYSLER), # CHRYSLER.PACIFICA_2018_HYBRID ReplayRoute("791340bc01ed993d|2019-04-08--10-26-00.bz2", Panda.SAFETY_SUBARU, # SUBARU.OUTBACK @@ -23,8 +22,6 @@ ReplayRoute("3cfdec54aa035f3f|2022-07-19--23-45-10.bz2", Panda.SAFETY_VOLKSWAGEN_PQ, # VOLKSWAGEN.PASSAT_NMS (openpilot longitudinal) Panda.FLAG_VOLKSWAGEN_LONG_CONTROL), ReplayRoute("fbbfa6af821552b9|2020-03-03--08-09-43.bz2", Panda.SAFETY_NISSAN), # NISSAN.XTRAIL - ReplayRoute("5b7c365c50084530_2020-04-15--16-13-24--3--rlog.bz2", Panda.SAFETY_HYUNDAI), # HYUNDAI.SONATA - ReplayRoute("610ebb9faaad6b43|2020-06-13--15-28-36.bz2", Panda.SAFETY_HYUNDAI_LEGACY), # HYUNDAI.IONIQ_EV_LTD ReplayRoute("5ab784f361e19b78_2020-06-08--16-30-41.bz2", Panda.SAFETY_SUBARU_LEGACY), # SUBARU.OUTBACK_PREGLOBAL ReplayRoute("bb50caf5f0945ab1|2021-06-19--17-20-18.bz2", Panda.SAFETY_TESLA), # TESLA.AP2_MODELS ReplayRoute("bd6a637565e91581_2021-10-29--22-18-31--1--rlog.bz2", Panda.SAFETY_MAZDA), # MAZDA.CX9_2021 @@ -39,7 +36,7 @@ for route, _, _, _ in logs: if not os.path.isfile(route): with open(route, "wb") as f: - r = requests.get(BASE_URL + route) + r = requests.get(BASE_URL + route, timeout=60) r.raise_for_status() f.write(r.content) From 6aa9c78fceabffbef6c19ef52bce4e6bf3a6e823 Mon Sep 17 00:00:00 2001 From: Jason Young Date: Mon, 31 Oct 2022 13:36:28 -0400 Subject: [PATCH 24/26] Revert "more temp hack outs" This reverts commit 804cae5c66ea3a946e833390f13968bbd8915e45. --- tests/safety/test_hyundai.py | 203 +++++++++++++++++++++ tests/safety/test_hyundai_canfd.py | 172 ++++++++++++++++++ tests/safety/test_toyota.py | 206 ++++++++++++++++++++++ tests/safety_replay/test_safety_replay.py | 5 +- 4 files changed, 585 insertions(+), 1 deletion(-) create mode 100755 tests/safety/test_hyundai.py create mode 100755 tests/safety/test_hyundai_canfd.py create mode 100755 tests/safety/test_toyota.py diff --git a/tests/safety/test_hyundai.py b/tests/safety/test_hyundai.py new file mode 100755 index 0000000000..6c35e874d8 --- /dev/null +++ b/tests/safety/test_hyundai.py @@ -0,0 +1,203 @@ +#!/usr/bin/env python3 +import unittest +from panda import Panda +from panda.tests.safety import libpandasafety_py +import panda.tests.safety.common as common +from panda.tests.safety.common import CANPackerPanda +from panda.tests.safety.hyundai_common import HyundaiButtonBase, HyundaiLongitudinalBase + + +# 4 bit checkusm used in some hyundai messages +# lives outside the can packer because we never send this msg +def checksum(msg): + addr, t, dat, bus = msg + + chksum = 0 + if addr == 902: + for i, b in enumerate(dat): + for j in range(8): + # exclude checksum and counter bits + if (i != 1 or j < 6) and (i != 3 or j < 6) and (i != 5 or j < 6) and (i != 7 or j < 6): + bit = (b >> j) & 1 + else: + bit = 0 + chksum += bit + chksum = (chksum ^ 9) & 0xF + ret = bytearray(dat) + ret[5] |= (chksum & 0x3) << 6 + ret[7] |= (chksum & 0xc) << 4 + else: + for i, b in enumerate(dat): + if addr in [608, 1057] and i == 7: + b &= 0x0F if addr == 1057 else 0xF0 + elif addr == 916 and i == 6: + b &= 0xF0 + elif addr == 916 and i == 7: + continue + chksum += sum(divmod(b, 16)) + chksum = (16 - chksum) % 16 + ret = bytearray(dat) + ret[6 if addr == 916 else 7] |= chksum << (4 if addr == 1057 else 0) + + return addr, t, ret, bus + + +class TestHyundaiSafety(HyundaiButtonBase, common.PandaSafetyTest, common.DriverTorqueSteeringSafetyTest): + TX_MSGS = [[832, 0], [1265, 0], [1157, 0]] + STANDSTILL_THRESHOLD = 30 # ~1kph + RELAY_MALFUNCTION_ADDR = 832 + RELAY_MALFUNCTION_BUS = 0 + FWD_BLACKLISTED_ADDRS = {2: [832, 1157]} + FWD_BUS_LOOKUP = {0: 2, 2: 0} + + MAX_RATE_UP = 3 + MAX_RATE_DOWN = 7 + MAX_TORQUE = 384 + MAX_RT_DELTA = 112 + RT_INTERVAL = 250000 + DRIVER_TORQUE_ALLOWANCE = 50 + DRIVER_TORQUE_FACTOR = 2 + + # Safety around steering req bit + MIN_VALID_STEERING_FRAMES = 89 + MAX_INVALID_STEERING_FRAMES = 2 + MIN_VALID_STEERING_RT_INTERVAL = 810000 # a ~10% buffer, can send steer up to 110Hz + + cnt_gas = 0 + cnt_speed = 0 + cnt_brake = 0 + cnt_cruise = 0 + cnt_button = 0 + + def setUp(self): + self.packer = CANPackerPanda("hyundai_kia_generic") + self.safety = libpandasafety_py.libpandasafety + self.safety.set_safety_hooks(Panda.SAFETY_HYUNDAI, 0) + self.safety.init_tests() + + def _button_msg(self, buttons, main_button=0, bus=0): + 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) + + def _user_brake_msg(self, brake): + values = {"DriverBraking": brake, "AliveCounterTCS": self.cnt_brake % 8} + self.__class__.cnt_brake += 1 + return self.packer.make_can_msg_panda("TCS13", 0, 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) + + 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, fix_checksum=checksum) + + # TODO: this is unused + def _torque_driver_msg(self, torque): + values = {"CR_Mdps_StrColTq": torque} + return self.packer.make_can_msg_panda("MDPS12", 0, 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) + + +class TestHyundaiSafetyCameraSCC(TestHyundaiSafety): + BUTTONS_TX_BUS = 2 # tx on 2, rx on 0 + SCC_BUS = 2 # rx on 2 + + def setUp(self): + self.packer = CANPackerPanda("hyundai_kia_generic") + self.safety = libpandasafety_py.libpandasafety + self.safety.set_safety_hooks(Panda.SAFETY_HYUNDAI, Panda.FLAG_HYUNDAI_CAMERA_SCC) + self.safety.init_tests() + + +class TestHyundaiLegacySafety(TestHyundaiSafety): + def setUp(self): + self.packer = CANPackerPanda("hyundai_kia_generic") + self.safety = libpandasafety_py.libpandasafety + self.safety.set_safety_hooks(Panda.SAFETY_HYUNDAI_LEGACY, 0) + self.safety.init_tests() + + +class TestHyundaiLegacySafetyEV(TestHyundaiSafety): + def setUp(self): + self.packer = CANPackerPanda("hyundai_kia_generic") + self.safety = libpandasafety_py.libpandasafety + self.safety.set_safety_hooks(Panda.SAFETY_HYUNDAI_LEGACY, 1) + self.safety.init_tests() + + def _user_gas_msg(self, gas): + values = {"Accel_Pedal_Pos": gas} + return self.packer.make_can_msg_panda("E_EMS11", 0, values, fix_checksum=checksum) + + +class TestHyundaiLegacySafetyHEV(TestHyundaiSafety): + def setUp(self): + self.packer = CANPackerPanda("hyundai_kia_generic") + self.safety = libpandasafety_py.libpandasafety + self.safety.set_safety_hooks(Panda.SAFETY_HYUNDAI_LEGACY, 2) + self.safety.init_tests() + + 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 TestHyundaiLongitudinalSafety(HyundaiLongitudinalBase, TestHyundaiSafety): + TX_MSGS = [[832, 0], [1265, 0], [1157, 0], [1056, 0], [1057, 0], [1290, 0], [905, 0], [1186, 0], [909, 0], [1155, 0], [2000, 0]] + + + DISABLED_ECU_UDS_MSG = (2000, 0) + DISABLED_ECU_ACTUATION_MSG = (1057, 0) + + def setUp(self): + self.packer = CANPackerPanda("hyundai_kia_generic") + self.safety = libpandasafety_py.libpandasafety + self.safety.set_safety_hooks(Panda.SAFETY_HYUNDAI, Panda.FLAG_HYUNDAI_LONG) + self.safety.init_tests() + + def _accel_msg(self, accel, aeb_req=False, aeb_decel=0): + values = { + "aReqRaw": accel, + "aReqValue": accel, + "AEB_CmdAct": int(aeb_req), + "CR_VSM_DecCmd": aeb_decel, + } + return self.packer.make_can_msg_panda("SCC12", self.SCC_BUS, values) + + def _fca11_msg(self, idx=0, vsm_aeb_req=False, fca_aeb_req=False, aeb_decel=0): + values = { + "CR_FCA_Alive": idx % 0xF, + "FCA_Status": 2, + "CR_VSM_DecCmd": aeb_decel, + "CF_VSM_DecCmdAct": int(vsm_aeb_req), + "FCA_CmdAct": int(fca_aeb_req), + } + return self.packer.make_can_msg_panda("FCA11", 0, values) + + def test_no_aeb_fca11(self): + self.assertTrue(self._tx(self._fca11_msg())) + self.assertFalse(self._tx(self._fca11_msg(vsm_aeb_req=True))) + self.assertFalse(self._tx(self._fca11_msg(fca_aeb_req=True))) + self.assertFalse(self._tx(self._fca11_msg(aeb_decel=1.0))) + + def test_no_aeb_scc12(self): + self.assertTrue(self._tx(self._accel_msg(0))) + self.assertFalse(self._tx(self._accel_msg(0, aeb_req=True))) + self.assertFalse(self._tx(self._accel_msg(0, aeb_decel=1.0))) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/safety/test_hyundai_canfd.py b/tests/safety/test_hyundai_canfd.py new file mode 100755 index 0000000000..4219277265 --- /dev/null +++ b/tests/safety/test_hyundai_canfd.py @@ -0,0 +1,172 @@ +#!/usr/bin/env python3 +import unittest +from panda import Panda +from panda.tests.safety import libpandasafety_py +import panda.tests.safety.common as common +from panda.tests.safety.common import CANPackerPanda +from panda.tests.safety.hyundai_common import HyundaiButtonBase, HyundaiLongitudinalBase + +class TestHyundaiCanfdBase(HyundaiButtonBase, common.PandaSafetyTest, common.DriverTorqueSteeringSafetyTest): + + TX_MSGS = [[0x50, 0], [0x1CF, 1], [0x2A4, 0]] + STANDSTILL_THRESHOLD = 30 # ~1kph + RELAY_MALFUNCTION_ADDR = 0x50 + RELAY_MALFUNCTION_BUS = 0 + FWD_BLACKLISTED_ADDRS = {2: [0x50, 0x2a4]} + FWD_BUS_LOOKUP = {0: 2, 2: 0} + + MAX_RATE_UP = 2 + MAX_RATE_DOWN = 3 + MAX_TORQUE = 270 + + MAX_RT_DELTA = 112 + RT_INTERVAL = 250000 + + DRIVER_TORQUE_ALLOWANCE = 250 + DRIVER_TORQUE_FACTOR = 2 + + # Safety around steering req bit + MIN_VALID_STEERING_FRAMES = 89 + MAX_INVALID_STEERING_FRAMES = 2 + MIN_VALID_STEERING_RT_INTERVAL = 810000 # a ~10% buffer, can send steer up to 110Hz + + PT_BUS = 0 + SCC_BUS = 2 + STEER_BUS = 0 + STEER_MSG = "" + BUTTONS_TX_BUS = 1 + + @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", self.PT_BUS, values) + + def _torque_cmd_msg(self, torque, steer_req=1): + values = {"TORQUE_REQUEST": torque, "STEER_REQ": steer_req} + return self.packer.make_can_msg_panda(self.STEER_MSG, self.STEER_BUS, 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", self.PT_BUS, values) + + def _user_brake_msg(self, brake): + values = {"DriverBraking": brake} + return self.packer.make_can_msg_panda("TCS", self.PT_BUS, values) + + def _user_gas_msg(self, gas): + values = {"ACCELERATOR_PEDAL": gas} + return self.packer.make_can_msg_panda("ACCELERATOR", self.PT_BUS, values) + + def _pcm_status_msg(self, enable): + values = {"CRUISE_STATUS": 3 if enable else 0} + return self.packer.make_can_msg_panda("CRUISE_INFO", self.SCC_BUS, values) + + def _button_msg(self, buttons, main_button=0, bus=None): + if bus is None: + bus = self.PT_BUS + values = { + "CRUISE_BUTTONS": buttons, + "ADAPTIVE_CRUISE_MAIN_BTN": main_button, + } + return self.packer.make_can_msg_panda("CRUISE_BUTTONS", 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" + BUTTONS_TX_BUS = 2 + + 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_HYBRID_GAS) + 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_HYBRID_GAS | 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 + SCC_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 | Panda.FLAG_HYUNDAI_EV_GAS) + self.safety.init_tests() + + +class TestHyundaiCanfdHDA2Long(HyundaiLongitudinalBase, TestHyundaiCanfdHDA2): + + TX_MSGS = [[0x50, 0], [0x1CF, 1], [0x2A4, 0], [0x51, 0], [0x730, 1], [0x12a, 1], [0x160, 1], + [0x1e0, 1], [0x1a0, 1], [0x1ea, 1], [0x200, 1], [0x345, 1], [0x1da, 1]] + + DISABLED_ECU_UDS_MSG = (0x730, 1) + DISABLED_ECU_ACTUATION_MSG = (0x1a0, 1) + + STEER_MSG = "LFA" + STEER_BUS = 1 + + 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 | Panda.FLAG_HYUNDAI_LONG | Panda.FLAG_HYUNDAI_EV_GAS) + self.safety.init_tests() + + def _accel_msg(self, accel, aeb_req=False, aeb_decel=0): + values = { + "ACCEL_REQ": accel, + "ACCEL_REQ2": accel, + } + return self.packer.make_can_msg_panda("CRUISE_INFO", 1, values) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/safety/test_toyota.py b/tests/safety/test_toyota.py new file mode 100755 index 0000000000..e758d7d233 --- /dev/null +++ b/tests/safety/test_toyota.py @@ -0,0 +1,206 @@ +#!/usr/bin/env python3 +import numpy as np +import random +import unittest + +from panda import Panda +from panda.tests.safety import libpandasafety_py +import panda.tests.safety.common as common +from panda.tests.safety.common import CANPackerPanda, make_msg, ALTERNATIVE_EXPERIENCE + +MAX_ACCEL = 2.0 +MIN_ACCEL = -3.5 + + +def interceptor_msg(gas, addr): + to_send = make_msg(0, addr, 6) + to_send[0].data[0] = (gas & 0xFF00) >> 8 + to_send[0].data[1] = gas & 0xFF + to_send[0].data[2] = (gas & 0xFF00) >> 8 + to_send[0].data[3] = gas & 0xFF + return to_send + + +class TestToyotaSafety(common.PandaSafetyTest, common.InterceptorSafetyTest, + common.MotorTorqueSteeringSafetyTest): + + TX_MSGS = [[0x283, 0], [0x2E6, 0], [0x2E7, 0], [0x33E, 0], [0x344, 0], [0x365, 0], [0x366, 0], [0x4CB, 0], # DSU bus 0 + [0x128, 1], [0x141, 1], [0x160, 1], [0x161, 1], [0x470, 1], # DSU bus 1 + [0x2E4, 0], [0x191, 0], [0x411, 0], [0x412, 0], [0x343, 0], [0x1D2, 0], # LKAS + ACC + [0x200, 0], [0x750, 0]] # interceptor + blindspot monitor + STANDSTILL_THRESHOLD = 0 # kph + RELAY_MALFUNCTION_ADDR = 0x2E4 + RELAY_MALFUNCTION_BUS = 0 + FWD_BLACKLISTED_ADDRS = {2: [0x2E4, 0x412, 0x191, 0x343]} + FWD_BUS_LOOKUP = {0: 2, 2: 0} + INTERCEPTOR_THRESHOLD = 805 + + MAX_RATE_UP = 15 + MAX_RATE_DOWN = 25 + MAX_TORQUE = 1500 + MAX_RT_DELTA = 450 + RT_INTERVAL = 250000 + MAX_TORQUE_ERROR = 350 + TORQUE_MEAS_TOLERANCE = 1 # toyota safety adds one to be conservative for rounding + EPS_SCALE = 73 + + # Safety around steering req bit + MIN_VALID_STEERING_FRAMES = 18 + MAX_INVALID_STEERING_FRAMES = 1 + MIN_VALID_STEERING_RT_INTERVAL = 170000 # a ~10% buffer, can send steer up to 110Hz + + def setUp(self): + self.packer = CANPackerPanda("toyota_nodsu_pt_generated") + self.safety = libpandasafety_py.libpandasafety + self.safety.set_safety_hooks(Panda.SAFETY_TOYOTA, self.EPS_SCALE) + self.safety.init_tests() + + def _torque_meas_msg(self, torque): + values = {"STEER_TORQUE_EPS": (torque / self.EPS_SCALE) * 100.} + return self.packer.make_can_msg_panda("STEER_TORQUE_SENSOR", 0, values) + + def _torque_cmd_msg(self, torque, steer_req=1): + values = {"STEER_TORQUE_CMD": torque, "STEER_REQUEST": steer_req} + return self.packer.make_can_msg_panda("STEERING_LKA", 0, values) + + def _lta_msg(self, req, req2, angle_cmd): + values = {"STEER_REQUEST": req, "STEER_REQUEST_2": req2, "STEER_ANGLE_CMD": angle_cmd} + return self.packer.make_can_msg_panda("STEERING_LTA", 0, values) + + def _accel_msg(self, accel, cancel_req=0): + values = {"ACCEL_CMD": accel, "CANCEL_REQ": cancel_req} + return self.packer.make_can_msg_panda("ACC_CONTROL", 0, values) + + def _speed_msg(self, speed): + values = {("WHEEL_SPEED_%s" % n): speed for n in ["FR", "FL", "RR", "RL"]} + return self.packer.make_can_msg_panda("WHEEL_SPEEDS", 0, values) + + def _user_brake_msg(self, brake): + values = {"BRAKE_PRESSED": brake} + return self.packer.make_can_msg_panda("BRAKE_MODULE", 0, values) + + def _user_gas_msg(self, gas): + cruise_active = self.safety.get_controls_allowed() + values = {"GAS_RELEASED": not gas, "CRUISE_ACTIVE": cruise_active} + return self.packer.make_can_msg_panda("PCM_CRUISE", 0, values) + + def _pcm_status_msg(self, enable): + values = {"CRUISE_ACTIVE": enable} + return self.packer.make_can_msg_panda("PCM_CRUISE", 0, values) + + def _interceptor_gas_cmd(self, gas): + return interceptor_msg(gas, 0x200) + + def _interceptor_user_gas(self, gas): + return interceptor_msg(gas, 0x201) + + def test_block_aeb(self): + for controls_allowed in (True, False): + for bad in (True, False): + for _ in range(10): + self.safety.set_controls_allowed(controls_allowed) + dat = [random.randint(1, 255) for _ in range(7)] + if not bad: + dat = [0]*6 + dat[-1:] + msg = common.package_can_msg([0x283, 0, bytes(dat), 0]) + self.assertEqual(not bad, self._tx(msg)) + + def test_accel_actuation_limits(self, stock_longitudinal=False): + limits = ((MIN_ACCEL, MAX_ACCEL, ALTERNATIVE_EXPERIENCE.DEFAULT), + (MIN_ACCEL, MAX_ACCEL, ALTERNATIVE_EXPERIENCE.RAISE_LONGITUDINAL_LIMITS_TO_ISO_MAX)) + + for min_accel, max_accel, alternative_experience in limits: + for accel in np.arange(min_accel - 1, max_accel + 1, 0.1): + for controls_allowed in [True, False]: + self.safety.set_controls_allowed(controls_allowed) + self.safety.set_alternative_experience(alternative_experience) + if stock_longitudinal: + should_tx = False + elif controls_allowed: + should_tx = int(min_accel * 1000) <= int(accel * 1000) <= int(max_accel * 1000) + else: + should_tx = np.isclose(accel, 0, atol=0.0001) + self.assertEqual(should_tx, self._tx(self._accel_msg(accel))) + + # Only allow LTA msgs with no actuation + def test_lta_steer_cmd(self): + for engaged in [True, False]: + self.safety.set_controls_allowed(engaged) + + # good msg + self.assertTrue(self._tx(self._lta_msg(0, 0, 0))) + + # bad msgs + self.assertFalse(self._tx(self._lta_msg(1, 0, 0))) + self.assertFalse(self._tx(self._lta_msg(0, 1, 0))) + self.assertFalse(self._tx(self._lta_msg(0, 0, 1))) + + for _ in range(20): + req = random.choice([0, 1]) + req2 = random.choice([0, 1]) + angle = random.randint(-50, 50) + should_tx = not req and not req2 and angle == 0 + self.assertEqual(should_tx, self._tx(self._lta_msg(req, req2, angle))) + + def test_rx_hook(self): + # checksum checks + for msg in ["trq", "pcm"]: + self.safety.set_controls_allowed(1) + if msg == "trq": + to_push = self._torque_meas_msg(0) + if msg == "pcm": + to_push = self._pcm_status_msg(True) + self.assertTrue(self._rx(to_push)) + to_push[0].data[4] = 0 + to_push[0].data[5] = 0 + to_push[0].data[6] = 0 + to_push[0].data[7] = 0 + self.assertFalse(self._rx(to_push)) + self.assertFalse(self.safety.get_controls_allowed()) + + +class TestToyotaAltBrakeSafety(TestToyotaSafety): + def setUp(self): + self.packer = CANPackerPanda("toyota_new_mc_pt_generated") + self.safety = libpandasafety_py.libpandasafety + self.safety.set_safety_hooks(Panda.SAFETY_TOYOTA, self.EPS_SCALE | Panda.FLAG_TOYOTA_ALT_BRAKE) + self.safety.init_tests() + + def _user_brake_msg(self, brake): + values = {"BRAKE_PRESSED": brake} + return self.packer.make_can_msg_panda("BRAKE_MODULE", 0, values) + + # No LTA on these cars + def test_lta_steer_cmd(self): + pass + + +class TestToyotaStockLongitudinal(TestToyotaSafety): + def setUp(self): + self.packer = CANPackerPanda("toyota_nodsu_pt_generated") + self.safety = libpandasafety_py.libpandasafety + self.safety.set_safety_hooks(Panda.SAFETY_TOYOTA, self.EPS_SCALE | Panda.FLAG_TOYOTA_STOCK_LONGITUDINAL) + self.safety.init_tests() + + def test_accel_actuation_limits(self, stock_longitudinal=True): + super().test_accel_actuation_limits(stock_longitudinal=stock_longitudinal) + + def test_acc_cancel(self): + """ + Regardless of controls allowed, never allow ACC_CONTROL if cancel bit isn't set + """ + for controls_allowed in [True, False]: + self.safety.set_controls_allowed(controls_allowed) + for accel in np.arange(MIN_ACCEL - 1, MAX_ACCEL + 1, 0.1): + self.assertFalse(self._tx(self._accel_msg(accel))) + should_tx = np.isclose(accel, 0, atol=0.0001) + self.assertEqual(should_tx, self._tx(self._accel_msg(accel, cancel_req=1))) + + def test_fwd_hook(self): + # forward ACC_CONTROL + self.FWD_BLACKLISTED_ADDRS[2].remove(0x343) + super().test_fwd_hook() + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/safety_replay/test_safety_replay.py b/tests/safety_replay/test_safety_replay.py index 9b85fc2d5a..8478e6f6b6 100755 --- a/tests/safety_replay/test_safety_replay.py +++ b/tests/safety_replay/test_safety_replay.py @@ -14,6 +14,7 @@ logs = [ ReplayRoute("2425568437959f9d|2019-12-22--16-24-37.bz2", Panda.SAFETY_HONDA_NIDEC), # HONDA.CIVIC (fcw presents: 0x1FA blocked as expected) + ReplayRoute("38bfd238edecbcd7|2019-06-07--10-15-25.bz2", Panda.SAFETY_TOYOTA, 66), # TOYOTA.PRIUS ReplayRoute("f89c604cf653e2bf|2018-09-29--13-46-50.bz2", Panda.SAFETY_GM), # GM.VOLT ReplayRoute("6fb4948a7ebe670e|2019-11-12--00-35-53.bz2", Panda.SAFETY_CHRYSLER), # CHRYSLER.PACIFICA_2018_HYBRID ReplayRoute("791340bc01ed993d|2019-04-08--10-26-00.bz2", Panda.SAFETY_SUBARU, # SUBARU.OUTBACK @@ -22,6 +23,8 @@ ReplayRoute("3cfdec54aa035f3f|2022-07-19--23-45-10.bz2", Panda.SAFETY_VOLKSWAGEN_PQ, # VOLKSWAGEN.PASSAT_NMS (openpilot longitudinal) Panda.FLAG_VOLKSWAGEN_LONG_CONTROL), ReplayRoute("fbbfa6af821552b9|2020-03-03--08-09-43.bz2", Panda.SAFETY_NISSAN), # NISSAN.XTRAIL + ReplayRoute("5b7c365c50084530_2020-04-15--16-13-24--3--rlog.bz2", Panda.SAFETY_HYUNDAI), # HYUNDAI.SONATA + ReplayRoute("610ebb9faaad6b43|2020-06-13--15-28-36.bz2", Panda.SAFETY_HYUNDAI_LEGACY), # HYUNDAI.IONIQ_EV_LTD ReplayRoute("5ab784f361e19b78_2020-06-08--16-30-41.bz2", Panda.SAFETY_SUBARU_LEGACY), # SUBARU.OUTBACK_PREGLOBAL ReplayRoute("bb50caf5f0945ab1|2021-06-19--17-20-18.bz2", Panda.SAFETY_TESLA), # TESLA.AP2_MODELS ReplayRoute("bd6a637565e91581_2021-10-29--22-18-31--1--rlog.bz2", Panda.SAFETY_MAZDA), # MAZDA.CX9_2021 @@ -36,7 +39,7 @@ for route, _, _, _ in logs: if not os.path.isfile(route): with open(route, "wb") as f: - r = requests.get(BASE_URL + route, timeout=60) + r = requests.get(BASE_URL + route) r.raise_for_status() f.write(r.content) From b626af260b24a6461d7f1d64af0c0f351793b21c Mon Sep 17 00:00:00 2001 From: Jason Young Date: Mon, 31 Oct 2022 13:36:34 -0400 Subject: [PATCH 25/26] Revert "temp hack out other safeties to build on H7" This reverts commit de5559acdab041ded1a71b087dc0cd06ebda43d4. --- board/safety.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/board/safety.h b/board/safety.h index 7435561a9a..12416c484a 100644 --- a/board/safety.h +++ b/board/safety.h @@ -3,11 +3,11 @@ // include the safety policies. #include "safety/safety_defaults.h" #include "safety/safety_honda.h" -//#include "safety/safety_toyota.h" +#include "safety/safety_toyota.h" #include "safety/safety_tesla.h" #include "safety/safety_gm.h" #include "safety/safety_ford.h" -//#include "safety/safety_hyundai.h" +#include "safety/safety_hyundai.h" #include "safety/safety_chrysler.h" #include "safety/safety_subaru.h" #include "safety/safety_subaru_legacy.h" @@ -25,7 +25,7 @@ // CAN-FD only safety modes #ifdef CANFD -//#include "safety/safety_hyundai_canfd.h" +#include "safety/safety_hyundai_canfd.h" #endif // from cereal.car.CarParams.SafetyModel @@ -288,21 +288,21 @@ typedef struct { const safety_hook_config safety_hook_registry[] = { {SAFETY_SILENT, &nooutput_hooks}, {SAFETY_HONDA_NIDEC, &honda_nidec_hooks}, -// {SAFETY_TOYOTA, &toyota_hooks}, + {SAFETY_TOYOTA, &toyota_hooks}, {SAFETY_ELM327, &elm327_hooks}, {SAFETY_GM, &gm_hooks}, {SAFETY_HONDA_BOSCH, &honda_bosch_hooks}, -// {SAFETY_HYUNDAI, &hyundai_hooks}, + {SAFETY_HYUNDAI, &hyundai_hooks}, {SAFETY_CHRYSLER, &chrysler_hooks}, {SAFETY_SUBARU, &subaru_hooks}, {SAFETY_VOLKSWAGEN_MQB, &volkswagen_mqb_hooks}, {SAFETY_NISSAN, &nissan_hooks}, {SAFETY_NOOUTPUT, &nooutput_hooks}, -// {SAFETY_HYUNDAI_LEGACY, &hyundai_legacy_hooks}, + {SAFETY_HYUNDAI_LEGACY, &hyundai_legacy_hooks}, {SAFETY_MAZDA, &mazda_hooks}, {SAFETY_BODY, &body_hooks}, #ifdef CANFD -// {SAFETY_HYUNDAI_CANFD, &hyundai_canfd_hooks}, + {SAFETY_HYUNDAI_CANFD, &hyundai_canfd_hooks}, #endif #ifdef ALLOW_DEBUG {SAFETY_TESLA, &tesla_hooks}, From 3625167dedd03846dcf9be2cc8283dd499c7e2a6 Mon Sep 17 00:00:00 2001 From: Jason Young Date: Mon, 31 Oct 2022 13:50:47 -0400 Subject: [PATCH 26/26] bump Docker refs --- Dockerfile.panda | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile.panda b/Dockerfile.panda index fa3fa4ea2a..97ad49dbf7 100644 --- a/Dockerfile.panda +++ b/Dockerfile.panda @@ -50,8 +50,8 @@ RUN curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-instal ENV PATH="/root/.pyenv/bin:/root/.pyenv/shims:${PATH}" ENV PANDA_PATH=/tmp/openpilot/panda -ENV OPENPILOT_REF="96e8d5c9fe1a8084dfa5d97c78d4ea2037272420" -ENV OPENDBC_REF="7bd94e3ff4a2890eb69118f0dfadb64f9d32d618" +ENV OPENPILOT_REF="01071d4ef91f0bdb4bdaa0e03f00c6a3f3c05fb6" +ENV OPENDBC_REF="6994f10d7b176ad29f1ca7881635fa22840bf12a" COPY requirements.txt /tmp/ RUN pyenv install 3.8.10 && \