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