From d21c6591c1dead728b2e644f2f55cde2449269c1 Mon Sep 17 00:00:00 2001 From: Vehicle Researcher Date: Wed, 23 Jan 2019 15:28:16 -0800 Subject: [PATCH] Squashed 'panda/' changes from 293fa33..9ee6285 9ee6285 optimize board build for size to avoid going over the limit. (#150) 20e8fa9 Start introducing Bounties a2046e9 make it smaller 1dfcf2b update panda price 37ee289 chrysler safety: fixed comments c2dfbad tesla safety: return -1 to block forward (#149) 74c0c1b update README be0061d Chrysler: safety now based on motor torque 039d183 Chrysler: fixed regression test 9193eeb Chrysler: safety limits updated 04f1d44 Chrysler safety: 3 sa max rate down for now cf3ecd6 Chrysler safety: re-using hyundai framework 49ed9bc Update CLICKS for longer bootup time of EONS and avoid unwanted fast charge mode git-subtree-dir: panda git-subtree-split: 9ee628557f3f33759c62b567964b918a597d3387 --- README.md | 2 +- VERSION | 2 +- board/bootstub.c | 3 + board/build.mk | 4 +- board/main.c | 6 +- board/safety/safety_chrysler.h | 158 ++++++++++++------------- board/safety/safety_tesla.h | 6 +- buy.png | Bin 12200 -> 4264 bytes tests/safety/libpandasafety_py.py | 6 +- tests/safety/test.c | 32 ++++- tests/safety/test_chrysler.py | 187 +++++++++++++++++++++--------- 11 files changed, 261 insertions(+), 145 deletions(-) diff --git a/README.md b/README.md index e323d400e1..42f432dfc3 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Welcome to panda [panda](http://github.com/commaai/panda) is the nicest universal car interface ever. - + diff --git a/VERSION b/VERSION index 301779b03e..02e8c95da5 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v1.1.7 \ No newline at end of file +v1.1.8 \ No newline at end of file diff --git a/board/bootstub.c b/board/bootstub.c index 4e516110c5..e44986c29e 100644 --- a/board/bootstub.c +++ b/board/bootstub.c @@ -51,6 +51,9 @@ void fail() { // know where to sig check extern void *_app_start[]; +// FIXME: sometimes your panda will fail flashing and will quickly blink a single Green LED +// BOUNTY: $200 coupon on shop.comma.ai or $100 check. + int main() { __disable_irq(); clock_init(); diff --git a/board/build.mk b/board/build.mk index aee724c190..9f2c4250c2 100644 --- a/board/build.mk +++ b/board/build.mk @@ -1,4 +1,4 @@ -CFLAGS += -I inc -I ../ -nostdlib -fno-builtin -std=gnu11 -O2 +CFLAGS += -I inc -I ../ -nostdlib -fno-builtin -std=gnu11 -Os CFLAGS += -Tstm32_flash.ld @@ -51,6 +51,8 @@ obj/$(PROJ_NAME).bin: obj/$(STARTUP_FILE).o obj/main.$(PROJ_NAME).o $(CC) -Wl,--section-start,.isr_vector=0x8004000 $(CFLAGS) -o obj/$(PROJ_NAME).elf $^ $(OBJCOPY) -v -O binary obj/$(PROJ_NAME).elf obj/code.bin SETLEN=1 ../crypto/sign.py obj/code.bin $@ $(CERT) + @BINSIZE=$$(du -b "obj/$(PROJ_NAME).bin" | cut -f 1) ; if [ $$BINSIZE -ge 32768 ]; then echo "ERROR obj/$(PROJ_NAME).bin is too big!"; exit 1; fi; + obj/bootstub.$(PROJ_NAME).bin: obj/$(STARTUP_FILE).o obj/bootstub.$(PROJ_NAME).o obj/sha.$(PROJ_NAME).o obj/rsa.$(PROJ_NAME).o $(CC) $(CFLAGS) -o obj/bootstub.$(PROJ_NAME).elf $^ diff --git a/board/main.c b/board/main.c index 8bb6a0cee0..b1033bb732 100644 --- a/board/main.c +++ b/board/main.c @@ -589,6 +589,8 @@ int main() { uint64_t marker = 0; #define CURRENT_THRESHOLD 0xF00 #define CLICKS 8 + // Enough clicks to ensure that enumeration happened. Should be longer than bootup time of the device connected to EON + #define CLICKS_BOOTUP 30 #endif for (cnt=0;;cnt++) { @@ -615,8 +617,8 @@ int main() { } break; case USB_POWER_CDP: - // been CLICKS clicks since we switched to CDP - if ((cnt-marker) >= CLICKS) { + // been CLICKS_BOOTUP clicks since we switched to CDP + if ((cnt-marker) >= CLICKS_BOOTUP ) { // measure current draw, if positive and no enumeration, switch to DCP if (!is_enumerated && current < CURRENT_THRESHOLD) { puts("USBP: no enumeration with current draw, switching to DCP mode\n"); diff --git a/board/safety/safety_chrysler.h b/board/safety/safety_chrysler.h index eadc8eaa7c..b1c6a743f1 100644 --- a/board/safety/safety_chrysler.h +++ b/board/safety/safety_chrysler.h @@ -1,20 +1,19 @@ -// 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; +const int CHRYSLER_MAX_STEER = 261; +const int CHRYSLER_MAX_RT_DELTA = 112; // max delta torque allowed for real time checks +const int32_t CHRYSLER_RT_INTERVAL = 250000; // 250ms between real time checks +const int CHRYSLER_MAX_RATE_UP = 3; +const int CHRYSLER_MAX_RATE_DOWN = 3; +const int CHRYSLER_MAX_TORQUE_ERROR = 80; // max torque cmd in excess of torque motor + +int chrysler_camera_detected = 0; +int chrysler_rt_torque_last = 0; int chrysler_desired_torque_last = 0; +int chrysler_cruise_engaged_last = 0; +uint32_t chrysler_ts_last = 0; +struct sample_t chrysler_torque_meas; // last few torques measured static void chrysler_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { - int bus_number = (to_push->RDTR >> 4) & 0xFF; + int bus = (to_push->RDTR >> 4) & 0xFF; uint32_t addr; if (to_push->RIR & 4) { // Extended @@ -26,40 +25,37 @@ static void chrysler_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { addr = to_push->RIR >> 21; } - if (addr == 0x144 && bus_number == 0) { - chrysler_speed = ((to_push->RDLR & 0xFF000000) >> 16) | (to_push->RDHR & 0xFF); - } + // Measured eps torque + if (addr == 544) { + int rdhr = to_push->RDHR; + int torque_meas_new = ((rdhr & 0x7) << 8) + ((rdhr & 0xFF00) >> 8) - 1024; - // check if stock LKAS ECU is still online - if (addr == 0x292 && bus_number == 0) { - chrysler_lkas_detected = 1; - controls_allowed = 0; + // update array of samples + update_sample(&chrysler_torque_meas, torque_meas_new); } - // ["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) { + // enter controls on rising edge of ACC, exit controls on ACC off + if (addr == 0x1f4) { + int cruise_engaged = ((to_push->RDLR & 0x380000) >> 19) == 7; + if (cruise_engaged && !chrysler_cruise_engaged_last) { controls_allowed = 1; - } else { + } else if (!cruise_engaged) { controls_allowed = 0; } + chrysler_cruise_engaged_last = cruise_engaged; } - // exit controls on brake press by human - if (addr == 0x140) { - if (to_push->RDLR & 0x4) { - controls_allowed = 0; - } + // check if stock camera ECU is still online + if (bus == 0 && addr == 0x292) { + chrysler_camera_detected = 1; + 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) { + + // There can be only one! (camera) + if (chrysler_camera_detected) { return 0; } @@ -72,65 +68,69 @@ static int chrysler_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { 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. + + // LKA STEER 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; + int desired_torque = ((rdlr & 0x7) << 8) + ((rdlr & 0xFF00) >> 8) - 1024; + uint32_t ts = TIM2->CNT; + int violation = 0; + + if (controls_allowed) { + + // *** global torque limit check *** + violation |= max_limit_check(desired_torque, CHRYSLER_MAX_STEER, -CHRYSLER_MAX_STEER); + + // *** torque rate limit check *** + violation |= dist_to_meas_check(desired_torque, chrysler_desired_torque_last, + &chrysler_torque_meas, CHRYSLER_MAX_RATE_UP, CHRYSLER_MAX_RATE_DOWN, CHRYSLER_MAX_TORQUE_ERROR); + + // used next time + chrysler_desired_torque_last = desired_torque; + + // *** torque real time rate limit check *** + violation |= rt_rate_limit_check(desired_torque, chrysler_rt_torque_last, CHRYSLER_MAX_RT_DELTA); + + // every RT_INTERVAL set the new limits + uint32_t ts_elapsed = get_ts_elapsed(ts, chrysler_ts_last); + if (ts_elapsed > CHRYSLER_RT_INTERVAL) { + chrysler_rt_torque_last = desired_torque; + chrysler_ts_last = ts; } } - if (steer < (chrysler_desired_torque_last - max_rate)) { - return false; + + // no torque if controls is not allowed + if (!controls_allowed && (desired_torque != 0)) { + violation = 1; + } + + // reset to 0 if either controls is not allowed or there's a violation + if (violation || !controls_allowed) { + chrysler_desired_torque_last = 0; + chrysler_rt_torque_last = 0; + chrysler_ts_last = ts; } - if (steer > (chrysler_desired_torque_last + max_rate)) { + + if (violation) { return false; } - - chrysler_desired_torque_last = steer; } + // FORCE CANCEL: safety check only relevant when spamming the cancel button. + // ensuring that only the cancel button press is sent when controls are off. + // This avoids unintended engagements while still allowing resume spam + // TODO: fix bug preventing the button msg to be fwd'd on bus 2 + // 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, + .init = nooutput_init, .rx = chrysler_rx_hook, .tx = chrysler_tx_hook, - .tx_lin = chrysler_tx_lin_hook, + .tx_lin = nooutput_tx_lin_hook, .ignition = default_ign_hook, - .fwd = chrysler_fwd_hook, + .fwd = nooutput_fwd_hook, }; - diff --git a/board/safety/safety_tesla.h b/board/safety/safety_tesla.h index a13e78f5a5..78c450e85e 100644 --- a/board/safety/safety_tesla.h +++ b/board/safety/safety_tesla.h @@ -258,7 +258,7 @@ static int tesla_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) // remove EPB_epasControl if (addr == 0x214) { - return false; + return -1; } return 2; // Custom EPAS bus @@ -269,12 +269,12 @@ static int tesla_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) // remove GTW_epasControl in forwards if (addr == 0x101) { - return false; + return -1; } return 0; // Chassis CAN } - return false; + return -1; } const safety_hooks tesla_hooks = { diff --git a/buy.png b/buy.png index a4a9e0fd40a4268a6b88b068bd6cdc7dd095ab01..72c705742251735c5bec921906b15c7f1303b12a 100644 GIT binary patch literal 4264 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 C>W0Js diff --git a/tests/safety/libpandasafety_py.py b/tests/safety/libpandasafety_py.py index c6df9d3340..53936761d5 100644 --- a/tests/safety/libpandasafety_py.py +++ b/tests/safety/libpandasafety_py.py @@ -42,10 +42,13 @@ void set_toyota_torque_meas(int min, int max); void set_cadillac_torque_driver(int min, int max); void set_gm_torque_driver(int min, int max); void set_hyundai_torque_driver(int min, int max); +void set_chrysler_torque_meas(int min, int max); void set_toyota_rt_torque_last(int t); void set_toyota_desired_torque_last(int t); int get_toyota_torque_meas_min(void); int get_toyota_torque_meas_max(void); +int get_chrysler_torque_meas_min(void); +int get_chrysler_torque_meas_max(void); void init_tests_honda(void); int get_ego_speed(void); @@ -84,8 +87,9 @@ int toyota_ipas_tx_hook(CAN_FIFOMailBox_TypeDef *to_send); void init_tests_chrysler(void); void chrysler_rx_hook(CAN_FIFOMailBox_TypeDef *to_push); int chrysler_tx_hook(CAN_FIFOMailBox_TypeDef *to_send); -void chrysler_init(int16_t param); void set_chrysler_desired_torque_last(int t); +void set_chrysler_rt_torque_last(int t); + """) diff --git a/tests/safety/test.c b/tests/safety/test.c index af0db3c92c..b1390c41c2 100644 --- a/tests/safety/test.c +++ b/tests/safety/test.c @@ -26,6 +26,7 @@ struct sample_t toyota_torque_meas; struct sample_t cadillac_torque_driver; struct sample_t gm_torque_driver; struct sample_t hyundai_torque_driver; +struct sample_t chrysler_torque_driver; TIM_TypeDef timer; TIM_TypeDef *TIM2 = &timer; @@ -81,6 +82,19 @@ void set_hyundai_torque_driver(int min, int max){ hyundai_torque_driver.max = max; } +void set_chrysler_torque_meas(int min, int max){ + chrysler_torque_meas.min = min; + chrysler_torque_meas.max = max; +} + +int get_chrysler_torque_meas_min(void){ + return chrysler_torque_meas.min; +} + +int get_chrysler_torque_meas_max(void){ + return chrysler_torque_meas.max; +} + int get_toyota_torque_meas_min(void){ return toyota_torque_meas.min; } @@ -105,6 +119,10 @@ void set_hyundai_rt_torque_last(int t){ hyundai_rt_torque_last = t; } +void set_chrysler_rt_torque_last(int t){ + chrysler_rt_torque_last = t; +} + void set_toyota_desired_torque_last(int t){ toyota_desired_torque_last = t; } @@ -181,6 +199,15 @@ void init_tests_hyundai(void){ set_timer(0); } +void init_tests_chrysler(void){ + chrysler_torque_driver.min = 0; + chrysler_torque_driver.max = 0; + chrysler_desired_torque_last = 0; + chrysler_rt_torque_last = 0; + chrysler_ts_last = 0; + set_timer(0); +} + void init_tests_honda(void){ ego_speed = 0; gas_interceptor_detected = 0; @@ -188,11 +215,6 @@ void init_tests_honda(void){ gas_prev = 0; } -void init_tests_chrysler(void){ - chrysler_desired_torque_last = 0; - set_timer(0); -} - void set_gmlan_digital_output(int to_set){ } diff --git a/tests/safety/test_chrysler.py b/tests/safety/test_chrysler.py index 9b8b17720f..568c92aaaa 100755 --- a/tests/safety/test_chrysler.py +++ b/tests/safety/test_chrysler.py @@ -3,86 +3,169 @@ import unittest import numpy as np import libpandasafety_py +MAX_RATE_UP = 3 +MAX_RATE_DOWN = 3 +MAX_STEER = 261 + +MAX_RT_DELTA = 112 +RT_INTERVAL = 250000 + +MAX_TORQUE_ERROR = 80 + +def twos_comp(val, bits): + if val >= 0: + return val + else: + return (2**bits) + val + +def sign(a): + if a > 0: + return 1 + else: + return -1 class TestChryslerSafety(unittest.TestCase): @classmethod def setUp(cls): cls.safety = libpandasafety_py.libpandasafety - cls.safety.chrysler_init(0) + cls.safety.nooutput_init(0) cls.safety.init_tests_chrysler() - def _acc_msg(self, active): + def _button_msg(self, buttons): to_send = libpandasafety_py.ffi.new('CAN_FIFOMailBox_TypeDef *') - to_send[0].RIR = 0x1f4 << 21 - to_send[0].RDLR = 0xfe3fff1f if active else 0xfe0fff1f + to_send[0].RIR = 1265 << 21 + to_send[0].RDLR = buttons return to_send - - def _brake_msg(self, brake): + def _set_prev_torque(self, t): + self.safety.set_chrysler_desired_torque_last(t) + self.safety.set_chrysler_rt_torque_last(t) + self.safety.set_chrysler_torque_meas(t, t) + + def _torque_meas_msg(self, torque): to_send = libpandasafety_py.ffi.new('CAN_FIFOMailBox_TypeDef *') - to_send[0].RIR = 0x140 << 21 - to_send[0].RDLR = 0x485 if brake else 0x480 + to_send[0].RIR = 544 << 21 + to_send[0].RDHR = ((torque + 1024) >> 8) + (((torque + 1024) & 0xff) << 8) return to_send - def _steer_msg(self, angle): + def _torque_msg(self, torque): 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) + to_send[0].RDLR = ((torque + 1024) >> 8) + (((torque + 1024) & 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): + def test_steer_safety_check(self): + for enabled in [0, 1]: + for t in range(-MAX_STEER*2, MAX_STEER*2): + self.safety.set_controls_allowed(enabled) + self._set_prev_torque(t) + if abs(t) > MAX_STEER or (not enabled and abs(t) > 0): + self.assertFalse(self.safety.chrysler_tx_hook(self._torque_msg(t))) + else: + self.assertTrue(self.safety.chrysler_tx_hook(self._torque_msg(t))) + + def test_manually_enable_controls_allowed(self): + self.safety.set_controls_allowed(1) + self.assertTrue(self.safety.get_controls_allowed()) 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)) + + def test_enable_control_allowed_from_cruise(self): + to_push = libpandasafety_py.ffi.new('CAN_FIFOMailBox_TypeDef *') + to_push[0].RIR = 0x1f4 << 21 + to_push[0].RDLR = 0x380000 + + self.safety.chrysler_rx_hook(to_push) 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): + def test_disable_control_allowed_from_cruise(self): + to_push = libpandasafety_py.ffi.new('CAN_FIFOMailBox_TypeDef *') + to_push[0].RIR = 0x1f4 << 21 + to_push[0].RDLR = 0 + 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.safety.chrysler_rx_hook(to_push) 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_non_realtime_limit_up(self): + self.safety.set_controls_allowed(True) + + self._set_prev_torque(0) + self.assertTrue(self.safety.chrysler_tx_hook(self._torque_msg(MAX_RATE_UP))) + + self._set_prev_torque(0) + self.assertFalse(self.safety.chrysler_tx_hook(self._torque_msg(MAX_RATE_UP + 1))) + + def test_non_realtime_limit_down(self): + self.safety.set_controls_allowed(True) + + self.safety.set_chrysler_rt_torque_last(MAX_STEER) + torque_meas = MAX_STEER - MAX_TORQUE_ERROR - 20 + self.safety.set_chrysler_torque_meas(torque_meas, torque_meas) + self.safety.set_chrysler_desired_torque_last(MAX_STEER) + self.assertTrue(self.safety.chrysler_tx_hook(self._torque_msg(MAX_STEER - MAX_RATE_DOWN))) + + self.safety.set_chrysler_rt_torque_last(MAX_STEER) + self.safety.set_chrysler_torque_meas(torque_meas, torque_meas) + self.safety.set_chrysler_desired_torque_last(MAX_STEER) + self.assertFalse(self.safety.chrysler_tx_hook(self._torque_msg(MAX_STEER - MAX_RATE_DOWN + 1))) + + def test_exceed_torque_sensor(self): + self.safety.set_controls_allowed(True) + + for sign in [-1, 1]: + self._set_prev_torque(0) + for t in np.arange(0, MAX_TORQUE_ERROR + 2, 2): # step needs to be smaller than MAX_TORQUE_ERROR + t *= sign + self.assertTrue(self.safety.chrysler_tx_hook(self._torque_msg(t))) + + self.assertFalse(self.safety.chrysler_tx_hook(self._torque_msg(sign * (MAX_TORQUE_ERROR + 2)))) + + def test_realtime_limit_up(self): + self.safety.set_controls_allowed(True) + + for sign in [-1, 1]: + self.safety.init_tests_chrysler() + self._set_prev_torque(0) + for t in np.arange(0, MAX_RT_DELTA+1, 1): + t *= sign + self.safety.set_chrysler_torque_meas(t, t) + self.assertTrue(self.safety.chrysler_tx_hook(self._torque_msg(t))) + self.assertFalse(self.safety.chrysler_tx_hook(self._torque_msg(sign * (MAX_RT_DELTA + 1)))) + + self._set_prev_torque(0) + for t in np.arange(0, MAX_RT_DELTA+1, 1): + t *= sign + self.safety.set_chrysler_torque_meas(t, t) + self.assertTrue(self.safety.chrysler_tx_hook(self._torque_msg(t))) + + # Increase timer to update rt_torque_last + self.safety.set_timer(RT_INTERVAL + 1) + self.assertTrue(self.safety.chrysler_tx_hook(self._torque_msg(sign * MAX_RT_DELTA))) + self.assertTrue(self.safety.chrysler_tx_hook(self._torque_msg(sign * (MAX_RT_DELTA + 1)))) + + def test_torque_measurements(self): + self.safety.chrysler_rx_hook(self._torque_meas_msg(50)) + self.safety.chrysler_rx_hook(self._torque_meas_msg(-50)) + self.safety.chrysler_rx_hook(self._torque_meas_msg(0)) + self.safety.chrysler_rx_hook(self._torque_meas_msg(0)) + self.safety.chrysler_rx_hook(self._torque_meas_msg(0)) + self.safety.chrysler_rx_hook(self._torque_meas_msg(0)) + + self.assertEqual(-50, self.safety.get_chrysler_torque_meas_min()) + self.assertEqual(50, self.safety.get_chrysler_torque_meas_max()) + + self.safety.chrysler_rx_hook(self._torque_meas_msg(0)) + self.assertEqual(0, self.safety.get_chrysler_torque_meas_max()) + self.assertEqual(-50, self.safety.get_chrysler_torque_meas_min()) + + self.safety.chrysler_rx_hook(self._torque_meas_msg(0)) + self.assertEqual(0, self.safety.get_chrysler_torque_meas_max()) + self.assertEqual(0, self.safety.get_chrysler_torque_meas_min()) - 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()