Skip to content

Commit d7a1032

Browse files
committed
[HKG] Add ALT_BUTTONS, ALT_STEERING, & refactor safety.
As a newish contributor to this codebase, I should make clear up front that I haven't taken up this refactoring lightly or without good reason. I would love to avoid it but it seems necessary and less bad than all the other options. If there is another way to accomplish these goals I'm all ears. Root problem: HKG flags combine to produce combinatoric configurations. Supporting this requires tradeoffs between maintainability, convention, and quality. Alternatives considered: 1. Continue making RX & TX allowlists overly permissive. This seems antithetical to the whole point of safety flags. 2. Continue Copy-pasting nested branches with 1-line differences. It seems like this has already been done to the limit of reasonable maintainability (3-4 conditions deep). Also, to support the new conditions here would mean duplicating the code 8x. Callout: MISRA I am not a MISRA expert but AFAIU this conforms. Happy to discuss and iterate if this is incorrect. There are other options that trade readability for reduced dynamism. But at a certain point making everything static for the sake of MISRA seems to miss the forest for the trees. LMK what you think. I'd love to hear if there's a better way to solve this.
1 parent 10d8cc2 commit d7a1032

File tree

3 files changed

+188
-162
lines changed

3 files changed

+188
-162
lines changed

opendbc/safety/safety/safety_hyundai_canfd.h

Lines changed: 114 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,26 @@
33
#include "safety_declarations.h"
44
#include "safety_hyundai_common.h"
55

6-
// *** Addresses checked in rx hook ***
7-
// EV, ICE, HYBRID: ACCELERATOR (0x35), ACCELERATOR_BRAKE_ALT (0x100), ACCELERATOR_ALT (0x105)
8-
#define HYUNDAI_CANFD_COMMON_RX_CHECKS(pt_bus) \
9-
{.msg = {{0x35, (pt_bus), 32, .check_checksum = true, .max_counter = 0xffU, .frequency = 100U}, \
10-
{0x100, (pt_bus), 32, .check_checksum = true, .max_counter = 0xffU, .frequency = 100U}, \
11-
{0x105, (pt_bus), 32, .check_checksum = true, .max_counter = 0xffU, .frequency = 100U}}}, \
12-
{.msg = {{0x175, (pt_bus), 24, .check_checksum = true, .max_counter = 0xffU, .frequency = 50U}, { 0 }, { 0 }}}, \
13-
{.msg = {{0xa0, (pt_bus), 24, .check_checksum = true, .max_counter = 0xffU, .frequency = 100U}, { 0 }, { 0 }}}, \
14-
{.msg = {{0xea, (pt_bus), 24, .check_checksum = true, .max_counter = 0xffU, .frequency = 100U}, { 0 }, { 0 }}}, \
15-
16-
#define HYUNDAI_CANFD_BUTTONS_ADDR_CHECK(pt_bus) \
17-
{.msg = {{0x1cf, (pt_bus), 8, .check_checksum = false, .max_counter = 0xfU, .frequency = 50U}, { 0 }, { 0 }}}, \
18-
19-
#define HYUNDAI_CANFD_ALT_BUTTONS_ADDR_CHECK(pt_bus) \
20-
{.msg = {{0x1aa, (pt_bus), 16, .check_checksum = false, .max_counter = 0xffU, .frequency = 50U}, { 0 }, { 0 }}}, \
21-
22-
// SCC_CONTROL (from ADAS unit or camera)
23-
#define HYUNDAI_CANFD_SCC_ADDR_CHECK(scc_bus) \
24-
{.msg = {{0x1a0, (scc_bus), 32, .check_checksum = true, .max_counter = 0xffU, .frequency = 50U}, { 0 }, { 0 }}}, \
6+
#define MAX_RX_CHECKS 16
7+
8+
static safety_config hyundai_canfd_init_safety_config(void) {
9+
static RxCheck hyundai_canfd_rx_checks[MAX_RX_CHECKS] = {0};
10+
safety_config ret = {
11+
.rx_checks = hyundai_canfd_rx_checks,
12+
.rx_checks_len = 0,
13+
.tx_msgs = NULL,
14+
.tx_msgs_len = 0
15+
};
16+
return ret;
17+
}
18+
19+
static void add_rx_check(safety_config *safetyConfig, RxCheck config) {
20+
const uint8_t index = safetyConfig->rx_checks_len;
21+
safetyConfig->rx_checks_len++;
22+
if (index < (uint8_t)MAX_RX_CHECKS) {
23+
(void)memcpy(&safetyConfig->rx_checks[index], &config, sizeof(RxCheck));
24+
}
25+
}
2526

