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 ;
}
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 ;
return is_lkas_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 ,
} ;
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 ;
}
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 ,
} ;