GCC Code Coverage Report


Directory: ./
File: safety/safety_volkswagen_mqb.h
Date: 2025-02-27 09:09:49
Exec Total Coverage
Lines: 95 95 100.0%
Functions: 4 4 100.0%
Branches: 86 89 96.6%

Line Branch Exec Source
1 #pragma once
2
3 #include "safety_declarations.h"
4 #include "safety_volkswagen_common.h"
5
6 static bool volkswagen_mqb_brake_pedal_switch = false;
7 static bool volkswagen_mqb_brake_pressure_detected = false;
8
9
10 67 static safety_config volkswagen_mqb_init(uint16_t param) {
11 // Transmit of GRA_ACC_01 is allowed on bus 0 and 2 to keep compatibility with gateway and camera integration
12 static const CanMsg VOLKSWAGEN_MQB_STOCK_TX_MSGS[] = {{MSG_HCA_01, 0, 8}, {MSG_GRA_ACC_01, 0, 8}, {MSG_GRA_ACC_01, 2, 8},
13 {MSG_LDW_02, 0, 8}, {MSG_LH_EPS_03, 2, 8}};
14
15 static const CanMsg VOLKSWAGEN_MQB_LONG_TX_MSGS[] = {{MSG_HCA_01, 0, 8}, {MSG_LDW_02, 0, 8}, {MSG_LH_EPS_03, 2, 8},
16 {MSG_ACC_02, 0, 8}, {MSG_ACC_06, 0, 8}, {MSG_ACC_07, 0, 8}};
17
18 static RxCheck volkswagen_mqb_rx_checks[] = {
19 {.msg = {{MSG_ESP_19, 0, 8, .check_checksum = false, .max_counter = 0U, .frequency = 100U}, { 0 }, { 0 }}},
20 {.msg = {{MSG_LH_EPS_03, 0, 8, .check_checksum = true, .max_counter = 15U, .frequency = 100U}, { 0 }, { 0 }}},
21 {.msg = {{MSG_ESP_05, 0, 8, .check_checksum = true, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}},
22 {.msg = {{MSG_TSK_06, 0, 8, .check_checksum = true, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}},
23 {.msg = {{MSG_MOTOR_20, 0, 8, .check_checksum = true, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}},
24 {.msg = {{MSG_MOTOR_14, 0, 8, .check_checksum = false, .max_counter = 0U, .frequency = 10U}, { 0 }, { 0 }}},
25 {.msg = {{MSG_GRA_ACC_01, 0, 8, .check_checksum = true, .max_counter = 15U, .frequency = 33U}, { 0 }, { 0 }}},
26 };
27
28 UNUSED(param);
29
30 67 volkswagen_set_button_prev = false;
31 67 volkswagen_resume_button_prev = false;
32 67 volkswagen_mqb_brake_pedal_switch = false;
33 67 volkswagen_mqb_brake_pressure_detected = false;
34
35 #ifdef ALLOW_DEBUG
36 67 volkswagen_longitudinal = GET_FLAG(param, FLAG_VOLKSWAGEN_LONG_CONTROL);
37 #endif
38 67 gen_crc_lookup_table_8(0x2F, volkswagen_crc8_lut_8h2f);
39
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 32 times.
67 return volkswagen_longitudinal ? BUILD_SAFETY_CFG(volkswagen_mqb_rx_checks, VOLKSWAGEN_MQB_LONG_TX_MSGS) : \
40 BUILD_SAFETY_CFG(volkswagen_mqb_rx_checks, VOLKSWAGEN_MQB_STOCK_TX_MSGS);
41 }
42
43 21021 static void volkswagen_mqb_rx_hook(const CANPacket_t *to_push) {
44
2/2
✓ Branch 0 taken 9757 times.
✓ Branch 1 taken 11264 times.
21021 if (GET_BUS(to_push) == 0U) {
45 9757 int addr = GET_ADDR(to_push);
46
47 // Update in-motion state by sampling wheel speeds
48
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 9741 times.
9757 if (addr == MSG_ESP_19) {
49 // sum 4 wheel speeds
50 16 int speed = 0;
51
2/2
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 16 times.
80 for (uint8_t i = 0U; i < 8U; i += 2U) {
52 64 int wheel_speed = GET_BYTE(to_push, i) | (GET_BYTE(to_push, i + 1U) << 8);
53 64 speed += wheel_speed;
54 }
55 // Check all wheel speeds for any movement
56 16 vehicle_moving = speed > 0;
57 }
58
59 // Update driver input torque samples
60 // Signal: LH_EPS_03.EPS_Lenkmoment (absolute torque)
61 // Signal: LH_EPS_03.EPS_VZ_Lenkmoment (direction)
62
2/2
✓ Branch 0 taken 4024 times.
✓ Branch 1 taken 5733 times.
9757 if (addr == MSG_LH_EPS_03) {
63 4024 int torque_driver_new = GET_BYTE(to_push, 5) | ((GET_BYTE(to_push, 6) & 0x1FU) << 8);
64 4024 int sign = (GET_BYTE(to_push, 6) & 0x80U) >> 7;
65
2/2
✓ Branch 0 taken 1976 times.
✓ Branch 1 taken 2048 times.
4024 if (sign == 1) {
66 1976 torque_driver_new *= -1;
67 }
68 4024 update_sample(&torque_driver, torque_driver_new);
69 }
70
71
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 9743 times.
9757 if (addr == MSG_TSK_06) {
72 // When using stock ACC, enter controls on rising edge of stock ACC engage, exit on disengage
73 // Always exit controls on main switch off
74 // Signal: TSK_06.TSK_Status
75 14 int acc_status = (GET_BYTE(to_push, 3) & 0x7U);
76
4/6
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 11 times.
14 bool cruise_engaged = (acc_status == 3) || (acc_status == 4) || (acc_status == 5);
77
4/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 3 times.
14 acc_main_on = cruise_engaged || (acc_status == 2);
78
79
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7 times.
14 if (!volkswagen_longitudinal) {
80 7 pcm_cruise_check(cruise_engaged);
81 }
82
83
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 11 times.
14 if (!acc_main_on) {
84 3 controls_allowed = false;
85 }
86 }
87
88
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 9750 times.
9757 if (addr == MSG_GRA_ACC_01) {
89 // If using openpilot longitudinal, enter controls on falling edge of Set or Resume with main switch on
90 // Signal: GRA_ACC_01.GRA_Tip_Setzen
91 // Signal: GRA_ACC_01.GRA_Tip_Wiederaufnahme
92
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if (volkswagen_longitudinal) {
93 7 bool set_button = GET_BIT(to_push, 16U);
94 7 bool resume_button = GET_BIT(to_push, 19U);
95
8/8
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 1 times.
7 if ((volkswagen_set_button_prev && !set_button) || (volkswagen_resume_button_prev && !resume_button)) {
96 2 controls_allowed = acc_main_on;
97 }
98 7 volkswagen_set_button_prev = set_button;
99 7 volkswagen_resume_button_prev = resume_button;
100 }
101 // Always exit controls on rising edge of Cancel
102 // Signal: GRA_ACC_01.GRA_Abbrechen
103
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 6 times.
7 if (GET_BIT(to_push, 13U)) {
104 1 controls_allowed = false;
105 }
106 }
107
108 // Signal: Motor_20.MO_Fahrpedalrohwert_01
109
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 9737 times.
9757 if (addr == MSG_MOTOR_20) {
110 20 gas_pressed = ((GET_BYTES(to_push, 0, 4) >> 12) & 0xFFU) != 0U;
111 }
112
113 // Signal: Motor_14.MO_Fahrer_bremst (ECU detected brake pedal switch F63)
114
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 9715 times.
9757 if (addr == MSG_MOTOR_14) {
115 42 volkswagen_mqb_brake_pedal_switch = (GET_BYTE(to_push, 3) & 0x10U) >> 4;
116 }
117
118 // Signal: ESP_05.ESP_Fahrer_bremst (ESP detected driver brake pressure above platform specified threshold)
119
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 9741 times.
9757 if (addr == MSG_ESP_05) {
120 16 volkswagen_mqb_brake_pressure_detected = (GET_BYTE(to_push, 3) & 0x4U) >> 2;
121 }
122
123
4/4
✓ Branch 0 taken 9727 times.
✓ Branch 1 taken 30 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 9721 times.
9757 brake_pressed = volkswagen_mqb_brake_pedal_switch || volkswagen_mqb_brake_pressure_detected;
124
125 9757 generic_rx_checks((addr == MSG_HCA_01));
126 }
127 21021 }
128
129 6855 static bool volkswagen_mqb_tx_hook(const CANPacket_t *to_send) {
130 // lateral limits
131 const SteeringLimits VOLKSWAGEN_MQB_STEERING_LIMITS = {
132 .max_steer = 300, // 3.0 Nm (EPS side max of 3.0Nm with fault if violated)
133 .max_rt_delta = 75, // 4 max rate up * 50Hz send rate * 250000 RT interval / 1000000 = 50 ; 50 * 1.5 for safety pad = 75
134 .max_rt_interval = 250000, // 250ms between real time checks
135 .max_rate_up = 4, // 2.0 Nm/s RoC limit (EPS rack has own soft-limit of 5.0 Nm/s)
136 .max_rate_down = 10, // 5.0 Nm/s RoC limit (EPS rack has own soft-limit of 5.0 Nm/s)
137 .driver_torque_allowance = 80,
138 .driver_torque_multiplier = 3,
139 .type = TorqueDriverLimited,
140 };
141
142 // longitudinal limits
143 // acceleration in m/s2 * 1000 to avoid floating point math
144 const LongitudinalLimits VOLKSWAGEN_MQB_LONG_LIMITS = {
145 .max_accel = 2000,
146 .min_accel = -3500,
147 .inactive_accel = 3010, // VW sends one increment above the max range when inactive
148 };
149
150 6855 int addr = GET_ADDR(to_send);
151 6855 bool tx = true;
152
153 // Safety check for HCA_01 Heading Control Assist torque
154 // Signal: HCA_01.HCA_01_LM_Offset (absolute torque)
155 // Signal: HCA_01.HCA_01_LM_OffSign (direction)
156
2/2
✓ Branch 0 taken 4924 times.
✓ Branch 1 taken 1931 times.
6855 if (addr == MSG_HCA_01) {
157 4924 int desired_torque = GET_BYTE(to_send, 2) | ((GET_BYTE(to_send, 3) & 0x1U) << 8);
158 4924 bool sign = GET_BIT(to_send, 31U);
159
2/2
✓ Branch 0 taken 2434 times.
✓ Branch 1 taken 2490 times.
4924 if (sign) {
160 2434 desired_torque *= -1;
161 }
162
163 4924 bool steer_req = GET_BIT(to_send, 30U);
164
165
2/2
✓ Branch 1 taken 2750 times.
✓ Branch 2 taken 2174 times.
4924 if (steer_torque_cmd_checks(desired_torque, steer_req, VOLKSWAGEN_MQB_STEERING_LIMITS)) {
166 2750 tx = false;
167 }
168 }
169
170 // Safety check for both ACC_06 and ACC_07 acceleration requests
171 // To avoid floating point math, scale upward and compare to pre-scaled safety m/s2 boundaries
172
4/4
✓ Branch 0 taken 6212 times.
✓ Branch 1 taken 643 times.
✓ Branch 2 taken 1277 times.
✓ Branch 3 taken 4935 times.
6855 if ((addr == MSG_ACC_06) || (addr == MSG_ACC_07)) {
173 1920 bool violation = false;
174 1920 int desired_accel = 0;
175
176
2/2
✓ Branch 0 taken 643 times.
✓ Branch 1 taken 1277 times.
1920 if (addr == MSG_ACC_06) {
177 // Signal: ACC_06.ACC_Sollbeschleunigung_02 (acceleration in m/s2, scale 0.005, offset -7.22)
178 643 desired_accel = ((((GET_BYTE(to_send, 4) & 0x7U) << 8) | GET_BYTE(to_send, 3)) * 5U) - 7220U;
179 } else {
180 // Signal: ACC_07.ACC_Folgebeschl (acceleration in m/s2, scale 0.03, offset -4.6)
181 1277 int secondary_accel = (GET_BYTE(to_send, 4) * 30U) - 4600U;
182 1277 violation |= (secondary_accel != 3020); // enforce always inactive (one increment above max range) at this time
183 // Signal: ACC_07.ACC_Sollbeschleunigung_02 (acceleration in m/s2, scale 0.005, offset -7.22)
184 1277 desired_accel = (((GET_BYTE(to_send, 7) << 3) | ((GET_BYTE(to_send, 6) & 0xE0U) >> 5)) * 5U) - 7220U;
185 }
186
187 1920 violation |= longitudinal_accel_checks(desired_accel, VOLKSWAGEN_MQB_LONG_LIMITS);
188
189
2/2
✓ Branch 0 taken 1544 times.
✓ Branch 1 taken 376 times.
1920 if (violation) {
190 1544 tx = false;
191 }
192 }
193
194 // FORCE CANCEL: ensuring that only the cancel button press is sent when controls are off.
195 // This avoids unintended engagements while still allowing resume spam
196
4/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6849 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 1 times.
6855 if ((addr == MSG_GRA_ACC_01) && !controls_allowed) {
197 // disallow resume and set: bits 16 and 19
198
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
5 if ((GET_BYTE(to_send, 2) & 0x9U) != 0U) {
199 2 tx = false;
200 }
201 }
202
203 6855 return tx;
204 }
205
206 16896 static int volkswagen_mqb_fwd_hook(int bus_num, int addr) {
207 16896 int bus_fwd = -1;
208
209
3/3
✓ Branch 0 taken 5632 times.
✓ Branch 1 taken 5632 times.
✓ Branch 2 taken 5632 times.
16896 switch (bus_num) {
210 5632 case 0:
211
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 5630 times.
5632 if (addr == MSG_LH_EPS_03) {
212 // openpilot needs to replace apparent driver steering input torque to pacify VW Emergency Assist
213 2 bus_fwd = -1;
214 } else {
215 // Forward all remaining traffic from Extended CAN onward
216 5630 bus_fwd = 2;
217 }
218 5632 break;
219 5632 case 2:
220
4/4
✓ Branch 0 taken 5630 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 5628 times.
5632 if ((addr == MSG_HCA_01) || (addr == MSG_LDW_02)) {
221 // openpilot takes over LKAS steering control and related HUD messages from the camera
222 4 bus_fwd = -1;
223
8/8
✓ Branch 0 taken 2814 times.
✓ Branch 1 taken 2814 times.
✓ Branch 2 taken 2813 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 2812 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 2811 times.
5628 } else if (volkswagen_longitudinal && ((addr == MSG_ACC_02) || (addr == MSG_ACC_06) || (addr == MSG_ACC_07))) {
224 // openpilot takes over acceleration/braking control and related HUD messages from the stock ACC radar
225 3 bus_fwd = -1;
226 } else {
227 // Forward all remaining traffic from Extended CAN devices to J533 gateway
228 5625 bus_fwd = 0;
229 }
230 5632 break;
231 5632 default:
232 // No other buses should be in use; fallback to do-not-forward
233 5632 bus_fwd = -1;
234 5632 break;
235 }
236
237 16896 return bus_fwd;
238 }
239
240 const safety_hooks volkswagen_mqb_hooks = {
241 .init = volkswagen_mqb_init,
242 .rx = volkswagen_mqb_rx_hook,
243 .tx = volkswagen_mqb_tx_hook,
244 .fwd = volkswagen_mqb_fwd_hook,
245 .get_counter = volkswagen_mqb_meb_get_counter,
246 .get_checksum = volkswagen_mqb_meb_get_checksum,
247 .compute_checksum = volkswagen_mqb_meb_compute_crc,
248 };
249