Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions opendbc/safety/declarations.h
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,21 @@ typedef uint32_t (*get_checksum_t)(const CANPacket_t *msg);
typedef uint32_t (*compute_checksum_t)(const CANPacket_t *msg);
typedef uint8_t (*get_counter_t)(const CANPacket_t *msg);
typedef bool (*get_quality_flag_valid_t)(const CANPacket_t *msg);
typedef struct {
int scratch[2];
bool ignition;
bool seen;
bool updated;
uint32_t age;
} ignition_can_state_t;
typedef void (*ignition_can_hook_t)(const CANPacket_t *msg, ignition_can_state_t *state);

static inline void update_ignition_can_state(ignition_can_state_t *state, bool ignition_active) {
state->ignition = ignition_active;
state->seen = true;
state->updated = true;
state->age = 0U;
}

typedef safety_config (*safety_hook_init)(uint16_t param);
typedef void (*rx_hook)(const CANPacket_t *msg);
Expand All @@ -218,6 +233,7 @@ typedef struct {
rx_hook rx;
tx_hook tx;
fwd_hook fwd;
ignition_can_hook_t ignition_hook;
get_checksum_t get_checksum;
compute_checksum_t compute_checksum;
get_counter_t get_counter;
Expand Down Expand Up @@ -264,6 +280,11 @@ extern bool acc_main_on; // referred to as "ACC off" in ISO 15622:2018
extern int cruise_button_prev;
extern bool safety_rx_checks_invalid;

// CAN-based ignition detection (used by panda)
extern bool ignition_can;
extern uint32_t ignition_can_cnt;
void ignition_can_hook(const CANPacket_t *msg);

// for safety modes with torque steering control
extern int desired_torque_last; // last desired steer torque
extern int rt_torque_last; // last desired torque for real time check
Expand Down Expand Up @@ -323,6 +344,7 @@ extern const safety_hooks body_hooks;
extern const safety_hooks chrysler_hooks;
extern const safety_hooks chrysler_cusw_hooks;
extern const safety_hooks elm327_hooks;
extern const safety_hooks silent_hooks;
extern const safety_hooks nooutput_hooks;
extern const safety_hooks alloutput_hooks;
extern const safety_hooks ford_hooks;
Expand Down
6 changes: 6 additions & 0 deletions opendbc/safety/modes/defaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ const safety_hooks nooutput_hooks = {
.tx = nooutput_tx_hook,
};

const safety_hooks silent_hooks = {
.init = nooutput_init,
.rx = default_rx_hook,
.tx = nooutput_tx_hook,
};

// *** all output safety mode ***
static safety_config alloutput_init(uint16_t param) {
// Enables passthrough mode where relay is open and bus 0 gets forwarded to bus 2 and vice versa
Expand Down
8 changes: 8 additions & 0 deletions opendbc/safety/modes/gm.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ typedef enum {
static GmHardware gm_hw = GM_ASCM;
static bool gm_pcm_cruise = false;

static void gm_ignition_hook(const CANPacket_t *msg, ignition_can_state_t *state) {
if ((msg->bus == 0U) && (msg->addr == 0x1F1U) && (GET_LEN(msg) == 8U)) {
// SystemPowerMode (2=Run, 3=Crank Request)
update_ignition_can_state(state, (msg->data[0] & 0x2U) != 0U);
}
}

static void gm_rx_hook(const CANPacket_t *msg) {
const int GM_STANDSTILL_THRSLD = 10; // 0.311kph

Expand Down Expand Up @@ -240,4 +247,5 @@ const safety_hooks gm_hooks = {
.init = gm_init,
.rx = gm_rx_hook,
.tx = gm_tx_hook,
.ignition_hook = gm_ignition_hook,
};
7 changes: 7 additions & 0 deletions opendbc/safety/modes/mazda.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@
#define MAZDA_MAIN 0
#define MAZDA_CAM 2

static void mazda_ignition_hook(const CANPacket_t *msg, ignition_can_state_t *state) {
if ((msg->bus == 0U) && (msg->addr == 0x9EU) && (GET_LEN(msg) == 8U)) {
update_ignition_can_state(state, (msg->data[0] >> 5U) == 0x6U);
}
}

// track msgs coming from OP so that we know what CAM msgs to drop and what to forward
static void mazda_rx_hook(const CANPacket_t *msg) {
if ((int)msg->bus == MAZDA_MAIN) {
Expand Down Expand Up @@ -102,4 +108,5 @@ const safety_hooks mazda_hooks = {
.init = mazda_init,
.rx = mazda_rx_hook,
.tx = mazda_tx_hook,
.ignition_hook = mazda_ignition_hook,
};
16 changes: 16 additions & 0 deletions opendbc/safety/modes/rivian.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,21 @@

#include "opendbc/safety/declarations.h"

static void rivian_ignition_hook(const CANPacket_t *msg, ignition_can_state_t *state) {
if ((msg->bus == 0U) && (msg->addr == 0x152U) && (GET_LEN(msg) == 8U)) {
// 0x152 overlaps with Subaru pre-global which has this bit as the high beam
const int counter = msg->data[1] & 0xFU; // max is only 14

if ((state->scratch[1] != 0) && (counter == ((state->scratch[0] + 1) % 15))) {
// VDM_OutputSignals->VDM_EpasPowerMode
const uint8_t power_mode = (msg->data[7] >> 4U) & 0x3U;
update_ignition_can_state(state, power_mode == 1U); // VDM_EpasPowerMode_Drive_On=1
}
state->scratch[0] = counter;
state->scratch[1] = 1;
}
}

static uint8_t rivian_get_counter(const CANPacket_t *msg) {
// Signal: ESP_Status_Counter, VDM_PropStatus_Counter
return msg->data[1] & 0xFU;
Expand Down Expand Up @@ -175,6 +190,7 @@ const safety_hooks rivian_hooks = {
.init = rivian_init,
.rx = rivian_rx_hook,
.tx = rivian_tx_hook,
.ignition_hook = rivian_ignition_hook,
.get_counter = rivian_get_counter,
.get_checksum = rivian_get_checksum,
.compute_checksum = rivian_compute_checksum,
Expand Down
16 changes: 16 additions & 0 deletions opendbc/safety/modes/tesla.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,21 @@ static bool tesla_stock_lkas_prev = false;
static bool tesla_autopark = false;
static bool tesla_autopark_prev = false;

static void tesla_ignition_hook(const CANPacket_t *msg, ignition_can_state_t *state) {
if ((msg->bus == 0U) && (msg->addr == 0x221U) && (GET_LEN(msg) == 8U)) {
// 0x221 overlaps with Rivian which has random data on byte 0
const int counter = msg->data[6] >> 4U;

if ((state->scratch[1] != 0) && (counter == ((state->scratch[0] + 1) % 16))) {
// VCFRONT_LVPowerState->VCFRONT_vehiclePowerState
const uint8_t power_state = (msg->data[0] >> 5U) & 0x3U;
update_ignition_can_state(state, power_state == 0x3U); // VEHICLE_POWER_STATE_DRIVE=3
}
state->scratch[0] = counter;
state->scratch[1] = 1;
}
}

static uint8_t tesla_get_counter(const CANPacket_t *msg) {

uint8_t cnt = 0;
Expand Down Expand Up @@ -386,6 +401,7 @@ const safety_hooks tesla_hooks = {
.rx = tesla_rx_hook,
.tx = tesla_tx_hook,
.fwd = tesla_fwd_hook,
.ignition_hook = tesla_ignition_hook,
.get_counter = tesla_get_counter,
.get_checksum = tesla_get_checksum,
.compute_checksum = tesla_compute_checksum,
Expand Down
108 changes: 75 additions & 33 deletions opendbc/safety/safety.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#pragma once

#include <stddef.h>

#include "opendbc/safety/helpers.h"
#include "opendbc/safety/lateral.h"
#include "opendbc/safety/longitudinal.h"
Expand Down Expand Up @@ -58,6 +60,10 @@ bool acc_main_on = false; // referred to as "ACC off" in ISO 15622:2018
int cruise_button_prev = 0;
bool safety_rx_checks_invalid = false;

// CAN-based ignition detection (used by panda)
bool ignition_can = false;
uint32_t ignition_can_cnt = 0U;

// for safety modes with torque steering control
int desired_torque_last = 0; // last desired steer torque
int rt_torque_last = 0; // last desired torque for real time check
Expand All @@ -84,14 +90,81 @@ int alternative_experience = 0;
// time since safety mode has been changed
uint32_t safety_mode_cnt = 0U;

static const safety_hook_config safety_hook_registry[] = {
{SAFETY_SILENT, &silent_hooks},
{SAFETY_HONDA_NIDEC, &honda_nidec_hooks},
{SAFETY_TOYOTA, &toyota_hooks},
{SAFETY_ELM327, &elm327_hooks},
{SAFETY_GM, &gm_hooks},
{SAFETY_HONDA_BOSCH, &honda_bosch_hooks},
{SAFETY_HYUNDAI, &hyundai_hooks},
{SAFETY_CHRYSLER, &chrysler_hooks},
{SAFETY_SUBARU, &subaru_hooks},
{SAFETY_VOLKSWAGEN_MQB, &volkswagen_mqb_hooks},
{SAFETY_NISSAN, &nissan_hooks},
{SAFETY_NOOUTPUT, &nooutput_hooks},
{SAFETY_HYUNDAI_LEGACY, &hyundai_legacy_hooks},
{SAFETY_MAZDA, &mazda_hooks},
{SAFETY_BODY, &body_hooks},
{SAFETY_FORD, &ford_hooks},
{SAFETY_RIVIAN, &rivian_hooks},
{SAFETY_TESLA, &tesla_hooks},
{SAFETY_HYUNDAI_CANFD, &hyundai_canfd_hooks},
#ifdef ALLOW_DEBUG
{SAFETY_CHRYSLER_CUSW, &chrysler_cusw_hooks},
{SAFETY_PSA, &psa_hooks},
{SAFETY_SUBARU_PREGLOBAL, &subaru_preglobal_hooks},
{SAFETY_VOLKSWAGEN_MLB, &volkswagen_mlb_hooks},
{SAFETY_VOLKSWAGEN_PQ, &volkswagen_pq_hooks},
{SAFETY_ALLOUTPUT, &alloutput_hooks},
#endif
};

static ignition_can_state_t ignition_hook_states[sizeof(safety_hook_registry) / sizeof(safety_hook_registry[0])];

uint16_t current_safety_mode = SAFETY_SILENT;
uint16_t current_safety_param = 0;
static const safety_hooks *current_hooks = &nooutput_hooks;
static const safety_hooks *current_hooks = &silent_hooks;
safety_config current_safety_config;

static void generic_rx_checks(void);
static void stock_ecu_check(bool stock_ecu_detected);

static void update_ignition_can(void) {
bool seen = false;
bool active = false;
uint32_t min_cnt = 0U;

for (size_t i = 0U; i < (sizeof(safety_hook_registry) / sizeof(safety_hook_registry[0])); i++) {
if ((safety_hook_registry[i].hooks->ignition_hook != NULL) && ignition_hook_states[i].seen) {
active |= ignition_hook_states[i].ignition;
if (!seen || (ignition_hook_states[i].age < min_cnt)) {
min_cnt = ignition_hook_states[i].age;
}
seen = true;
}
}

ignition_can = active;
ignition_can_cnt = seen ? min_cnt : 0U;
}

void ignition_can_hook(const CANPacket_t *msg) {
bool updated = false;

for (size_t i = 0U; i < (sizeof(safety_hook_registry) / sizeof(safety_hook_registry[0])); i++) {
if (safety_hook_registry[i].hooks->ignition_hook != NULL) {
ignition_hook_states[i].updated = false;
safety_hook_registry[i].hooks->ignition_hook(msg, &ignition_hook_states[i]);
updated |= ignition_hook_states[i].updated;
}
}

if (updated) {
update_ignition_can();
}
}

static bool is_msg_valid(RxCheck addr_list[], int index) {
bool valid = true;
if (index != -1) {
Expand Down Expand Up @@ -384,36 +457,6 @@ static void reset_sample(struct sample_t *sample) {
}

int set_safety_hooks(uint16_t mode, uint16_t param) {
const safety_hook_config safety_hook_registry[] = {
{SAFETY_SILENT, &nooutput_hooks},
{SAFETY_HONDA_NIDEC, &honda_nidec_hooks},
{SAFETY_TOYOTA, &toyota_hooks},
{SAFETY_ELM327, &elm327_hooks},
{SAFETY_GM, &gm_hooks},
{SAFETY_HONDA_BOSCH, &honda_bosch_hooks},
{SAFETY_HYUNDAI, &hyundai_hooks},
{SAFETY_CHRYSLER, &chrysler_hooks},
{SAFETY_SUBARU, &subaru_hooks},
{SAFETY_VOLKSWAGEN_MQB, &volkswagen_mqb_hooks},
{SAFETY_NISSAN, &nissan_hooks},
{SAFETY_NOOUTPUT, &nooutput_hooks},
{SAFETY_HYUNDAI_LEGACY, &hyundai_legacy_hooks},
{SAFETY_MAZDA, &mazda_hooks},
{SAFETY_BODY, &body_hooks},
{SAFETY_FORD, &ford_hooks},
{SAFETY_RIVIAN, &rivian_hooks},
{SAFETY_TESLA, &tesla_hooks},
{SAFETY_HYUNDAI_CANFD, &hyundai_canfd_hooks},
#ifdef ALLOW_DEBUG
{SAFETY_CHRYSLER_CUSW, &chrysler_cusw_hooks},
{SAFETY_PSA, &psa_hooks},
{SAFETY_SUBARU_PREGLOBAL, &subaru_preglobal_hooks},
{SAFETY_VOLKSWAGEN_MLB, &volkswagen_mlb_hooks},
{SAFETY_VOLKSWAGEN_PQ, &volkswagen_pq_hooks},
{SAFETY_ALLOUTPUT, &alloutput_hooks},
#endif
};

// reset state set by safety mode
safety_mode_cnt = 0U;
relay_malfunction = false;
Expand Down Expand Up @@ -456,8 +499,7 @@ int set_safety_hooks(uint16_t mode, uint16_t param) {
current_safety_config.disable_forwarding = false;

int set_status = -1; // not set
int hook_config_count = sizeof(safety_hook_registry) / sizeof(safety_hook_config);
for (int i = 0; i < hook_config_count; i++) {
for (size_t i = 0U; i < (sizeof(safety_hook_registry) / sizeof(safety_hook_registry[0])); i++) {
if (safety_hook_registry[i].id == mode) {
current_hooks = safety_hook_registry[i].hooks;
current_safety_mode = mode;
Expand Down
5 changes: 5 additions & 0 deletions opendbc/safety/tests/libsafety/libsafety_py.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@ class CANPacket:
bool get_cruise_engaged_prev(void);
void set_cruise_engaged_prev(bool engaged);
bool get_vehicle_moving(void);
void ignition_can_hook(CANPacket_t *msg);
void set_ignition_can(bool c);
bool get_ignition_can(void);
void set_ignition_can_cnt(uint32_t c);
uint32_t get_ignition_can_cnt(void);
void set_timer(uint32_t t);
void safety_tick_current_safety_config();
Expand Down
21 changes: 21 additions & 0 deletions opendbc/safety/tests/libsafety/safety.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,22 @@ bool get_vehicle_moving(void){
return vehicle_moving;
}

void set_ignition_can(bool c) {
ignition_can = c;
}

bool get_ignition_can(void) {
return ignition_can;
}

void set_ignition_can_cnt(uint32_t c) {
ignition_can_cnt = c;
}

uint32_t get_ignition_can_cnt(void) {
return ignition_can_cnt;
}

bool get_acc_main_on(void){
return acc_main_on;
}
Expand Down Expand Up @@ -198,6 +214,11 @@ void init_tests(void){
ts_steer_req_mismatch_last = 0;
valid_steer_req_count = 0;
invalid_steer_req_count = 0;
ignition_can = false;
ignition_can_cnt = 0U;
for (size_t i = 0U; i < (sizeof(safety_hook_registry) / sizeof(safety_hook_registry[0])); i++) {
ignition_hook_states[i] = (ignition_can_state_t){0};
}

// assumes autopark on safety mode init to avoid a fault. get rid of that for testing
tesla_autopark = false;
Expand Down
4 changes: 4 additions & 0 deletions opendbc/safety/tests/misra/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,7 @@ SAFETY_UNUSED(safety_tx_hook);
SAFETY_UNUSED(safety_fwd_hook);
SAFETY_UNUSED(safety_tick);
SAFETY_UNUSED(set_safety_hooks);

// Called by panda and via libsafety tests (FFI)
SAFETY_UNUSED(ignition_can_reset);
SAFETY_UNUSED(ignition_can_hook);
4 changes: 3 additions & 1 deletion opendbc/safety/tests/mutation.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,11 @@ def _site_key(site):


def _is_in_constexpr_context(node):
"""Check if a node is inside a static or file-scope variable initializer."""
"""Check if a node is inside a build-time constant expression context."""
current = node.parent
while current is not None:
if current.type in ("array_declarator", "enumerator"):
return True
if current.type == "init_declarator":
decl = current.parent
if decl and decl.type == "declaration":
Expand Down
Loading
Loading