293fa33 Honda: fixed message forwarding addresses from can2 to can0 799c338 Chrysler safety controls (#130) c05b15b Toyota frc on (#141) 8291971 Toyota: using a more generalized CRUISE_ACTIVE bit that works on all cars 6f157aa Toyota frc on (#140) 8d2470c bumped panda version 915ee4f Honda: forwarding CAN0 to camera, so camera can stay on (#139) git-subtree-dir: panda git-subtree-split: 293fa33f830f0c7cdfad31f621c4bdc016aa7d41pull/3/head
							parent
							
								
									a51a60b598
								
							
						
					
					
						commit
						c10a755516
					
				
				 10 changed files with 289 additions and 23 deletions
			
			
		| @ -0,0 +1,136 @@ | |||||||
|  | // board enforces
 | ||||||
|  | //   in-state
 | ||||||
|  | //      ACC is active (green)
 | ||||||
|  | //   out-state
 | ||||||
|  | //      brake pressed
 | ||||||
|  | //      stock LKAS ECU is online
 | ||||||
|  | //      ACC is not active (white or disabled)
 | ||||||
|  | 
 | ||||||
|  | // chrysler_: namespacing
 | ||||||
|  | int chrysler_speed = 0; | ||||||
|  | 
 | ||||||
|  | // silence everything if stock ECUs are still online
 | ||||||
|  | int chrysler_lkas_detected = 0; | ||||||
|  | int chrysler_desired_torque_last = 0; | ||||||
|  | 
 | ||||||
|  | static void chrysler_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { | ||||||
|  |   int bus_number = (to_push->RDTR >> 4) & 0xFF; | ||||||
|  |   uint32_t addr; | ||||||
|  |   if (to_push->RIR & 4) { | ||||||
|  |     // Extended
 | ||||||
|  |     // Not looked at, but have to be separated
 | ||||||
|  |     // to avoid address collision
 | ||||||
|  |     addr = to_push->RIR >> 3; | ||||||
|  |   } else { | ||||||
|  |     // Normal
 | ||||||
|  |     addr = to_push->RIR >> 21; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   if (addr == 0x144 && bus_number == 0) { | ||||||
|  |     chrysler_speed = ((to_push->RDLR & 0xFF000000) >> 16) | (to_push->RDHR & 0xFF); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // check if stock LKAS ECU is still online
 | ||||||
|  |   if (addr == 0x292 && bus_number == 0) { | ||||||
|  |     chrysler_lkas_detected = 1; | ||||||
|  |     controls_allowed = 0; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // ["ACC_2"]['ACC_STATUS_2'] == 7 for active (green) Adaptive Cruise Control
 | ||||||
|  |   if (addr == 0x1f4 && bus_number == 0) { | ||||||
|  |     if (((to_push->RDLR & 0x380000) >> 19) == 7) { | ||||||
|  |       controls_allowed = 1; | ||||||
|  |     } else { | ||||||
|  |       controls_allowed = 0; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // exit controls on brake press by human
 | ||||||
|  |   if (addr == 0x140) { | ||||||
|  |     if (to_push->RDLR & 0x4) { | ||||||
|  |       controls_allowed = 0; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // if controls_allowed
 | ||||||
|  | //     allow steering up to limit
 | ||||||
|  | // else
 | ||||||
|  | //     block all commands that produce actuation
 | ||||||
|  | static int chrysler_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { | ||||||
|  |   // There can be only one! (LKAS)
 | ||||||
|  |   if (chrysler_lkas_detected) { | ||||||
|  |     return 0; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   uint32_t addr; | ||||||
|  |   if (to_send->RIR & 4) { | ||||||
|  |     // Extended
 | ||||||
|  |     addr = to_send->RIR >> 3; | ||||||
|  |   } else { | ||||||
|  |     // Normal
 | ||||||
|  |     addr = to_send->RIR >> 21; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // LKA STEER: Too large of values cause the steering actuator ECU to silently
 | ||||||
|  |   // fault and no longer actuate the wheel until the car is rebooted.
 | ||||||
|  |   if (addr == 0x292) { | ||||||
|  |     int rdlr = to_send->RDLR; | ||||||
|  |     int straight = 1024; | ||||||
|  |     int steer = ((rdlr & 0x7) << 8) + ((rdlr & 0xFF00) >> 8) - straight; | ||||||
|  |     int max_steer = 230; | ||||||
|  |     int max_rate = 50; // ECU is fine with 100, but 3 is typical.
 | ||||||
|  |     if (steer > max_steer) { | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |     if (steer < -max_steer) { | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |     if (!controls_allowed && steer != 0) { | ||||||
|  |       // If controls not allowed, only allow steering to move closer to 0.
 | ||||||
|  |       if (chrysler_desired_torque_last == 0) { | ||||||
|  | 	return false; | ||||||
|  |       } | ||||||
|  |       if ((chrysler_desired_torque_last > 0) && (steer >= chrysler_desired_torque_last)) { | ||||||
|  | 	return false; | ||||||
|  |       } | ||||||
|  |       if ((chrysler_desired_torque_last < 0) && (steer <= chrysler_desired_torque_last)) { | ||||||
|  | 	return false; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     if (steer < (chrysler_desired_torque_last - max_rate)) { | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |     if (steer > (chrysler_desired_torque_last + max_rate)) { | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |     
 | ||||||
|  |     chrysler_desired_torque_last = steer; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // 1 allows the message through
 | ||||||
|  |   return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int chrysler_tx_lin_hook(int lin_num, uint8_t *data, int len) { | ||||||
|  |   // LIN is not used.
 | ||||||
|  |   return false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void chrysler_init(int16_t param) { | ||||||
|  |   controls_allowed = 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int chrysler_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) { | ||||||
|  |   return -1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const safety_hooks chrysler_hooks = { | ||||||
|  |   .init = chrysler_init, | ||||||
|  |   .rx = chrysler_rx_hook, | ||||||
|  |   .tx = chrysler_tx_hook, | ||||||
|  |   .tx_lin = chrysler_tx_lin_hook, | ||||||
|  |   .ignition = default_ign_hook, | ||||||
|  |   .fwd = chrysler_fwd_hook, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| @ -0,0 +1,88 @@ | |||||||
|  | #!/usr/bin/env python2 | ||||||
|  | import unittest | ||||||
|  | import numpy as np | ||||||
|  | import libpandasafety_py | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class TestChryslerSafety(unittest.TestCase): | ||||||
|  |   @classmethod | ||||||
|  |   def setUp(cls): | ||||||
|  |     cls.safety = libpandasafety_py.libpandasafety | ||||||
|  |     cls.safety.chrysler_init(0) | ||||||
|  |     cls.safety.init_tests_chrysler() | ||||||
|  | 
 | ||||||
|  |   def _acc_msg(self, active): | ||||||
|  |     to_send = libpandasafety_py.ffi.new('CAN_FIFOMailBox_TypeDef *') | ||||||
|  |     to_send[0].RIR = 0x1f4 << 21 | ||||||
|  |     to_send[0].RDLR = 0xfe3fff1f if active else 0xfe0fff1f | ||||||
|  |     return to_send | ||||||
|  |      | ||||||
|  | 
 | ||||||
|  |   def _brake_msg(self, brake): | ||||||
|  |     to_send = libpandasafety_py.ffi.new('CAN_FIFOMailBox_TypeDef *') | ||||||
|  |     to_send[0].RIR = 0x140 << 21 | ||||||
|  |     to_send[0].RDLR = 0x485 if brake else 0x480 | ||||||
|  |     return to_send | ||||||
|  | 
 | ||||||
|  |   def _steer_msg(self, angle): | ||||||
|  |     to_send = libpandasafety_py.ffi.new('CAN_FIFOMailBox_TypeDef *') | ||||||
|  |     to_send[0].RIR = 0x292 << 21 | ||||||
|  |     c_angle = (1024 + angle) | ||||||
|  |     to_send[0].RDLR = 0x10 | ((c_angle & 0xf00) >> 8) | ((c_angle & 0xff) << 8) | ||||||
|  |     return to_send | ||||||
|  | 
 | ||||||
|  |   def test_default_controls_not_allowed(self): | ||||||
|  |     self.assertFalse(self.safety.get_controls_allowed()) | ||||||
|  | 
 | ||||||
|  |   def test_acc_enables_controls(self): | ||||||
|  |     self.safety.set_controls_allowed(0) | ||||||
|  |     self.safety.chrysler_rx_hook(self._acc_msg(0)) | ||||||
|  |     self.assertFalse(self.safety.get_controls_allowed()) | ||||||
|  |     self.safety.chrysler_rx_hook(self._acc_msg(1)) | ||||||
|  |     self.assertTrue(self.safety.get_controls_allowed()) | ||||||
|  |     self.safety.chrysler_rx_hook(self._acc_msg(0)) | ||||||
|  |     self.assertFalse(self.safety.get_controls_allowed()) | ||||||
|  | 
 | ||||||
|  |   def test_disengage_on_brake(self): | ||||||
|  |     self.safety.set_controls_allowed(1) | ||||||
|  |     self.safety.chrysler_rx_hook(self._brake_msg(0)) | ||||||
|  |     self.assertTrue(self.safety.get_controls_allowed()) | ||||||
|  |     self.safety.chrysler_rx_hook(self._brake_msg(1)) | ||||||
|  |     self.assertFalse(self.safety.get_controls_allowed()) | ||||||
|  | 
 | ||||||
|  |   def test_steer_calculation(self): | ||||||
|  |     self.assertEqual(0x14, self._steer_msg(0)[0].RDLR)  # straight, no steering | ||||||
|  | 
 | ||||||
|  |   def test_steer_tx(self): | ||||||
|  |     self.safety.set_controls_allowed(1) | ||||||
|  |     self.assertTrue(self.safety.chrysler_tx_hook(self._steer_msg(0))) | ||||||
|  |     self.safety.set_chrysler_desired_torque_last(227) | ||||||
|  |     self.assertTrue(self.safety.chrysler_tx_hook(self._steer_msg(230))) | ||||||
|  |     self.assertFalse(self.safety.chrysler_tx_hook(self._steer_msg(231))) | ||||||
|  |     self.safety.set_chrysler_desired_torque_last(-227) | ||||||
|  |     self.assertFalse(self.safety.chrysler_tx_hook(self._steer_msg(-231))) | ||||||
|  |     self.assertTrue(self.safety.chrysler_tx_hook(self._steer_msg(-230))) | ||||||
|  |     # verify max change | ||||||
|  |     self.safety.set_chrysler_desired_torque_last(0) | ||||||
|  |     self.assertFalse(self.safety.chrysler_tx_hook(self._steer_msg(230))) | ||||||
|  |      | ||||||
|  |     self.safety.set_controls_allowed(0) | ||||||
|  |     self.safety.set_chrysler_desired_torque_last(0) | ||||||
|  |     self.assertFalse(self.safety.chrysler_tx_hook(self._steer_msg(3))) | ||||||
|  |     self.assertTrue(self.safety.chrysler_tx_hook(self._steer_msg(0))) | ||||||
|  |     # verify when controls not allowed we can still go back towards 0 | ||||||
|  |     self.safety.set_chrysler_desired_torque_last(10) | ||||||
|  |     self.assertFalse(self.safety.chrysler_tx_hook(self._steer_msg(10))) | ||||||
|  |     self.assertFalse(self.safety.chrysler_tx_hook(self._steer_msg(11))) | ||||||
|  |     self.assertTrue(self.safety.chrysler_tx_hook(self._steer_msg(7))) | ||||||
|  |     self.assertTrue(self.safety.chrysler_tx_hook(self._steer_msg(4))) | ||||||
|  |     self.assertTrue(self.safety.chrysler_tx_hook(self._steer_msg(0))) | ||||||
|  |     self.safety.set_chrysler_desired_torque_last(-10) | ||||||
|  |     self.assertFalse(self.safety.chrysler_tx_hook(self._steer_msg(-10))) | ||||||
|  |     self.assertFalse(self.safety.chrysler_tx_hook(self._steer_msg(-11))) | ||||||
|  |     self.assertTrue(self.safety.chrysler_tx_hook(self._steer_msg(-7))) | ||||||
|  |     self.assertTrue(self.safety.chrysler_tx_hook(self._steer_msg(-4))) | ||||||
|  |     self.assertTrue(self.safety.chrysler_tx_hook(self._steer_msg(0))) | ||||||
|  | 
 | ||||||
|  | if __name__ == "__main__": | ||||||
|  |   unittest.main() | ||||||
					Loading…
					
					
				
		Reference in new issue