Line | Branch | Exec | Source |
---|---|---|---|
1 | #pragma once | ||
2 | |||
3 | #include "safety_declarations.h" | ||
4 | |||
5 | // Safety-relevant CAN messages for Ford vehicles. | ||
6 | #define FORD_EngBrakeData 0x165 // RX from PCM, for driver brake pedal and cruise state | ||
7 | #define FORD_EngVehicleSpThrottle 0x204 // RX from PCM, for driver throttle input | ||
8 | #define FORD_DesiredTorqBrk 0x213 // RX from ABS, for standstill state | ||
9 | #define FORD_BrakeSysFeatures 0x415 // RX from ABS, for vehicle speed | ||
10 | #define FORD_EngVehicleSpThrottle2 0x202 // RX from PCM, for second vehicle speed | ||
11 | #define FORD_Yaw_Data_FD1 0x91 // RX from RCM, for yaw rate | ||
12 | #define FORD_Steering_Data_FD1 0x083 // TX by OP, various driver switches and LKAS/CC buttons | ||
13 | #define FORD_ACCDATA 0x186 // TX by OP, ACC controls | ||
14 | #define FORD_ACCDATA_3 0x18A // TX by OP, ACC/TJA user interface | ||
15 | #define FORD_Lane_Assist_Data1 0x3CA // TX by OP, Lane Keep Assist | ||
16 | #define FORD_LateralMotionControl 0x3D3 // TX by OP, Lateral Control message | ||
17 | #define FORD_LateralMotionControl2 0x3D6 // TX by OP, alternate Lateral Control message | ||
18 | #define FORD_IPMA_Data 0x3D8 // TX by OP, IPMA and LKAS user interface | ||
19 | |||
20 | // CAN bus numbers. | ||
21 | #define FORD_MAIN_BUS 0U | ||
22 | #define FORD_CAM_BUS 2U | ||
23 | |||
24 | 601038 | static uint8_t ford_get_counter(const CANPacket_t *to_push) { | |
25 | 601038 | int addr = GET_ADDR(to_push); | |
26 | |||
27 | 601038 | uint8_t cnt = 0; | |
28 |
2/2✓ Branch 0 taken 295929 times.
✓ Branch 1 taken 305109 times.
|
601038 | if (addr == FORD_BrakeSysFeatures) { |
29 | // Signal: VehVActlBrk_No_Cnt | ||
30 | 295929 | cnt = (GET_BYTE(to_push, 2) >> 2) & 0xFU; | |
31 |
1/2✓ Branch 0 taken 305109 times.
✗ Branch 1 not taken.
|
305109 | } else if (addr == FORD_Yaw_Data_FD1) { |
32 | // Signal: VehRollYaw_No_Cnt | ||
33 | 305109 | cnt = GET_BYTE(to_push, 5); | |
34 | } else { | ||
35 | } | ||
36 | 601038 | return cnt; | |
37 | } | ||
38 | |||
39 | 601038 | static uint32_t ford_get_checksum(const CANPacket_t *to_push) { | |
40 | 601038 | int addr = GET_ADDR(to_push); | |
41 | |||
42 | 601038 | uint8_t chksum = 0; | |
43 |
2/2✓ Branch 0 taken 295929 times.
✓ Branch 1 taken 305109 times.
|
601038 | if (addr == FORD_BrakeSysFeatures) { |
44 | // Signal: VehVActlBrk_No_Cs | ||
45 | 295929 | chksum = GET_BYTE(to_push, 3); | |
46 |
1/2✓ Branch 0 taken 305109 times.
✗ Branch 1 not taken.
|
305109 | } else if (addr == FORD_Yaw_Data_FD1) { |
47 | // Signal: VehRollYawW_No_Cs | ||
48 | 305109 | chksum = GET_BYTE(to_push, 4); | |
49 | } else { | ||
50 | } | ||
51 | 601038 | return chksum; | |
52 | } | ||
53 | |||
54 | 601038 | static uint32_t ford_compute_checksum(const CANPacket_t *to_push) { | |
55 | 601038 | int addr = GET_ADDR(to_push); | |
56 | |||
57 | 601038 | uint8_t chksum = 0; | |
58 |
2/2✓ Branch 0 taken 295929 times.
✓ Branch 1 taken 305109 times.
|
601038 | if (addr == FORD_BrakeSysFeatures) { |
59 | 295929 | chksum += GET_BYTE(to_push, 0) + GET_BYTE(to_push, 1); // Veh_V_ActlBrk | |
60 | 295929 | chksum += GET_BYTE(to_push, 2) >> 6; // VehVActlBrk_D_Qf | |
61 | 295929 | chksum += (GET_BYTE(to_push, 2) >> 2) & 0xFU; // VehVActlBrk_No_Cnt | |
62 | 295929 | chksum = 0xFFU - chksum; | |
63 |
1/2✓ Branch 0 taken 305109 times.
✗ Branch 1 not taken.
|
305109 | } else if (addr == FORD_Yaw_Data_FD1) { |
64 | 305109 | chksum += GET_BYTE(to_push, 0) + GET_BYTE(to_push, 1); // VehRol_W_Actl | |
65 | 305109 | chksum += GET_BYTE(to_push, 2) + GET_BYTE(to_push, 3); // VehYaw_W_Actl | |
66 | 305109 | chksum += GET_BYTE(to_push, 5); // VehRollYaw_No_Cnt | |
67 | 305109 | chksum += GET_BYTE(to_push, 6) >> 6; // VehRolWActl_D_Qf | |
68 | 305109 | chksum += (GET_BYTE(to_push, 6) >> 4) & 0x3U; // VehYawWActl_D_Qf | |
69 | 305109 | chksum = 0xFFU - chksum; | |
70 | } else { | ||
71 | } | ||
72 | |||
73 | 601038 | return chksum; | |
74 | } | ||
75 | |||
76 | 625107 | static bool ford_get_quality_flag_valid(const CANPacket_t *to_push) { | |
77 | 625107 | int addr = GET_ADDR(to_push); | |
78 | |||
79 | 625107 | bool valid = false; | |
80 |
2/2✓ Branch 0 taken 295929 times.
✓ Branch 1 taken 329178 times.
|
625107 | if (addr == FORD_BrakeSysFeatures) { |
81 | 295929 | valid = (GET_BYTE(to_push, 2) >> 6) == 0x3U; // VehVActlBrk_D_Qf | |
82 |
2/2✓ Branch 0 taken 24069 times.
✓ Branch 1 taken 305109 times.
|
329178 | } else if (addr == FORD_EngVehicleSpThrottle2) { |
83 | 24069 | valid = ((GET_BYTE(to_push, 4) >> 5) & 0x3U) == 0x3U; // VehVActlEng_D_Qf | |
84 |
1/2✓ Branch 0 taken 305109 times.
✗ Branch 1 not taken.
|
305109 | } else if (addr == FORD_Yaw_Data_FD1) { |
85 | 305109 | valid = ((GET_BYTE(to_push, 6) >> 4) & 0x3U) == 0x3U; // VehYawWActl_D_Qf | |
86 | } else { | ||
87 | } | ||
88 | 625107 | return valid; | |
89 | } | ||
90 | |||
91 | static bool ford_longitudinal = false; | ||
92 | |||
93 | #define FORD_INACTIVE_CURVATURE 1000U | ||
94 | #define FORD_INACTIVE_CURVATURE_RATE 4096U | ||
95 | #define FORD_INACTIVE_PATH_OFFSET 512U | ||
96 | #define FORD_INACTIVE_PATH_ANGLE 1000U | ||
97 | |||
98 | #define FORD_CANFD_INACTIVE_CURVATURE_RATE 1024U | ||
99 | |||
100 | #define FORD_MAX_SPEED_DELTA 2.0 // m/s | ||
101 | |||
102 | 642006 | static bool ford_lkas_msg_check(int addr) { | |
103 | return (addr == FORD_ACCDATA_3) | ||
104 |
2/2✓ Branch 0 taken 641994 times.
✓ Branch 1 taken 6 times.
|
642000 | || (addr == FORD_Lane_Assist_Data1) |
105 |
2/2✓ Branch 0 taken 641988 times.
✓ Branch 1 taken 6 times.
|
641994 | || (addr == FORD_LateralMotionControl) |
106 |
2/2✓ Branch 0 taken 641982 times.
✓ Branch 1 taken 6 times.
|
641988 | || (addr == FORD_LateralMotionControl2) |
107 |
4/4✓ Branch 0 taken 642000 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 641976 times.
|
1284006 | || (addr == FORD_IPMA_Data); |
108 | } | ||
109 | |||
110 | // Curvature rate limits | ||
111 | static const SteeringLimits FORD_STEERING_LIMITS = { | ||
112 | .max_steer = 1000, | ||
113 | .angle_deg_to_can = 50000, // 1 / (2e-5) rad to can | ||
114 | .max_angle_error = 100, // 0.002 * FORD_STEERING_LIMITS.angle_deg_to_can | ||
115 | .angle_rate_up_lookup = { | ||
116 | {5., 25., 25.}, | ||
117 | {0.00045, 0.0001, 0.0001} | ||
118 | }, | ||
119 | .angle_rate_down_lookup = { | ||
120 | {5., 25., 25.}, | ||
121 | {0.00045, 0.00015, 0.00015} | ||
122 | }, | ||
123 | |||
124 | // no blending at low speed due to lack of torque wind-up and inaccurate current curvature | ||
125 | .angle_error_min_speed = 10.0, // m/s | ||
126 | |||
127 | .enforce_angle_error = true, | ||
128 | .inactive_angle_is_zero = true, | ||
129 | }; | ||
130 | |||
131 | 650454 | static void ford_rx_hook(const CANPacket_t *to_push) { | |
132 |
2/2✓ Branch 0 taken 633558 times.
✓ Branch 1 taken 16896 times.
|
650454 | if (GET_BUS(to_push) == FORD_MAIN_BUS) { |
133 | 633558 | int addr = GET_ADDR(to_push); | |
134 | |||
135 | // Update in motion state from standstill signal | ||
136 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 633534 times.
|
633558 | if (addr == FORD_DesiredTorqBrk) { |
137 | // Signal: VehStop_D_Stat | ||
138 | 24 | vehicle_moving = ((GET_BYTE(to_push, 3) >> 3) & 0x3U) != 1U; | |
139 | } | ||
140 | |||
141 | // Update vehicle speed | ||
142 |
2/2✓ Branch 0 taken 295890 times.
✓ Branch 1 taken 337668 times.
|
633558 | if (addr == FORD_BrakeSysFeatures) { |
143 | // Signal: Veh_V_ActlBrk | ||
144 | 295890 | UPDATE_VEHICLE_SPEED(((GET_BYTE(to_push, 0) << 8) | GET_BYTE(to_push, 1)) * 0.01 / 3.6); | |
145 | } | ||
146 | |||
147 | // Check vehicle speed against a second source | ||
148 |
2/2✓ Branch 0 taken 24033 times.
✓ Branch 1 taken 609525 times.
|
633558 | if (addr == FORD_EngVehicleSpThrottle2) { |
149 | // Disable controls if speeds from ABS and PCM ECUs are too far apart. | ||
150 | // Signal: Veh_V_ActlEng | ||
151 | 24033 | float filtered_pcm_speed = ((GET_BYTE(to_push, 6) << 8) | GET_BYTE(to_push, 7)) * 0.01 / 3.6; | |
152 |
2/2✓ Branch 0 taken 11760 times.
✓ Branch 1 taken 12273 times.
|
24033 | bool is_invalid_speed = ABS(filtered_pcm_speed - ((float)vehicle_speed.values[0] / VEHICLE_SPEED_FACTOR)) > FORD_MAX_SPEED_DELTA; |
153 |
2/2✓ Branch 0 taken 13710 times.
✓ Branch 1 taken 10323 times.
|
24033 | if (is_invalid_speed) { |
154 | 13710 | controls_allowed = false; | |
155 | } | ||
156 | } | ||
157 | |||
158 | // Update vehicle yaw rate | ||
159 |
2/2✓ Branch 0 taken 305070 times.
✓ Branch 1 taken 328488 times.
|
633558 | if (addr == FORD_Yaw_Data_FD1) { |
160 | // Signal: VehYaw_W_Actl | ||
161 | 305070 | float ford_yaw_rate = (((GET_BYTE(to_push, 2) << 8U) | GET_BYTE(to_push, 3)) * 0.0002) - 6.5; | |
162 |
2/2✓ Branch 0 taken 304968 times.
✓ Branch 1 taken 102 times.
|
305070 | float current_curvature = ford_yaw_rate / MAX(vehicle_speed.values[0] / VEHICLE_SPEED_FACTOR, 0.1); |
163 | // convert current curvature into units on CAN for comparison with desired curvature | ||
164 | 305070 | update_sample(&angle_meas, ROUND(current_curvature * FORD_STEERING_LIMITS.angle_deg_to_can)); | |
165 | } | ||
166 | |||
167 | // Update gas pedal | ||
168 |
2/2✓ Branch 0 taken 33 times.
✓ Branch 1 taken 633525 times.
|
633558 | if (addr == FORD_EngVehicleSpThrottle) { |
169 | // Pedal position: (0.1 * val) in percent | ||
170 | // Signal: ApedPos_Pc_ActlArb | ||
171 | 33 | gas_pressed = (((GET_BYTE(to_push, 0) & 0x03U) << 8) | GET_BYTE(to_push, 1)) > 0U; | |
172 | } | ||
173 | |||
174 | // Update brake pedal and cruise state | ||
175 |
2/2✓ Branch 0 taken 78 times.
✓ Branch 1 taken 633480 times.
|
633558 | if (addr == FORD_EngBrakeData) { |
176 | // Signal: BpedDrvAppl_D_Actl | ||
177 | 78 | brake_pressed = ((GET_BYTE(to_push, 0) >> 4) & 0x3U) == 2U; | |
178 | |||
179 | // Signal: CcStat_D_Actl | ||
180 | 78 | unsigned int cruise_state = GET_BYTE(to_push, 1) & 0x07U; | |
181 |
3/4✓ Branch 0 taken 78 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 48 times.
|
78 | bool cruise_engaged = (cruise_state == 4U) || (cruise_state == 5U); |
182 | 78 | pcm_cruise_check(cruise_engaged); | |
183 | } | ||
184 | |||
185 | // If steering controls messages are received on the destination bus, it's an indication | ||
186 | // that the relay might be malfunctioning. | ||
187 | 633558 | bool stock_ecu_detected = ford_lkas_msg_check(addr); | |
188 |
2/2✓ Branch 0 taken 422372 times.
✓ Branch 1 taken 211186 times.
|
633558 | if (ford_longitudinal) { |
189 |
4/4✓ Branch 0 taken 422362 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 422360 times.
|
422372 | stock_ecu_detected = stock_ecu_detected || (addr == FORD_ACCDATA); |
190 | } | ||
191 | 633558 | generic_rx_checks(stock_ecu_detected); | |
192 | } | ||
193 | |||
194 | 650454 | } | |
195 | |||
196 | 50482 | static bool ford_tx_hook(const CANPacket_t *to_send) { | |
197 | const LongitudinalLimits FORD_LONG_LIMITS = { | ||
198 | // acceleration cmd limits (used for brakes) | ||
199 | // Signal: AccBrkTot_A_Rq | ||
200 | .max_accel = 5641, // 1.9999 m/s^s | ||
201 | .min_accel = 4231, // -3.4991 m/s^2 | ||
202 | .inactive_accel = 5128, // -0.0008 m/s^2 | ||
203 | |||
204 | // gas cmd limits | ||
205 | // Signal: AccPrpl_A_Rq & AccPrpl_A_Pred | ||
206 | .max_gas = 700, // 2.0 m/s^2 | ||
207 | .min_gas = 450, // -0.5 m/s^2 | ||
208 | .inactive_gas = 0, // -5.0 m/s^2 | ||
209 | }; | ||
210 | |||
211 | 50482 | bool tx = true; | |
212 | |||
213 | 50482 | int addr = GET_ADDR(to_send); | |
214 | |||
215 | // Safety check for ACCDATA accel and brake requests | ||
216 |
2/2✓ Branch 0 taken 2062 times.
✓ Branch 1 taken 48420 times.
|
50482 | if (addr == FORD_ACCDATA) { |
217 | // Signal: AccPrpl_A_Rq | ||
218 | 2062 | int gas = ((GET_BYTE(to_send, 6) & 0x3U) << 8) | GET_BYTE(to_send, 7); | |
219 | // Signal: AccPrpl_A_Pred | ||
220 | 2062 | int gas_pred = ((GET_BYTE(to_send, 2) & 0x3U) << 8) | GET_BYTE(to_send, 3); | |
221 | // Signal: AccBrkTot_A_Rq | ||
222 | 2062 | int accel = ((GET_BYTE(to_send, 0) & 0x1FU) << 8) | GET_BYTE(to_send, 1); | |
223 | // Signal: CmbbDeny_B_Actl | ||
224 | 2062 | bool cmbb_deny = GET_BIT(to_send, 37U); | |
225 | |||
226 | // Signal: AccBrkPrchg_B_Rq & AccBrkDecel_B_Rq | ||
227 |
3/4✓ Branch 0 taken 1032 times.
✓ Branch 1 taken 1030 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1032 times.
|
2062 | bool brake_actuation = GET_BIT(to_send, 54U) || GET_BIT(to_send, 55U); |
228 | |||
229 | 2062 | bool violation = false; | |
230 | 2062 | violation |= longitudinal_accel_checks(accel, FORD_LONG_LIMITS); | |
231 | 2062 | violation |= longitudinal_gas_checks(gas, FORD_LONG_LIMITS); | |
232 | 2062 | violation |= longitudinal_gas_checks(gas_pred, FORD_LONG_LIMITS); | |
233 | |||
234 | // Safety check for stock AEB | ||
235 | 2062 | violation |= cmbb_deny; // do not prevent stock AEB actuation | |
236 | |||
237 |
4/4✓ Branch 1 taken 1032 times.
✓ Branch 2 taken 1030 times.
✓ Branch 3 taken 380 times.
✓ Branch 4 taken 652 times.
|
2062 | violation |= !get_longitudinal_allowed() && brake_actuation; |
238 | |||
239 |
2/2✓ Branch 0 taken 1504 times.
✓ Branch 1 taken 558 times.
|
2062 | if (violation) { |
240 | 1504 | tx = false; | |
241 | } | ||
242 | } | ||
243 | |||
244 | // Safety check for Steering_Data_FD1 button signals | ||
245 | // Note: Many other signals in this message are not relevant to safety (e.g. blinkers, wiper switches, high beam) | ||
246 | // which we passthru in OP. | ||
247 |
2/2✓ Branch 0 taken 42 times.
✓ Branch 1 taken 50440 times.
|
50482 | if (addr == FORD_Steering_Data_FD1) { |
248 | // Violation if resume button is pressed while controls not allowed, or | ||
249 | // if cancel button is pressed when cruise isn't engaged. | ||
250 | 42 | bool violation = false; | |
251 |
4/4✓ Branch 0 taken 12 times.
✓ Branch 1 taken 30 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 6 times.
|
42 | violation |= GET_BIT(to_send, 8U) && !cruise_engaged_prev; // Signal: CcAslButtnCnclPress (cancel) |
252 |
4/4✓ Branch 0 taken 12 times.
✓ Branch 1 taken 30 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 6 times.
|
42 | violation |= GET_BIT(to_send, 25U) && !controls_allowed; // Signal: CcAsllButtnResPress (resume) |
253 | |||
254 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 30 times.
|
42 | if (violation) { |
255 | 12 | tx = false; | |
256 | } | ||
257 | } | ||
258 | |||
259 | // Safety check for Lane_Assist_Data1 action | ||
260 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 50473 times.
|
50482 | if (addr == FORD_Lane_Assist_Data1) { |
261 | // Do not allow steering using Lane_Assist_Data1 (Lane-Departure Aid). | ||
262 | // This message must be sent for Lane Centering to work, and can include | ||
263 | // values such as the steering angle or lane curvature for debugging, | ||
264 | // but the action (LkaActvStats_D2_Req) must be set to zero. | ||
265 | 9 | unsigned int action = GET_BYTE(to_send, 0) >> 5; | |
266 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 3 times.
|
9 | if (action != 0U) { |
267 | 6 | tx = false; | |
268 | } | ||
269 | } | ||
270 | |||
271 | // Safety check for LateralMotionControl action | ||
272 |
2/2✓ Branch 0 taken 16121 times.
✓ Branch 1 taken 34361 times.
|
50482 | if (addr == FORD_LateralMotionControl) { |
273 | // Signal: LatCtl_D_Rq | ||
274 | 16121 | bool steer_control_enabled = ((GET_BYTE(to_send, 4) >> 2) & 0x7U) != 0U; | |
275 | 16121 | unsigned int raw_curvature = (GET_BYTE(to_send, 0) << 3) | (GET_BYTE(to_send, 1) >> 5); | |
276 | 16121 | unsigned int raw_curvature_rate = ((GET_BYTE(to_send, 1) & 0x1FU) << 8) | GET_BYTE(to_send, 2); | |
277 | 16121 | unsigned int raw_path_angle = (GET_BYTE(to_send, 3) << 3) | (GET_BYTE(to_send, 4) >> 5); | |
278 | 16121 | unsigned int raw_path_offset = (GET_BYTE(to_send, 5) << 2) | (GET_BYTE(to_send, 6) >> 6); | |
279 | |||
280 | // These signals are not yet tested with the current safety limits | ||
281 |
6/6✓ Branch 0 taken 6440 times.
✓ Branch 1 taken 9681 times.
✓ Branch 2 taken 2040 times.
✓ Branch 3 taken 4400 times.
✓ Branch 4 taken 400 times.
✓ Branch 5 taken 1640 times.
|
16121 | bool violation = (raw_curvature_rate != FORD_INACTIVE_CURVATURE_RATE) || (raw_path_angle != FORD_INACTIVE_PATH_ANGLE) || (raw_path_offset != FORD_INACTIVE_PATH_OFFSET); |
282 | |||
283 | // Check angle error and steer_control_enabled | ||
284 | 16121 | int desired_curvature = raw_curvature - FORD_INACTIVE_CURVATURE; // /FORD_STEERING_LIMITS.angle_deg_to_can to get real curvature | |
285 | 16121 | violation |= steer_angle_cmd_checks(desired_curvature, steer_control_enabled, FORD_STEERING_LIMITS); | |
286 | |||
287 |
2/2✓ Branch 0 taken 15299 times.
✓ Branch 1 taken 822 times.
|
16121 | if (violation) { |
288 | 15299 | tx = false; | |
289 | } | ||
290 | } | ||
291 | |||
292 | // Safety check for LateralMotionControl2 action | ||
293 |
2/2✓ Branch 0 taken 32242 times.
✓ Branch 1 taken 18240 times.
|
50482 | if (addr == FORD_LateralMotionControl2) { |
294 | // Signal: LatCtl_D2_Rq | ||
295 | 32242 | bool steer_control_enabled = ((GET_BYTE(to_send, 0) >> 4) & 0x7U) != 0U; | |
296 | 32242 | unsigned int raw_curvature = (GET_BYTE(to_send, 2) << 3) | (GET_BYTE(to_send, 3) >> 5); | |
297 | 32242 | unsigned int raw_curvature_rate = (GET_BYTE(to_send, 6) << 3) | (GET_BYTE(to_send, 7) >> 5); | |
298 | 32242 | unsigned int raw_path_angle = ((GET_BYTE(to_send, 3) & 0x1FU) << 6) | (GET_BYTE(to_send, 4) >> 2); | |
299 | 32242 | unsigned int raw_path_offset = ((GET_BYTE(to_send, 4) & 0x3U) << 8) | GET_BYTE(to_send, 5); | |
300 | |||
301 | // These signals are not yet tested with the current safety limits | ||
302 |
6/6✓ Branch 0 taken 12880 times.
✓ Branch 1 taken 19362 times.
✓ Branch 2 taken 4080 times.
✓ Branch 3 taken 8800 times.
✓ Branch 4 taken 800 times.
✓ Branch 5 taken 3280 times.
|
32242 | bool violation = (raw_curvature_rate != FORD_CANFD_INACTIVE_CURVATURE_RATE) || (raw_path_angle != FORD_INACTIVE_PATH_ANGLE) || (raw_path_offset != FORD_INACTIVE_PATH_OFFSET); |
303 | |||
304 | // Check angle error and steer_control_enabled | ||
305 | 32242 | int desired_curvature = raw_curvature - FORD_INACTIVE_CURVATURE; // /FORD_STEERING_LIMITS.angle_deg_to_can to get real curvature | |
306 | 32242 | violation |= steer_angle_cmd_checks(desired_curvature, steer_control_enabled, FORD_STEERING_LIMITS); | |
307 | |||
308 |
2/2✓ Branch 0 taken 30598 times.
✓ Branch 1 taken 1644 times.
|
32242 | if (violation) { |
309 | 30598 | tx = false; | |
310 | } | ||
311 | } | ||
312 | |||
313 | 50482 | return tx; | |
314 | } | ||
315 | |||
316 | 25344 | static int ford_fwd_hook(int bus_num, int addr) { | |
317 | 25344 | int bus_fwd = -1; | |
318 | |||
319 |
3/3✓ Branch 0 taken 8448 times.
✓ Branch 1 taken 8448 times.
✓ Branch 2 taken 8448 times.
|
25344 | switch (bus_num) { |
320 | 8448 | case FORD_MAIN_BUS: { | |
321 | // Forward all traffic from bus 0 onward | ||
322 | 8448 | bus_fwd = FORD_CAM_BUS; | |
323 | 8448 | break; | |
324 | } | ||
325 | 8448 | case FORD_CAM_BUS: { | |
326 |
2/2✓ Branch 1 taken 15 times.
✓ Branch 2 taken 8433 times.
|
8448 | if (ford_lkas_msg_check(addr)) { |
327 | // Block stock LKAS and UI messages | ||
328 | 15 | bus_fwd = -1; | |
329 |
4/4✓ Branch 0 taken 5622 times.
✓ Branch 1 taken 2811 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 5620 times.
|
8433 | } else if (ford_longitudinal && (addr == FORD_ACCDATA)) { |
330 | // Block stock ACC message | ||
331 | 2 | bus_fwd = -1; | |
332 | } else { | ||
333 | // Forward remaining traffic | ||
334 | 8431 | bus_fwd = FORD_MAIN_BUS; | |
335 | } | ||
336 | 8448 | break; | |
337 | } | ||
338 | 8448 | default: { | |
339 | // No other buses should be in use; fallback to do-not-forward | ||
340 | 8448 | bus_fwd = -1; | |
341 | 8448 | break; | |
342 | } | ||
343 | } | ||
344 | |||
345 | 25344 | return bus_fwd; | |
346 | } | ||
347 | |||
348 | 96 | static safety_config ford_init(uint16_t param) { | |
349 | 96 | bool ford_canfd = false; | |
350 | |||
351 | // warning: quality flags are not yet checked in openpilot's CAN parser, | ||
352 | // this may be the cause of blocked messages | ||
353 | static RxCheck ford_rx_checks[] = { | ||
354 | {.msg = {{FORD_BrakeSysFeatures, 0, 8, .check_checksum = true, .max_counter = 15U, .quality_flag=true, .frequency = 50U}, { 0 }, { 0 }}}, | ||
355 | // FORD_EngVehicleSpThrottle2 has a counter that either randomly skips or by 2, likely ECU bug | ||
356 | // Some hybrid models also experience a bug where this checksum mismatches for one or two frames under heavy acceleration with ACC | ||
357 | // It has been confirmed that the Bronco Sport's camera only disallows ACC for bad quality flags, not counters or checksums, so we match that | ||
358 | {.msg = {{FORD_EngVehicleSpThrottle2, 0, 8, .check_checksum = false, .quality_flag=true, .frequency = 50U}, { 0 }, { 0 }}}, | ||
359 | {.msg = {{FORD_Yaw_Data_FD1, 0, 8, .check_checksum = true, .max_counter = 255U, .quality_flag=true, .frequency = 100U}, { 0 }, { 0 }}}, | ||
360 | // These messages have no counter or checksum | ||
361 | {.msg = {{FORD_EngBrakeData, 0, 8, .frequency = 10U}, { 0 }, { 0 }}}, | ||
362 | {.msg = {{FORD_EngVehicleSpThrottle, 0, 8, .frequency = 100U}, { 0 }, { 0 }}}, | ||
363 | {.msg = {{FORD_DesiredTorqBrk, 0, 8, .frequency = 50U}, { 0 }, { 0 }}}, | ||
364 | }; | ||
365 | |||
366 | #define FORD_COMMON_TX_MSGS \ | ||
367 | {FORD_Steering_Data_FD1, 0, 8}, \ | ||
368 | {FORD_Steering_Data_FD1, 2, 8}, \ | ||
369 | {FORD_ACCDATA_3, 0, 8}, \ | ||
370 | {FORD_Lane_Assist_Data1, 0, 8}, \ | ||
371 | {FORD_IPMA_Data, 0, 8}, \ | ||
372 | |||
373 | static const CanMsg FORD_CANFD_LONG_TX_MSGS[] = { | ||
374 | FORD_COMMON_TX_MSGS | ||
375 | {FORD_ACCDATA, 0, 8}, | ||
376 | {FORD_LateralMotionControl2, 0, 8}, | ||
377 | }; | ||
378 | |||
379 | static const CanMsg FORD_CANFD_STOCK_TX_MSGS[] = { | ||
380 | FORD_COMMON_TX_MSGS | ||
381 | {FORD_LateralMotionControl2, 0, 8}, | ||
382 | }; | ||
383 | |||
384 | static const CanMsg FORD_STOCK_TX_MSGS[] = { | ||
385 | FORD_COMMON_TX_MSGS | ||
386 | {FORD_LateralMotionControl, 0, 8}, | ||
387 | }; | ||
388 | |||
389 | static const CanMsg FORD_LONG_TX_MSGS[] = { | ||
390 | FORD_COMMON_TX_MSGS | ||
391 | {FORD_ACCDATA, 0, 8}, | ||
392 | {FORD_LateralMotionControl, 0, 8}, | ||
393 | }; | ||
394 | |||
395 | UNUSED(param); | ||
396 | #ifdef ALLOW_DEBUG | ||
397 | 96 | const uint16_t FORD_PARAM_LONGITUDINAL = 1; | |
398 | 96 | const uint16_t FORD_PARAM_CANFD = 2; | |
399 | 96 | ford_longitudinal = GET_FLAG(param, FORD_PARAM_LONGITUDINAL); | |
400 | 96 | ford_canfd = GET_FLAG(param, FORD_PARAM_CANFD); | |
401 | #endif | ||
402 | |||
403 | // Longitudinal is the default for CAN, and optional for CAN FD w/ ALLOW_DEBUG | ||
404 |
4/4✓ Branch 0 taken 63 times.
✓ Branch 1 taken 33 times.
✓ Branch 2 taken 33 times.
✓ Branch 3 taken 30 times.
|
96 | ford_longitudinal = !ford_canfd || ford_longitudinal; |
405 | |||
406 | safety_config ret; | ||
407 | // FIXME: cppcheck thinks that ford_canfd is always false. This is not true | ||
408 | // if ALLOW_DEBUG is defined but cppcheck is run without ALLOW_DEBUG | ||
409 | // cppcheck-suppress knownConditionTrueFalse | ||
410 |
2/2✓ Branch 0 taken 63 times.
✓ Branch 1 taken 33 times.
|
96 | if (ford_canfd) { |
411 |
2/2✓ Branch 0 taken 33 times.
✓ Branch 1 taken 30 times.
|
63 | ret = ford_longitudinal ? BUILD_SAFETY_CFG(ford_rx_checks, FORD_CANFD_LONG_TX_MSGS) : \ |
412 | BUILD_SAFETY_CFG(ford_rx_checks, FORD_CANFD_STOCK_TX_MSGS); | ||
413 | } else { | ||
414 | // cppcheck-suppress knownConditionTrueFalse | ||
415 |
1/2✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
|
33 | ret = ford_longitudinal ? BUILD_SAFETY_CFG(ford_rx_checks, FORD_LONG_TX_MSGS) : \ |
416 | BUILD_SAFETY_CFG(ford_rx_checks, FORD_STOCK_TX_MSGS); | ||
417 | } | ||
418 | 96 | return ret; | |
419 | } | ||
420 | |||
421 | const safety_hooks ford_hooks = { | ||
422 | .init = ford_init, | ||
423 | .rx = ford_rx_hook, | ||
424 | .tx = ford_tx_hook, | ||
425 | .fwd = ford_fwd_hook, | ||
426 | .get_counter = ford_get_counter, | ||
427 | .get_checksum = ford_get_checksum, | ||
428 | .compute_checksum = ford_compute_checksum, | ||
429 | .get_quality_flag_valid = ford_get_quality_flag_valid, | ||
430 | }; | ||
431 |