diff --git a/tests/safety/common.py b/tests/safety/common.py index f954875937..3077df2be2 100644 --- a/tests/safety/common.py +++ b/tests/safety/common.py @@ -99,6 +99,22 @@ def _generic_limit_safety_check(self, msg_function: MessageFunction, min_allowed should_tx = (should_tx or v == inactive_value) and msg_allowed self.assertEqual(self._tx(msg_function(v)), should_tx, (controls_allowed, should_tx, v)) + def _common_measurement_test(self, msg_func: Callable, min_value: float, max_value: float, factor: int, + meas_min_func: Callable[[], int], meas_max_func: Callable[[], int]): + """Tests accurate measurement parsing, and that the struct is reset on safety mode init""" + for val in np.arange(min_value, max_value, 0.5): + for i in range(MAX_SAMPLE_VALS): + self.assertTrue(self._rx(msg_func(val + i * 0.1))) + + # assert close by one decimal place + self.assertAlmostEqual(meas_min_func() / factor, val, delta=0.1) + self.assertAlmostEqual(meas_max_func() / factor - 0.5, val, delta=0.1) + + # ensure sample_t is reset on safety init + self._reset_safety_hooks() + self.assertEqual(meas_min_func(), 0) + self.assertEqual(meas_max_func(), 0) + class InterceptorSafetyTest(PandaSafetyTestBase): @@ -620,45 +636,10 @@ def test_reset_torque_measurements(self): self.assertEqual(self.safety.get_torque_meas_min(), 0) self.assertEqual(self.safety.get_torque_meas_max(), 0) -class MeasurementSafetyTest(PandaSafetyTestBase): - DEG_TO_CAN: float = 1 - - @classmethod - def setUpClass(cls): - if cls.__name__ == "MeasurementSafetyTest": - cls.safety = None - raise unittest.SkipTest - - @abc.abstractmethod - def _angle_meas_msg(self, angle: float): - pass - @abc.abstractmethod - def _speed_msg(self, speed): - pass +class AngleSteeringSafetyTest(PandaSafetyTestBase): - def common_measurement_test(self, msg_func, min_value, max_value, factor, get_min_func, get_max_func): - for val in np.arange(min_value, max_value, 0.5): - for i in range(MAX_SAMPLE_VALS): - self.assertTrue(self._rx(msg_func(val + i * 0.1))) - - # assert close by one decimal place - self.assertAlmostEqual(get_min_func() / factor, val, delta=0.1) - self.assertAlmostEqual(get_max_func() / factor - 0.5, val, delta=0.1) - - # ensure sample_t is reset on safety init - self._reset_safety_hooks() - self.assertEqual(get_min_func(), 0) - self.assertEqual(get_max_func(), 0) - - def test_vehicle_speed_measurements(self): - self.common_measurement_test(self._speed_msg, 0, 80, VEHICLE_SPEED_FACTOR, self.safety.get_vehicle_speed_min, self.safety.get_vehicle_speed_max) - - def test_steering_angle_measurements(self): - self.common_measurement_test(self._angle_meas_msg, -180, 180, self.DEG_TO_CAN, self.safety.get_angle_meas_min, self.safety.get_angle_meas_max) - - -class AngleSteeringSafetyTest(MeasurementSafetyTest): + DEG_TO_CAN: int ANGLE_RATE_BP: List[float] ANGLE_RATE_UP: List[float] # windup limit ANGLE_RATE_DOWN: List[float] # unwind limit @@ -669,10 +650,18 @@ def setUpClass(cls): cls.safety = None raise unittest.SkipTest + @abc.abstractmethod + def _speed_msg(self, speed): + pass + @abc.abstractmethod def _angle_cmd_msg(self, angle: float, enabled: bool): pass + @abc.abstractmethod + def _angle_meas_msg(self, angle: float): + pass + def _set_prev_desired_angle(self, t): t = int(t * self.DEG_TO_CAN) self.safety.set_desired_angle_last(t) @@ -685,6 +674,12 @@ def _reset_speed_measurement(self, speed): for _ in range(MAX_SAMPLE_VALS): self._rx(self._speed_msg(speed)) + def test_vehicle_speed_measurements(self): + self._common_measurement_test(self._speed_msg, 0, 80, VEHICLE_SPEED_FACTOR, self.safety.get_vehicle_speed_min, self.safety.get_vehicle_speed_max) + + def test_steering_angle_measurements(self): + self._common_measurement_test(self._angle_meas_msg, -180, 180, self.DEG_TO_CAN, self.safety.get_angle_meas_min, self.safety.get_angle_meas_max) + def test_angle_cmd_when_enabled(self): # when controls are allowed, angle cmd rate limit is enforced speeds = [0., 1., 5., 10., 15., 50.] diff --git a/tests/safety/test_subaru.py b/tests/safety/test_subaru.py index 96731c51ff..bedb3cd0ae 100755 --- a/tests/safety/test_subaru.py +++ b/tests/safety/test_subaru.py @@ -4,7 +4,7 @@ from panda import Panda from panda.tests.libpanda import libpanda_py import panda.tests.safety.common as common -from panda.tests.safety.common import CANPackerPanda, MeasurementSafetyTest +from panda.tests.safety.common import CANPackerPanda from functools import partial class SubaruMsg(enum.IntEnum): @@ -52,7 +52,7 @@ def gen2_long_additional_tx_msgs(): def fwd_blacklisted_addr(lkas_msg=SubaruMsg.ES_LKAS): return {SUBARU_CAM_BUS: [lkas_msg, SubaruMsg.ES_DashStatus, SubaruMsg.ES_LKAS_State, SubaruMsg.ES_Infotainment]} -class TestSubaruSafetyBase(common.PandaSafetyTest, MeasurementSafetyTest): +class TestSubaruSafetyBase(common.PandaSafetyTest): FLAGS = 0 STANDSTILL_THRESHOLD = 0 # kph RELAY_MALFUNCTION_ADDR = SubaruMsg.ES_LKAS