From 29f3e4fb3d89e5ebe8e8d5241e054f0a204f489c Mon Sep 17 00:00:00 2001 From: Yuze Pan Date: Thu, 21 May 2026 09:02:28 +0800 Subject: [PATCH 1/3] Split CAN comms into source and header files --- SConscript | 14 +- board/can_comms.c | 163 ++++++++++++++++++++++++ board/can_comms.h | 148 +-------------------- board/comms_constants.h | 4 + board/config.h | 3 +- board/drivers/can_common_declarations.h | 43 +++++++ board/drivers/drivers.h | 34 +---- board/main_definitions.h | 15 +-- board/main_state.c | 23 ++++ tests/libpanda/SConscript | 4 +- 10 files changed, 254 insertions(+), 197 deletions(-) create mode 100644 board/can_comms.c create mode 100644 board/comms_constants.h create mode 100644 board/drivers/can_common_declarations.h create mode 100644 board/main_state.c diff --git a/SConscript b/SConscript index de770920385..890ed05ba71 100644 --- a/SConscript +++ b/SConscript @@ -61,7 +61,9 @@ def to_c_uint32(x): return "{" + 'U,'.join(map(str, nums)) + "U}" -def build_project(project_name, project, main, extra_flags): +def build_project(project_name, project, main, extra_flags, extra_sources=None): + if extra_sources is None: + extra_sources = [] project_dir = Dir(f'./board/obj/{project_name}/') flags = project["FLAGS"] + extra_flags + common_flags + [ @@ -115,8 +117,8 @@ def build_project(project_name, project, main, extra_flags): # Build + sign main (aka app) main_elf = env.Program(f"{project_dir}/main.elf", [ startup, - main - ], LINKFLAGS=[f"-Wl,--section-start,.isr_vector={project['APP_START_ADDRESS']}"] + flags) + main, + ] + extra_sources, LINKFLAGS=[f"-Wl,--section-start,.isr_vector={project['APP_START_ADDRESS']}"] + flags) main_bin = env.Objcopy(f"{project_dir}/main.bin", main_elf) sign_py = File(f"./board/crypto/sign.py").srcnode().relpath env.Command(f"./board/obj/{project_name}.bin.signed", main_bin, f"SETLEN=1 {sign_py} $SOURCE $TARGET {cert_fn}") @@ -161,16 +163,16 @@ common_flags += [f"-DHEALTH_PACKET_VERSION=0x{hh:08X}U", f"-DCAN_PACKET_VERSION_ f"-DJUNGLE_HEALTH_PACKET_VERSION=0x{jh:08X}U"] # panda fw -build_project("panda_h7", base_project_h7, "./board/main.c", []) +build_project("panda_h7", base_project_h7, "./board/main.c", [], ["./board/main_state.c", "./board/can_comms.c"]) # panda jungle fw flags = [ "-DPANDA_JUNGLE", ] -build_project("panda_jungle_h7", base_project_h7, "./board/jungle/main.c", flags) +build_project("panda_jungle_h7", base_project_h7, "./board/jungle/main.c", flags, ["./board/main_state.c", "./board/can_comms.c"]) # body fw -build_project("body_h7", base_project_h7, "./board/body/main.c", ["-DPANDA_BODY"]) +build_project("body_h7", base_project_h7, "./board/body/main.c", ["-DPANDA_BODY"], ["./board/main_state.c", "./board/can_comms.c"]) # test files SConscript('tests/libpanda/SConscript') diff --git a/board/can_comms.c b/board/can_comms.c new file mode 100644 index 00000000000..724e6ed63b3 --- /dev/null +++ b/board/can_comms.c @@ -0,0 +1,163 @@ +/* + CAN transactions to and from the host come in the form of + a certain number of CANPacket_t. The transaction is split + into multiple transfers or chunks. + + CAN packet byte layout (wire format used by comms_can_{read,write}): + +--------+--------+--------+--------+--------+--------+--------+------------------------------+ + | byte 0 | byte 1 | byte 2 | byte 3 | byte 4 | byte 5 | byte 6 | ... byte 13 / byte 69 | + +--------+--------+--------+--------+--------+--------+--------+------------------------------+ + | DLC | addr | addr | addr | flags | cksum | data0 | ... data7 / data63 | + | bus | | | | | | | (classic CAN / CAN FD) | + | fd | | | | | | | | + +--------+--------+--------+--------+--------+--------+--------+------------------------------+ + Byte/bit fields: + byte 0: DLC[7:4], bus[3:1], fd[0] + bytes 1..4: (addr << 3) | (extended << 2) | (returned << 1) | rejected + byte 5: checksum = XOR(header[0..4] + payload) + bytes 6..13 (classic CAN, up to 8 bytes) / bytes 6..69 (CAN FD, up to 64 bytes): payload + + USB/SPI transfer chunking used by this file: + +--------------------------------------------+ ... +--------------------------------------------+ + | transport chunk 0 | | transport chunk N | + +--------------------------------------------+ +--------------------------------------------+ + | concatenated CANPacket_t bytes | | continuation and/or next CANPacket_t bytes | + | (no per-64-byte counter/header in protocol)| | | + +--------------------------------------------+ +--------------------------------------------+ + + * comms_can_read outputs this buffer in chunks of a specified length. + chunks are always the given length, except the last one. + * comms_can_write reads in this buffer in chunks. + * both functions maintain an overflow buffer for a partial CANPacket_t that + spans multiple transfers/chunks. + * the overflow buffers are reset by a dedicated control transfer handler, + which is sent by the host on each start of a connection. +*/ + +#include +#include + +#include "opendbc/safety/can.h" + +#include "board/can.h" +#include "board/can_comms.h" +#include "board/comms_constants.h" +#include "board/drivers/can_common_declarations.h" + +void *memcpy(void *dest, const void *src, unsigned int len); + +void can_tx_comms_resume_usb(void); +void can_tx_comms_resume_spi(void); + +typedef struct { + uint32_t ptr; + uint32_t tail_size; + uint8_t data[sizeof(CANPacket_t)]; +} asm_buffer; + +static uint32_t min_u32(uint32_t a, uint32_t b) { + return (a < b) ? a : b; +} + +static asm_buffer can_read_buffer = {.ptr = 0U, .tail_size = 0U}; + +int comms_can_read(uint8_t *data, uint32_t max_len) { + uint32_t pos = 0U; + + // Send tail of previous message if it is in buffer + if (can_read_buffer.ptr > 0U) { + uint32_t overflow_len = min_u32(max_len - pos, can_read_buffer.ptr); + (void)memcpy(&data[pos], can_read_buffer.data, overflow_len); + pos += overflow_len; + (void)memcpy(can_read_buffer.data, &can_read_buffer.data[overflow_len], can_read_buffer.ptr - overflow_len); + can_read_buffer.ptr -= overflow_len; + } + + if (can_read_buffer.ptr == 0U) { + // Fill rest of buffer with new data + CANPacket_t can_packet; + while ((pos < max_len) && can_pop(&can_rx_q, &can_packet)) { + uint32_t pckt_len = CANPACKET_HEAD_SIZE + dlc_to_len[can_packet.data_len_code]; + if ((pos + pckt_len) <= max_len) { + (void)memcpy(&data[pos], (uint8_t*)&can_packet, pckt_len); + pos += pckt_len; + } else { + (void)memcpy(&data[pos], (uint8_t*)&can_packet, max_len - pos); + can_read_buffer.ptr += pckt_len - (max_len - pos); + // cppcheck-suppress objectIndex + (void)memcpy(can_read_buffer.data, &((uint8_t*)&can_packet)[(max_len - pos)], can_read_buffer.ptr); + pos = max_len; + } + } + } + + return pos; +} + +static asm_buffer can_write_buffer = {.ptr = 0U, .tail_size = 0U}; + +// send on CAN +void comms_can_write(const uint8_t *data, uint32_t len) { + uint32_t pos = 0U; + + // Assembling can message with data from buffer + if (can_write_buffer.ptr != 0U) { + if (can_write_buffer.tail_size <= (len - pos)) { + // we have enough data to complete the buffer + CANPacket_t to_push = {0}; + (void)memcpy(&can_write_buffer.data[can_write_buffer.ptr], &data[pos], can_write_buffer.tail_size); + can_write_buffer.ptr += can_write_buffer.tail_size; + pos += can_write_buffer.tail_size; + + // send out + (void)memcpy((uint8_t*)&to_push, can_write_buffer.data, can_write_buffer.ptr); + can_send(&to_push, to_push.bus, false); + + // reset overflow buffer + can_write_buffer.ptr = 0U; + can_write_buffer.tail_size = 0U; + } else { + // maybe next time + uint32_t data_size = len - pos; + (void) memcpy(&can_write_buffer.data[can_write_buffer.ptr], &data[pos], data_size); + can_write_buffer.tail_size -= data_size; + can_write_buffer.ptr += data_size; + pos += data_size; + } + } + + // rest of the message + while (pos < len) { + uint32_t pckt_len = CANPACKET_HEAD_SIZE + dlc_to_len[(data[pos] >> 4U)]; + if ((pos + pckt_len) <= len) { + CANPacket_t to_push = {0}; + (void)memcpy((uint8_t*)&to_push, &data[pos], pckt_len); + can_send(&to_push, to_push.bus, false); + pos += pckt_len; + } else { + (void)memcpy(can_write_buffer.data, &data[pos], len - pos); + can_write_buffer.ptr = len - pos; + can_write_buffer.tail_size = pckt_len - can_write_buffer.ptr; + pos += can_write_buffer.ptr; + } + } + + refresh_can_tx_slots_available(); +} + +void comms_can_reset(void) { + can_write_buffer.ptr = 0U; + can_write_buffer.tail_size = 0U; + can_read_buffer.ptr = 0U; + can_read_buffer.tail_size = 0U; +} + +// TODO: make this more general! +void refresh_can_tx_slots_available(void) { + if (can_tx_check_min_slots_free(MAX_CAN_MSGS_PER_USB_BULK_TRANSFER)) { + can_tx_comms_resume_usb(); + } + if (can_tx_check_min_slots_free(MAX_CAN_MSGS_PER_SPI_BULK_TRANSFER)) { + can_tx_comms_resume_spi(); + } +} diff --git a/board/can_comms.h b/board/can_comms.h index f79c8ba4e46..6312a4e8baa 100644 --- a/board/can_comms.h +++ b/board/can_comms.h @@ -1,144 +1,8 @@ -/* - CAN transactions to and from the host come in the form of - a certain number of CANPacket_t. The transaction is split - into multiple transfers or chunks. +#pragma once - CAN packet byte layout (wire format used by comms_can_{read,write}): - +--------+--------+--------+--------+--------+--------+--------+------------------------------+ - | byte 0 | byte 1 | byte 2 | byte 3 | byte 4 | byte 5 | byte 6 | ... byte 13 / byte 69 | - +--------+--------+--------+--------+--------+--------+--------+------------------------------+ - | DLC | addr | addr | addr | flags | cksum | data0 | ... data7 / data63 | - | bus | | | | | | | (classic CAN / CAN FD) | - | fd | | | | | | | | - +--------+--------+--------+--------+--------+--------+--------+------------------------------+ - Byte/bit fields: - byte 0: DLC[7:4], bus[3:1], fd[0] - bytes 1..4: (addr << 3) | (extended << 2) | (returned << 1) | rejected - byte 5: checksum = XOR(header[0..4] + payload) - bytes 6..13 (classic CAN, up to 8 bytes) / bytes 6..69 (CAN FD, up to 64 bytes): payload +#include - USB/SPI transfer chunking used by this file: - +--------------------------------------------+ ... +--------------------------------------------+ - | transport chunk 0 | | transport chunk N | - +--------------------------------------------+ +--------------------------------------------+ - | concatenated CANPacket_t bytes | | continuation and/or next CANPacket_t bytes | - | (no per-64-byte counter/header in protocol)| | | - +--------------------------------------------+ +--------------------------------------------+ - - * comms_can_read outputs this buffer in chunks of a specified length. - chunks are always the given length, except the last one. - * comms_can_write reads in this buffer in chunks. - * both functions maintain an overflow buffer for a partial CANPacket_t that - spans multiple transfers/chunks. - * the overflow buffers are reset by a dedicated control transfer handler, - which is sent by the host on each start of a connection. -*/ - -typedef struct { - uint32_t ptr; - uint32_t tail_size; - uint8_t data[72]; -} asm_buffer; - -static asm_buffer can_read_buffer = {.ptr = 0U, .tail_size = 0U}; - -int comms_can_read(uint8_t *data, uint32_t max_len) { - uint32_t pos = 0U; - - // Send tail of previous message if it is in buffer - if (can_read_buffer.ptr > 0U) { - uint32_t overflow_len = MIN(max_len - pos, can_read_buffer.ptr); - (void)memcpy(&data[pos], can_read_buffer.data, overflow_len); - pos += overflow_len; - (void)memcpy(can_read_buffer.data, &can_read_buffer.data[overflow_len], can_read_buffer.ptr - overflow_len); - can_read_buffer.ptr -= overflow_len; - } - - if (can_read_buffer.ptr == 0U) { - // Fill rest of buffer with new data - CANPacket_t can_packet; - while ((pos < max_len) && can_pop(&can_rx_q, &can_packet)) { - uint32_t pckt_len = CANPACKET_HEAD_SIZE + dlc_to_len[can_packet.data_len_code]; - if ((pos + pckt_len) <= max_len) { - (void)memcpy(&data[pos], (uint8_t*)&can_packet, pckt_len); - pos += pckt_len; - } else { - (void)memcpy(&data[pos], (uint8_t*)&can_packet, max_len - pos); - can_read_buffer.ptr += pckt_len - (max_len - pos); - // cppcheck-suppress objectIndex - (void)memcpy(can_read_buffer.data, &((uint8_t*)&can_packet)[(max_len - pos)], can_read_buffer.ptr); - pos = max_len; - } - } - } - - return pos; -} - -static asm_buffer can_write_buffer = {.ptr = 0U, .tail_size = 0U}; - -// send on CAN -void comms_can_write(const uint8_t *data, uint32_t len) { - uint32_t pos = 0U; - - // Assembling can message with data from buffer - if (can_write_buffer.ptr != 0U) { - if (can_write_buffer.tail_size <= (len - pos)) { - // we have enough data to complete the buffer - CANPacket_t to_push = {0}; - (void)memcpy(&can_write_buffer.data[can_write_buffer.ptr], &data[pos], can_write_buffer.tail_size); - can_write_buffer.ptr += can_write_buffer.tail_size; - pos += can_write_buffer.tail_size; - - // send out - (void)memcpy((uint8_t*)&to_push, can_write_buffer.data, can_write_buffer.ptr); - can_send(&to_push, to_push.bus, false); - - // reset overflow buffer - can_write_buffer.ptr = 0U; - can_write_buffer.tail_size = 0U; - } else { - // maybe next time - uint32_t data_size = len - pos; - (void) memcpy(&can_write_buffer.data[can_write_buffer.ptr], &data[pos], data_size); - can_write_buffer.tail_size -= data_size; - can_write_buffer.ptr += data_size; - pos += data_size; - } - } - - // rest of the message - while (pos < len) { - uint32_t pckt_len = CANPACKET_HEAD_SIZE + dlc_to_len[(data[pos] >> 4U)]; - if ((pos + pckt_len) <= len) { - CANPacket_t to_push = {0}; - (void)memcpy((uint8_t*)&to_push, &data[pos], pckt_len); - can_send(&to_push, to_push.bus, false); - pos += pckt_len; - } else { - (void)memcpy(can_write_buffer.data, &data[pos], len - pos); - can_write_buffer.ptr = len - pos; - can_write_buffer.tail_size = pckt_len - can_write_buffer.ptr; - pos += can_write_buffer.ptr; - } - } - - refresh_can_tx_slots_available(); -} - -void comms_can_reset(void) { - can_write_buffer.ptr = 0U; - can_write_buffer.tail_size = 0U; - can_read_buffer.ptr = 0U; - can_read_buffer.tail_size = 0U; -} - -// TODO: make this more general! -void refresh_can_tx_slots_available(void) { - if (can_tx_check_min_slots_free(MAX_CAN_MSGS_PER_USB_BULK_TRANSFER)) { - can_tx_comms_resume_usb(); - } - if (can_tx_check_min_slots_free(MAX_CAN_MSGS_PER_SPI_BULK_TRANSFER)) { - can_tx_comms_resume_spi(); - } -} +int comms_can_read(uint8_t *data, uint32_t max_len); +void comms_can_write(const uint8_t *data, uint32_t len); +void comms_can_reset(void); +void refresh_can_tx_slots_available(void); diff --git a/board/comms_constants.h b/board/comms_constants.h new file mode 100644 index 00000000000..ec6e3271567 --- /dev/null +++ b/board/comms_constants.h @@ -0,0 +1,4 @@ +#pragma once + +#define MAX_CAN_MSGS_PER_USB_BULK_TRANSFER 51U +#define MAX_CAN_MSGS_PER_SPI_BULK_TRANSFER 170U diff --git a/board/config.h b/board/config.h index 1b7d938cc81..301734cf1d5 100644 --- a/board/config.h +++ b/board/config.h @@ -12,8 +12,7 @@ #define CAN_INIT_TIMEOUT_MS 500U #define USBPACKET_MAX_SIZE 0x40U -#define MAX_CAN_MSGS_PER_USB_BULK_TRANSFER 51U -#define MAX_CAN_MSGS_PER_SPI_BULK_TRANSFER 170U +#include "board/comms_constants.h" // USB definitions #define USB_VID 0x3801U diff --git a/board/drivers/can_common_declarations.h b/board/drivers/can_common_declarations.h new file mode 100644 index 00000000000..43d14758928 --- /dev/null +++ b/board/drivers/can_common_declarations.h @@ -0,0 +1,43 @@ +#pragma once + +#include +#include + +#include "board/can.h" + +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; + int8_t forwarding_bus; + 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 can_ring can_rx_q; +extern can_ring can_tx1_q; +extern can_ring can_tx2_q; +extern can_ring can_tx3_q; +extern can_ring *can_queues[PANDA_CAN_CNT]; +extern bus_config_t bus_config[PANDA_CAN_CNT]; + +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); +void can_clear(can_ring *q); +bool can_tx_check_min_slots_free(uint32_t min); +uint8_t calculate_checksum(const uint8_t *dat, uint32_t len); +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); diff --git a/board/drivers/drivers.h b/board/drivers/drivers.h index 91af64d76d0..92ccc33452e 100644 --- a/board/drivers/drivers.h +++ b/board/drivers/drivers.h @@ -15,24 +15,7 @@ void bootkick_tick(bool ignition, bool recent_heartbeat); // ******************** 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; - int8_t forwarding_bus; - 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; +#include "board/drivers/can_common_declarations.h" extern uint32_t safety_tx_blocked; extern uint32_t safety_rx_invalid; @@ -52,19 +35,10 @@ extern bool can_loopback; 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) @@ -74,12 +48,6 @@ void can_set_orientation(bool flipped); #ifdef PANDA_JUNGLE void can_set_forwarding(uint8_t from, uint8_t to); #endif -bool can_tx_check_min_slots_free(uint32_t min); -uint8_t calculate_checksum(const uint8_t *dat, uint32_t len); -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 ******************** diff --git a/board/main_definitions.h b/board/main_definitions.h index 83c91090579..eaa12c6806a 100644 --- a/board/main_definitions.h +++ b/board/main_definitions.h @@ -1,14 +1,3 @@ -#include "main_declarations.h" +#pragma once -// ********************* Globals ********************** -uint8_t hw_type = 0; -board *current_board; -uint32_t uptime_cnt = 0; - -// heartbeat state -uint32_t heartbeat_counter = 0; -bool heartbeat_lost = false; -bool heartbeat_disabled = false; // set over USB - -// siren state -bool siren_enabled = false; +#include "board/main_declarations.h" diff --git a/board/main_state.c b/board/main_state.c new file mode 100644 index 00000000000..5b81478c411 --- /dev/null +++ b/board/main_state.c @@ -0,0 +1,23 @@ +#include +#include + +#ifdef STM32H7 +#include "stm32h7xx.h" +#else +typedef struct TIM_TypeDef TIM_TypeDef; +#endif + +#include "board/main_declarations.h" + +// ********************* Globals ********************** +uint8_t hw_type = 0; +board *current_board; +uint32_t uptime_cnt = 0; + +// heartbeat state +uint32_t heartbeat_counter = 0; +bool heartbeat_lost = false; +bool heartbeat_disabled = false; // set over USB + +// siren state +bool siren_enabled = false; diff --git a/tests/libpanda/SConscript b/tests/libpanda/SConscript index 1b82b0e450f..85884135fe7 100644 --- a/tests/libpanda/SConscript +++ b/tests/libpanda/SConscript @@ -12,4 +12,6 @@ env = Environment( ) panda = env.SharedObject("panda.os", "panda.c") -libpanda = env.SharedLibrary("libpanda.so", [panda]) +main_state = env.SharedObject("main_state.os", "../../board/main_state.c") +can_comms = env.SharedObject("can_comms.os", "../../board/can_comms.c") +libpanda = env.SharedLibrary("libpanda.so", [panda, main_state, can_comms]) From 79d34122a5a3a1a55bbbfd39dd1400bcd2fa61d4 Mon Sep 17 00:00:00 2001 From: Yuze Pan Date: Thu, 21 May 2026 09:10:06 +0800 Subject: [PATCH 2/3] Avoid driver declaration churn in CAN comms split --- board/can_comms.c | 13 +++++++- board/drivers/can_common_declarations.h | 43 ------------------------- board/drivers/drivers.h | 34 ++++++++++++++++++- 3 files changed, 45 insertions(+), 45 deletions(-) delete mode 100644 board/drivers/can_common_declarations.h diff --git a/board/can_comms.c b/board/can_comms.c index 724e6ed63b3..b42814b8f9f 100644 --- a/board/can_comms.c +++ b/board/can_comms.c @@ -42,10 +42,21 @@ #include "board/can.h" #include "board/can_comms.h" #include "board/comms_constants.h" -#include "board/drivers/can_common_declarations.h" void *memcpy(void *dest, const void *src, unsigned int len); +typedef struct { + volatile uint32_t w_ptr; + volatile uint32_t r_ptr; + uint32_t fifo_size; + CANPacket_t *elems; +} can_ring; + +extern can_ring can_rx_q; + +bool can_pop(can_ring *q, CANPacket_t *elem); +void can_send(CANPacket_t *to_push, uint8_t bus_number, bool skip_tx_hook); +bool can_tx_check_min_slots_free(uint32_t min); void can_tx_comms_resume_usb(void); void can_tx_comms_resume_spi(void); diff --git a/board/drivers/can_common_declarations.h b/board/drivers/can_common_declarations.h deleted file mode 100644 index 43d14758928..00000000000 --- a/board/drivers/can_common_declarations.h +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -#include -#include - -#include "board/can.h" - -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; - int8_t forwarding_bus; - 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 can_ring can_rx_q; -extern can_ring can_tx1_q; -extern can_ring can_tx2_q; -extern can_ring can_tx3_q; -extern can_ring *can_queues[PANDA_CAN_CNT]; -extern bus_config_t bus_config[PANDA_CAN_CNT]; - -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); -void can_clear(can_ring *q); -bool can_tx_check_min_slots_free(uint32_t min); -uint8_t calculate_checksum(const uint8_t *dat, uint32_t len); -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); diff --git a/board/drivers/drivers.h b/board/drivers/drivers.h index 92ccc33452e..91af64d76d0 100644 --- a/board/drivers/drivers.h +++ b/board/drivers/drivers.h @@ -15,7 +15,24 @@ void bootkick_tick(bool ignition, bool recent_heartbeat); // ******************** can_common ******************** -#include "board/drivers/can_common_declarations.h" +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; + int8_t forwarding_bus; + 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; @@ -35,10 +52,19 @@ extern bool can_loopback; 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) @@ -48,6 +74,12 @@ void can_set_orientation(bool flipped); #ifdef PANDA_JUNGLE void can_set_forwarding(uint8_t from, uint8_t to); #endif +bool can_tx_check_min_slots_free(uint32_t min); +uint8_t calculate_checksum(const uint8_t *dat, uint32_t len); +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 ******************** From 773e21474e057fbe1e3b89b4bfcbf1c40fd48c01 Mon Sep 17 00:00:00 2001 From: Yuze Pan Date: Thu, 21 May 2026 09:12:36 +0800 Subject: [PATCH 3/3] Suppress MISRA for cross-unit CAN comms hooks --- board/drivers/can_common.h | 1 + board/drivers/spi.h | 1 + board/drivers/usb.h | 1 + 3 files changed, 3 insertions(+) diff --git a/board/drivers/can_common.h b/board/drivers/can_common.h index 6237c7aebe9..03aad340b4d 100644 --- a/board/drivers/can_common.h +++ b/board/drivers/can_common.h @@ -152,6 +152,7 @@ void can_set_forwarding(uint8_t from, uint8_t to) { } #endif +// cppcheck-suppress misra-c2012-8.7 ; used from can_comms.c bool can_tx_check_min_slots_free(uint32_t min) { return (can_slots_empty(&can_tx1_q) >= min) && diff --git a/board/drivers/spi.h b/board/drivers/spi.h index 283d845e0ac..237e72e0b88 100644 --- a/board/drivers/spi.h +++ b/board/drivers/spi.h @@ -253,6 +253,7 @@ void spi_tx_done(bool reset) { } } +// cppcheck-suppress misra-c2012-8.7 ; used from can_comms.c void can_tx_comms_resume_spi(void) { spi_can_tx_ready = true; } diff --git a/board/drivers/usb.h b/board/drivers/usb.h index 47c91c993b9..699b8e4b2c1 100644 --- a/board/drivers/usb.h +++ b/board/drivers/usb.h @@ -868,6 +868,7 @@ void usb_irqhandler(void) { //USBx->GINTMSK = 0xFFFFFFFF & ~(USB_OTG_GINTMSK_NPTXFEM | USB_OTG_GINTMSK_PTXFEM | USB_OTG_GINTSTS_SOF | USB_OTG_GINTSTS_EOPF); } +// cppcheck-suppress misra-c2012-8.7 ; used from can_comms.c void can_tx_comms_resume_usb(void) { ENTER_CRITICAL(); if (!outep3_processing && (USBx_OUTEP(3U)->DOEPCTL & USB_OTG_DOEPCTL_NAKSTS) != 0U) {