Skip to content

Commit 598074c

Browse files
authored
Volkswagen safety updates: Phase 2 (#445)
* CRC and counter checks, standstill/brake checks * Clean up a tsk_06 that snuck through * Be consistent about how we call _msg_esp_05 * Reduce scope: haunted by the ghost of MISRA future * Improved check/test for in-motion braking * MISRA styling fix
1 parent b2ffaae commit 598074c

7 files changed

+266
-7
lines changed

board/safety.h

+15
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,21 @@ int safety_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) {
5757
return current_hooks->fwd(bus_num, to_fwd);
5858
}
5959

60+
// Given a CRC-8 poly, generate a static lookup table to use with a fast CRC-8
61+
// algorithm. Called at init time for safety modes using CRC-8.
62+
void gen_crc_lookup_table(uint8_t poly, uint8_t crc_lut[]) {
63+
for (int i = 0; i < 256; i++) {
64+
uint8_t crc = i;
65+
for (int j = 0; j < 8; j++) {
66+
if ((crc & 0x80U) != 0U)
67+
crc = (uint8_t)((crc << 1) ^ poly);
68+
else
69+
crc <<= 1;
70+
}
71+
crc_lut[i] = crc;
72+
}
73+
}
74+
6075
bool msg_allowed(int addr, int bus, const AddrBus addr_list[], int len) {
6176
bool allowed = false;
6277
for (int i = 0; i < len; i++) {

board/safety/safety_volkswagen.h

+77-5
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ const int VOLKSWAGEN_DRIVER_TORQUE_ALLOWANCE = 80;
88
const int VOLKSWAGEN_DRIVER_TORQUE_FACTOR = 3;
99

1010
// Safety-relevant CAN messages for the Volkswagen MQB platform
11+
#define MSG_ESP_19 0x0B2 // RX from ABS, for wheel speeds
1112
#define MSG_EPS_01 0x09F // RX from EPS, for driver steering torque
13+
#define MSG_ESP_05 0x106 // RX from ABS, for brake switch state
1214
#define MSG_MOTOR_20 0x121 // RX from ECU, for driver throttle input
1315
#define MSG_ACC_06 0x122 // RX from ACC radar, for status and engagement
1416
#define MSG_HCA_01 0x126 // TX by OP, Heading Control Assist steering torque
@@ -19,11 +21,12 @@ const int VOLKSWAGEN_DRIVER_TORQUE_FACTOR = 3;
1921
const AddrBus VOLKSWAGEN_MQB_TX_MSGS[] = {{MSG_HCA_01, 0}, {MSG_GRA_ACC_01, 0}, {MSG_GRA_ACC_01, 2}, {MSG_LDW_02, 0}};
2022
const int VOLKSWAGEN_MQB_TX_MSGS_LEN = sizeof(VOLKSWAGEN_MQB_TX_MSGS) / sizeof(VOLKSWAGEN_MQB_TX_MSGS[0]);
2123

22-
// TODO: do checksum and counter checks
2324
AddrCheckStruct volkswagen_mqb_rx_checks[] = {
24-
{.addr = {MSG_EPS_01}, .bus = 0, .expected_timestep = 10000U},
25-
{.addr = {MSG_ACC_06}, .bus = 0, .expected_timestep = 20000U},
26-
{.addr = {MSG_MOTOR_20}, .bus = 0, .expected_timestep = 20000U},
25+
{.addr = {MSG_ESP_19}, .bus = 0, .check_checksum = false, .max_counter = 0U, .expected_timestep = 10000U},
26+
{.addr = {MSG_EPS_01}, .bus = 0, .check_checksum = true, .max_counter = 15U, .expected_timestep = 10000U},
27+
{.addr = {MSG_ESP_05}, .bus = 0, .check_checksum = true, .max_counter = 15U, .expected_timestep = 20000U},
28+
{.addr = {MSG_MOTOR_20}, .bus = 0, .check_checksum = true, .max_counter = 15U, .expected_timestep = 20000U},
29+
{.addr = {MSG_ACC_06}, .bus = 0, .check_checksum = true, .max_counter = 15U, .expected_timestep = 20000U},
2730
};
2831
const int VOLKSWAGEN_MQB_RX_CHECKS_LEN = sizeof(volkswagen_mqb_rx_checks) / sizeof(volkswagen_mqb_rx_checks[0]);
2932

@@ -32,9 +35,56 @@ struct sample_t volkswagen_torque_driver; // Last few driver torques measured
3235
int volkswagen_rt_torque_last = 0;
3336
int volkswagen_desired_torque_last = 0;
3437
uint32_t volkswagen_ts_last = 0;
38+
bool volkswagen_moving = false;
39+
bool volkswagen_brake_pressed_prev = false;
3540
int volkswagen_gas_prev = 0;
3641
int volkswagen_torque_msg = 0;
3742
int volkswagen_lane_msg = 0;
43+
uint8_t volkswagen_crc8_lut_8h2f[256]; // Static lookup table for CRC8 poly 0x2F, aka 8H2F/AUTOSAR
44+
45+
46+
static uint8_t volkswagen_get_checksum(CAN_FIFOMailBox_TypeDef *to_push) {
47+
return (uint8_t)GET_BYTE(to_push, 0);
48+
}
49+
50+
static uint8_t volkswagen_get_counter(CAN_FIFOMailBox_TypeDef *to_push) {
51+
return (uint8_t)GET_BYTE(to_push, 1) & 0xFU;
52+
}
53+
54+
static uint8_t volkswagen_mqb_compute_crc(CAN_FIFOMailBox_TypeDef *to_push) {
55+
int addr = GET_ADDR(to_push);
56+
int len = GET_LEN(to_push);
57+
58+
// This is CRC-8H2F/AUTOSAR with a twist. See the OpenDBC implementation
59+
// of this algorithm for a version with explanatory comments.
60+
61+
uint8_t crc = 0xFFU;
62+
for (int i = 1; i < len; i++) {
63+
crc ^= (uint8_t)GET_BYTE(to_push, i);
64+
crc = volkswagen_crc8_lut_8h2f[crc];
65+
}
66+
67+
uint8_t counter = volkswagen_get_counter(to_push);
68+
switch(addr) {
69+
case MSG_EPS_01:
70+
crc ^= (uint8_t[]){0xF5,0xF5,0xF5,0xF5,0xF5,0xF5,0xF5,0xF5,0xF5,0xF5,0xF5,0xF5,0xF5,0xF5,0xF5,0xF5}[counter];
71+
break;
72+
case MSG_ESP_05:
73+
crc ^= (uint8_t[]){0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07}[counter];
74+
break;
75+
case MSG_MOTOR_20:
76+
crc ^= (uint8_t[]){0xE9,0x65,0xAE,0x6B,0x7B,0x35,0xE5,0x5F,0x4E,0xC7,0x86,0xA2,0xBB,0xDD,0xEB,0xB4}[counter];
77+
break;
78+
case MSG_ACC_06:
79+
crc ^= (uint8_t[]){0x37,0x7D,0xF3,0xA9,0x18,0x46,0x6D,0x4D,0x3D,0x71,0x92,0x9C,0xE5,0x32,0x10,0xB9}[counter];
80+
break;
81+
default: // Undefined CAN message, CRC check expected to fail
82+
break;
83+
}
84+
crc = volkswagen_crc8_lut_8h2f[crc];
85+
86+
return crc ^ 0xFFU;
87+
}
3888

3989
static void volkswagen_mqb_init(int16_t param) {
4090
UNUSED(param);
@@ -43,17 +93,29 @@ static void volkswagen_mqb_init(int16_t param) {
4393
relay_malfunction = false;
4494
volkswagen_torque_msg = MSG_HCA_01;
4595
volkswagen_lane_msg = MSG_LDW_02;
96+
gen_crc_lookup_table(0x2F, volkswagen_crc8_lut_8h2f);
4697
}
4798

4899
static int volkswagen_mqb_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) {
49100

50101
bool valid = addr_safety_check(to_push, volkswagen_mqb_rx_checks, VOLKSWAGEN_MQB_RX_CHECKS_LEN,
51-
NULL, NULL, NULL);
102+
volkswagen_get_checksum, volkswagen_mqb_compute_crc, volkswagen_get_counter);
52103

53104
if (valid) {
54105
int bus = GET_BUS(to_push);
55106
int addr = GET_ADDR(to_push);
56107

108+
// Update in-motion state by sampling front wheel speeds
109+
// Signal: ESP_19.ESP_VL_Radgeschw_02 (front left) in scaled km/h
110+
// Signal: ESP_19.ESP_VR_Radgeschw_02 (front right) in scaled km/h
111+
if ((bus == 0) && (addr == MSG_ESP_19)) {
112+
int wheel_speed_fl = GET_BYTE(to_push, 4) | (GET_BYTE(to_push, 5) << 8);
113+
int wheel_speed_fr = GET_BYTE(to_push, 6) | (GET_BYTE(to_push, 7) << 8);
114+
// Check for average front speed in excess of 0.3m/s, 1.08km/h
115+
// DBC speed scale 0.0075: 0.3m/s = 144, sum both wheels to compare
116+
volkswagen_moving = (wheel_speed_fl + wheel_speed_fr) > 288;
117+
}
118+
57119
// Update driver input torque samples
58120
// Signal: EPS_01.Driver_Strain (absolute torque)
59121
// Signal: EPS_01.Driver_Strain_VZ (direction)
@@ -83,6 +145,16 @@ static int volkswagen_mqb_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) {
83145
volkswagen_gas_prev = gas;
84146
}
85147

148+
// Exit controls on rising edge of brake press
149+
// Signal: ESP_05.ESP_Fahrer_bremst
150+
if ((bus == 0) && (addr == MSG_ESP_05)) {
151+
bool brake_pressed = (GET_BYTE(to_push, 3) & 0x4) >> 2;
152+
if (brake_pressed && (!(volkswagen_brake_pressed_prev) || volkswagen_moving)) {
153+
controls_allowed = 0;
154+
}
155+
volkswagen_brake_pressed_prev = brake_pressed;
156+
}
157+
86158
// If there are HCA messages on bus 0 not sent by OP, there's a relay problem
87159
if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && (bus == 0) && (addr == MSG_HCA_01)) {
88160
relay_malfunction = true;

board/safety_declarations.h

+1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ bool driver_limit_check(int val, int val_last, struct sample_t *val_driver,
4949
const int MAX_ALLOWANCE, const int DRIVER_FACTOR);
5050
bool rt_rate_limit_check(int val, int val_last, const int MAX_RT_DELTA);
5151
float interpolate(struct lookup_t xy, float x);
52+
void gen_crc_lookup_table(uint8_t poly, uint8_t crc_lut[]);
5253
bool msg_allowed(int addr, int bus, const AddrBus addr_list[], int len);
5354
int get_addr_check_index(CAN_FIFOMailBox_TypeDef *to_push, AddrCheckStruct addr_list[], const int len);
5455
void update_counter(AddrCheckStruct addr_list[], int index, uint8_t counter);

requirements.txt

+1
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ requests
99
flake8==3.7.9
1010
pylint==2.4.3
1111
cffi==1.11.4
12+
crcmod

tests/safety/libpandasafety_py.py

+2
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@
9494
int get_volkswagen_gas_prev(void);
9595
int get_volkswagen_torque_driver_min(void);
9696
int get_volkswagen_torque_driver_max(void);
97+
bool get_volkswagen_moving(void);
98+
bool get_volkswagen_brake_pressed_prev(void);
9799
void set_volkswagen_desired_torque_last(int t);
98100
void set_volkswagen_rt_torque_last(int t);
99101
void set_volkswagen_torque_driver(int min, int max);

tests/safety/test.c

+11
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,14 @@ void set_volkswagen_desired_torque_last(int t){
232232
volkswagen_desired_torque_last = t;
233233
}
234234

235+
int get_volkswagen_moving(void){
236+
return volkswagen_moving;
237+
}
238+
239+
int get_volkswagen_brake_pressed_prev(void){
240+
return volkswagen_brake_pressed_prev;
241+
}
242+
235243
int get_volkswagen_gas_prev(void){
236244
return volkswagen_gas_prev;
237245
}
@@ -334,6 +342,9 @@ void init_tests_subaru(void){
334342

335343
void init_tests_volkswagen(void){
336344
init_tests();
345+
volkswagen_moving = false;
346+
volkswagen_brake_pressed_prev = false;
347+
volkswagen_gas_prev = 0;
337348
volkswagen_torque_driver.min = 0;
338349
volkswagen_torque_driver.max = 0;
339350
volkswagen_desired_torque_last = 0;

0 commit comments

Comments
 (0)