You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
156 lines
5.3 KiB
156 lines
5.3 KiB
2 months ago
|
import unittest
|
||
|
|
||
|
import opendbc.safety.tests.common as common
|
||
|
from opendbc.safety.tests.libsafety import libsafety_py
|
||
|
from opendbc.safety.tests.common import make_msg
|
||
|
|
||
|
|
||
|
class Buttons:
|
||
|
NONE = 0
|
||
|
RESUME = 1
|
||
|
SET = 2
|
||
|
CANCEL = 4
|
||
|
|
||
|
|
||
|
PREV_BUTTON_SAMPLES = 8
|
||
|
ENABLE_BUTTONS = (Buttons.RESUME, Buttons.SET, Buttons.CANCEL)
|
||
|
|
||
|
|
||
|
class HyundaiButtonBase:
|
||
|
# pylint: disable=no-member,abstract-method
|
||
|
BUTTONS_TX_BUS = 0 # tx on this bus, rx on 0
|
||
|
SCC_BUS = 0 # rx on this bus
|
||
|
|
||
|
def test_button_sends(self):
|
||
|
"""
|
||
|
Only RES and CANCEL buttons are allowed
|
||
|
- RES allowed while controls allowed
|
||
|
- CANCEL allowed while cruise is enabled
|
||
|
"""
|
||
|
self.safety.set_controls_allowed(0)
|
||
|
self.assertFalse(self._tx(self._button_msg(Buttons.RESUME, bus=self.BUTTONS_TX_BUS)))
|
||
|
self.assertFalse(self._tx(self._button_msg(Buttons.SET, bus=self.BUTTONS_TX_BUS)))
|
||
|
|
||
|
self.safety.set_controls_allowed(1)
|
||
|
self.assertTrue(self._tx(self._button_msg(Buttons.RESUME, bus=self.BUTTONS_TX_BUS)))
|
||
|
self.assertFalse(self._tx(self._button_msg(Buttons.SET, bus=self.BUTTONS_TX_BUS)))
|
||
|
|
||
|
for enabled in (True, False):
|
||
|
self._rx(self._pcm_status_msg(enabled))
|
||
|
self.assertEqual(enabled, self._tx(self._button_msg(Buttons.CANCEL, bus=self.BUTTONS_TX_BUS)))
|
||
|
|
||
|
def test_enable_control_allowed_from_cruise(self):
|
||
|
"""
|
||
|
Hyundai non-longitudinal only enables on PCM rising edge and recent button press. Tests PCM enabling with:
|
||
|
- disallowed: No buttons
|
||
|
- disallowed: Buttons that don't enable cruise
|
||
|
- allowed: Buttons that do enable cruise
|
||
|
- allowed: Main button with all above combinations
|
||
|
"""
|
||
|
for main_button in (0, 1):
|
||
|
for btn in range(8):
|
||
|
for _ in range(PREV_BUTTON_SAMPLES): # reset
|
||
|
self._rx(self._button_msg(Buttons.NONE))
|
||
|
|
||
|
self._rx(self._pcm_status_msg(False))
|
||
|
self.assertFalse(self.safety.get_controls_allowed())
|
||
|
self._rx(self._button_msg(btn, main_button=main_button))
|
||
|
self._rx(self._pcm_status_msg(True))
|
||
|
controls_allowed = btn in ENABLE_BUTTONS or main_button
|
||
|
self.assertEqual(controls_allowed, self.safety.get_controls_allowed())
|
||
|
|
||
|
def test_sampling_cruise_buttons(self):
|
||
|
"""
|
||
|
Test that we allow controls on recent button press, but not as button leaves sliding window
|
||
|
"""
|
||
|
self._rx(self._button_msg(Buttons.SET))
|
||
|
for i in range(2 * PREV_BUTTON_SAMPLES):
|
||
|
self._rx(self._pcm_status_msg(False))
|
||
|
self.assertFalse(self.safety.get_controls_allowed())
|
||
|
self._rx(self._pcm_status_msg(True))
|
||
|
controls_allowed = i < PREV_BUTTON_SAMPLES
|
||
|
self.assertEqual(controls_allowed, self.safety.get_controls_allowed())
|
||
|
self._rx(self._button_msg(Buttons.NONE))
|
||
|
|
||
|
|
||
|
class HyundaiLongitudinalBase(common.LongitudinalAccelSafetyTest):
|
||
|
# pylint: disable=no-member,abstract-method
|
||
|
|
||
|
DISABLED_ECU_UDS_MSG: tuple[int, int]
|
||
|
DISABLED_ECU_ACTUATION_MSG: tuple[int, int]
|
||
|
|
||
|
@classmethod
|
||
|
def setUpClass(cls):
|
||
|
if cls.__name__ == "HyundaiLongitudinalBase":
|
||
|
cls.safety = None
|
||
|
raise unittest.SkipTest
|
||
|
|
||
|
# override these tests from PandaCarSafetyTest, hyundai longitudinal uses button enable
|
||
|
def test_disable_control_allowed_from_cruise(self):
|
||
|
pass
|
||
|
|
||
|
def test_enable_control_allowed_from_cruise(self):
|
||
|
pass
|
||
|
|
||
|
def test_sampling_cruise_buttons(self):
|
||
|
pass
|
||
|
|
||
|
def test_cruise_engaged_prev(self):
|
||
|
pass
|
||
|
|
||
|
def test_button_sends(self):
|
||
|
pass
|
||
|
|
||
|
def _pcm_status_msg(self, enable):
|
||
|
raise Exception
|
||
|
|
||
|
def _accel_msg(self, accel, aeb_req=False, aeb_decel=0):
|
||
|
raise NotImplementedError
|
||
|
|
||
|
def test_set_resume_buttons(self):
|
||
|
"""
|
||
|
SET and RESUME enter controls allowed on their falling edge.
|
||
|
"""
|
||
|
for btn_prev in range(8):
|
||
|
for btn_cur in range(8):
|
||
|
self._rx(self._button_msg(Buttons.NONE))
|
||
|
self.safety.set_controls_allowed(0)
|
||
|
for _ in range(10):
|
||
|
self._rx(self._button_msg(btn_prev))
|
||
|
self.assertFalse(self.safety.get_controls_allowed())
|
||
|
|
||
|
# should enter controls allowed on falling edge and not transitioning to cancel
|
||
|
should_enable = btn_cur != btn_prev and \
|
||
|
btn_cur != Buttons.CANCEL and \
|
||
|
btn_prev in (Buttons.RESUME, Buttons.SET)
|
||
|
|
||
|
self._rx(self._button_msg(btn_cur))
|
||
|
self.assertEqual(should_enable, self.safety.get_controls_allowed())
|
||
|
|
||
|
def test_cancel_button(self):
|
||
|
self.safety.set_controls_allowed(1)
|
||
|
self._rx(self._button_msg(Buttons.CANCEL))
|
||
|
self.assertFalse(self.safety.get_controls_allowed())
|
||
|
|
||
|
def test_tester_present_allowed(self, ecu_disable: bool = True):
|
||
|
"""
|
||
|
Ensure tester present diagnostic message is allowed to keep ECU knocked out
|
||
|
for longitudinal control.
|
||
|
"""
|
||
|
|
||
|
addr, bus = self.DISABLED_ECU_UDS_MSG
|
||
|
for should_tx, msg in ((True, b"\x02\x3E\x80\x00\x00\x00\x00\x00"),
|
||
|
(False, b"\x03\xAA\xAA\x00\x00\x00\x00\x00")):
|
||
|
tester_present = libsafety_py.make_CANPacket(addr, bus, msg)
|
||
|
self.assertEqual(should_tx and ecu_disable, self._tx(tester_present))
|
||
|
|
||
|
def test_disabled_ecu_alive(self):
|
||
|
"""
|
||
|
If the ECU knockout failed, make sure the relay malfunction is shown
|
||
|
"""
|
||
|
|
||
|
addr, bus = self.DISABLED_ECU_ACTUATION_MSG
|
||
|
self.assertFalse(self.safety.get_relay_malfunction())
|
||
|
self._rx(make_msg(bus, addr, 8))
|
||
|
self.assertTrue(self.safety.get_relay_malfunction())
|