From 9a7c443494f9a37856848553de0404cdac75d462 Mon Sep 17 00:00:00 2001 From: tzarjakob Date: Sat, 18 Nov 2023 10:12:45 +0100 Subject: [PATCH] first version of can manager library --- can-manager/can-manager.c | 215 ------------------------------------ can-manager/can-manager.h | 30 ----- can-manager/can_manager.c | 226 ++++++++++++++++++++++++++++++++++++++ can-manager/can_manager.h | 57 ++++++++++ can-manager/can_types.h | 12 ++ 5 files changed, 295 insertions(+), 245 deletions(-) delete mode 100644 can-manager/can-manager.c delete mode 100644 can-manager/can-manager.h create mode 100644 can-manager/can_manager.c create mode 100644 can-manager/can_manager.h create mode 100644 can-manager/can_types.h diff --git a/can-manager/can-manager.c b/can-manager/can-manager.c deleted file mode 100644 index ec9a47c..0000000 --- a/can-manager/can-manager.c +++ /dev/null @@ -1,215 +0,0 @@ -#include "can-manager.h" -#include "main.h" - -float CAN_error_rate; -generic_queue_t primary_rx_queue; -generic_queue_t secondary_rx_queue; -generic_queue_t primary_tx_queue; -generic_queue_t secondary_tx_queue; -bool readPrimary = true; -CAN_HandleTypeDef *_can_primary; -CAN_HandleTypeDef *_can_secondary; -uint32_t _CAN_err_count = 0; -uint32_t _CAN_tot_tx_count = 0; - -bool can_init_primary(CAN_HandleTypeDef * hcan, void(primary_can_rx_handler)(void)) { - _can_primary = hcan; - - // GENQ_init(&primary_can_add_rx_message, 1000 * sizeof(CAN_MessageTypeDef), sizeof(CAN_MessageTypeDef), ); - - CAN_FilterTypeDef *filter; - - filter->FilterMode = CAN_FILTERMODE_IDMASK; - filter->FilterIdLow = 0; - filter->FilterIdHigh = 0xFFFF; - filter->FilterMaskIdHigh = 0; - filter->FilterMaskIdLow = 0; - filter->FilterFIFOAssignment = CAN_FILTER_FIFO0; - filter->FilterBank = 0; - filter->FilterScale = CAN_FILTERSCALE_16BIT; - filter->FilterActivation = ENABLE; - - _CAN_activate_filter(hcan, &filter); - - if (HAL_CAN_Start(hcan) != HAL_OK) - _CAN_error_handler("HAL_CAN_Start() failed"); - return false; - - return true; -} - -bool can_init_secondary(CAN_HandleTypeDef * hcan, void(secondary_can_rx_handler)(void)) { - _can_secondary = hcan; - - CAN_FilterTypeDef *filter; - - filter->FilterMode = CAN_FILTERMODE_IDMASK; - filter->FilterIdLow = 0; - filter->FilterIdHigh = 0xFFFF; - filter->FilterMaskIdHigh = 0; - filter->FilterMaskIdLow = 0; - filter->FilterFIFOAssignment = CAN_FILTER_FIFO1; - filter->FilterBank = 1; - filter->FilterScale = CAN_FILTERSCALE_16BIT; - filter->FilterActivation = ENABLE; - filter->SlaveStartFilterBank = 1; - - _CAN_activate_filter(hcan, &filter); - - if (HAL_CAN_Start(hcan) != HAL_OK) - _CAN_error_handler("HAL_CAN_Start() failed"); - return false; - - return true; -} - -HAL_StatusTypeDef _CAN_activate_filter(CAN_HandleTypeDef *hcan, CAN_FilterTypeDef *filter) { - HAL_StatusTypeDef s; - if ((s = HAL_CAN_ConfigFilter(hcan, filter)) != HAL_OK) - _CAN_error_handler("Failed to initialize a CAN filter"); - - return s; -} - -bool primary_can_add_tx_message(CAN_MessageTypeDef message) { - return CANFQ_push(primary_rx_queue, message); -} - -bool secondary_can_add_tx_message(CAN_MessageTypeDef message) { - return CANFQ_push(secondary_rx_queue, message); -} - -HAL_StatusTypeDef _CAN_activate_interrupts(CAN_HandleTypeDef *hcan) { - HAL_StatusTypeDef s_rx; - - //TODO: eh? - // uint32_t irq_rx = (hcan == &CAN_PRIMARY_NETWORK) ? - // CAN_IT_RX_FIFO0_MSG_PENDING : CAN_IT_RX_FIFO1_MSG_PENDING; - - // if ((s_rx = HAL_CAN_ActivateNotification(hcan, irq_rx)) != HAL_OK) - // _CAN_error_handler("Failed to activate a CAN RX interrupt"); - - HAL_CAN_ActivateNotification(hcan, - CAN_IT_TX_MAILBOX_EMPTY | - CAN_IT_ERROR_WARNING | - CAN_IT_ERROR_PASSIVE | - CAN_IT_BUSOFF | - CAN_IT_LAST_ERROR_CODE | - CAN_IT_ERROR - ); - - return s_rx; -} - -void _CAN_error_handler(char * msg) { - _CAN_err_count++; - CAN_error_rate = (float)_CAN_err_count / (float)_CAN_tot_tx_count; - - #if CAN_DEBUG - LOG_write(LOGLEVEL_ERR, "[CAN/Error Handler] %s", msg); - #endif -} - -void consume_primary_rx_queue() { - CAN_MessageTypeDef message; - CANFQ_pop(&primary_rx_queue, &message); - primary_can_rx_handler(&message); -} - -void consume_secondary_rx_queue() { - CAN_MessageTypeDef message; - CANFQ_pop(&secondary_rx_queue, &message); - secondary_can_rx_handler(&message); -} - -bool primary_can_add_tx_message(CAN_MessageTypeDef *message) { - CANFQ_push(&primary_tx_queue, message); - return false; -} - -bool secondary_can_add_tx_message(CAN_MessageTypeDef *message) { - CANFQ_push(&secondary_tx_queue, message); - return false; -} - -void HAL_CAN_ErrorCallback(CAN_HandleTypeDef *hcan) { - uint32_t e = hcan->ErrorCode; - - if (e & HAL_CAN_ERROR_EWG) - _CAN_error_handler("Protocol Error Warning"); - if (e & HAL_CAN_ERROR_EPV) - _CAN_error_handler("Error Passive"); - if (e & HAL_CAN_ERROR_BOF) - _CAN_error_handler("Bus-off Error"); - if (e & HAL_CAN_ERROR_STF) - _CAN_error_handler("Stuff Error"); - if (e & HAL_CAN_ERROR_FOR) - _CAN_error_handler("Form Error"); - if (e & HAL_CAN_ERROR_ACK) - _CAN_error_handler("ACK Error"); - if (e & HAL_CAN_ERROR_BR) - _CAN_error_handler("Bit Recessive Error"); - if (e & HAL_CAN_ERROR_BD) - _CAN_error_handler("Bit Dominant Error"); - if (e & HAL_CAN_ERROR_CRC) - _CAN_error_handler("CRC Error"); - if (e & HAL_CAN_ERROR_RX_FOV0) - _CAN_error_handler("FIFO0 Overrun"); - if (e & HAL_CAN_ERROR_RX_FOV1) - _CAN_error_handler("FIFO1 Overrun"); - if (e & HAL_CAN_ERROR_TX_ALST0) - _CAN_error_handler("Mailbox 0 TX failure (arbitration lost)"); - if (e & HAL_CAN_ERROR_TX_TERR0) - _CAN_error_handler("Mailbox 0 TX failure (tx error)"); - if (e & HAL_CAN_ERROR_TX_ALST1) - _CAN_error_handler("Mailbox 1 TX failure (arbitration lost)"); - if (e & HAL_CAN_ERROR_TX_TERR1) - _CAN_error_handler("Mailbox 1 TX failure (tx error)"); - if (e & HAL_CAN_ERROR_TX_ALST2) - _CAN_error_handler("Mailbox 2 TX failure (arbitration lost)"); - if (e & HAL_CAN_ERROR_TX_TERR2) - _CAN_error_handler("Mailbox 2 TX failure (tx error)"); - if (e & HAL_CAN_ERROR_TIMEOUT) - _CAN_error_handler("Timeout Error"); - if (e & HAL_CAN_ERROR_NOT_INITIALIZED) - _CAN_error_handler("Peripheral not initialized"); - if (e & HAL_CAN_ERROR_NOT_READY) - _CAN_error_handler("Peripheral not ready"); - if (e & HAL_CAN_ERROR_NOT_STARTED) - _CAN_error_handler("Peripheral not strated"); - if (e & HAL_CAN_ERROR_PARAM) - _CAN_error_handler("Parameter Error"); -} - -HAL_StatusTypeDef CAN_send(CAN_MessageTypeDef *message, CAN_HandleTypeDef *hcan) { - CAN_TxHeaderTypeDef header; - header.StdId = message->id; - header.IDE = CAN_ID_STD; - header.RTR = CAN_RTR_DATA; - header.DLC = message->size; - header.TransmitGlobalTime = DISABLE; - - _CAN_wait(hcan); - - //TODO add _inc_tot_tx() function - _CAN_tot_tx_count++; - CAN_error_rate = (float)_CAN_err_count / (float)_CAN_tot_tx_count; - - #if CAN_DEBUG - LOG_write(LOGLEVEL_DEBUG, "[CAN] Sending 0x%02X", message->id); - #endif - - return HAL_CAN_AddTxMessage(hcan, &header, message->data, NULL); -} - -void flush_tx_queue() { - CAN_MessageTypeDef message; - while (!GENQ_is_empty(&primary_tx_queue)) { - CANFQ_pop(&primary_rx_queue, &message); - CAN_send(&message, _can_primary); - } - while (!GENQ_is_empty(&secondary_tx_queue)) { - CANFQ_pop(&secondary_rx_queue, &message); - CAN_send(&message, _can_secondary); - } -} diff --git a/can-manager/can-manager.h b/can-manager/can-manager.h deleted file mode 100644 index 4a7e026..0000000 --- a/can-manager/can-manager.h +++ /dev/null @@ -1,30 +0,0 @@ -#include "stdbool.h" -#include "generic_queue.h" - -typedef uint16_t CAN_IdTypeDef; -typedef struct { - CAN_IdTypeDef id; - uint8_t size; - uint8_t data[8]; -} CAN_MessageTypeDef; - -bool can_init_primary(CAN_HandleTypeDef *hcan, void(primary_can_rx_handler)(void)); -bool can_init_secondary(CAN_HandleTypeDef *hcan, void(secondary_can_rx_handler)(void)); - -HAL_StatusTypeDef _CAN_activate_filter(CAN_HandleTypeDef *hcan, CAN_FilterTypeDef *filter); -HAL_StatusTypeDef _CAN_activate_interrupts(CAN_HandleTypeDef *hcan); - -bool primary_can_add_tx_message(CAN_MessageTypeDef message); -bool secondary_can_add_tx_message(CAN_MessageTypeDef message); - -void consume_primary_rx_queue(); -void consume_secondary_rx_queue(); - -bool primary_can_add_rx_message(CAN_MessageTypeDef *message); -bool secondary_can_add_rx_message(CAN_MessageTypeDef *message); - -void primary_can_rx_handler(CAN_MessageTypeDef *message); -void secondary_can_rx_handler(CAN_MessageTypeDef *message); - -void flush_tx_queue(); - diff --git a/can-manager/can_manager.c b/can-manager/can_manager.c new file mode 100644 index 0000000..13cacf3 --- /dev/null +++ b/can-manager/can_manager.c @@ -0,0 +1,226 @@ +/**** + * Instruction to use the can manager library. + * + * @author Giacomo Mazzucchi + * @author Alessandro Conforti +*/ +#include "can_manager.h" + +int _max_can_id = 0; +generic_queue_t _rx_queues[MAX_CAN_BUSES]; +generic_queue_t _tx_queues[MAX_CAN_BUSES]; +uint8_t _rx_queues_data[CAN_MANAGER_MAX_QUEUE_ELEMENTS * sizeof(generic_queue_t) * MAX_CAN_BUSES]; +uint8_t _tx_queues_data[CAN_MANAGER_MAX_QUEUE_ELEMENTS * sizeof(generic_queue_t) * MAX_CAN_BUSES]; +void (*can_rx_msg_handlers[MAX_CAN_BUSES])(can_manager_message_t *); + +#ifdef FDCAN_MANAGER + +FDCAN_HandleTypeDef *fdcan_buses[MAX_CAN_BUSES]; + +int fdcan_init( + FDCAN_HandleTypeDef *hcan, void(can_rx_msg_handler)(can_manager_message_t *), uint32_t activation_interrupt, + uint32_t filter_config) { + if (_max_can_id >= MAX_CAN_BUSES) { + return -1; + } + + int assigned_id = _max_can_id; + can_rx_msg_handlers[assigned_id] = can_rx_msg_handler; + + GENQ_init( + &_rx_queues[assigned_id], sizeof(generic_queue_t), CAN_MANAGER_MAX_QUEUE_ELEMENTS, + &_rx_queues_data[assigned_id]); + GENQ_init( + &_tx_queues[assigned_id], sizeof(generic_queue_t), CAN_MANAGER_MAX_QUEUE_ELEMENTS, + &_tx_queues_data[assigned_id]); + + fdcan_buses[assigned_id] = hcan; + + _max_can_id++; + + FDCAN_FilterTypeDef filter = { + .IdType = FDCAN_STANDARD_ID, + .FilterIndex = 0, + .FilterType = FDCAN_FILTER_RANGE, + .FilterConfig = filter_config, + .FilterID1 = 0, + .FilterID2 = ((1U << 11) - 1) << 8, + .IsCalibrationMsg = 0, + .RxBufferIndex = 0}; + + // TODO better error handling + HAL_FDCAN_ConfigFilter(hcan, &filter); + HAL_FDCAN_ActivateNotification(hcan, activation_interrupt, 0); + // TODO give the possibility to remove the start + HAL_FDCAN_Start(hcan); + + return assigned_id; +} + +void _fdcan_wait(FDCAN_HandleTypeDef *nwk) { + uint32_t start_timestamp = HAL_GetTick(); + while (HAL_FDCAN_GetTxFifoFreeLevel(nwk) == 0) + if (HAL_GetTick() > start_timestamp + 5) + return; +} + +int _fdcan_send(int can_id, can_manager_message_t *msg) { + CM_CAN_ID_CHECK(can_id); + FDCAN_HandleTypeDef *hcan = fdcan_buses[can_id]; + + uint32_t dlc_len = 0; + switch (msg->size) { + case 0: + dlc_len = FDCAN_DLC_BYTES_0; + break; + case 1: + dlc_len = FDCAN_DLC_BYTES_1; + break; + case 2: + dlc_len = FDCAN_DLC_BYTES_2; + break; + case 3: + dlc_len = FDCAN_DLC_BYTES_3; + break; + case 4: + dlc_len = FDCAN_DLC_BYTES_4; + break; + case 5: + dlc_len = FDCAN_DLC_BYTES_5; + break; + case 6: + dlc_len = FDCAN_DLC_BYTES_6; + break; + case 7: + dlc_len = FDCAN_DLC_BYTES_7; + break; + case 8: + dlc_len = FDCAN_DLC_BYTES_8; + break; + } + + FDCAN_TxHeaderTypeDef header = { + .Identifier = msg->id, + .IdType = FDCAN_STANDARD_ID, + .TxFrameType = FDCAN_DATA_FRAME, + .DataLength = dlc_len, + .ErrorStateIndicator = FDCAN_ESI_ACTIVE, + .BitRateSwitch = FDCAN_BRS_OFF, + .FDFormat = FDCAN_CLASSIC_CAN, + .TxEventFifoControl = FDCAN_STORE_TX_EVENTS, + .MessageMarker = 0, + }; + + // TODO flag for this + _fdcan_wait(hcan); + + HAL_StatusTypeDef result = HAL_FDCAN_AddMessageToTxFifoQ(hcan, &header, msg->data); + return result == HAL_OK; +} + +#else + +CAN_HandleTypeDef *can_buses[MAX_CAN_BUSES]; + +int can_init( + CAN_HandleTypeDef *hcan, void(can_rx_msg_handler)(can_manager_message_t *), uint32_t activation_interrupt, + uint32_t filter_config) { + if (_max_can_id >= MAX_CAN_BUSES) { + return -1; + } + + int assigned_id = _max_can_id; + can_rx_msg_handlers[assigned_id] = can_rx_msg_handler; + + GENQ_init( + &_rx_queues[assigned_id], sizeof(generic_queue_t), CAN_MANAGER_MAX_QUEUE_ELEMENTS, + &_rx_queues_data[assigned_id]); + GENQ_init( + &_tx_queues[assigned_id], sizeof(generic_queue_t), CAN_MANAGER_MAX_QUEUE_ELEMENTS, + &_tx_queues_data[assigned_id]); + + can_buses[assigned_id] = hcan; + _max_can_id++; + + CAN_FilterTypeDef filter = + {.FilterMode = CAN_FILTERMODE_IDMASK, + .FilterIdLow = 0, + .FilterIdHigh = 0xFFFF, + .FilterMaskIdHigh = 0, + .FilterMaskIdLow = 0, + .FilterFIFOAssignment = filter_config, + .FilterBank = 0, + .FilterScale = CAN_FILTERSCALE_16BIT, + .FilterActivation = ENABLE } + + // TODO better error handling + if (HAL_CAN_ConfigFilter(hcan, &filter) != HAL_OK) { + return -1; + } + if (HAL_CAN_ActivateNotification(hcan, activation_interrupt) != HAL_OK) { + return -1; + } + HAL_CAN_ActivateNotification( + hcan, CAN_IT_TX_MAILBOX_EMPTY | CAN_IT_ERROR_WARNING | CAN_IT_ERROR_PASSIVE | CAN_IT_BUSOFF | + CAN_IT_LAST_ERROR_CODE | CAN_IT_ERROR); + if (HAL_CAN_Start(hcan) != HAL_OK) { + return -1; + } + return assigned_id; +} + +void _can_wait(CAN_HandleTypeDef *hcan) { + uint32_t start_timestamp = HAL_GetTick(); + while (HAL_CAN_GetTxMailboxesFreeLevel(hcan) == 0) + if (HAL_GetTick() > start_timestamp + 5) + return; +} + +int _can_send(int can_id, can_manager_message_t *msg) { + CM_CAN_ID_CHECK(can_id); + CAN_HandleTypeDef *hcan = can_buses[can_id]; + CAN_TxHeaderTypeDef header = + {.StdId = msg->id, .IDE = CAN_ID_STD, .RTR = CAN_RTR_DATA, .DLC = msg->size, .TransmitGlobalTime = DISABLE} + + // TODO flag for this + _can_wait(hcan); + + if (HAL_CAN_AddTxMessage(hcan, &header, msg->data, NULL) != HAL_OK) { + return 0; + } + return 1; +} +#endif + +int add_to_rx_queue(int can_id, can_manager_message_t *msg) { + CM_CAN_ID_CHECK(can_id); + return GENQ_push(&_rx_queues[can_id], (uint8_t *)msg); +} + +int add_to_tx_queue(int can_id, can_manager_message_t *msg) { + CM_CAN_ID_CHECK(can_id); + return GENQ_push(&_tx_queues[can_id], (uint8_t *)msg); +} + +int consume_rx_queue(int can_id) { + CM_CAN_ID_CHECK(can_id); + can_manager_message_t msg; + if (GENQ_pop(&_rx_queues[can_id], (uint8_t *)&msg)) { + (*can_rx_msg_handlers[can_id])(&msg); + return 1; + } + return 0; +} + +int flush_tx_queue(int can_id) { + CM_CAN_ID_CHECK(can_id); + can_manager_message_t msg; + if (GENQ_pop(&_tx_queues[can_id], (uint8_t *)&msg)) { +#ifdef FDCAN_MANAGER + return _fdcan_send(can_id, &msg); +#else + return _can_send(can_id, &msg); +#endif + } + return 0; +} diff --git a/can-manager/can_manager.h b/can-manager/can_manager.h new file mode 100644 index 0000000..8195fcb --- /dev/null +++ b/can-manager/can_manager.h @@ -0,0 +1,57 @@ +#ifndef CAN_MANAGER_H +#define CAN_MANAGER_H + +#include "can_types.h" +#include "generic_queue.h" +#include "main.h" +#include "stdbool.h" + +#define FDCAN_MANAGER +#define MAX_CAN_BUSES 2 +#define CAN_MANAGER_MAX_QUEUE_ELEMENTS 50 + +#define CM_CAN_ID_CHECK(can_id) \ + if (can_id < 0 || can_id >= MAX_CAN_BUSES) \ + return 0 + +#ifdef FDCAN_MANAGER +int fdcan_init( + FDCAN_HandleTypeDef *hcan, void(can_rx_msg_handler)(can_manager_message_t *), uint32_t activation_interrupt, + uint32_t filter_config); +#else +int can_init( + CAN_HandleTypeDef *hcan, void(can_rx_msg_handler)(can_manager_message_t *), uint32_t activation_interrupt, + uint32_t filter_config); +#endif +int consume_rx_queue(int can_id); +int flush_tx_queue(int can_id); +int add_to_rx_queue(int can_id, can_manager_message_t *msg); +int add_to_tx_queue(int can_id, can_manager_message_t *msg); + +#endif // CAN_MANAGER_H + +/*** + * + +// CAN_interrupt +can_manager_add_rx_queue(primary_can_id, &can_msg); + +int main() { + // hcan, handler, priority + int primary_can_id = can_init(&hcan1, handle_primary); + int secondary_can_id = can_init(&hcan2, handle_secondary); + + while(1) { + consume_rx_queue(primary_can_id); + consume_rx_queue(secondary_can_id); + flush_tx_queue(primary_can_id); + flush_tx_queue(secondary_can_id); + } +} + +// libreria +void consume_rx_queue() { + // una volta per ogni coda, bastano circular_buffer +} + +*/ diff --git a/can-manager/can_types.h b/can-manager/can_types.h new file mode 100644 index 0000000..41a519a --- /dev/null +++ b/can-manager/can_types.h @@ -0,0 +1,12 @@ +#ifndef CAN_TYPES_H +#define CAN_TYPES_H + +#include + +typedef struct { + uint16_t id; + uint8_t size; + uint8_t data[8]; +} can_manager_message_t; + +#endif // #ifndef CAN_TYPES_H