panda/board/safety/safety_toyota.h

228 lines
7.2 KiB
C
Raw Normal View History

2017-10-28 17:22:32 -06:00
// global torque limit
const int TOYOTA_MAX_TORQUE = 1500; // max torque cmd allowed ever
2017-10-28 17:22:32 -06:00
// rate based torque limit + stay within actually applied
2017-10-28 21:50:04 -06:00
// 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
2017-10-28 17:22:32 -06:00
// real time torque limit to prevent controls spamming
2017-10-28 17:29:23 -06:00
// the real time limit is 1500/sec
const int TOYOTA_MAX_RT_DELTA = 375; // max delta torque allowed for real time checks
2019-06-14 11:57:14 -06:00
const uint32_t TOYOTA_RT_INTERVAL = 250000; // 250ms between real time checks
2017-10-28 17:22:32 -06:00
// longitudinal limits
const int TOYOTA_MAX_ACCEL = 1500; // 1.5 m/s2
const int TOYOTA_MIN_ACCEL = -3000; // 3.0 m/s2
2017-10-28 17:22:32 -06:00
const int TOYOTA_GAS_INTERCEPTOR_THRESHOLD = 475; // ratio between offset and gain from dbc file
// global actuation limit states
int toyota_dbc_eps_torque_factor = 100; // conversion factor for STEER_TORQUE_EPS in %: see dbc file
2017-10-28 17:22:32 -06:00
// states
int toyota_giraffe_switch_1 = 0; // is giraffe switch 1 high?
int toyota_camera_forwarded = 0; // should we forward the camera bus?
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
int toyota_gas_prev = 0;
struct sample_t toyota_torque_meas; // last 3 motor torques produced by the eps
2018-04-11 15:31:45 -06:00
2017-08-24 23:31:34 -06:00
static void toyota_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) {
int addr = to_push->RIR >> 21;
// get eps motor torque (0.66 factor in dbc)
if (addr == 0x260) {
2018-06-01 17:27:55 -06:00
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;
2017-10-28 17:22:32 -06:00
2018-04-11 15:31:45 -06:00
// update array of sample
update_sample(&toyota_torque_meas, torque_meas_new);
2019-06-03 17:06:02 -06:00
// increase torque_meas by 1 to be conservative on rounding
toyota_torque_meas.min--;
toyota_torque_meas.max++;
2017-10-28 17:22:32 -06:00
}
2018-04-11 20:24:03 -06:00
// enter controls on rising edge of ACC, exit controls on ACC off
if (addr == 0x1D2) {
// 5th bit is CRUISE_ACTIVE
int cruise_engaged = to_push->RDLR & 0x20;
if (!cruise_engaged) {
2017-08-24 23:31:34 -06:00
controls_allowed = 0;
} else if (cruise_engaged && !toyota_cruise_engaged_last) {
controls_allowed = 1;
2017-08-24 23:31:34 -06:00
}
toyota_cruise_engaged_last = cruise_engaged;
}
// exit controls on rising edge of interceptor gas press
if (addr == 0x201) {
gas_interceptor_detected = 1;
int gas_interceptor = ((to_push->RDLR & 0xFF) << 8) | ((to_push->RDLR & 0xFF00) >> 8);
if ((gas_interceptor > TOYOTA_GAS_INTERCEPTOR_THRESHOLD) &&
(gas_interceptor_prev <= TOYOTA_GAS_INTERCEPTOR_THRESHOLD) &&
long_controls_allowed) {
controls_allowed = 0;
}
gas_interceptor_prev = gas_interceptor;
2017-08-24 23:31:34 -06:00
}
// exit controls on rising edge of gas press
if (addr == 0x2C1) {
int gas = (to_push->RDHR >> 16) & 0xFF;
if ((gas > 0) && (toyota_gas_prev == 0) && !gas_interceptor_detected && long_controls_allowed) {
controls_allowed = 0;
}
toyota_gas_prev = gas;
}
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 ((addr == 0x2E4) && (bus == 0)) {
toyota_giraffe_switch_1 = 1;
}
2017-08-24 23:31:34 -06:00
}
static int toyota_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
int tx = 1;
int addr = to_send->RIR >> 21;
int bus = (to_send->RDTR >> 4) & 0xF;
// Check if msg is sent on BUS 0
if (bus == 0) {
2018-04-11 15:45:52 -06:00
// no IPAS in non IPAS mode
if ((addr == 0x266) || (addr == 0x167)) {
tx = 0;
}
2018-04-11 15:45:52 -06:00
// GAS PEDAL: safety check
if (addr == 0x200) {
if (controls_allowed && long_controls_allowed) {
// all messages are fine here
} else {
if ((to_send->RDLR & 0xFFFF0000) != to_send->RDLR) {
tx = 0;
}
}
}
// ACCEL: safety check on byte 1-2
if (addr == 0x343) {
2018-06-16 19:08:22 -06:00
int desired_accel = ((to_send->RDLR & 0xFF) << 8) | ((to_send->RDLR >> 8) & 0xFF);
desired_accel = to_signed(desired_accel, 16);
if (controls_allowed && long_controls_allowed) {
2019-06-12 21:12:48 -06:00
bool violation = max_limit_check(desired_accel, TOYOTA_MAX_ACCEL, TOYOTA_MIN_ACCEL);
if (violation) {
tx = 0;
}
} else if (desired_accel != 0) {
tx = 0;
}
}
// STEER: safety check on bytes 2-3
if (addr == 0x2E4) {
2018-06-16 19:08:22 -06:00
int desired_torque = (to_send->RDLR & 0xFF00) | ((to_send->RDLR >> 16) & 0xFF);
desired_torque = to_signed(desired_torque, 16);
2019-06-12 21:12:48 -06:00
bool violation = 0;
2017-10-28 17:32:36 -06:00
uint32_t ts = TIM2->CNT;
if (controls_allowed) {
2017-10-28 17:22:32 -06:00
// *** global torque limit check ***
violation |= max_limit_check(desired_torque, TOYOTA_MAX_TORQUE, -TOYOTA_MAX_TORQUE);
2017-10-28 17:22:32 -06:00
// *** 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);
2017-10-28 17:31:10 -06:00
// used next time
toyota_desired_torque_last = desired_torque;
2017-10-28 17:31:10 -06:00
2017-10-28 17:22:32 -06:00
// *** torque real time rate limit check ***
violation |= rt_rate_limit_check(desired_torque, toyota_rt_torque_last, TOYOTA_MAX_RT_DELTA);
2017-10-28 17:22:32 -06:00
// 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;
}
2017-10-28 17:22:32 -06:00
}
2017-10-28 17:22:32 -06:00
// no torque if controls is not allowed
if (!controls_allowed && (desired_torque != 0)) {
violation = 1;
}
2017-10-28 17:22:32 -06:00
// 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;
2017-10-28 17:22:32 -06:00
}
if (violation) {
tx = 0;
}
2017-08-24 23:31:34 -06:00
}
}
// 1 allows the message through
return tx;
2017-08-24 23:31:34 -06:00
}
2018-01-26 01:35:33 -07:00
static void toyota_init(int16_t param) {
2017-08-24 23:31:34 -06:00
controls_allowed = 0;
toyota_giraffe_switch_1 = 0;
toyota_camera_forwarded = 0;
toyota_dbc_eps_torque_factor = param;
2017-08-24 23:31:34 -06:00
}
static int toyota_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) {
int bus_fwd = -1;
if (toyota_camera_forwarded && !toyota_giraffe_switch_1) {
if (bus_num == 0) {
bus_fwd = 2;
} else if (bus_num == 2) {
int addr = to_fwd->RIR>>21;
// block stock lkas messages and stock acc messages (if OP is doing ACC)
int is_lkas_msg = ((addr == 0x2E4) || (addr == 0x412));
// in TSSP 2.0 the camera does ACC as well, so filter 0x343
int is_acc_msg = (addr == 0x343);
int block_msg = is_lkas_msg || (is_acc_msg && long_controls_allowed);
if (!block_msg) {
bus_fwd = 0;
}
}
}
return bus_fwd;
}
2017-08-24 23:31:34 -06:00
const safety_hooks toyota_hooks = {
.init = toyota_init,
.rx = toyota_rx_hook,
.tx = toyota_tx_hook,
.tx_lin = nooutput_tx_lin_hook,
2018-05-25 19:20:55 -06:00
.ignition = default_ign_hook,
.fwd = toyota_fwd_hook,
2017-08-24 23:31:34 -06:00
};