#include "bsp_can.h" #include "FreeRTOS.h" #include "bsp.h" #include "bsp_uart.h" #include "main.h" #include "semphr.h" typedef struct { CAN_RxHeaderTypeDef header; uint8_t data[8]; } can_raw_rx_t; typedef struct { CAN_TxHeaderTypeDef header; uint8_t data[8]; } can_raw_tx_t; typedef struct { void (*fn)(bsp_can_t can, uint32_t id, uint8_t *data, void *arg); void *arg; } can_callback_t; typedef struct __attribute__((packed)) { uint8_t start_frame; uint32_t id : 31; uint8_t type : 1; uint8_t data[8]; // NOLINT(modernize-avoid-c-arrays) uint8_t end_frame; } CanUartPack; enum UART_PACK_FRAME { START = 0xa5, END = 0Xe3 }; extern CAN_HandleTypeDef hcan1; extern CAN_HandleTypeDef hcan2; static uint8_t *uart_recv_buff_addr[BSP_CAN_EXT_NUM]; static uint8_t uart_recv_buff[BSP_CAN_EXT_NUM][2][2 * sizeof(CanUartPack)]; static can_callback_t callback_list[BSP_CAN_NUM][BSP_CAN_CB_NUM]; static bool bsp_can_initd = false; static uint32_t mailbox[BSP_CAN_BASE_NUM]; static can_raw_rx_t rx_buff[BSP_CAN_BASE_NUM]; static CAN_TxHeaderTypeDef tx_buff[BSP_CAN_BASE_NUM]; static CanUartPack tx_ext_buff[BSP_CAN_EXT_NUM]; static SemaphoreHandle_t tx_cplt[BSP_CAN_EXT_NUM]; static SemaphoreHandle_t rx_cplt_wait_sem[BSP_CAN_BASE_NUM]; CAN_HandleTypeDef *bsp_can_get_handle(bsp_can_t can) { switch (can) { case BSP_CAN_2: return &hcan2; case BSP_CAN_1: return &hcan1; default: return NULL; } } bsp_uart_t bsp_ext_can_get_handle(bsp_can_t can) { switch (can) { case BSP_CAN_3: return BSP_UART_CAN3; case BSP_CAN_4: return BSP_UART_CAN4; default: return BSP_UART_ERR; } } static bsp_can_t can_get(CAN_HandleTypeDef *hcan) { if (hcan->Instance == CAN2) { return BSP_CAN_2; } else if (hcan->Instance == CAN1) { return BSP_CAN_1; } else { return BSP_CAN_ERR; } } void HAL_CAN_TxMailbox0CompleteCallback(CAN_HandleTypeDef *hcan) { BaseType_t px_higher_priority_task_woken = 0; xSemaphoreGiveFromISR(rx_cplt_wait_sem[can_get(hcan)], &px_higher_priority_task_woken); if (px_higher_priority_task_woken != pdFALSE) { portYIELD(); } } void HAL_CAN_TxMailbox1CompleteCallback(CAN_HandleTypeDef *hcan) { BaseType_t px_higher_priority_task_woken = 0; xSemaphoreGiveFromISR(rx_cplt_wait_sem[can_get(hcan)], &px_higher_priority_task_woken); if (px_higher_priority_task_woken != pdFALSE) { portYIELD(); } } void HAL_CAN_TxMailbox2CompleteCallback(CAN_HandleTypeDef *hcan) { BaseType_t px_higher_priority_task_woken = 0; xSemaphoreGiveFromISR(rx_cplt_wait_sem[can_get(hcan)], &px_higher_priority_task_woken); if (px_higher_priority_task_woken != pdFALSE) { portYIELD(); } } void HAL_CAN_ErrorCallback(CAN_HandleTypeDef *hcan) { HAL_CAN_ResetError(hcan); BaseType_t px_higher_priority_task_woken = 0; xSemaphoreGiveFromISR(rx_cplt_wait_sem[can_get(hcan)], &px_higher_priority_task_woken); if (px_higher_priority_task_woken != pdFALSE) { portYIELD(); } } static void tx_cplt_callback(void *arg) { SemaphoreHandle_t *sem = (SemaphoreHandle_t *)arg; BaseType_t px_higher_priority_task_woken = 0; xSemaphoreGiveFromISR(sem, &px_higher_priority_task_woken); portYIELD_FROM_ISR(px_higher_priority_task_woken); } static void rx_callback_fn(void *arg) { bsp_can_t can = (uint8_t **)(arg)-uart_recv_buff_addr + BSP_CAN_BASE_NUM; int32_t index = 0; uint8_t *data = *(uint8_t **)(arg); uint32_t len = bsp_uart_get_count(bsp_ext_can_get_handle(can)); if (uart_recv_buff_addr[can - BSP_CAN_BASE_NUM] == uart_recv_buff[can - BSP_CAN_BASE_NUM][0]) { uart_recv_buff_addr[can - BSP_CAN_BASE_NUM] = uart_recv_buff[can - BSP_CAN_BASE_NUM][1]; } else { uart_recv_buff_addr[can - BSP_CAN_BASE_NUM] = uart_recv_buff[can - BSP_CAN_BASE_NUM][0]; } bsp_uart_abort_receive(bsp_ext_can_get_handle(can)); bsp_uart_receive(bsp_ext_can_get_handle(can), uart_recv_buff_addr[can - BSP_CAN_BASE_NUM], sizeof(CanUartPack), false); while (index <= (int32_t)(len) - (int32_t)(sizeof(CanUartPack))) { CanUartPack *pack = (CanUartPack *)(data + index); if (pack->start_frame != START || pack->end_frame != END) { index++; continue; } else { callback_list[can][CAN_RX_MSG_CALLBACK].fn( can, pack->id, pack->data, callback_list[can][CAN_RX_MSG_CALLBACK].arg); index += sizeof(CanUartPack); } } }; void bsp_can_init(void) { for (int i = 0; i < BSP_CAN_BASE_NUM; i++) { rx_cplt_wait_sem[i] = xSemaphoreCreateBinary(); } CAN_FilterTypeDef can_filter = {0}; can_filter.FilterBank = 0; can_filter.FilterIdHigh = 0; can_filter.FilterIdLow = 0; can_filter.FilterMode = CAN_FILTERMODE_IDMASK; can_filter.FilterScale = CAN_FILTERSCALE_32BIT; can_filter.FilterMaskIdHigh = 0; can_filter.FilterMaskIdLow = 0; can_filter.FilterActivation = ENABLE; can_filter.SlaveStartFilterBank = 14; can_filter.FilterFIFOAssignment = CAN_FILTER_FIFO0; for (int i = 0; i < BSP_CAN_EXT_NUM; i++) { tx_cplt[i] = xSemaphoreCreateBinary(); xSemaphoreGive(tx_cplt[i]); uart_recv_buff_addr[i] = uart_recv_buff[i][0]; bsp_uart_receive(bsp_ext_can_get_handle(i + BSP_CAN_BASE_NUM), uart_recv_buff_addr[i], sizeof(CanUartPack), false); } HAL_CAN_ConfigFilter(bsp_can_get_handle(BSP_CAN_1), &can_filter); HAL_CAN_Start(bsp_can_get_handle(BSP_CAN_1)); HAL_CAN_ActivateNotification(bsp_can_get_handle(BSP_CAN_1), CAN_IT_RX_FIFO0_MSG_PENDING); HAL_CAN_ActivateNotification(bsp_can_get_handle(BSP_CAN_1), CAN_IT_TX_MAILBOX_EMPTY); can_filter.FilterBank = 14; can_filter.FilterFIFOAssignment = CAN_FILTER_FIFO1; HAL_CAN_ConfigFilter(bsp_can_get_handle(BSP_CAN_2), &can_filter); HAL_CAN_Start(bsp_can_get_handle(BSP_CAN_2)); HAL_CAN_ActivateNotification(bsp_can_get_handle(BSP_CAN_2), CAN_IT_RX_FIFO1_MSG_PENDING); HAL_CAN_ActivateNotification(bsp_can_get_handle(BSP_CAN_2), CAN_IT_TX_MAILBOX_EMPTY); bsp_can_initd = true; bsp_uart_register_callback( BSP_UART_CAN3, BSP_UART_IDLE_LINE_CB, rx_callback_fn, &uart_recv_buff_addr[BSP_CAN_3 - BSP_CAN_BASE_NUM]); bsp_uart_register_callback( BSP_UART_CAN4, BSP_UART_IDLE_LINE_CB, rx_callback_fn, &uart_recv_buff_addr[BSP_CAN_4 - BSP_CAN_BASE_NUM]); bsp_uart_register_callback(BSP_UART_CAN3, BSP_UART_TX_CPLT_CB, tx_cplt_callback, tx_cplt[0]); bsp_uart_register_callback(BSP_UART_CAN4, BSP_UART_TX_CPLT_CB, tx_cplt_callback, tx_cplt[1]); } static void can_rx_cb_fn(bsp_can_t can) { uint32_t fifo = CAN_FILTER_FIFO0; if (can == BSP_CAN_2) { fifo = CAN_FILTER_FIFO1; } if (callback_list[can][CAN_RX_MSG_CALLBACK].fn) { while (HAL_CAN_GetRxMessage(bsp_can_get_handle(can), fifo, &rx_buff[can].header, rx_buff[can].data) == HAL_OK) { if (rx_buff[can].header.IDE == CAN_ID_STD) { callback_list[can][CAN_RX_MSG_CALLBACK].fn( can, rx_buff[can].header.StdId, rx_buff[can].data, callback_list[can][CAN_RX_MSG_CALLBACK].arg); } else { callback_list[can][CAN_RX_MSG_CALLBACK].fn( can, rx_buff[can].header.ExtId, rx_buff[can].data, callback_list[can][CAN_RX_MSG_CALLBACK].arg); } } } } void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan) { (void)hcan; can_rx_cb_fn(BSP_CAN_1); } void HAL_CAN_RxFifo1MsgPendingCallback(CAN_HandleTypeDef *hcan) { (void)hcan; can_rx_cb_fn(BSP_CAN_2); } bsp_status_t bsp_can_register_callback( bsp_can_t can, bsp_can_callback_t type, void (*callback)(bsp_can_t can, uint32_t id, uint8_t *data, void *arg), void *callback_arg) { assert_param(callback); assert_param(type != BSP_CAN_CB_NUM); callback_list[can][type].fn = callback; callback_list[can][type].arg = callback_arg; return BSP_OK; } bsp_status_t bsp_ext_can_trans_packet(bsp_can_t can, bsp_can_format_t format, uint32_t id, uint8_t *data) { if (format == CAN_FORMAT_EXT_REMOTE || format == CAN_FORMAT_STD_REMOTE) { return BSP_ERR; } tx_ext_buff[can - BSP_CAN_BASE_NUM].id = id; tx_ext_buff[can - BSP_CAN_BASE_NUM].type = format; memcpy(tx_ext_buff[can - BSP_CAN_BASE_NUM].data, data, 8); tx_ext_buff[can - BSP_CAN_BASE_NUM].start_frame = START; tx_ext_buff[can - BSP_CAN_BASE_NUM].end_frame = END; xSemaphoreTake(tx_cplt[can - BSP_CAN_BASE_NUM], UINT32_MAX); return bsp_uart_transmit(bsp_ext_can_get_handle(can), (uint8_t *)(&tx_ext_buff[can - BSP_CAN_BASE_NUM]), sizeof(tx_ext_buff[can - BSP_CAN_BASE_NUM]), false); } bsp_status_t bsp_can_trans_packet(bsp_can_t can, bsp_can_format_t format, uint32_t id, uint8_t *data) { CAN_TxHeaderTypeDef header; if (can >= BSP_CAN_BASE_NUM) { return bsp_ext_can_trans_packet(can, format, id, data); } switch (format) { case CAN_FORMAT_STD_DATA: header.StdId = id; header.IDE = CAN_ID_STD; header.RTR = CAN_RTR_DATA; header.TransmitGlobalTime = DISABLE; header.DLC = 8; break; case CAN_FORMAT_EXT_DATA: header.ExtId = id; header.IDE = CAN_ID_EXT; header.RTR = CAN_RTR_DATA; header.TransmitGlobalTime = DISABLE; header.DLC = 8; break; case CAN_FORMAT_STD_REMOTE: header.StdId = id; header.IDE = CAN_ID_STD; header.RTR = CAN_RTR_REMOTE; header.TransmitGlobalTime = DISABLE; header.DLC = 8; break; case CAN_FORMAT_EXT_REMOTE: header.ExtId = id; header.IDE = CAN_ID_EXT; header.RTR = CAN_RTR_REMOTE; header.TransmitGlobalTime = DISABLE; header.DLC = 8; } uint32_t tsr = READ_REG(bsp_can_get_handle(can)->Instance->TSR); while (((tsr & CAN_TSR_TME0) == 0U) && ((tsr & CAN_TSR_TME1) == 0U) && ((tsr & CAN_TSR_TME2) == 0U)) { xSemaphoreTake(rx_cplt_wait_sem[can], 1); tsr = READ_REG(bsp_can_get_handle(can)->Instance->TSR); } HAL_StatusTypeDef res = HAL_CAN_AddTxMessage( bsp_can_get_handle(can), &tx_buff[can], data, mailbox + can); if (res == HAL_OK) { return BSP_OK; } else { return BSP_ERR; } }