#pragma once #include "board/can.h" #include "board/health.h" #include "board/crc.h" #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 // ******************** bootkick ******************** extern bool bootkick_reset_triggered; void bootkick_tick(bool ignition, bool recent_heartbeat, bool wake); // ******************** can_common ******************** typedef struct { volatile uint32_t w_ptr; volatile uint32_t r_ptr; uint32_t fifo_size; CANPacket_t *elems; } can_ring; typedef struct { uint8_t bus_lookup; uint8_t can_num_lookup; uint32_t can_speed; uint32_t can_data_speed; bool canfd_auto; bool canfd_enabled; bool brs_enabled; bool canfd_non_iso; } bus_config_t; extern uint32_t safety_tx_blocked; extern uint32_t safety_rx_invalid; extern uint32_t tx_buffer_overflow; extern uint32_t rx_buffer_overflow; 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; // ******************* functions prototypes ********************* bool can_init(uint8_t can_number); void process_can(uint8_t can_number); // ********************* instantiate queues ********************* extern can_ring *can_queues[PANDA_CAN_CNT]; // helpers #define WORD_TO_BYTE_ARRAY(dst8, src32) 0[dst8] = ((src32) & 0xFFU); 1[dst8] = (((src32) >> 8U) & 0xFFU); 2[dst8] = (((src32) >> 16U) & 0xFFU); 3[dst8] = (((src32) >> 24U) & 0xFFU) #define BYTE_ARRAY_TO_WORD(dst32, src8) ((dst32) = 0[src8] | (1[src8] << 8U) | (2[src8] << 16U) | (3[src8] << 24U)) // ********************* interrupt safe queue ********************* bool can_pop(can_ring *q, CANPacket_t *elem); bool can_push(can_ring *q, const CANPacket_t *elem); uint32_t can_slots_empty(const can_ring *q); extern bus_config_t bus_config[PANDA_CAN_CNT]; #define CANIF_FROM_CAN_NUM(num) (cans[num]) #define BUS_NUM_FROM_CAN_NUM(num) (bus_config[num].bus_lookup) #define CAN_NUM_FROM_BUS_NUM(num) (bus_config[num].can_num_lookup) void can_init_all(void); void can_set_orientation(bool flipped); bool can_tx_check_min_slots_free(uint32_t min); bool can_check_checksum(CANPacket_t *packet); bool is_speed_valid(uint32_t speed, const uint32_t *all_speeds, uint8_t len); // ******************** clock_source ******************** void clock_source_set_timer_params(uint16_t param1, uint16_t param2); void clock_source_init(bool enable_channel1); // ******************** fan ******************** struct fan_state_t { uint16_t tach_counter; uint16_t rpm; uint8_t power; uint8_t stall_counter; uint8_t stall_threshold; uint8_t cooldown_counter; }; extern struct fan_state_t fan_state; void fan_set_power(uint8_t percentage); void llfan_init(void); void fan_init(void); // Call this at FAN_TICK_FREQ void fan_tick(void); // ******************** fdcan ******************** #ifdef STM32H7 typedef struct { volatile uint32_t header[2]; volatile uint32_t data_word[CANPACKET_DATA_SIZE_MAX/4U]; } canfd_fifo; extern FDCAN_GlobalTypeDef *cans[PANDA_CAN_CNT]; #define CAN_ACK_ERROR 3U 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 ******************** #define HARNESS_STATUS_NC 0U #define HARNESS_STATUS_NORMAL 1U #define HARNESS_STATUS_FLIPPED 2U struct harness_t { uint8_t status; uint16_t sbu1_voltage_mV; uint16_t sbu2_voltage_mV; bool relay_driven; bool sbu_adc_lock; }; extern struct harness_t harness; struct harness_configuration { GPIO_TypeDef * const GPIO_SBU1; GPIO_TypeDef * const GPIO_SBU2; GPIO_TypeDef * const GPIO_relay_SBU1; GPIO_TypeDef * const GPIO_relay_SBU2; const uint8_t pin_SBU1; const uint8_t pin_SBU2; const uint8_t pin_relay_SBU1; const uint8_t pin_relay_SBU2; const adc_signal_t adc_signal_SBU1; const adc_signal_t adc_signal_SBU2; }; // The ignition relay is only used for testing purposes void set_intercept_relay(bool intercept, bool ignition_relay); bool harness_check_ignition(void); void harness_tick(void); void harness_init(void); // ******************** interrupts ******************** typedef struct interrupt { void (*handler)(void); uint32_t call_counter; uint32_t call_rate; uint32_t max_call_rate; // Call rate is defined as the amount of calls each second uint32_t call_rate_fault; } interrupt; void interrupt_timer_init(void); uint32_t microsecond_timer_get(void); extern interrupt interrupts[NUM_INTERRUPTS]; #define REGISTER_INTERRUPT(irq_num, func_ptr, call_rate_max, rate_fault) \ interrupts[irq_num].handler = (func_ptr); \ interrupts[irq_num].call_counter = 0U; \ interrupts[irq_num].call_rate = 0U; \ interrupts[irq_num].max_call_rate = (call_rate_max); \ interrupts[irq_num].call_rate_fault = (rate_fault); extern float interrupt_load; void handle_interrupt(IRQn_Type irq_type); // Every second void interrupt_timer_handler(void); void init_interrupts(bool check_rate_limit); // ******************** registers ******************** // 10 bit hash with 23 as a prime #define REGISTER_MAP_SIZE 0x3FFU #define HASHING_PRIME 23U // Do not put bits in the check mask that get changed by the hardware void register_set(volatile uint32_t *addr, uint32_t val, uint32_t mask); // Set individual bits. Also add them to the check_mask. // Do not use this to change bits that get reset by the hardware void register_set_bits(volatile uint32_t *addr, uint32_t val); // Clear individual bits. Also add them to the check_mask. // Do not use this to clear bits that get set by the hardware void register_clear_bits(volatile uint32_t *addr, uint32_t val); // To be called periodically void check_registers(void); void init_registers(void); // ******************** simple_watchdog ******************** typedef struct simple_watchdog_state_t { uint32_t fault; uint32_t last_ts; uint32_t threshold; } simple_watchdog_state_t; void simple_watchdog_kick(void); void simple_watchdog_init(uint32_t fault, uint32_t threshold); // ******************** spi ******************** // got max rate from hitting a non-existent endpoint // in a tight loop, plus some buffer #define SPI_IRQ_RATE 16000U #define SPI_BUF_SIZE 4096U extern uint8_t spi_buf_rx[SPI_BUF_SIZE]; extern uint8_t spi_buf_tx[SPI_BUF_SIZE]; extern uint16_t spi_error_count; void can_tx_comms_resume_spi(void); void spi_init(void); // ******************** debug ******************** bool debug_get_char(char *elem); void print(const char *a); void puth(unsigned int i); static void hexdump(const void *a, int l); static inline void puth4(unsigned int i); // ******************** usb ******************** void usb_init(void); void refresh_can_tx_slots_available(void); void can_tx_comms_resume_usb(void);