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 |