Safety Test Refactor: Honda (#495)

* nidec

* bosch

* button

* more common

* packer

* more packer

* readability

* tx too

* don't need that

* delete StdTest

* don't need to duplicate this

* only nidec has interceptor
master
Adeeb 2020-04-27 19:40:15 -07:00 committed by GitHub
parent 0632710acd
commit 1dbed65e38
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 229 additions and 391 deletions

View File

@ -197,59 +197,3 @@ class PandaSafetyTest(PandaSafetyTestBase):
self.assertFalse(self.safety.get_controls_allowed()) self.assertFalse(self.safety.get_controls_allowed())
self._rx(self._speed_msg(0)) self._rx(self._speed_msg(0))
# TODO: use PandaSafetyTest for all tests and delete this
class StdTest:
@staticmethod
def test_relay_malfunction(test, addr, bus=0):
# input is a test class and the address that, if seen on specified bus, triggers
# the relay_malfunction protection logic: both tx_hook and fwd_hook are
# expected to return failure
test.assertFalse(test.safety.get_relay_malfunction())
test.safety.safety_rx_hook(make_msg(bus, addr, 8))
test.assertTrue(test.safety.get_relay_malfunction())
for a in range(1, 0x800):
for b in range(0, 3):
test.assertFalse(test.safety.safety_tx_hook(make_msg(b, a, 8)))
test.assertEqual(-1, test.safety.safety_fwd_hook(b, make_msg(b, a, 8)))
@staticmethod
def test_manually_enable_controls_allowed(test):
test.safety.set_controls_allowed(1)
test.assertTrue(test.safety.get_controls_allowed())
test.safety.set_controls_allowed(0)
test.assertFalse(test.safety.get_controls_allowed())
@staticmethod
def test_spam_can_buses(test, TX_MSGS):
for addr in range(1, 0x800):
for bus in range(0, 4):
if all(addr != m[0] or bus != m[1] for m in TX_MSGS):
test.assertFalse(test.safety.safety_tx_hook(make_msg(bus, addr, 8)))
@staticmethod
def test_allow_brake_at_zero_speed(test):
# Brake was already pressed
test.safety.safety_rx_hook(test._speed_msg(0))
test.safety.safety_rx_hook(test._brake_msg(1))
test.safety.set_controls_allowed(1)
test.safety.safety_rx_hook(test._brake_msg(1))
test.assertTrue(test.safety.get_controls_allowed())
test.safety.safety_rx_hook(test._brake_msg(0))
test.assertTrue(test.safety.get_controls_allowed())
# rising edge of brake should disengage
test.safety.safety_rx_hook(test._brake_msg(1))
test.assertFalse(test.safety.get_controls_allowed())
test.safety.safety_rx_hook(test._brake_msg(0)) # reset no brakes
@staticmethod
def test_not_allow_brake_when_moving(test, standstill_threshold):
# Brake was already pressed
test.safety.safety_rx_hook(test._brake_msg(1))
test.safety.set_controls_allowed(1)
test.safety.safety_rx_hook(test._speed_msg(standstill_threshold))
test.safety.safety_rx_hook(test._brake_msg(1))
test.assertTrue(test.safety.get_controls_allowed())
test.safety.safety_rx_hook(test._speed_msg(standstill_threshold + 1))
test.safety.safety_rx_hook(test._brake_msg(1))
test.assertFalse(test.safety.get_controls_allowed())
test.safety.safety_rx_hook(test._speed_msg(0))

View File

@ -3,15 +3,18 @@ import unittest
import numpy as np import numpy as np
from panda import Panda from panda import Panda
from panda.tests.safety import libpandasafety_py from panda.tests.safety import libpandasafety_py
from panda.tests.safety.common import StdTest, make_msg, MAX_WRONG_COUNTERS, UNSAFE_MODE import panda.tests.safety.common as common
from panda.tests.safety.common import CANPackerPanda, make_msg, \
MAX_WRONG_COUNTERS, UNSAFE_MODE
MAX_BRAKE = 255 MAX_BRAKE = 255
INTERCEPTOR_THRESHOLD = 344 INTERCEPTOR_THRESHOLD = 344
N_TX_MSGS = [[0xE4, 0], [0x194, 0], [0x1FA, 0], [0x200, 0], [0x30C, 0], [0x33D, 0]]
BH_TX_MSGS = [[0xE4, 0], [0x296, 1], [0x33D, 0]] # Bosch Harness
BG_TX_MSGS = [[0xE4, 2], [0x296, 0], [0x33D, 2]] # Bosch Giraffe
class Btn:
CANCEL = 2
SET = 3
RESUME = 4
HONDA_N_HW = 0 HONDA_N_HW = 0
HONDA_BG_HW = 1 HONDA_BG_HW = 1
@ -25,283 +28,141 @@ def honda_interceptor_msg(gas, addr):
((gas2 & 0xff) << 24) | ((gas2 & 0xff00) << 8) ((gas2 & 0xff) << 24) | ((gas2 & 0xff00) << 8)
return to_send return to_send
def honda_checksum(msg, addr, len_msg):
checksum = 0
while addr > 0:
checksum += addr
addr >>= 4
for i in range (0, 2*len_msg):
if i < 8:
checksum += (msg.RDLR >> (4 * i))
else:
checksum += (msg.RDHR >> (4 * (i - 8)))
return (8 - checksum) & 0xF
class TestHondaSafety(common.PandaSafetyTest):
class TestHondaSafety(unittest.TestCase):
cnt_speed = 0 cnt_speed = 0
cnt_gas = 0 cnt_gas = 0
cnt_button = 0 cnt_button = 0
PT_BUS = 0
@classmethod @classmethod
def setUp(cls): def setUpClass(cls):
cls.safety = libpandasafety_py.libpandasafety if cls.__name__ == "TestHondaSafety":
cls.safety.set_safety_hooks(Panda.SAFETY_HONDA_NIDEC, 0) cls.packer = None
cls.safety.init_tests_honda() cls.safety = None
raise unittest.SkipTest
# override these inherited tests. honda doesn't use pcm enable
def test_disable_control_allowed_from_cruise(self): pass
def test_enable_control_allowed_from_cruise(self): pass
def _speed_msg(self, speed): def _speed_msg(self, speed):
bus = 1 if self.safety.get_honda_hw() == HONDA_BH_HW else 0 values = {"XMISSION_SPEED": speed, "COUNTER": self.cnt_speed % 4}
to_send = make_msg(bus, 0x158)
to_send[0].RDLR = speed
to_send[0].RDHR |= (self.cnt_speed % 4) << 28
to_send[0].RDHR |= honda_checksum(to_send[0], 0x158, 8) << 24
self.__class__.cnt_speed += 1 self.__class__.cnt_speed += 1
return to_send return self.packer.make_can_msg_panda("ENGINE_DATA", self.PT_BUS, values)
def _button_msg(self, buttons, addr): def _button_msg(self, buttons):
bus = 1 if self.safety.get_honda_hw() == HONDA_BH_HW else 0 values = {"CRUISE_BUTTONS": buttons, "COUNTER": self.cnt_button % 4}
to_send = make_msg(bus, addr)
to_send[0].RDLR = buttons << 5
to_send[0].RDHR |= (self.cnt_button % 4) << 28
to_send[0].RDHR |= honda_checksum(to_send[0], addr, 8) << 24
self.__class__.cnt_button += 1 self.__class__.cnt_button += 1
return to_send return self.packer.make_can_msg_panda("SCM_BUTTONS", self.PT_BUS, values)
def _brake_msg(self, brake): def _brake_msg(self, brake):
bus = 1 if self.safety.get_honda_hw() == HONDA_BH_HW else 0 values = {"BRAKE_PRESSED": brake, "COUNTER": self.cnt_gas % 4}
to_send = make_msg(bus, 0x17C)
to_send[0].RDHR = 0x200000 if brake else 0
to_send[0].RDHR |= (self.cnt_gas % 4) << 28
to_send[0].RDHR |= honda_checksum(to_send[0], 0x17C, 8) << 24
self.__class__.cnt_gas += 1 self.__class__.cnt_gas += 1
return to_send return self.packer.make_can_msg_panda("POWERTRAIN_DATA", self.PT_BUS, values)
def _alt_brake_msg(self, brake):
to_send = make_msg(0, 0x1BE)
to_send[0].RDLR = 0x10 if brake else 0
return to_send
def _gas_msg(self, gas): def _gas_msg(self, gas):
bus = 1 if self.safety.get_honda_hw() == HONDA_BH_HW else 0 values = {"PEDAL_GAS": gas, "COUNTER": self.cnt_gas % 4}
to_send = make_msg(bus, 0x17C)
to_send[0].RDLR = 1 if gas else 0
to_send[0].RDHR |= (self.cnt_gas % 4) << 28
to_send[0].RDHR |= honda_checksum(to_send[0], 0x17C, 8) << 24
self.__class__.cnt_gas += 1 self.__class__.cnt_gas += 1
return to_send return self.packer.make_can_msg_panda("POWERTRAIN_DATA", self.PT_BUS, values)
def _send_brake_msg(self, brake): def _send_brake_msg(self, brake):
to_send = make_msg(0, 0x1FA) values = {}
to_send[0].RDLR = ((brake & 0x3) << 14) | ((brake & 0x3FF) >> 2) if self.safety.get_honda_hw() == HONDA_N_HW:
return to_send values = {"COMPUTER_BRAKE": brake}
return self.packer.make_can_msg_panda("BRAKE_COMMAND", 0, values)
def _send_steer_msg(self, steer): def _send_steer_msg(self, steer):
bus = 2 if self.safety.get_honda_hw() == HONDA_BG_HW else 0 values = {"STEER_TORQUE": steer}
to_send = make_msg(bus, 0xE4, 6) return self.packer.make_can_msg_panda("STEERING_CONTROL", 0, values)
to_send[0].RDLR = steer
return to_send
def test_spam_can_buses(self):
hw_type = self.safety.get_honda_hw()
if hw_type == HONDA_N_HW:
tx_msgs = N_TX_MSGS
elif hw_type == HONDA_BH_HW:
tx_msgs = BH_TX_MSGS
elif hw_type == HONDA_BG_HW:
tx_msgs = BG_TX_MSGS
StdTest.test_spam_can_buses(self, tx_msgs)
def test_relay_malfunction(self):
hw = self.safety.get_honda_hw()
bus = 2 if hw == HONDA_BG_HW else 0
StdTest.test_relay_malfunction(self, 0xE4, bus=bus)
def test_default_controls_not_allowed(self):
self.assertFalse(self.safety.get_controls_allowed())
def test_manually_enable_controls_allowed(self):
StdTest.test_manually_enable_controls_allowed(self)
def test_resume_button(self): def test_resume_button(self):
RESUME_BTN = 4
self.safety.set_controls_allowed(0) self.safety.set_controls_allowed(0)
self.safety.safety_rx_hook(self._button_msg(RESUME_BTN, 0x296)) self._rx(self._button_msg(Btn.RESUME))
self.assertTrue(self.safety.get_controls_allowed()) self.assertTrue(self.safety.get_controls_allowed())
def test_set_button(self): def test_set_button(self):
SET_BTN = 3
self.safety.set_controls_allowed(0) self.safety.set_controls_allowed(0)
self.safety.safety_rx_hook(self._button_msg(SET_BTN, 0x296)) self._rx(self._button_msg(Btn.SET))
self.assertTrue(self.safety.get_controls_allowed()) self.assertTrue(self.safety.get_controls_allowed())
def test_cancel_button(self): def test_cancel_button(self):
CANCEL_BTN = 2
self.safety.set_controls_allowed(1) self.safety.set_controls_allowed(1)
self.safety.safety_rx_hook(self._button_msg(CANCEL_BTN, 0x296)) self._rx(self._button_msg(Btn.CANCEL))
self.assertFalse(self.safety.get_controls_allowed()) self.assertFalse(self.safety.get_controls_allowed())
def test_sample_speed(self): def test_sample_speed(self):
self.assertEqual(0, self.safety.get_honda_moving()) self.assertEqual(0, self.safety.get_honda_moving())
self.safety.safety_rx_hook(self._speed_msg(100)) self._rx(self._speed_msg(100))
self.assertEqual(1, self.safety.get_honda_moving()) self.assertEqual(1, self.safety.get_honda_moving())
def test_prev_brake(self):
self.assertFalse(self.safety.get_brake_pressed_prev())
self.safety.safety_rx_hook(self._brake_msg(True))
self.assertTrue(self.safety.get_brake_pressed_prev())
def test_disengage_on_brake(self): def test_disengage_on_brake(self):
self.safety.set_controls_allowed(1) self.safety.set_controls_allowed(1)
self.safety.safety_rx_hook(self._brake_msg(1)) self._rx(self._brake_msg(1))
self.assertFalse(self.safety.get_controls_allowed()) self.assertFalse(self.safety.get_controls_allowed())
def test_alt_disengage_on_brake(self):
self.safety.set_honda_alt_brake_msg(1)
self.safety.set_controls_allowed(1)
self.safety.safety_rx_hook(self._alt_brake_msg(1))
self.assertFalse(self.safety.get_controls_allowed())
self.safety.set_honda_alt_brake_msg(0)
self.safety.set_controls_allowed(1)
self.safety.safety_rx_hook(self._alt_brake_msg(1))
self.assertTrue(self.safety.get_controls_allowed())
def test_brake_disengage(self):
StdTest.test_allow_brake_at_zero_speed(self)
StdTest.test_not_allow_brake_when_moving(self, 0)
def test_prev_gas(self):
self.safety.safety_rx_hook(self._gas_msg(False))
self.assertFalse(self.safety.get_gas_pressed_prev())
self.safety.safety_rx_hook(self._gas_msg(True))
self.assertTrue(self.safety.get_gas_pressed_prev())
def test_prev_gas_interceptor(self): def test_prev_gas_interceptor(self):
self.safety.safety_rx_hook(honda_interceptor_msg(0x0, 0x201)) self._rx(honda_interceptor_msg(0x0, 0x201))
self.assertFalse(self.safety.get_gas_interceptor_prev()) self.assertFalse(self.safety.get_gas_interceptor_prev())
self.safety.safety_rx_hook(honda_interceptor_msg(0x1000, 0x201)) self._rx(honda_interceptor_msg(0x1000, 0x201))
self.assertTrue(self.safety.get_gas_interceptor_prev()) self.assertTrue(self.safety.get_gas_interceptor_prev())
self.safety.safety_rx_hook(honda_interceptor_msg(0x0, 0x201)) self._rx(honda_interceptor_msg(0x0, 0x201))
self.safety.set_gas_interceptor_detected(False) self.safety.set_gas_interceptor_detected(False)
def test_disengage_on_gas(self):
self.safety.safety_rx_hook(self._gas_msg(0))
self.safety.set_controls_allowed(1)
self.safety.safety_rx_hook(self._gas_msg(1))
self.assertFalse(self.safety.get_controls_allowed())
def test_unsafe_mode_no_disengage_on_gas(self):
self.safety.safety_rx_hook(self._gas_msg(0))
self.safety.set_controls_allowed(1)
self.safety.set_unsafe_mode(UNSAFE_MODE.DISABLE_DISENGAGE_ON_GAS)
self.safety.safety_rx_hook(self._gas_msg(1))
self.assertTrue(self.safety.get_controls_allowed())
self.safety.set_unsafe_mode(UNSAFE_MODE.DEFAULT)
def test_allow_engage_with_gas_pressed(self):
self.safety.safety_rx_hook(self._gas_msg(1))
self.safety.set_controls_allowed(1)
self.safety.safety_rx_hook(self._gas_msg(1))
self.assertTrue(self.safety.get_controls_allowed())
def test_disengage_on_gas_interceptor(self): def test_disengage_on_gas_interceptor(self):
for g in range(0, 0x1000): for g in range(0, 0x1000):
self.safety.safety_rx_hook(honda_interceptor_msg(0, 0x201)) self._rx(honda_interceptor_msg(0, 0x201))
self.safety.set_controls_allowed(True) self.safety.set_controls_allowed(True)
self.safety.safety_rx_hook(honda_interceptor_msg(g, 0x201)) self._rx(honda_interceptor_msg(g, 0x201))
remain_enabled = g <= INTERCEPTOR_THRESHOLD remain_enabled = g <= INTERCEPTOR_THRESHOLD
self.assertEqual(remain_enabled, self.safety.get_controls_allowed()) self.assertEqual(remain_enabled, self.safety.get_controls_allowed())
self.safety.safety_rx_hook(honda_interceptor_msg(0, 0x201)) self._rx(honda_interceptor_msg(0, 0x201))
self.safety.set_gas_interceptor_detected(False) self.safety.set_gas_interceptor_detected(False)
def test_unsafe_mode_no_disengage_on_gas_interceptor(self): def test_unsafe_mode_no_disengage_on_gas_interceptor(self):
self.safety.set_controls_allowed(True) self.safety.set_controls_allowed(True)
self.safety.set_unsafe_mode(UNSAFE_MODE.DISABLE_DISENGAGE_ON_GAS) self.safety.set_unsafe_mode(UNSAFE_MODE.DISABLE_DISENGAGE_ON_GAS)
for g in range(0, 0x1000): for g in range(0, 0x1000):
self.safety.safety_rx_hook(honda_interceptor_msg(g, 0x201)) self._rx(honda_interceptor_msg(g, 0x201))
self.assertTrue(self.safety.get_controls_allowed()) self.assertTrue(self.safety.get_controls_allowed())
self.safety.safety_rx_hook(honda_interceptor_msg(0, 0x201)) self._rx(honda_interceptor_msg(0, 0x201))
self.safety.set_gas_interceptor_detected(False) self.safety.set_gas_interceptor_detected(False)
self.safety.set_unsafe_mode(UNSAFE_MODE.DEFAULT) self.safety.set_unsafe_mode(UNSAFE_MODE.DEFAULT)
self.safety.set_controls_allowed(False) self.safety.set_controls_allowed(False)
def test_allow_engage_with_gas_interceptor_pressed(self): def test_allow_engage_with_gas_interceptor_pressed(self):
self.safety.safety_rx_hook(honda_interceptor_msg(0x1000, 0x201)) self._rx(honda_interceptor_msg(0x1000, 0x201))
self.safety.set_controls_allowed(1) self.safety.set_controls_allowed(1)
self.safety.safety_rx_hook(honda_interceptor_msg(0x1000, 0x201)) self._rx(honda_interceptor_msg(0x1000, 0x201))
self.assertTrue(self.safety.get_controls_allowed()) self.assertTrue(self.safety.get_controls_allowed())
self.safety.safety_rx_hook(honda_interceptor_msg(0, 0x201)) self._rx(honda_interceptor_msg(0, 0x201))
self.safety.set_gas_interceptor_detected(False) self.safety.set_gas_interceptor_detected(False)
def test_brake_safety_check(self):
hw = self.safety.get_honda_hw()
if hw == HONDA_N_HW:
for fwd_brake in [False, True]:
self.safety.set_honda_fwd_brake(fwd_brake)
for brake in np.arange(0, MAX_BRAKE + 10, 1):
for controls_allowed in [True, False]:
self.safety.set_controls_allowed(controls_allowed)
if fwd_brake:
send = False # block openpilot brake msg when fwd'ing stock msg
elif controls_allowed:
send = MAX_BRAKE >= brake >= 0
else:
send = brake == 0
self.assertEqual(send, self.safety.safety_tx_hook(self._send_brake_msg(brake)))
self.safety.set_honda_fwd_brake(False)
def test_gas_interceptor_safety_check(self):
if self.safety.get_honda_hw() == HONDA_N_HW:
for gas in np.arange(0, 4000, 100):
for controls_allowed in [True, False]:
self.safety.set_controls_allowed(controls_allowed)
if controls_allowed:
send = True
else:
send = gas == 0
self.assertEqual(send, self.safety.safety_tx_hook(honda_interceptor_msg(gas, 0x200)))
def test_steer_safety_check(self): def test_steer_safety_check(self):
self.safety.set_controls_allowed(0) self.safety.set_controls_allowed(0)
self.assertTrue(self.safety.safety_tx_hook(self._send_steer_msg(0x0000))) self.assertTrue(self._tx(self._send_steer_msg(0x0000)))
self.assertFalse(self.safety.safety_tx_hook(self._send_steer_msg(0x1000))) self.assertFalse(self._tx(self._send_steer_msg(0x1000)))
def test_spam_cancel_safety_check(self):
hw = self.safety.get_honda_hw()
if hw != HONDA_N_HW:
RESUME_BTN = 4
SET_BTN = 3
CANCEL_BTN = 2
BUTTON_MSG = 0x296
self.safety.set_controls_allowed(0)
self.assertTrue(self.safety.safety_tx_hook(self._button_msg(CANCEL_BTN, BUTTON_MSG)))
self.assertFalse(self.safety.safety_tx_hook(self._button_msg(RESUME_BTN, BUTTON_MSG)))
self.assertFalse(self.safety.safety_tx_hook(self._button_msg(SET_BTN, BUTTON_MSG)))
# do not block resume if we are engaged already
self.safety.set_controls_allowed(1)
self.assertTrue(self.safety.safety_tx_hook(self._button_msg(RESUME_BTN, BUTTON_MSG)))
def test_rx_hook(self): def test_rx_hook(self):
# TODO: move this test to common
# checksum checks # checksum checks
SET_BTN = 3 for msg in ["btn", "gas", "speed"]:
for msg in ["btn1", "btn2", "gas", "speed"]:
self.safety.set_controls_allowed(1) self.safety.set_controls_allowed(1)
if msg == "btn1": # TODO: add this coverage back by re-running all tests with the acura dbc
if self.safety.get_honda_hw() == HONDA_N_HW: # to_push = self._button_msg(Btn.SET, 0x1A6) # only in Honda_NIDEC
to_push = self._button_msg(SET_BTN, 0x1A6) # only in Honda_NIDEC if msg == "btn":
else: to_push = self._button_msg(Btn.SET)
continue
if msg == "btn2":
to_push = self._button_msg(SET_BTN, 0x296)
if msg == "gas": if msg == "gas":
to_push = self._gas_msg(0) to_push = self._gas_msg(0)
if msg == "speed": if msg == "speed":
to_push = self._speed_msg(0) to_push = self._speed_msg(0)
self.assertTrue(self.safety.safety_rx_hook(to_push)) self.assertTrue(self._rx(to_push))
to_push[0].RDHR = 0 # invalidate checksum if msg != "btn":
self.assertFalse(self.safety.safety_rx_hook(to_push)) to_push[0].RDHR = 0 # invalidate checksum
self.assertFalse(self.safety.get_controls_allowed()) self.assertFalse(self._rx(to_push))
self.assertFalse(self.safety.get_controls_allowed())
# counter # counter
# reset wrong_counters to zero by sending valid messages # reset wrong_counters to zero by sending valid messages
@ -311,161 +172,194 @@ class TestHondaSafety(unittest.TestCase):
self.__class__.cnt_button += 1 self.__class__.cnt_button += 1
if i < MAX_WRONG_COUNTERS: if i < MAX_WRONG_COUNTERS:
self.safety.set_controls_allowed(1) self.safety.set_controls_allowed(1)
self.safety.safety_rx_hook(self._button_msg(SET_BTN, 0x296)) self._rx(self._button_msg(Btn.SET))
self.safety.safety_rx_hook(self._speed_msg(0)) self._rx(self._speed_msg(0))
self.safety.safety_rx_hook(self._gas_msg(0)) self._rx(self._gas_msg(0))
else: else:
self.assertFalse(self.safety.safety_rx_hook(self._button_msg(SET_BTN, 0x296))) self.assertFalse(self._rx(self._button_msg(Btn.SET)))
self.assertFalse(self.safety.safety_rx_hook(self._speed_msg(0))) self.assertFalse(self._rx(self._speed_msg(0)))
self.assertFalse(self.safety.safety_rx_hook(self._gas_msg(0))) self.assertFalse(self._rx(self._gas_msg(0)))
self.assertFalse(self.safety.get_controls_allowed()) self.assertFalse(self.safety.get_controls_allowed())
# restore counters for future tests with a couple of good messages # restore counters for future tests with a couple of good messages
for i in range(2): for i in range(2):
self.safety.set_controls_allowed(1) self.safety.set_controls_allowed(1)
self.safety.safety_rx_hook(self._button_msg(SET_BTN, 0x296)) self._rx(self._button_msg(Btn.SET))
self.safety.safety_rx_hook(self._speed_msg(0)) self._rx(self._speed_msg(0))
self.safety.safety_rx_hook(self._gas_msg(0)) self._rx(self._gas_msg(0))
self.safety.safety_rx_hook(self._button_msg(SET_BTN, 0x296)) self._rx(self._button_msg(Btn.SET))
self.assertTrue(self.safety.get_controls_allowed()) self.assertTrue(self.safety.get_controls_allowed())
def test_tx_hook_on_pedal_pressed(self):
for mode in [UNSAFE_MODE.DEFAULT, UNSAFE_MODE.DISABLE_DISENGAGE_ON_GAS]:
for pedal in ['brake', 'gas']:
self.safety.set_unsafe_mode(mode)
allow_ctrl = False
if pedal == 'brake':
# brake_pressed_prev and honda_moving
self._rx(self._speed_msg(100))
self._rx(self._brake_msg(1))
elif pedal == 'gas':
# gas_pressed_prev
self._rx(self._gas_msg(1))
allow_ctrl = mode == UNSAFE_MODE.DISABLE_DISENGAGE_ON_GAS
self.safety.set_controls_allowed(1)
hw = self.safety.get_honda_hw()
if hw == HONDA_N_HW:
self.safety.set_honda_fwd_brake(False)
self.assertEqual(allow_ctrl, self._tx(self._send_brake_msg(MAX_BRAKE)))
self.assertEqual(allow_ctrl, self._tx(self._send_steer_msg(0x1000)))
# reset status
self.safety.set_controls_allowed(0)
self.safety.set_unsafe_mode(UNSAFE_MODE.DEFAULT)
self._tx(self._send_brake_msg(0))
self._tx(self._send_steer_msg(0))
if pedal == 'brake':
self._rx(self._speed_msg(0))
self._rx(self._brake_msg(0))
elif pedal == 'gas':
self._rx(self._gas_msg(0))
class TestHondaNidecSafety(TestHondaSafety):
TX_MSGS = [[0xE4, 0], [0x194, 0], [0x1FA, 0], [0x200, 0], [0x30C, 0], [0x33D, 0]]
STANDSTILL_THRESHOLD = 0
RELAY_MALFUNCTION_ADDR = 0xE4
RELAY_MALFUNCTION_BUS = 0
FWD_BLACKLISTED_ADDRS = {2: [0xE4, 0x194, 0x33D, 0x30C]}
FWD_BUS_LOOKUP = {0: 2, 2: 0}
def setUp(self):
self.packer = CANPackerPanda("honda_civic_touring_2016_can_generated")
self.safety = libpandasafety_py.libpandasafety
self.safety.set_safety_hooks(Panda.SAFETY_HONDA_NIDEC, 0)
self.safety.init_tests_honda()
def test_fwd_hook(self): def test_fwd_hook(self):
buss = list(range(0x0, 0x3)) # normal operation, not forwarding AEB
msgs = list(range(0x1, 0x800)) self.FWD_BLACKLISTED_ADDRS[2].append(0x1FA)
fwd_brake = [False, True] self.safety.set_honda_fwd_brake(False)
super().test_fwd_hook()
for f in fwd_brake: # TODO: test latching until AEB event is over?
self.safety.set_honda_fwd_brake(f) # forwarding AEB brake signal
blocked_msgs = [0xE4, 0x194, 0x33D] self.FWD_BLACKLISTED_ADDRS = {2: [0xE4, 0x194, 0x33D, 0x30C]}
blocked_msgs += [0x30C] self.safety.set_honda_fwd_brake(True)
if not f: super().test_fwd_hook()
blocked_msgs += [0x1FA]
for b in buss:
for m in msgs:
if b == 0:
fwd_bus = 2
elif b == 1:
fwd_bus = -1
elif b == 2:
fwd_bus = -1 if m in blocked_msgs else 0
# assume len 8
self.assertEqual(fwd_bus, self.safety.safety_fwd_hook(b, make_msg(b, m, 8)))
def test_brake_safety_check(self):
for fwd_brake in [False, True]:
self.safety.set_honda_fwd_brake(fwd_brake)
for brake in np.arange(0, MAX_BRAKE + 10, 1):
for controls_allowed in [True, False]:
self.safety.set_controls_allowed(controls_allowed)
if fwd_brake:
send = False # block openpilot brake msg when fwd'ing stock msg
elif controls_allowed:
send = MAX_BRAKE >= brake >= 0
else:
send = brake == 0
self.assertEqual(send, self._tx(self._send_brake_msg(brake)))
self.safety.set_honda_fwd_brake(False) self.safety.set_honda_fwd_brake(False)
def test_tx_hook_on_pedal_pressed(self): def test_gas_interceptor_safety_check(self):
for pedal in ['brake', 'gas', 'interceptor']: for gas in np.arange(0, 4000, 100):
if pedal == 'brake': for controls_allowed in [True, False]:
# brake_pressed_prev and honda_moving self.safety.set_controls_allowed(controls_allowed)
self.safety.safety_rx_hook(self._speed_msg(100)) if controls_allowed:
self.safety.safety_rx_hook(self._brake_msg(1)) send = True
elif pedal == 'gas': else:
# gas_pressed_prev send = gas == 0
self.safety.safety_rx_hook(self._gas_msg(1)) self.assertEqual(send, self._tx(honda_interceptor_msg(gas, 0x200)))
elif pedal == 'interceptor':
# gas_interceptor_prev > INTERCEPTOR_THRESHOLD def test_tx_hook_on_interceptor_pressed(self):
self.safety.safety_rx_hook(honda_interceptor_msg(INTERCEPTOR_THRESHOLD+1, 0x201)) for mode in [UNSAFE_MODE.DEFAULT, UNSAFE_MODE.DISABLE_DISENGAGE_ON_GAS]:
self.safety.safety_rx_hook(honda_interceptor_msg(INTERCEPTOR_THRESHOLD+1, 0x201)) self.safety.set_unsafe_mode(mode)
# gas_interceptor_prev > INTERCEPTOR_THRESHOLD
self._rx(honda_interceptor_msg(INTERCEPTOR_THRESHOLD+1, 0x201))
self._rx(honda_interceptor_msg(INTERCEPTOR_THRESHOLD+1, 0x201))
allow_ctrl = mode == UNSAFE_MODE.DISABLE_DISENGAGE_ON_GAS
self.safety.set_controls_allowed(1) self.safety.set_controls_allowed(1)
hw = self.safety.get_honda_hw() self.safety.set_honda_fwd_brake(False)
if hw == HONDA_N_HW: self.assertEqual(allow_ctrl, self._tx(self._send_brake_msg(MAX_BRAKE)))
self.safety.set_honda_fwd_brake(False) self.assertEqual(allow_ctrl, self._tx(honda_interceptor_msg(INTERCEPTOR_THRESHOLD, 0x200)))
self.assertFalse(self.safety.safety_tx_hook(self._send_brake_msg(MAX_BRAKE))) self.assertEqual(allow_ctrl, self._tx(self._send_steer_msg(0x1000)))
self.assertFalse(self.safety.safety_tx_hook(honda_interceptor_msg(INTERCEPTOR_THRESHOLD, 0x200)))
self.assertFalse(self.safety.safety_tx_hook(self._send_steer_msg(0x1000)))
# reset status
self.safety.set_controls_allowed(0)
self.safety.safety_tx_hook(self._send_brake_msg(0))
self.safety.safety_tx_hook(self._send_steer_msg(0))
self.safety.safety_tx_hook(honda_interceptor_msg(0, 0x200))
if pedal == 'brake':
self.safety.safety_rx_hook(self._speed_msg(0))
self.safety.safety_rx_hook(self._brake_msg(0))
elif pedal == 'gas':
self.safety.safety_rx_hook(self._gas_msg(0))
elif pedal == 'interceptor':
self.safety.set_gas_interceptor_detected(False)
def test_tx_hook_on_pedal_pressed_on_unsafe_gas_mode(self):
for pedal in ['brake', 'gas', 'interceptor']:
self.safety.set_unsafe_mode(UNSAFE_MODE.DISABLE_DISENGAGE_ON_GAS)
if pedal == 'brake':
# brake_pressed_prev and honda_moving
self.safety.safety_rx_hook(self._speed_msg(100))
self.safety.safety_rx_hook(self._brake_msg(1))
allow_ctrl = False
elif pedal == 'gas':
# gas_pressed_prev
self.safety.safety_rx_hook(self._gas_msg(1))
allow_ctrl = True
elif pedal == 'interceptor':
# gas_interceptor_prev > INTERCEPTOR_THRESHOLD
self.safety.safety_rx_hook(honda_interceptor_msg(INTERCEPTOR_THRESHOLD+1, 0x201))
self.safety.safety_rx_hook(honda_interceptor_msg(INTERCEPTOR_THRESHOLD+1, 0x201))
allow_ctrl = True
self.safety.set_controls_allowed(1)
hw = self.safety.get_honda_hw()
if hw == HONDA_N_HW:
self.safety.set_honda_fwd_brake(False)
self.assertEqual(allow_ctrl, self.safety.safety_tx_hook(self._send_brake_msg(MAX_BRAKE)))
self.assertEqual(allow_ctrl, self.safety.safety_tx_hook(honda_interceptor_msg(INTERCEPTOR_THRESHOLD, 0x200)))
self.assertEqual(allow_ctrl, self.safety.safety_tx_hook(self._send_steer_msg(0x1000)))
# reset status # reset status
self.safety.set_controls_allowed(0) self.safety.set_controls_allowed(0)
self.safety.set_unsafe_mode(UNSAFE_MODE.DEFAULT) self.safety.set_unsafe_mode(UNSAFE_MODE.DEFAULT)
self.safety.safety_tx_hook(self._send_brake_msg(0)) self._tx(self._send_brake_msg(0))
self.safety.safety_tx_hook(self._send_steer_msg(0)) self._tx(self._send_steer_msg(0))
self.safety.safety_tx_hook(honda_interceptor_msg(0, 0x200)) self._tx(honda_interceptor_msg(0, 0x200))
if pedal == 'brake': self.safety.set_gas_interceptor_detected(False)
self.safety.safety_rx_hook(self._speed_msg(0))
self.safety.safety_rx_hook(self._brake_msg(0))
elif pedal == 'gas':
self.safety.safety_rx_hook(self._gas_msg(0))
elif pedal == 'interceptor':
self.safety.set_gas_interceptor_detected(False)
class TestHondaBoschGiraffeSafety(TestHondaSafety):
@classmethod
def setUp(cls):
TestHondaSafety.setUp()
cls.safety = libpandasafety_py.libpandasafety
cls.safety.set_safety_hooks(Panda.SAFETY_HONDA_BOSCH_GIRAFFE, 0)
cls.safety.init_tests_honda()
def test_fwd_hook(self):
buss = range(0x0, 0x3)
msgs = range(0x1, 0x800)
hw = self.safety.get_honda_hw()
bus_rdr_cam = 2 if hw == HONDA_BH_HW else 1
bus_rdr_car = 0 if hw == HONDA_BH_HW else 2
bus_pt = 1 if hw == HONDA_BH_HW else 0
blocked_msgs = [0xE4, 0x33D]
for b in buss:
for m in msgs:
if b == bus_pt:
fwd_bus = -1
elif b == bus_rdr_cam:
fwd_bus = -1 if m in blocked_msgs else bus_rdr_car
elif b == bus_rdr_car:
fwd_bus = bus_rdr_cam
# assume len 8
self.assertEqual(fwd_bus, self.safety.safety_fwd_hook(b, make_msg(b, m, 8)))
class TestHondaBoschHarnessSafety(TestHondaBoschGiraffeSafety): class TestHondaBoschHarnessSafety(TestHondaSafety):
@classmethod TX_MSGS = [[0xE4, 0], [0x296, 1], [0x33D, 0]] # Bosch Harness
def setUp(cls): STANDSTILL_THRESHOLD = 0
TestHondaBoschGiraffeSafety.setUp() RELAY_MALFUNCTION_ADDR = 0xE4
cls.safety = libpandasafety_py.libpandasafety RELAY_MALFUNCTION_BUS = 0
cls.safety.set_safety_hooks(Panda.SAFETY_HONDA_BOSCH_HARNESS, 0) FWD_BLACKLISTED_ADDRS = {2: [0xE4, 0x33D]}
cls.safety.init_tests_honda() FWD_BUS_LOOKUP = {0: 2, 2: 0}
PT_BUS = 1
def setUp(self):
self.packer = CANPackerPanda("honda_accord_s2t_2018_can_generated")
self.safety = libpandasafety_py.libpandasafety
self.safety.set_safety_hooks(Panda.SAFETY_HONDA_BOSCH_HARNESS, 0)
self.safety.init_tests_honda()
def _alt_brake_msg(self, brake):
to_send = make_msg(0, 0x1BE)
to_send[0].RDLR = 0x10 if brake else 0
return to_send
def test_spam_cancel_safety_check(self):
self.safety.set_controls_allowed(0)
self.assertTrue(self._tx(self._button_msg(Btn.CANCEL)))
self.assertFalse(self._tx(self._button_msg(Btn.RESUME)))
self.assertFalse(self._tx(self._button_msg(Btn.SET)))
# do not block resume if we are engaged already
self.safety.set_controls_allowed(1)
self.assertTrue(self._tx(self._button_msg(Btn.RESUME)))
def test_alt_disengage_on_brake(self):
self.safety.set_honda_alt_brake_msg(1)
self.safety.set_controls_allowed(1)
self._rx(self._alt_brake_msg(1))
self.assertFalse(self.safety.get_controls_allowed())
self.safety.set_honda_alt_brake_msg(0)
self.safety.set_controls_allowed(1)
self._rx(self._alt_brake_msg(1))
self.assertTrue(self.safety.get_controls_allowed())
class TestHondaBoschGiraffeSafety(TestHondaBoschHarnessSafety):
TX_MSGS = [[0xE4, 2], [0x296, 0], [0x33D, 2]] # Bosch Giraffe
STANDSTILL_THRESHOLD = 0
RELAY_MALFUNCTION_ADDR = 0xE4
RELAY_MALFUNCTION_BUS = 2
FWD_BLACKLISTED_ADDRS = {1: [0xE4, 0x33D]}
FWD_BUS_LOOKUP = {1: 2, 2: 1}
PT_BUS = 0
def setUp(self):
super().setUp()
self.safety = libpandasafety_py.libpandasafety
self.safety.set_safety_hooks(Panda.SAFETY_HONDA_BOSCH_GIRAFFE, 0)
self.safety.init_tests_honda()
def _send_steer_msg(self, steer):
values = {"STEER_TORQUE": steer}
return self.packer.make_can_msg_panda("STEERING_CONTROL", 2, values)
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()