int toyota_giraffe_switch_1 = 0; // is giraffe switch 1 high? int toyota_camera_forwarded = 0; // should we forward the camera bus? // global torque limit const int TOYOTA_MAX_TORQUE = 1500; // max torque cmd allowed ever // rate based torque limit + stay within actually applied // packet is sent at 100hz, so this limit is 1000/sec const int TOYOTA_MAX_RATE_UP = 10; // ramp up slow const int TOYOTA_MAX_RATE_DOWN = 25; // ramp down fast const int TOYOTA_MAX_TORQUE_ERROR = 350; // max torque cmd in excess of torque motor // real time torque limit to prevent controls spamming // the real time limit is 1500/sec const int TOYOTA_MAX_RT_DELTA = 375; // max delta torque allowed for real time checks const int TOYOTA_RT_INTERVAL = 250000; // 250ms between real time checks // longitudinal limits const int TOYOTA_MAX_ACCEL = 1500; // 1.5 m/s2 const int TOYOTA_MIN_ACCEL = -3000; // 3.0 m/s2 // global actuation limit state int toyota_actuation_limits = 1; // by default steer limits are imposed int toyota_dbc_eps_torque_factor = 100; // conversion factor for STEER_TORQUE_EPS in %: see dbc file // state of torque limits int toyota_desired_torque_last = 0; // last desired steer torque int toyota_rt_torque_last = 0; // last desired torque for real time check uint32_t toyota_ts_last = 0; int toyota_cruise_engaged_last = 0; // cruise state struct sample_t toyota_torque_meas; // last 3 motor torques produced by the eps static void toyota_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { // get eps motor torque (0.66 factor in dbc) if ((to_push->RIR>>21) == 0x260) { int torque_meas_new = (((to_push->RDHR) & 0xFF00) | ((to_push->RDHR >> 16) & 0xFF)); torque_meas_new = to_signed(torque_meas_new, 16); // scale by dbc_factor torque_meas_new = (torque_meas_new * toyota_dbc_eps_torque_factor) / 100; // increase torque_meas by 1 to be conservative on rounding torque_meas_new += (torque_meas_new > 0 ? 1 : -1); // update array of sample update_sample(&toyota_torque_meas, torque_meas_new); } // enter controls on rising edge of ACC, exit controls on ACC off if ((to_push->RIR>>21) == 0x1D2) { // 5th bit is CRUISE_ACTIVE int cruise_engaged = to_push->RDLR & 0x20; if (cruise_engaged && !toyota_cruise_engaged_last) { controls_allowed = 1; } else if (!cruise_engaged) { controls_allowed = 0; } toyota_cruise_engaged_last = cruise_engaged; } int bus = (to_push->RDTR >> 4) & 0xF; // msgs are only on bus 2 if panda is connected to frc if (bus == 2) { toyota_camera_forwarded = 1; } // 0x2E4 is lkas cmd. If it is on bus 0, then giraffe switch 1 is high if ((to_push->RIR>>21) == 0x2E4 && (bus == 0)) { toyota_giraffe_switch_1 = 1; } } static int toyota_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { // Check if msg is sent on BUS 0 if (((to_send->RDTR >> 4) & 0xF) == 0) { // no IPAS in non IPAS mode if (((to_send->RIR>>21) == 0x266) || ((to_send->RIR>>21) == 0x167)) return false; // GAS PEDAL: safety check if ((to_send->RIR>>21) == 0x200) { if (controls_allowed && toyota_actuation_limits) { // all messages are fine here } else { if ((to_send->RDLR & 0xFFFF0000) != to_send->RDLR) return 0; } } // ACCEL: safety check on byte 1-2 if ((to_send->RIR>>21) == 0x343) { int desired_accel = ((to_send->RDLR & 0xFF) << 8) | ((to_send->RDLR >> 8) & 0xFF); desired_accel = to_signed(desired_accel, 16); if (controls_allowed && toyota_actuation_limits) { int violation = max_limit_check(desired_accel, TOYOTA_MAX_ACCEL, TOYOTA_MIN_ACCEL); if (violation) return 0; } else if (!controls_allowed && (desired_accel != 0)) { return 0; } } // STEER: safety check on bytes 2-3 if ((to_send->RIR>>21) == 0x2E4) { int desired_torque = (to_send->RDLR & 0xFF00) | ((to_send->RDLR >> 16) & 0xFF); desired_torque = to_signed(desired_torque, 16); int violation = 0; uint32_t ts = TIM2->CNT; // only check if controls are allowed and actuation_limits are imposed if (controls_allowed && toyota_actuation_limits) { // *** global torque limit check *** violation |= max_limit_check(desired_torque, TOYOTA_MAX_TORQUE, -TOYOTA_MAX_TORQUE); // *** torque rate limit check *** violation |= dist_to_meas_check(desired_torque, toyota_desired_torque_last, &toyota_torque_meas, TOYOTA_MAX_RATE_UP, TOYOTA_MAX_RATE_DOWN, TOYOTA_MAX_TORQUE_ERROR); // used next time toyota_desired_torque_last = desired_torque; // *** torque real time rate limit check *** violation |= rt_rate_limit_check(desired_torque, toyota_rt_torque_last, TOYOTA_MAX_RT_DELTA); // every RT_INTERVAL set the new limits uint32_t ts_elapsed = get_ts_elapsed(ts, toyota_ts_last); if (ts_elapsed > TOYOTA_RT_INTERVAL) { toyota_rt_torque_last = desired_torque; toyota_ts_last = ts; } } // 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) { toyota_desired_torque_last = 0; toyota_rt_torque_last = 0; toyota_ts_last = ts; } if (violation) { return false; } } } // 1 allows the message through return true; } static void toyota_init(int16_t param) { controls_allowed = 0; toyota_actuation_limits = 1; toyota_giraffe_switch_1 = 0; toyota_camera_forwarded = 0; toyota_dbc_eps_torque_factor = param; #ifdef PANDA lline_relay_release(); #endif } static int toyota_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) { // forward cam to radar and viceversa if car, except lkas cmd and hud // don't forward when switch 1 is high if ((bus_num == 0 || bus_num == 2) && toyota_camera_forwarded && !toyota_giraffe_switch_1) { int addr = to_fwd->RIR>>21; bool is_lkas_msg = (addr == 0x2E4 || addr == 0x412) && bus_num == 2; // in TSSP 2.0 the camera does ACC as well, so filter 0x343 bool is_acc_msg = (addr == 0x343 && bus_num == 2); return (is_lkas_msg || is_acc_msg)? -1 : (uint8_t)(~bus_num & 0x2); } return -1; } const safety_hooks toyota_hooks = { .init = toyota_init, .rx = toyota_rx_hook, .tx = toyota_tx_hook, .tx_lin = nooutput_tx_lin_hook, .ignition = default_ign_hook, .fwd = toyota_fwd_hook, .relay = nooutput_relay_hook, }; static void toyota_nolimits_init(int16_t param) { controls_allowed = 0; toyota_actuation_limits = 0; toyota_giraffe_switch_1 = 0; toyota_camera_forwarded = 0; toyota_dbc_eps_torque_factor = param; #ifdef PANDA lline_relay_release(); #endif } const safety_hooks toyota_nolimits_hooks = { .init = toyota_nolimits_init, .rx = toyota_rx_hook, .tx = toyota_tx_hook, .tx_lin = nooutput_tx_lin_hook, .ignition = default_ign_hook, .fwd = toyota_fwd_hook, .relay = nooutput_relay_hook, };