openpilot is an open source driver assistance system. openpilot performs the functions of Automated Lane Centering and Adaptive Cruise Control for over 200 supported car makes and models.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

264 lines
8.0 KiB

#include "can_common_declarations.h"
uint32_t safety_tx_blocked = 0;
uint32_t safety_rx_invalid = 0;
uint32_t tx_buffer_overflow = 0;
uint32_t rx_buffer_overflow = 0;
can_health_t can_health[CAN_HEALTH_ARRAY_SIZE] = {{0}, {0}, {0}};
// Ignition detected from CAN meessages
bool ignition_can = false;
uint32_t ignition_can_cnt = 0U;
int can_live = 0;
int pending_can_live = 0;
int can_silent = ALL_CAN_SILENT;
bool can_loopback = false;
// ********************* instantiate queues *********************
#define can_buffer(x, size) \
static CANPacket_t elems_##x[size]; \
extern can_ring can_##x; \
can_ring can_##x = { .w_ptr = 0, .r_ptr = 0, .fifo_size = (size), .elems = (CANPacket_t *)&(elems_##x) };
#define CAN_RX_BUFFER_SIZE 4096U
#define CAN_TX_BUFFER_SIZE 416U
#ifdef STM32H7
// ITCM RAM and DTCM RAM are the fastest for Cortex-M7 core access
__attribute__((section(".axisram"))) can_buffer(rx_q, CAN_RX_BUFFER_SIZE)
__attribute__((section(".itcmram"))) can_buffer(tx1_q, CAN_TX_BUFFER_SIZE)
__attribute__((section(".itcmram"))) can_buffer(tx2_q, CAN_TX_BUFFER_SIZE)
#else
can_buffer(rx_q, CAN_RX_BUFFER_SIZE)
can_buffer(tx1_q, CAN_TX_BUFFER_SIZE)
can_buffer(tx2_q, CAN_TX_BUFFER_SIZE)
#endif
can_buffer(tx3_q, CAN_TX_BUFFER_SIZE)
// FIXME:
// cppcheck-suppress misra-c2012-9.3
can_ring *can_queues[CAN_QUEUES_ARRAY_SIZE] = {&can_tx1_q, &can_tx2_q, &can_tx3_q};
// ********************* interrupt safe queue *********************
bool can_pop(can_ring *q, CANPacket_t *elem) {
bool ret = 0;
ENTER_CRITICAL();
if (q->w_ptr != q->r_ptr) {
*elem = q->elems[q->r_ptr];
if ((q->r_ptr + 1U) == q->fifo_size) {
q->r_ptr = 0;
} else {
q->r_ptr += 1U;
}
ret = 1;
}
EXIT_CRITICAL();
return ret;
}
bool can_push(can_ring *q, const CANPacket_t *elem) {
bool ret = false;
uint32_t next_w_ptr;
ENTER_CRITICAL();
if ((q->w_ptr + 1U) == q->fifo_size) {
next_w_ptr = 0;
} else {
next_w_ptr = q->w_ptr + 1U;
}
if (next_w_ptr != q->r_ptr) {
q->elems[q->w_ptr] = *elem;
q->w_ptr = next_w_ptr;
ret = true;
}
EXIT_CRITICAL();
if (!ret) {
#ifdef DEBUG
print("can_push to ");
if (q == &can_rx_q) {
print("can_rx_q");
} else if (q == &can_tx1_q) {
print("can_tx1_q");
} else if (q == &can_tx2_q) {
print("can_tx2_q");
} else if (q == &can_tx3_q) {
print("can_tx3_q");
} else {
print("unknown");
}
print(" failed!\n");
#endif
}
return ret;
}
uint32_t can_slots_empty(const can_ring *q) {
uint32_t ret = 0;
ENTER_CRITICAL();
if (q->w_ptr >= q->r_ptr) {
ret = q->fifo_size - 1U - q->w_ptr + q->r_ptr;
} else {
ret = q->r_ptr - q->w_ptr - 1U;
}
EXIT_CRITICAL();
return ret;
}
void can_clear(can_ring *q) {
ENTER_CRITICAL();
q->w_ptr = 0;
q->r_ptr = 0;
EXIT_CRITICAL();
// handle TX buffer full with zero ECUs awake on the bus
refresh_can_tx_slots_available();
}
// assign CAN numbering
// bus num: CAN Bus numbers in panda, sent to/from USB
// Min: 0; Max: 127; Bit 7 marks message as receipt (bus 129 is receipt for but 1)
// cans: Look up MCU can interface from bus number
// can number: numeric lookup for MCU CAN interfaces (0 = CAN1, 1 = CAN2, etc);
// bus_lookup: Translates from 'can number' to 'bus number'.
// can_num_lookup: Translates from 'bus number' to 'can number'.
// forwarding bus: If >= 0, forward all messages from this bus to the specified bus.
// Helpers
// Panda: Bus 0=CAN1 Bus 1=CAN2 Bus 2=CAN3
bus_config_t bus_config[BUS_CONFIG_ARRAY_SIZE] = {
{ .bus_lookup = 0U, .can_num_lookup = 0U, .forwarding_bus = -1, .can_speed = 5000U, .can_data_speed = 20000U, .canfd_auto = false, .canfd_enabled = false, .brs_enabled = false, .canfd_non_iso = false },
{ .bus_lookup = 1U, .can_num_lookup = 1U, .forwarding_bus = -1, .can_speed = 5000U, .can_data_speed = 20000U, .canfd_auto = false, .canfd_enabled = false, .brs_enabled = false, .canfd_non_iso = false },
{ .bus_lookup = 2U, .can_num_lookup = 2U, .forwarding_bus = -1, .can_speed = 5000U, .can_data_speed = 20000U, .canfd_auto = false, .canfd_enabled = false, .brs_enabled = false, .canfd_non_iso = false },
{ .bus_lookup = 0xFFU, .can_num_lookup = 0xFFU, .forwarding_bus = -1, .can_speed = 333U, .can_data_speed = 333U, .canfd_auto = false, .canfd_enabled = false, .brs_enabled = false, .canfd_non_iso = false },
};
void can_init_all(void) {
for (uint8_t i=0U; i < PANDA_CAN_CNT; i++) {
if (!current_board->has_canfd) {
bus_config[i].can_data_speed = 0U;
}
can_clear(can_queues[i]);
(void)can_init(i);
}
}
void can_set_orientation(bool flipped) {
bus_config[0].bus_lookup = flipped ? 2U : 0U;
bus_config[0].can_num_lookup = flipped ? 2U : 0U;
bus_config[2].bus_lookup = flipped ? 0U : 2U;
bus_config[2].can_num_lookup = flipped ? 0U : 2U;
}
#ifdef PANDA_JUNGLE
void can_set_forwarding(uint8_t from, uint8_t to) {
bus_config[from].forwarding_bus = to;
}
#endif
void ignition_can_hook(CANPacket_t *to_push) {
int bus = GET_BUS(to_push);
if (bus == 0) {
int addr = GET_ADDR(to_push);
int len = GET_LEN(to_push);
// GM exception
if ((addr == 0x1F1) && (len == 8)) {
// SystemPowerMode (2=Run, 3=Crank Request)
ignition_can = (GET_BYTE(to_push, 0) & 0x2U) != 0U;
ignition_can_cnt = 0U;
}
// Rivian R1S/T GEN1 exception
if ((addr == 0x152) && (len == 8)) {
// 0x152 overlaps with Subaru pre-global which has this bit as the high beam
int counter = GET_BYTE(to_push, 1) & 0xFU; // max is only 14
static int prev_counter_rivian = -1;
if ((counter == ((prev_counter_rivian + 1) % 15)) && (prev_counter_rivian != -1)) {
// VDM_OutputSignals->VDM_EpasPowerMode
ignition_can = ((GET_BYTE(to_push, 7) >> 4U) & 0x3U) == 1U; // VDM_EpasPowerMode_Drive_On=1
ignition_can_cnt = 0U;
}
prev_counter_rivian = counter;
}
// Tesla Model 3/Y exception
if ((addr == 0x221) && (len == 8)) {
// 0x221 overlaps with Rivian which has random data on byte 0
int counter = GET_BYTE(to_push, 6) >> 4;
static int prev_counter_tesla = -1;
if ((counter == ((prev_counter_tesla + 1) % 16)) && (prev_counter_tesla != -1)) {
// VCFRONT_LVPowerState->VCFRONT_vehiclePowerState
int power_state = (GET_BYTE(to_push, 0) >> 5U) & 0x3U;
ignition_can = power_state == 0x3; // VEHICLE_POWER_STATE_DRIVE=3
ignition_can_cnt = 0U;
}
prev_counter_tesla = counter;
}
// Mazda exception
if ((addr == 0x9E) && (len == 8)) {
ignition_can = (GET_BYTE(to_push, 0) >> 5) == 0x6U;
ignition_can_cnt = 0U;
}
}
}
bool can_tx_check_min_slots_free(uint32_t min) {
return
(can_slots_empty(&can_tx1_q) >= min) &&
(can_slots_empty(&can_tx2_q) >= min) &&
(can_slots_empty(&can_tx3_q) >= min);
}
uint8_t calculate_checksum(const uint8_t *dat, uint32_t len) {
uint8_t checksum = 0U;
for (uint32_t i = 0U; i < len; i++) {
checksum ^= dat[i];
}
return checksum;
}
void can_set_checksum(CANPacket_t *packet) {
packet->checksum = 0U;
packet->checksum = calculate_checksum((uint8_t *) packet, CANPACKET_HEAD_SIZE + GET_LEN(packet));
}
bool can_check_checksum(CANPacket_t *packet) {
return (calculate_checksum((uint8_t *) packet, CANPACKET_HEAD_SIZE + GET_LEN(packet)) == 0U);
}
void can_send(CANPacket_t *to_push, uint8_t bus_number, bool skip_tx_hook) {
if (skip_tx_hook || safety_tx_hook(to_push) != 0) {
if (bus_number < PANDA_BUS_CNT) {
// add CAN packet to send queue
tx_buffer_overflow += can_push(can_queues[bus_number], to_push) ? 0U : 1U;
process_can(CAN_NUM_FROM_BUS_NUM(bus_number));
}
} else {
safety_tx_blocked += 1U;
to_push->returned = 0U;
to_push->rejected = 1U;
// data changed
can_set_checksum(to_push);
rx_buffer_overflow += can_push(&can_rx_q, to_push) ? 0U : 1U;
}
}
bool is_speed_valid(uint32_t speed, const uint32_t *all_speeds, uint8_t len) {
bool ret = false;
for (uint8_t i = 0U; i < len; i++) {
if (all_speeds[i] == speed) {
ret = true;
}
}
return ret;
}