panda/board/safety/safety_gm.h

223 lines
6.3 KiB
C
Raw Normal View History

// board enforces
// in-state
// accel set/resume
// out-state
// cancel button
// regen paddle
// accel rising edge
// brake rising edge
// brake > 0mph
2018-09-20 17:42:11 -06:00
const int GM_MAX_STEER = 300;
const int GM_MAX_RT_DELTA = 128; // max delta torque allowed for real time checks
2019-06-14 11:57:14 -06:00
const uint32_t GM_RT_INTERVAL = 250000; // 250ms between real time checks
const int GM_MAX_RATE_UP = 7;
const int GM_MAX_RATE_DOWN = 17;
const int GM_DRIVER_TORQUE_ALLOWANCE = 50;
const int GM_DRIVER_TORQUE_FACTOR = 4;
2018-06-14 13:58:45 -06:00
const int GM_MAX_GAS = 3072;
const int GM_MAX_REGEN = 1404;
const int GM_MAX_BRAKE = 350;
const AddrBus GM_TX_MSGS[] = {{384, 0}, {1033, 0}, {1034, 0}, {715, 0}, {880, 0}, // pt bus
{161, 1}, {774, 1}, {776, 1}, {784, 1}, // obs bus
{789, 2}, // ch bus
{0x104c006c, 3}, {0x10400060, 3}}; // gmlan
int gm_brake_prev = 0;
int gm_gas_prev = 0;
bool gm_moving = false;
int gm_rt_torque_last = 0;
int gm_desired_torque_last = 0;
uint32_t gm_ts_last = 0;
struct sample_t gm_torque_driver; // last few driver torques measured
static void gm_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) {
int bus = GET_BUS(to_push);
int addr = GET_ADDR(to_push);
if (addr == 388) {
int torque_driver_new = ((GET_BYTE(to_push, 6) & 0x7) << 8) | GET_BYTE(to_push, 7);
torque_driver_new = to_signed(torque_driver_new, 11);
// update array of samples
update_sample(&gm_torque_driver, torque_driver_new);
}
// sample speed, really only care if car is moving or not
// rear left wheel speed
if (addr == 842) {
gm_moving = GET_BYTE(to_push, 0) | GET_BYTE(to_push, 1);
}
// ACC steering wheel buttons
if (addr == 481) {
int button = (GET_BYTE(to_push, 5) & 0x70) >> 4;
switch (button) {
case 2: // resume
case 3: // set
controls_allowed = 1;
break;
case 6: // cancel
controls_allowed = 0;
break;
default:
break; // any other button is irrelevant
}
}
// exit controls on rising edge of brake press or on brake press when
// speed > 0
if (addr == 241) {
int brake = GET_BYTE(to_push, 1);
// Brake pedal's potentiometer returns near-zero reading
// even when pedal is not pressed
2018-03-04 01:28:54 -07:00
if (brake < 10) {
brake = 0;
}
if (brake && (!gm_brake_prev || gm_moving)) {
controls_allowed = 0;
}
gm_brake_prev = brake;
}
// exit controls on rising edge of gas press
if (addr == 417) {
int gas = GET_BYTE(to_push, 6);
if (gas && !gm_gas_prev && long_controls_allowed) {
controls_allowed = 0;
}
gm_gas_prev = gas;
}
// exit controls on regen paddle
if (addr == 189) {
bool regen = GET_BYTE(to_push, 0) & 0x20;
if (regen) {
controls_allowed = 0;
}
}
// Check if ASCM or LKA camera are online
// on powertrain bus.
// 384 = ASCMLKASteeringCmd
// 715 = ASCMGasRegenCmd
2019-11-27 01:19:41 -07:00
if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && (bus == 0) && ((addr == 384) || (addr == 715))) {
relay_malfunction = true;
}
}
// all commands: gas/regen, friction brake and steering
// if controls_allowed and no pedals pressed
// allow all commands up to limit
// else
// block all commands that produce actuation
static int gm_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
int tx = 1;
int addr = GET_ADDR(to_send);
int bus = GET_BUS(to_send);
2019-12-18 01:17:25 -07:00
if (!msg_allowed(addr, bus, GM_TX_MSGS, sizeof(GM_TX_MSGS)/sizeof(GM_TX_MSGS[0]))) {
tx = 0;
}
if (relay_malfunction) {
tx = 0;
}
// disallow actuator commands if gas or brake (with vehicle moving) are pressed
// and the the latching controls_allowed flag is True
int pedal_pressed = gm_gas_prev || (gm_brake_prev && gm_moving);
2019-06-12 21:12:48 -06:00
bool current_controls_allowed = controls_allowed && !pedal_pressed;
// BRAKE: safety check
if (addr == 789) {
int brake = ((GET_BYTE(to_send, 0) & 0xFU) << 8) + GET_BYTE(to_send, 1);
brake = (0x1000 - brake) & 0xFFF;
if (!current_controls_allowed || !long_controls_allowed) {
if (brake != 0) {
tx = 0;
}
}
if (brake > GM_MAX_BRAKE) {
tx = 0;
}
}
// LKA STEER: safety check
if (addr == 384) {
int desired_torque = ((GET_BYTE(to_send, 0) & 0x7U) << 8) + GET_BYTE(to_send, 1);
uint32_t ts = TIM2->CNT;
2019-06-12 21:12:48 -06:00
bool violation = 0;
desired_torque = to_signed(desired_torque, 11);
if (current_controls_allowed) {
// *** global torque limit check ***
violation |= max_limit_check(desired_torque, GM_MAX_STEER, -GM_MAX_STEER);
// *** torque rate limit check ***
violation |= driver_limit_check(desired_torque, gm_desired_torque_last, &gm_torque_driver,
GM_MAX_STEER, GM_MAX_RATE_UP, GM_MAX_RATE_DOWN,
GM_DRIVER_TORQUE_ALLOWANCE, GM_DRIVER_TORQUE_FACTOR);
// used next time
gm_desired_torque_last = desired_torque;
// *** torque real time rate limit check ***
violation |= rt_rate_limit_check(desired_torque, gm_rt_torque_last, GM_MAX_RT_DELTA);
// every RT_INTERVAL set the new limits
uint32_t ts_elapsed = get_ts_elapsed(ts, gm_ts_last);
if (ts_elapsed > GM_RT_INTERVAL) {
gm_rt_torque_last = desired_torque;
gm_ts_last = ts;
}
}
// no torque if controls is not allowed
if (!current_controls_allowed && (desired_torque != 0)) {
violation = 1;
}
// reset to 0 if either controls is not allowed or there's a violation
if (violation || !current_controls_allowed) {
gm_desired_torque_last = 0;
gm_rt_torque_last = 0;
gm_ts_last = ts;
}
if (violation) {
tx = 0;
}
}
// GAS/REGEN: safety check
if (addr == 715) {
int gas_regen = ((GET_BYTE(to_send, 2) & 0x7FU) << 5) + ((GET_BYTE(to_send, 3) & 0xF8U) >> 3);
2019-10-02 12:40:38 -06:00
// Disabled message is !engaged with gas
// value that corresponds to max regen.
if (!current_controls_allowed || !long_controls_allowed) {
bool apply = GET_BYTE(to_send, 0) & 1U;
if (apply || (gas_regen != GM_MAX_REGEN)) {
tx = 0;
}
}
if (gas_regen > GM_MAX_GAS) {
tx = 0;
}
}
// 1 allows the message through
return tx;
}
2019-09-08 15:07:05 -06:00
const safety_hooks gm_hooks = {
.init = nooutput_init,
.rx = gm_rx_hook,
.tx = gm_tx_hook,
.tx_lin = nooutput_tx_lin_hook,
2019-09-08 15:07:05 -06:00
.fwd = default_fwd_hook,
};