Native Safety

Extend native safety and health contracts with explicit AOL state and bounded message handling. Keep vehicle-specific admissions outside the generic layer.

Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com>
This commit is contained in:
firestar5683
2026-09-25 14:53:18 -05:00
parent ddcc9ed3f3
commit df0e7bd551
21 changed files with 1081 additions and 98 deletions
+20
View File
@@ -0,0 +1,20 @@
#pragma once
// IRQs: CAN1_TX, CAN1_RX0, CAN1_SCE
// CAN2_TX, CAN2_RX0, CAN2_SCE
// CAN3_TX, CAN3_RX0, CAN3_SCE
#define CAN_ARRAY_SIZE 3
#define CAN_IRQS_ARRAY_SIZE 3
extern CAN_TypeDef *cans[CAN_ARRAY_SIZE];
extern uint8_t can_irq_number[CAN_IRQS_ARRAY_SIZE][CAN_IRQS_ARRAY_SIZE];
bool can_set_speed(uint8_t can_number);
void can_clear_send(CAN_TypeDef *CANx, uint8_t can_number);
void update_can_health_pkt(uint8_t can_number, uint32_t ir_reg);
// ***************************** CAN *****************************
// CANx_TX IRQ Handler
// CANx_RX0 IRQ Handler
// blink blue when we are receiving CAN messages
void can_rx(uint8_t can_number);
+13 -5
View File
@@ -3,7 +3,11 @@
#include "board/can.h"
#include "board/health.h"
#include "board/crc.h"
#ifdef STM32H7
#include "opendbc/safety/can_tx.h"
#ifdef STM32F4
#include "board/stm32f4/lladc_declarations.h"
#include "board/drivers/bxcan_declarations.h"
#elif defined(STM32H7)
#include "board/stm32h7/lladc_declarations.h"
#endif
@@ -11,7 +15,7 @@
extern bool bootkick_reset_triggered;
void bootkick_tick(bool ignition, bool recent_heartbeat);
void bootkick_tick(bool ignition, bool recent_heartbeat, bool wake);
// ******************** can_common ********************
@@ -43,6 +47,12 @@ extern can_health_t can_health[PANDA_CAN_CNT];
// Ignition detected from CAN messages
extern bool ignition_can;
extern uint32_t ignition_can_cnt;
extern bool wake_on_can;
extern uint32_t wake_on_can_cnt;
#ifdef PANDA_HKG_REMOTE_START
extern bool hkg_remote_climate_wake;
extern uint32_t hkg_remote_climate_wake_cnt;
#endif
extern bool can_silent;
extern bool can_loopback;
@@ -71,9 +81,7 @@ extern bus_config_t bus_config[PANDA_CAN_CNT];
void can_init_all(void);
void can_set_orientation(bool flipped);
bool can_tx_check_min_slots_free(uint32_t min);
void can_set_checksum(CANPacket_t *packet);
bool can_check_checksum(CANPacket_t *packet);
void can_send(CANPacket_t *to_push, uint8_t bus_number, bool skip_tx_hook);
bool is_speed_valid(uint32_t speed, const uint32_t *all_speeds, uint8_t len);
// ******************** clock_source ********************
@@ -112,6 +120,7 @@ extern FDCAN_GlobalTypeDef *cans[PANDA_CAN_CNT];
void can_clear_send(FDCAN_GlobalTypeDef *FDCANx, uint8_t can_number);
void update_can_health_pkt(uint8_t can_number, uint32_t ir_reg);
#endif
// ******************** harness ********************
@@ -176,7 +185,6 @@ void handle_interrupt(IRQn_Type irq_type);
void interrupt_timer_handler(void);
void init_interrupts(bool check_rate_limit);
#endif // STM32H7
// ******************** registers ********************
+12
View File
@@ -10,6 +10,18 @@
#define HEALTH_FLAG_NMI_RESET (1U << 7)
#define HEALTH_FLAG_HARDFAULT_RESET ((uint16_t)1U << 8)
#define AOL_SAFETY_PROTOCOL_MAGIC 0x314C4F41U // "AOL1", little endian
#define AOL_SAFETY_PROTOCOL_VERSION 1U
typedef struct __attribute__((packed)) {
uint32_t magic;
uint8_t version;
uint8_t request_mask;
uint8_t permission_mask;
uint8_t safety_mode;
uint16_t safety_param;
uint8_t capability_flags;
} aol_safety_health_t;
struct __attribute__((packed)) health_t {
uint32_t uptime_pkt;
uint16_t voltage_pkt;
+39 -2
View File
@@ -1,5 +1,14 @@
#pragma once
static bool panda_ignition_line(void) {
#ifdef PANDA_IGNORE_IGNITION_LINE
return false;
#else
return harness_check_ignition();
#endif
}
extern int _app_start[0xc000]; // Only first 3 sectors of size 0x4000 are used
// Prototypes
@@ -15,7 +24,7 @@ static int get_health_pkt(void *dat) {
health->current_pkt = (uint16_t)MIN(current_board->read_current_mA(), 0xFFFFU);
health->flags_pkt = 0U;
health->flags_pkt |= harness_check_ignition() ? HEALTH_FLAG_IGNITION_LINE : 0U;
health->flags_pkt |= panda_ignition_line() ? HEALTH_FLAG_IGNITION_LINE : 0U;
health->flags_pkt |= ignition_can ? HEALTH_FLAG_IGNITION_CAN : 0U;
health->flags_pkt |= controls_allowed ? HEALTH_FLAG_CONTROLS_ALLOWED : 0U;
health->flags_pkt |= power_save_enabled ? HEALTH_FLAG_POWER_SAVE_ENABLED : 0U;
@@ -48,8 +57,12 @@ static int get_health_pkt(void *dat) {
health->sound_output_level_pkt = sound_output_level;
#ifdef STM32H7
float temperature_encoded = (CLAMP(dts_get_temperature(), -40.0f, 214.5f) + 40.0f) + 0.5f;
health->temperature_pkt = (uint8_t)temperature_encoded;
#else
health->temperature_pkt = 0U;
#endif
return sizeof(*health);
}
@@ -65,6 +78,25 @@ int comms_control_handler(ControlPacket_t *req, uint8_t *resp) {
uint32_t time;
switch (req->request) {
// Fork-local read-only AOL capability and actual native permissions.
// Older firmware returns no matching packet, so the host fails closed.
case 0xd5:
{
aol_safety_health_t status = {
.magic = AOL_SAFETY_PROTOCOL_MAGIC,
.version = AOL_SAFETY_PROTOCOL_VERSION,
.request_mask = aol_get_request_mask(),
.permission_mask = aol_get_permission_mask(),
.safety_mode = (uint8_t)current_safety_mode,
.safety_param = current_safety_param,
.capability_flags = (aol_policy != NULL) ? (0x1U | (aol_optional_release_capable ? 0x2U : 0U)) : 0U,
};
for (unsigned int i = 0U; i < sizeof(status); i++) {
resp[i] = ((uint8_t *)&status)[i];
}
resp_len = sizeof(status);
}
break;
// **** 0xa8: get microsecond timer
case 0xa8:
time = microsecond_timer_get();
@@ -89,7 +121,7 @@ int comms_control_handler(ControlPacket_t *req, uint8_t *resp) {
resp_len = 2;
break;
// **** 0xb5: request deep sleep, wakes on CAN or SBU
#ifdef ALLOW_DEBUG
#if defined(ALLOW_DEBUG) && defined(STM32H7)
case 0xb5:
set_safety_mode(SAFETY_SILENT, 0U);
set_power_save_state(true);
@@ -293,6 +325,11 @@ int comms_control_handler(ControlPacket_t *req, uint8_t *resp) {
heartbeat_disabled = true;
}
break;
// A separate short-lived axis request leaves the legacy heartbeat protocol
// unchanged for every car without the exact Honda AOL safety parameter.
case 0xf5:
aol_set_host_request((uint8_t)req->param1);
break;
// **** 0xf9: set CAN FD data bitrate
case 0xf9:
if ((req->param1 < PANDA_CAN_CNT) &&
+20
View File
@@ -0,0 +1,20 @@
#pragma once
typedef enum {
SAMPLETIME_3_CYCLES = 0,
SAMPLETIME_15_CYCLES = 1,
SAMPLETIME_28_CYCLES = 2,
SAMPLETIME_56_CYCLES = 3,
SAMPLETIME_84_CYCLES = 4,
SAMPLETIME_112_CYCLES = 5,
SAMPLETIME_144_CYCLES = 6,
SAMPLETIME_480_CYCLES = 7
} adc_sample_time_t;
typedef struct {
ADC_TypeDef *adc;
uint8_t channel;
adc_sample_time_t sample_time;
} adc_signal_t;
#define ADC_CHANNEL_DEFAULT(a, c) {.adc = (a), .channel = (c), .sample_time = SAMPLETIME_480_CYCLES}
+3
View File
@@ -58,5 +58,8 @@ void fault_recovered(uint32_t fault);
// ******************** power_saving ********************
extern bool power_save_enabled;
#if defined(ALLOW_DEBUG) && defined(STM32H7)
extern volatile bool stop_mode_requested;
#endif
void set_power_save_state(bool enable);