2627
static bool hyundai_canfd_alt_buttons = false;
2728
static bool hyundai_canfd_hda2_alt_steering = false;
@@ -154,10 +155,16 @@ static bool hyundai_canfd_tx_hook(const CANPacket_t *to_send) {
154155
}
155156

156157
// cruise buttons check
157-
if (addr == 0x1cf) {
158-
int button = GET_BYTE(to_send, 2) & 0x7U;
159-
bool is_cancel = (button == HYUNDAI_BTN_CANCEL);
160-
bool is_resume = (button == HYUNDAI_BTN_RESUME);
158+
const int button_addr = hyundai_canfd_alt_buttons ? 0x1aa : 0x1cf;
159+
if (addr == button_addr) {
160+
int cruise_button = 0;
161+
if (addr == 0x1cf) {
162+
cruise_button = GET_BYTE(to_send, 2) & 0x7U;
163+
} else {
164+
cruise_button = (GET_BYTE(to_send, 4) >> 4) & 0x7U;
165+
}
166+
bool is_cancel = (cruise_button == HYUNDAI_BTN_CANCEL);
167+
bool is_resume = (cruise_button == HYUNDAI_BTN_RESUME);
161168

162169
bool allowed = (is_cancel && cruise_engaged_prev) || (is_resume && controls_allowed);
163170
if (!allowed) {
@@ -211,11 +218,12 @@ static int hyundai_canfd_fwd_hook(int bus_num, int addr) {
211218

212219
// HUD icons
213220
bool is_lfahda_msg = ((addr == 0x1e0) && !hyundai_canfd_hda2);
221+
bool is_ccnc_msg = (((addr == 0x161) || (addr == 0x162)) && !hyundai_canfd_hda2);
214222

215223
// CRUISE_INFO for non-HDA2, we send our own longitudinal commands
216224
bool is_scc_msg = ((addr == 0x1a0) && hyundai_longitudinal && !hyundai_canfd_hda2);
217225

218-
bool block_msg = is_lkas_msg || is_lfa_msg || is_lfahda_msg || is_scc_msg;
226+
bool block_msg = is_lkas_msg || is_lfa_msg || is_lfahda_msg || is_ccnc_msg || is_scc_msg;
219227
if (!block_msg) {
220228
bus_fwd = 0;
221229
}
@@ -228,22 +236,32 @@ static safety_config hyundai_canfd_init(uint16_t param) {
228236
const int HYUNDAI_PARAM_CANFD_HDA2_ALT_STEERING = 128;
229237
const int HYUNDAI_PARAM_CANFD_ALT_BUTTONS = 32;
230238

239+
// TODO: Build these more precisely like RX_CHECKS.
231240
static const CanMsg HYUNDAI_CANFD_HDA2_TX_MSGS[] = {
232241
{0x50, 0, 16}, // LKAS
233242
{0x1CF, 1, 8}, // CRUISE_BUTTON
243+
// TODO: Include this iff CANFD_ALT_BUTTONS
244+
{0x1AA, 1, 16}, // CRUISE_BUTTONS_ALT
234245
{0x2A4, 0, 24}, // CAM_0x2A4
235246
};
236247

237248
static const CanMsg HYUNDAI_CANFD_HDA2_ALT_STEERING_TX_MSGS[] = {
238249
{0x110, 0, 32}, // LKAS_ALT
239250
{0x1CF, 1, 8}, // CRUISE_BUTTON
251+
// TODO: Include this iff CANFD_ALT_BUTTONS
252+
{0x1AA, 1, 16}, // CRUISE_BUTTONS_ALT
253+
// Needed for cruise control in case of ALT_BUTTONS.
254+
{0x1A0, 1, 32}, // CRUISE_INFO
240255
{0x362, 0, 32}, // CAM_0x362
241256
};
242257

243258
static const CanMsg HYUNDAI_CANFD_HDA2_LONG_TX_MSGS[] = {
244259
{0x50, 0, 16}, // LKAS
245260
{0x1CF, 1, 8}, // CRUISE_BUTTON
261+
// TODO: Include this iff CANFD_ALT_BUTTONS
262+
{0x1AA, 1, 16}, // CRUISE_BUTTONS_ALT
246263
{0x2A4, 0, 24}, // CAM_0x2A4
264+
// LONG start
247265
{0x51, 0, 32}, // ADRV_0x51
248266
{0x730, 1, 8}, // tester present for ADAS ECU disable
249267
{0x12A, 1, 16}, // LFA
@@ -254,13 +272,41 @@ static safety_config hyundai_canfd_init(uint16_t param) {
254272
{0x200, 1, 8}, // ADRV_0x200
255273
{0x345, 1, 8}, // ADRV_0x345
256274
{0x1DA, 1, 32}, // ADRV_0x1da
275+
{0x38C, 1, 32}, // ADRV_0x38c
276+
{0x161, 1, 32}, // MSG_161
277+
{0x162, 1, 32}, // MSG_162
278+
};
279+
280+
static const CanMsg HYUNDAI_CANFD_HDA2_ALT_STEERING_LONG_TX_MSGS[] = {
281+
{0x110, 0, 32}, // LKAS_ALT
282+
{0x1CF, 1, 8}, // CRUISE_BUTTON
283+
// TODO: Include this iff CANFD_ALT_BUTTONS
284+
{0x1AA, 1, 16}, // CRUISE_BUTTONS_ALT
285+
{0x1A0, 1, 32}, // CRUISE_INFO
286+
{0x362, 0, 32}, // CAM_0x362
287+
// LONG start
288+
{0x51, 0, 32}, // ADRV_0x51
289+
{0x730, 1, 8}, // tester present for ADAS ECU disable
290+
{0x12A, 1, 16}, // LFA
291+
{0x160, 1, 16}, // ADRV_0x160
292+
{0x1E0, 1, 16}, // LFAHDA_CLUSTER
293+
{0x1EA, 1, 32}, // ADRV_0x1ea
294+
{0x200, 1, 8}, // ADRV_0x200
295+
{0x345, 1, 8}, // ADRV_0x345
296+
{0x1DA, 1, 32}, // ADRV_0x1da
297+
{0x38C, 1, 32}, // ADRV_0x38c
298+
{0x161, 1, 32}, // MSG_161
299+
{0x162, 1, 32}, // MSG_162
257300
};
258301

259302
static const CanMsg HYUNDAI_CANFD_HDA1_TX_MSGS[] = {
260303
{0x12A, 0, 16}, // LFA
261304
{0x1A0, 0, 32}, // CRUISE_INFO
262305
{0x1CF, 2, 8}, // CRUISE_BUTTON
306+
{0x1AA, 2, 16}, // CRUISE_BUTTONS_ALT
263307
{0x1E0, 0, 16}, // LFAHDA_CLUSTER
308+
{0x161, 0, 32}, // MSG_161
309+
{0x162, 0, 32}, // MSG_162
264310
};
265311

266312

@@ -275,77 +321,57 @@ static safety_config hyundai_canfd_init(uint16_t param) {
275321
hyundai_longitudinal = false;
276322
}
277323

278-
safety_config ret;
324+
safety_config ret = hyundai_canfd_init_safety_config();
325+
326+
// RX Common checks.
327+
const int pt_bus = hyundai_canfd_hda2 ? 1 : 0;
328+
add_rx_check(&ret, (RxCheck){.msg = {{0x175, (pt_bus), 24, .check_checksum = true, .max_counter = 0xffU, .frequency = 50U}, { 0 }, { 0 }}});
329+
add_rx_check(&ret, (RxCheck){.msg = {{0xa0, (pt_bus), 24, .check_checksum = true, .max_counter = 0xffU, .frequency = 100U}, { 0 }, { 0 }}});
330+
add_rx_check(&ret, (RxCheck){.msg = {{0xea, (pt_bus), 24, .check_checksum = true, .max_counter = 0xffU, .frequency = 100U}, { 0 }, { 0 }}});
331+
332+
if (hyundai_ev_gas_signal) {
333+
add_rx_check(&ret, (RxCheck){.msg = {{0x35, (pt_bus), 32, .check_checksum = true, .max_counter = 0xffU, .frequency = 100U}, { 0 }, { 0 }}});
334+
} else if (hyundai_hybrid_gas_signal) {
335+
add_rx_check(&ret, (RxCheck){.msg = {{0x105, (pt_bus), 32, .check_checksum = true, .max_counter = 0xffU, .frequency = 100U}, { 0 }, { 0 }}});
336+
} else {
337+
add_rx_check(&ret, (RxCheck){.msg = {{0x100, (pt_bus), 32, .check_checksum = true, .max_counter = 0xffU, .frequency = 100U}, { 0 }, { 0 }}});
338+
}
339+
340+
// RX Cruise buttons.
341+
if (hyundai_canfd_alt_buttons) {
342+
add_rx_check(&ret, (RxCheck){.msg = {{0x1aa, (pt_bus), 16, .check_checksum = false, .max_counter = 0xffU, .frequency = 50U}, { 0 }, { 0 }}});
343+
} else {
344+
add_rx_check(&ret, (RxCheck){.msg = {{0x1cf, (pt_bus), 8, .check_checksum = false, .max_counter = 0xfU, .frequency = 50U}, { 0 }, { 0 }}});
345+
}
346+
279347
if (hyundai_longitudinal) {
280-
if (hyundai_canfd_hda2) {
281-
static RxCheck hyundai_canfd_hda2_long_rx_checks[] = {
282-
HYUNDAI_CANFD_COMMON_RX_CHECKS(1)
283-
HYUNDAI_CANFD_BUTTONS_ADDR_CHECK(1)
284-
};
348+
// TX SCC_CONTROL.
349+
} else {
350+
// RX SCC_CONTROL.
351+
const int scc_bus = hyundai_canfd_hda2 ? 1 : hyundai_camera_scc ? 2 : 0;
352+
add_rx_check(&ret, (RxCheck){.msg = {{0x1a0, (scc_bus), 32, .check_checksum = true, .max_counter = 0xffU, .frequency = 50U}, { 0 }, { 0 }}});
353+
}
285354

286-
ret = BUILD_SAFETY_CFG(hyundai_canfd_hda2_long_rx_checks, HYUNDAI_CANFD_HDA2_LONG_TX_MSGS);
355+
// TX checks.
356+
if (hyundai_longitudinal) {
357+
if (hyundai_canfd_hda2) {
358+
if (hyundai_canfd_hda2_alt_steering) {
359+
SET_TX_MSGS(HYUNDAI_CANFD_HDA2_ALT_STEERING_LONG_TX_MSGS, ret);
360+
} else {
361+
SET_TX_MSGS(HYUNDAI_CANFD_HDA2_LONG_TX_MSGS, ret);
362+
}
287363
} else {
288-
static RxCheck hyundai_canfd_long_alt_buttons_rx_checks[] = {
289-
HYUNDAI_CANFD_COMMON_RX_CHECKS(0)
290-
HYUNDAI_CANFD_ALT_BUTTONS_ADDR_CHECK(0)
291-
};
292-
293-
// Longitudinal checks for HDA1
294-
static RxCheck hyundai_canfd_long_rx_checks[] = {
295-
HYUNDAI_CANFD_COMMON_RX_CHECKS(0)
296-
HYUNDAI_CANFD_BUTTONS_ADDR_CHECK(0)
297-
};
298-
299-
ret = hyundai_canfd_alt_buttons ? BUILD_SAFETY_CFG(hyundai_canfd_long_alt_buttons_rx_checks, HYUNDAI_CANFD_HDA1_TX_MSGS) : \
300-
BUILD_SAFETY_CFG(hyundai_canfd_long_rx_checks, HYUNDAI_CANFD_HDA1_TX_MSGS);
364+
SET_TX_MSGS(HYUNDAI_CANFD_HDA1_TX_MSGS, ret);
301365
}
302366
} else {
303367
if (hyundai_canfd_hda2) {
304-
// *** HDA2 checks ***
305-
// E-CAN is on bus 1, ADAS unit sends SCC messages on HDA2.
306-
// Does not use the alt buttons message
307-
static RxCheck hyundai_canfd_hda2_rx_checks[] = {
308-
HYUNDAI_CANFD_COMMON_RX_CHECKS(1)
309-
HYUNDAI_CANFD_BUTTONS_ADDR_CHECK(1)
310-
HYUNDAI_CANFD_SCC_ADDR_CHECK(1)
311-
};
312-
313-
ret = hyundai_canfd_hda2_alt_steering ? BUILD_SAFETY_CFG(hyundai_canfd_hda2_rx_checks, HYUNDAI_CANFD_HDA2_ALT_STEERING_TX_MSGS) : \
314-
BUILD_SAFETY_CFG(hyundai_canfd_hda2_rx_checks, HYUNDAI_CANFD_HDA2_TX_MSGS);
315-
} else if (!hyundai_camera_scc) {
316-
static RxCheck hyundai_canfd_radar_scc_alt_buttons_rx_checks[] = {
317-
HYUNDAI_CANFD_COMMON_RX_CHECKS(0)
318-
HYUNDAI_CANFD_ALT_BUTTONS_ADDR_CHECK(0)
319-
HYUNDAI_CANFD_SCC_ADDR_CHECK(0)
320-
};
321-
322-
// Radar sends SCC messages on these cars instead of camera
323-
static RxCheck hyundai_canfd_radar_scc_rx_checks[] = {
324-
HYUNDAI_CANFD_COMMON_RX_CHECKS(0)
325-
HYUNDAI_CANFD_BUTTONS_ADDR_CHECK(0)
326-
HYUNDAI_CANFD_SCC_ADDR_CHECK(0)
327-
};
328-
329-
ret = hyundai_canfd_alt_buttons ? BUILD_SAFETY_CFG(hyundai_canfd_radar_scc_alt_buttons_rx_checks, HYUNDAI_CANFD_HDA1_TX_MSGS) : \
330-
BUILD_SAFETY_CFG(hyundai_canfd_radar_scc_rx_checks, HYUNDAI_CANFD_HDA1_TX_MSGS);
368+
if (hyundai_canfd_hda2_alt_steering) {
369+
SET_TX_MSGS(HYUNDAI_CANFD_HDA2_ALT_STEERING_TX_MSGS, ret);
370+
} else {
371+
SET_TX_MSGS(HYUNDAI_CANFD_HDA2_TX_MSGS, ret);
372+
}
331373
} else {
332-
// *** Non-HDA2 checks ***
333-
static RxCheck hyundai_canfd_alt_buttons_rx_checks[] = {
334-
HYUNDAI_CANFD_COMMON_RX_CHECKS(0)
335-
HYUNDAI_CANFD_ALT_BUTTONS_ADDR_CHECK(0)
336-
HYUNDAI_CANFD_SCC_ADDR_CHECK(2)
337-
};
338-
339-
// Camera sends SCC messages on HDA1.
340-
// Both button messages exist on some platforms, so we ensure we track the correct one using flag
341-
static RxCheck hyundai_canfd_rx_checks[] = {
342-
HYUNDAI_CANFD_COMMON_RX_CHECKS(0)
343-
HYUNDAI_CANFD_BUTTONS_ADDR_CHECK(0)
344-
HYUNDAI_CANFD_SCC_ADDR_CHECK(2)
345-
};
346-
347-
ret = hyundai_canfd_alt_buttons ? BUILD_SAFETY_CFG(hyundai_canfd_alt_buttons_rx_checks, HYUNDAI_CANFD_HDA1_TX_MSGS) : \
348-
BUILD_SAFETY_CFG(hyundai_canfd_rx_checks, HYUNDAI_CANFD_HDA1_TX_MSGS);
374+
SET_TX_MSGS(HYUNDAI_CANFD_HDA1_TX_MSGS, ret);
349375
}
350376
}
351377

opendbc/safety/tests/libsafety/safety_helpers.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,16 @@ bool safety_config_valid() {
1212
const RxCheck addr = current_safety_config.rx_checks[i];
1313
bool valid = addr.status.msg_seen && !addr.status.lagging && addr.status.valid_checksum && (addr.status.wrong_counters < MAX_WRONG_COUNTERS) && addr.status.valid_quality_flag;
1414
if (!valid) {
15-
// printf("i %d seen %d lagging %d valid checksum %d wrong counters %d valid quality flag %d\n", i, addr.status.msg_seen, addr.status.lagging, addr.status.valid_checksum, addr.status.wrong_counters, addr.status.valid_quality_flag);
15+
printf("i %d seen %d lagging %d valid checksum %d wrong counters %d valid quality flag %d\n",
16+
i, addr.status.msg_seen, addr.status.lagging, addr.status.valid_checksum, addr.status.wrong_counters, addr.status.valid_quality_flag);
17+
for (int j = 0; j < MAX_ADDR_CHECK_MSGS; j++) {
18+
const CanMsgCheck msg = addr.msg[j];
19+
if (msg.addr == 0) {
20+
break;
21+
}
22+
printf("i %d j %d bus %d addr 0x%x len %d\n",
23+
i, j, msg.bus, msg.addr, msg.len);
24+
}
1625
return false;
1726
}
1827
}

0 commit comments

Comments
 (0)