GCC Code Coverage Report


Directory: ./
File: safety/safety_gm.h
Date: 2025-02-27 09:09:49
Exec Total Coverage
Lines: 93 93 100.0%
Functions: 4 4 100.0%
Branches: 102 106 96.2%

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