Line | Branch | Exec | Source |
---|---|---|---|
1 | #pragma once | ||
2 | |||
3 | #include "safety_declarations.h" | ||
4 | |||
5 | static const LongitudinalLimits *gm_long_limits; | ||
6 | |||
7 | enum { | ||
8 | GM_BTN_UNPRESS = 1, | ||
9 | GM_BTN_RESUME = 2, | ||
10 | GM_BTN_SET = 3, | ||
11 | GM_BTN_CANCEL = 6, | ||
12 | }; | ||
13 | |||
14 | typedef enum { | ||
15 | GM_ASCM, | ||
16 | GM_CAM | ||
17 | } GmHardware; | ||
18 | static GmHardware gm_hw = GM_ASCM; | ||
19 | static bool gm_cam_long = false; | ||
20 | static bool gm_pcm_cruise = false; | ||
21 | |||
22 | 31830 | static void gm_rx_hook(const CANPacket_t *to_push) { | |
23 | |||
24 | 31830 | const int GM_STANDSTILL_THRSLD = 10; // 0.311kph | |
25 | |||
26 | |||
27 | |||
28 |
2/2✓ Branch 0 taken 14934 times.
✓ Branch 1 taken 16896 times.
|
31830 | if (GET_BUS(to_push) == 0U) { |
29 | 14934 | int addr = GET_ADDR(to_push); | |
30 | |||
31 |
2/2✓ Branch 0 taken 4935 times.
✓ Branch 1 taken 9999 times.
|
14934 | if (addr == 0x184) { |
32 | 4935 | int torque_driver_new = ((GET_BYTE(to_push, 6) & 0x7U) << 8) | GET_BYTE(to_push, 7); | |
33 | 4935 | torque_driver_new = to_signed(torque_driver_new, 11); | |
34 | // update array of samples | ||
35 | 4935 | update_sample(&torque_driver, torque_driver_new); | |
36 | } | ||
37 | |||
38 | // sample rear wheel speeds | ||
39 |
2/2✓ Branch 0 taken 36 times.
✓ Branch 1 taken 14898 times.
|
14934 | if (addr == 0x34A) { |
40 | 36 | int left_rear_speed = (GET_BYTE(to_push, 0) << 8) | GET_BYTE(to_push, 1); | |
41 | 36 | int right_rear_speed = (GET_BYTE(to_push, 2) << 8) | GET_BYTE(to_push, 3); | |
42 |
3/4✓ Branch 0 taken 27 times.
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 27 times.
|
36 | vehicle_moving = (left_rear_speed > GM_STANDSTILL_THRSLD) || (right_rear_speed > GM_STANDSTILL_THRSLD); |
43 | } | ||
44 | |||
45 | // ACC steering wheel buttons (GM_CAM is tied to the PCM) | ||
46 |
4/4✓ Branch 0 taken 1413 times.
✓ Branch 1 taken 13521 times.
✓ Branch 2 taken 1412 times.
✓ Branch 3 taken 1 times.
|
14934 | if ((addr == 0x1E1) && !gm_pcm_cruise) { |
47 | 1412 | int button = (GET_BYTE(to_push, 5) & 0x70U) >> 4; | |
48 | |||
49 | // enter controls on falling edge of set or rising edge of resume (avoids fault) | ||
50 |
4/4✓ Branch 0 taken 1236 times.
✓ Branch 1 taken 176 times.
✓ Branch 2 taken 28 times.
✓ Branch 3 taken 1208 times.
|
1412 | bool set = (button != GM_BTN_SET) && (cruise_button_prev == GM_BTN_SET); |
51 |
4/4✓ Branch 0 taken 176 times.
✓ Branch 1 taken 1236 times.
✓ Branch 2 taken 28 times.
✓ Branch 3 taken 148 times.
|
1412 | bool res = (button == GM_BTN_RESUME) && (cruise_button_prev != GM_BTN_RESUME); |
52 |
4/4✓ Branch 0 taken 1384 times.
✓ Branch 1 taken 28 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 1360 times.
|
1412 | if (set || res) { |
53 | 52 | controls_allowed = true; | |
54 | } | ||
55 | |||
56 | // exit controls on cancel press | ||
57 |
2/2✓ Branch 0 taken 178 times.
✓ Branch 1 taken 1234 times.
|
1412 | if (button == GM_BTN_CANCEL) { |
58 | 178 | controls_allowed = false; | |
59 | } | ||
60 | |||
61 | 1412 | cruise_button_prev = button; | |
62 | } | ||
63 | |||
64 | // Reference for brake pressed signals: | ||
65 | // https://github.com/commaai/openpilot/blob/master/selfdrive/car/gm/carstate.py | ||
66 |
4/4✓ Branch 0 taken 15 times.
✓ Branch 1 taken 14919 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 2 times.
|
14934 | if ((addr == 0xBE) && (gm_hw == GM_ASCM)) { |
67 | 13 | brake_pressed = GET_BYTE(to_push, 1) >= 8U; | |
68 | } | ||
69 | |||
70 |
4/4✓ Branch 0 taken 27 times.
✓ Branch 1 taken 14907 times.
✓ Branch 2 taken 26 times.
✓ Branch 3 taken 1 times.
|
14934 | if ((addr == 0xC9) && (gm_hw == GM_CAM)) { |
71 | 26 | brake_pressed = GET_BIT(to_push, 40U); | |
72 | } | ||
73 | |||
74 |
2/2✓ Branch 0 taken 42 times.
✓ Branch 1 taken 14892 times.
|
14934 | if (addr == 0x1C4) { |
75 | 42 | gas_pressed = GET_BYTE(to_push, 5) != 0U; | |
76 | |||
77 | // enter controls on rising edge of ACC, exit controls when ACC off | ||
78 |
2/2✓ Branch 0 taken 20 times.
✓ Branch 1 taken 22 times.
|
42 | if (gm_pcm_cruise) { |
79 | 20 | bool cruise_engaged = (GET_BYTE(to_push, 1) >> 5) != 0U; | |
80 | 20 | pcm_cruise_check(cruise_engaged); | |
81 | } | ||
82 | } | ||
83 | |||
84 |
2/2✓ Branch 0 taken 39 times.
✓ Branch 1 taken 14895 times.
|
14934 | if (addr == 0xBD) { |
85 | 39 | regen_braking = (GET_BYTE(to_push, 0) >> 4) != 0U; | |
86 | } | ||
87 | |||
88 | 14934 | bool stock_ecu_detected = (addr == 0x180); // ASCMLKASteeringCmd | |
89 | |||
90 | // Check ASCMGasRegenCmd only if we're blocking it | ||
91 |
4/4✓ Branch 0 taken 10420 times.
✓ Branch 1 taken 4514 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 10418 times.
|
14934 | if (!gm_pcm_cruise && (addr == 0x2CB)) { |
92 | 2 | stock_ecu_detected = true; | |
93 | } | ||
94 | 14934 | generic_rx_checks(stock_ecu_detected); | |
95 | } | ||
96 | 31830 | } | |
97 | |||
98 | 40648 | static bool gm_tx_hook(const CANPacket_t *to_send) { | |
99 | const SteeringLimits GM_STEERING_LIMITS = { | ||
100 | .max_steer = 300, | ||
101 | .max_rate_up = 10, | ||
102 | .max_rate_down = 15, | ||
103 | .driver_torque_allowance = 65, | ||
104 | .driver_torque_multiplier = 4, | ||
105 | .max_rt_delta = 128, | ||
106 | .max_rt_interval = 250000, | ||
107 | .type = TorqueDriverLimited, | ||
108 | }; | ||
109 | |||
110 | 40648 | bool tx = true; | |
111 | 40648 | int addr = GET_ADDR(to_send); | |
112 | |||
113 | // BRAKE: safety check | ||
114 |
2/2✓ Branch 0 taken 16392 times.
✓ Branch 1 taken 24256 times.
|
40648 | if (addr == 0x315) { |
115 | 16392 | int brake = ((GET_BYTE(to_send, 0) & 0xFU) << 8) + GET_BYTE(to_send, 1); | |
116 | 16392 | brake = (0x1000 - brake) & 0xFFF; | |
117 |
2/2✓ Branch 1 taken 15580 times.
✓ Branch 2 taken 812 times.
|
16392 | if (longitudinal_brake_checks(brake, *gm_long_limits)) { |
118 | 15580 | tx = false; | |
119 | } | ||
120 | } | ||
121 | |||
122 | // LKA STEER: safety check | ||
123 |
2/2✓ Branch 0 taken 7839 times.
✓ Branch 1 taken 32809 times.
|
40648 | if (addr == 0x180) { |
124 | 7839 | int desired_torque = ((GET_BYTE(to_send, 0) & 0x7U) << 8) + GET_BYTE(to_send, 1); | |
125 | 7839 | desired_torque = to_signed(desired_torque, 11); | |
126 | |||
127 | 7839 | bool steer_req = GET_BIT(to_send, 3U); | |
128 | |||
129 |
2/2✓ Branch 1 taken 4035 times.
✓ Branch 2 taken 3804 times.
|
7839 | if (steer_torque_cmd_checks(desired_torque, steer_req, GM_STEERING_LIMITS)) { |
130 | 4035 | tx = false; | |
131 | } | ||
132 | } | ||
133 | |||
134 | // GAS/REGEN: safety check | ||
135 |
2/2✓ Branch 0 taken 16396 times.
✓ Branch 1 taken 24252 times.
|
40648 | if (addr == 0x2CB) { |
136 | 16396 | bool apply = GET_BIT(to_send, 0U); | |
137 | 16396 | int gas_regen = ((GET_BYTE(to_send, 2) & 0x7FU) << 5) + ((GET_BYTE(to_send, 3) & 0xF8U) >> 3); | |
138 | |||
139 | 16396 | bool violation = false; | |
140 | // Allow apply bit in pre-enabled and overriding states | ||
141 |
3/4✓ Branch 0 taken 8198 times.
✓ Branch 1 taken 8198 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8198 times.
|
16396 | violation |= !controls_allowed && apply; |
142 | 16396 | violation |= longitudinal_gas_checks(gas_regen, *gm_long_limits); | |
143 | |||
144 |
2/2✓ Branch 0 taken 12834 times.
✓ Branch 1 taken 3562 times.
|
16396 | if (violation) { |
145 | 12834 | tx = false; | |
146 | } | ||
147 | } | ||
148 | |||
149 | // BUTTONS: used for resume spamming and cruise cancellation with stock longitudinal | ||
150 |
3/4✓ Branch 0 taken 18 times.
✓ Branch 1 taken 40630 times.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
40648 | if ((addr == 0x1E1) && gm_pcm_cruise) { |
151 | 18 | int button = (GET_BYTE(to_send, 5) >> 4) & 0x7U; | |
152 | |||
153 |
4/4✓ Branch 0 taken 4 times.
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 3 times.
|
18 | bool allowed_cancel = (button == 6) && cruise_engaged_prev; |
154 |
2/2✓ Branch 0 taken 17 times.
✓ Branch 1 taken 1 times.
|
18 | if (!allowed_cancel) { |
155 | 17 | tx = false; | |
156 | } | ||
157 | } | ||
158 | |||
159 | 40648 | return tx; | |
160 | } | ||
161 | |||
162 | 25344 | static int gm_fwd_hook(int bus_num, int addr) { | |
163 | 25344 | int bus_fwd = -1; | |
164 | |||
165 |
2/2✓ Branch 0 taken 16896 times.
✓ Branch 1 taken 8448 times.
|
25344 | if (gm_hw == GM_CAM) { |
166 |
2/2✓ Branch 0 taken 5632 times.
✓ Branch 1 taken 11264 times.
|
16896 | if (bus_num == 0) { |
167 | // block PSCMStatus; forwarded through openpilot to hide an alert from the camera | ||
168 | 5632 | bool is_pscm_msg = (addr == 0x184); | |
169 |
2/2✓ Branch 0 taken 5630 times.
✓ Branch 1 taken 2 times.
|
5632 | if (!is_pscm_msg) { |
170 | 5630 | bus_fwd = 2; | |
171 | } | ||
172 | } | ||
173 | |||
174 |
2/2✓ Branch 0 taken 5632 times.
✓ Branch 1 taken 11264 times.
|
16896 | if (bus_num == 2) { |
175 | // block lkas message and acc messages if gm_cam_long, forward all others | ||
176 | 5632 | bool is_lkas_msg = (addr == 0x180); | |
177 |
6/6✓ Branch 0 taken 5630 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 5628 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 5626 times.
|
5632 | bool is_acc_msg = (addr == 0x315) || (addr == 0x2CB) || (addr == 0x370); |
178 |
6/6✓ Branch 0 taken 5630 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 5624 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 3 times.
|
5632 | bool block_msg = is_lkas_msg || (is_acc_msg && gm_cam_long); |
179 |
2/2✓ Branch 0 taken 5627 times.
✓ Branch 1 taken 5 times.
|
5632 | if (!block_msg) { |
180 | 5627 | bus_fwd = 0; | |
181 | } | ||
182 | } | ||
183 | } | ||
184 | |||
185 | 25344 | return bus_fwd; | |
186 | } | ||
187 | |||
188 | 98 | static safety_config gm_init(uint16_t param) { | |
189 | 98 | const uint16_t GM_PARAM_HW_CAM = 1; | |
190 | |||
191 | static const LongitudinalLimits GM_ASCM_LONG_LIMITS = { | ||
192 | .max_gas = 3072, | ||
193 | .min_gas = 1404, | ||
194 | .inactive_gas = 1404, | ||
195 | .max_brake = 400, | ||
196 | }; | ||
197 | |||
198 | static const CanMsg GM_ASCM_TX_MSGS[] = {{0x180, 0, 4}, {0x409, 0, 7}, {0x40A, 0, 7}, {0x2CB, 0, 8}, {0x370, 0, 6}, // pt bus | ||
199 | {0xA1, 1, 7}, {0x306, 1, 8}, {0x308, 1, 7}, {0x310, 1, 2}, // obs bus | ||
200 | {0x315, 2, 5}}; // ch bus | ||
201 | |||
202 | |||
203 | static const LongitudinalLimits GM_CAM_LONG_LIMITS = { | ||
204 | .max_gas = 3400, | ||
205 | .min_gas = 1514, | ||
206 | .inactive_gas = 1554, | ||
207 | .max_brake = 400, | ||
208 | }; | ||
209 | |||
210 | static const CanMsg GM_CAM_LONG_TX_MSGS[] = {{0x180, 0, 4}, {0x315, 0, 5}, {0x2CB, 0, 8}, {0x370, 0, 6}, // pt bus | ||
211 | {0x184, 2, 8}}; // camera bus | ||
212 | |||
213 | |||
214 | // TODO: do checksum and counter checks. Add correct timestep, 0.1s for now. | ||
215 | static RxCheck gm_rx_checks[] = { | ||
216 | {.msg = {{0x184, 0, 8, .frequency = 10U}, { 0 }, { 0 }}}, | ||
217 | {.msg = {{0x34A, 0, 5, .frequency = 10U}, { 0 }, { 0 }}}, | ||
218 | {.msg = {{0x1E1, 0, 7, .frequency = 10U}, { 0 }, { 0 }}}, | ||
219 | {.msg = {{0xBE, 0, 6, .frequency = 10U}, // Volt, Silverado, Acadia Denali | ||
220 | {0xBE, 0, 7, .frequency = 10U}, // Bolt EUV | ||
221 | {0xBE, 0, 8, .frequency = 10U}}}, // Escalade | ||
222 | {.msg = {{0x1C4, 0, 8, .frequency = 10U}, { 0 }, { 0 }}}, | ||
223 | {.msg = {{0xC9, 0, 8, .frequency = 10U}, { 0 }, { 0 }}}, | ||
224 | }; | ||
225 | |||
226 | static const CanMsg GM_CAM_TX_MSGS[] = {{0x180, 0, 4}, // pt bus | ||
227 | {0x1E1, 2, 7}, {0x184, 2, 8}}; // camera bus | ||
228 | |||
229 | 98 | gm_hw = GET_FLAG(param, GM_PARAM_HW_CAM) ? GM_CAM : GM_ASCM; | |
230 | |||
231 |
2/2✓ Branch 0 taken 34 times.
✓ Branch 1 taken 64 times.
|
98 | if (gm_hw == GM_ASCM) { |
232 | 34 | gm_long_limits = &GM_ASCM_LONG_LIMITS; | |
233 |
1/2✓ Branch 0 taken 64 times.
✗ Branch 1 not taken.
|
64 | } else if (gm_hw == GM_CAM) { |
234 | 64 | gm_long_limits = &GM_CAM_LONG_LIMITS; | |
235 | } else { | ||
236 | } | ||
237 | |||
238 | #ifdef ALLOW_DEBUG | ||
239 | 98 | const uint16_t GM_PARAM_HW_CAM_LONG = 2; | |
240 | 98 | gm_cam_long = GET_FLAG(param, GM_PARAM_HW_CAM_LONG); | |
241 | #endif | ||
242 |
4/4✓ Branch 0 taken 64 times.
✓ Branch 1 taken 34 times.
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 34 times.
|
98 | gm_pcm_cruise = (gm_hw == GM_CAM) && !gm_cam_long; |
243 | |||
244 | 98 | safety_config ret = BUILD_SAFETY_CFG(gm_rx_checks, GM_ASCM_TX_MSGS); | |
245 |
2/2✓ Branch 0 taken 64 times.
✓ Branch 1 taken 34 times.
|
98 | if (gm_hw == GM_CAM) { |
246 | // FIXME: cppcheck thinks that gm_cam_long is always false. This is not true | ||
247 | // if ALLOW_DEBUG is defined but cppcheck is run without ALLOW_DEBUG | ||
248 | // cppcheck-suppress knownConditionTrueFalse | ||
249 |
2/2✓ Branch 0 taken 34 times.
✓ Branch 1 taken 30 times.
|
64 | ret = gm_cam_long ? BUILD_SAFETY_CFG(gm_rx_checks, GM_CAM_LONG_TX_MSGS) : BUILD_SAFETY_CFG(gm_rx_checks, GM_CAM_TX_MSGS); |
250 | } | ||
251 | 98 | return ret; | |
252 | } | ||
253 | |||
254 | const safety_hooks gm_hooks = { | ||
255 | .init = gm_init, | ||
256 | .rx = gm_rx_hook, | ||
257 | .tx = gm_tx_hook, | ||
258 | .fwd = gm_fwd_hook, | ||
259 | }; | ||
260 |