|
| 1 | +// board enforces |
| 2 | +// in-state |
| 3 | +// accel set/resume |
| 4 | +// out-state |
| 5 | +// cancel button |
| 6 | +// regen paddle |
| 7 | +// accel rising edge |
| 8 | +// brake rising edge |
| 9 | +// brake > 0mph |
| 10 | + |
| 11 | +// gm_: poor man's namespacing |
| 12 | +int gm_brake_prev = 0; |
| 13 | +int gm_gas_prev = 0; |
| 14 | +int gm_speed = 0; |
| 15 | + |
| 16 | +// silence everything if stock ECUs are still online |
| 17 | +int gm_ascm_detected = 0; |
| 18 | + |
| 19 | +static void gm_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { |
| 20 | + |
| 21 | + uint32_t addr; |
| 22 | + if (to_push->RIR & 4) { |
| 23 | + // Extended |
| 24 | + // Not looked at, but have to be separated |
| 25 | + // to avoid address collision |
| 26 | + addr = to_push->RIR >> 3; |
| 27 | + } else { |
| 28 | + // Normal |
| 29 | + addr = to_push->RIR >> 21; |
| 30 | + } |
| 31 | + |
| 32 | + // sample speed, really only care if car is moving or not |
| 33 | + // rear left wheel speed |
| 34 | + if (addr == 842) { |
| 35 | + gm_speed = to_push->RDLR & 0xFFFF; |
| 36 | + } |
| 37 | + |
| 38 | + // check if stock ASCM ECU is still online |
| 39 | + int bus_number = (to_push->RDTR >> 4) & 0xFF; |
| 40 | + if (bus_number == 0 && addr == 715) { |
| 41 | + gm_ascm_detected = 1; |
| 42 | + controls_allowed = 0; |
| 43 | + } |
| 44 | + |
| 45 | + // ACC steering wheel buttons |
| 46 | + if (addr == 481) { |
| 47 | + int buttons = (to_push->RDHR >> 12) & 0x7; |
| 48 | + // res/set - enable, cancel button - disable |
| 49 | + if (buttons == 2 || buttons == 3) { |
| 50 | + controls_allowed = 1; |
| 51 | + } else if (buttons == 6) { |
| 52 | + controls_allowed = 0; |
| 53 | + } |
| 54 | + } |
| 55 | + |
| 56 | + // exit controls on rising edge of brake press or on brake press when |
| 57 | + // speed > 0 |
| 58 | + if (addr == 241) { |
| 59 | + int brake = (to_push->RDLR & 0xFF00) >> 8; |
| 60 | + // Brake pedal's potentiometer returns near-zero reading |
| 61 | + // even when pedal is not pressed |
| 62 | + if (brake <= 5) { |
| 63 | + brake = 0; |
| 64 | + } |
| 65 | + if (brake && (!gm_brake_prev || gm_speed)) { |
| 66 | + controls_allowed = 0; |
| 67 | + } |
| 68 | + gm_brake_prev = brake; |
| 69 | + } |
| 70 | + |
| 71 | + // exit controls on rising edge of gas press |
| 72 | + if (addr == 417) { |
| 73 | + int gas = to_push->RDHR & 0xFF0000; |
| 74 | + if (gas && !(gm_gas_prev)) { |
| 75 | + controls_allowed = 0; |
| 76 | + } |
| 77 | + gm_gas_prev = gas; |
| 78 | + } |
| 79 | + |
| 80 | + // exit controls on regen paddle |
| 81 | + if (addr == 189) { |
| 82 | + int regen = to_push->RDLR & 0x20; |
| 83 | + if (regen) { |
| 84 | + controls_allowed = 0; |
| 85 | + } |
| 86 | + } |
| 87 | +} |
| 88 | + |
| 89 | +// all commands: gas/regen, friction brake and steering |
| 90 | +// if controls_allowed and no pedals pressed |
| 91 | +// allow all commands up to limit |
| 92 | +// else |
| 93 | +// block all commands that produce actuation |
| 94 | + |
| 95 | +static int gm_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { |
| 96 | + |
| 97 | + // There can be only one! (ASCM) |
| 98 | + if (gm_ascm_detected) { |
| 99 | + return 0; |
| 100 | + } |
| 101 | + |
| 102 | + // disallow actuator commands if gas or brake (with vehicle moving) are pressed |
| 103 | + // and the the latching controls_allowed flag is True |
| 104 | + int pedal_pressed = gm_gas_prev || (gm_brake_prev && gm_speed); |
| 105 | + int current_controls_allowed = controls_allowed && !(pedal_pressed); |
| 106 | + |
| 107 | + uint32_t addr; |
| 108 | + if (to_send->RIR & 4) { |
| 109 | + // Extended |
| 110 | + addr = to_send->RIR >> 3; |
| 111 | + } else { |
| 112 | + // Normal |
| 113 | + addr = to_send->RIR >> 21; |
| 114 | + } |
| 115 | + |
| 116 | + // BRAKE: safety check |
| 117 | + if (addr == 789) { |
| 118 | + int rdlr = to_send->RDLR; |
| 119 | + int brake = ((rdlr & 0xF) << 8) + ((rdlr & 0xFF00) >> 8); |
| 120 | + brake = (0x1000 - brake) & 0xFFF; |
| 121 | + if (current_controls_allowed) { |
| 122 | + if (brake > 255) return 0; |
| 123 | + } else { |
| 124 | + if (brake != 0) return 0; |
| 125 | + } |
| 126 | + } |
| 127 | + |
| 128 | + // LKA STEER: safety check |
| 129 | + if (addr == 384) { |
| 130 | + int rdlr = to_send->RDLR; |
| 131 | + int steer = ((rdlr & 0x7) << 8) + ((rdlr & 0xFF00) >> 8); |
| 132 | + int max_steer = 255; |
| 133 | + if (current_controls_allowed) { |
| 134 | + // Signed arithmetic |
| 135 | + if (steer & 0x400) { |
| 136 | + if (steer < (0x800 - max_steer)) return 0; |
| 137 | + } else { |
| 138 | + if (steer > max_steer) return 0; |
| 139 | + } |
| 140 | + } else { |
| 141 | + if (steer != 0) return 0; |
| 142 | + } |
| 143 | + } |
| 144 | + |
| 145 | + // PARK ASSIST STEER: unlimited torque, no thanks |
| 146 | + if (addr == 823) return 0; |
| 147 | + |
| 148 | + // GAS/REGEN: safety check |
| 149 | + if (addr == 715) { |
| 150 | + int rdlr = to_send->RDLR; |
| 151 | + int gas_regen = ((rdlr & 0x7F0000) >> 11) + ((rdlr & 0xF8000000) >> 27); |
| 152 | + int apply = rdlr & 1; |
| 153 | + if (current_controls_allowed) { |
| 154 | + if (gas_regen > 3072) return 0; |
| 155 | + } else { |
| 156 | + // Disabled message is !engaed with gas |
| 157 | + // value that corresponds to max regen. |
| 158 | + if (apply || gas_regen != 1404) return 0; |
| 159 | + } |
| 160 | + } |
| 161 | + |
| 162 | + // 1 allows the message through |
| 163 | + return true; |
| 164 | +} |
| 165 | + |
| 166 | +static int gm_tx_lin_hook(int lin_num, uint8_t *data, int len) { |
| 167 | + // LIN is not used in Volt |
| 168 | + return false; |
| 169 | +} |
| 170 | + |
| 171 | +static void gm_init(int16_t param) { |
| 172 | + controls_allowed = 0; |
| 173 | +} |
| 174 | + |
| 175 | +const safety_hooks gm_hooks = { |
| 176 | + .init = gm_init, |
| 177 | + .rx = gm_rx_hook, |
| 178 | + .tx = gm_tx_hook, |
| 179 | + .tx_lin = gm_tx_lin_hook, |
| 180 | +}; |
| 181 | + |
0 commit comments