make libCLS more independen of HW

goal is to reuse libCLS on an diffrent MCU
This commit is contained in:
2024-02-05 19:46:48 +01:00
parent 31f3172ba3
commit a3c3b99fb3
18 changed files with 309 additions and 54 deletions

View File

@@ -1,33 +1,17 @@
#include "CLS_BSP.h"
#include "CLS.h"
#include "CLSAddress.h"
#include "cmsis_os2.h"
#include "fdcan.h"
osTimerId_t CLS_HeatbeatTimerId; // Timer ID
static uint8_t cls_hartbeat_counter = 0;
static FDCAN_TxHeaderTypeDef cls_hartbeat_header = {
.IdType = FDCAN_STANDARD_ID,
.Identifier = GENERATE_CLS_ADDRESS(CLS_CODE_STATUS,CLS_DEVICE,CLS_CH_STA_HEATBEAT),
.TxFrameType = FDCAN_DATA_FRAME,
.DataLength = FDCAN_DLC_BYTES_1,
.ErrorStateIndicator = FDCAN_ESI_PASSIVE,
.BitRateSwitch = FDCAN_BRS_OFF,
.FDFormat = FDCAN_CLASSIC_CAN,
.TxEventFifoControl = FDCAN_NO_TX_EVENTS,
.MessageMarker = 0xCC,
};
static CLS_BSP_TxHeaderType cls_hartbeat_header = CREATE_BSP_CAN_HEADER(GENERATE_CLS_ADDRESS(CLS_CODE_STATUS,CLS_DEVICE,CLS_CH_STA_HEATBEAT), CLS_BSP_DLC_BYTES_1);
uint8_t TxData[8];
FDCAN_TxHeaderTypeDef TxHeader;
void CLS_Heatbeat(void *argument) {
// Code to be executed every 500ms
cls_hartbeat_counter++;
if (HAL_FDCAN_GetTxFifoFreeLevel(&hfdcan1) > 1){
HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &cls_hartbeat_header, &cls_hartbeat_counter);
}
CLS_BSP_CAN_AddMessageToSend(&cls_hartbeat_header, &cls_hartbeat_counter);
}

View File

@@ -1,4 +1,3 @@
#include "fdcan.h"
#include "CanDataHandler.h"
#include "cmsis_os2.h"
#include "FreeRTOS.h"
@@ -17,7 +16,6 @@ const osThreadAttr_t CLS_FW_Task_attr = {
.stack_mem = CLS_FW_Task_stk,
.stack_size = sizeof(CLS_FW_Task_stk),
.priority = osPriorityNormal,
.tz_module = 0U,
.reserved = 0U
};

View File

@@ -8,11 +8,14 @@ target_sources(${PROJECT_NAME}
PRIVATE
${CMAKE_CURRENT_LIST_DIR}/CLS.c
${CMAKE_CURRENT_LIST_DIR}/CLSFirmware.c
${CMAKE_CURRENT_LIST_DIR}/CanDataHandler.c
INTERFACE
${CMAKE_CURRENT_LIST_DIR}/CLS.h
${CMAKE_CURRENT_LIST_DIR}/CLSAddress.h
${CMAKE_CURRENT_LIST_DIR}/CLSFirmware.h
${CMAKE_CURRENT_LIST_DIR}/CanDataHandler.h
)
target_include_directories(${PROJECT_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR})
target_link_libraries(${PROJECT_NAME} PUBLIC Tasks)
target_link_libraries(${PROJECT_NAME} PUBLIC Tasks)
target_link_libraries(${PROJECT_NAME} PRIVATE CLS_BSP)

View File

@@ -0,0 +1,345 @@
#include "CanDataHandler.h"
#include "string.h"
#define MAX_DATA_STORAGE 100
#define MAX_EVENT_STORAGE 100
#define MAX_FILTER_SLOTS 100
// storage for upto MAX_DATA_STORAGE diffrent messages
static CanDataMessageSlot CanDataStore[MAX_DATA_STORAGE] = {0};
// storage for upto MAX_EVENT_STORAGE diffrent event handlers
static CanDataEventSlot CanEventStore[MAX_DATA_STORAGE] = {0};
// storage for upto MAX_FILTER_SLOTS diffrent can filters
static CanDataFilterSlot CanFilterSlots[MAX_FILTER_SLOTS] = {0};
// this will setup the canfilter accoridng to the settings
void setup_StmCanFilter(const CanDataFilterSlot* filterSetting ) {
size_t f_index = filterSetting - CanFilterSlots;// index of the filter in CanFilterSlots
CLS_BSP_CAN_UniversalFilter clsFilterConfig = {
.filterIndex = f_index,
.filterDestination = filterSetting->fifo,
.filterMode = CLS_BSP_CAN_FILTER_LIST,
.id0 = filterSetting->id[0],
.id1 = filterSetting->id[1],
};
CLS_BSP_CAN_SetUniversalFilter(&clsFilterConfig);
}
// this will setup the canfilter using a custom defined filter
void setup_StmCanFilterManual(const CanDataFilterSlot* filterSetting, CLS_BSP_CAN_UniversalFilter * filter ) {
size_t f_index = filterSetting - CanFilterSlots;// index of the filter in CanFilterSlots
filter->filterIndex = f_index;
CLS_BSP_CAN_SetUniversalFilter(filter);
}
void CanDataHandler_init(void) {
// Reset all data message slots
for (int i = 0; i < MAX_DATA_STORAGE; i++) {
CanDataStore[i].msg.canid = 0;
CanDataStore[i].msg.data_length = 0;
memset(CanDataStore[i].msg.data, 0, MAX_DATA_LENGTH);
CanDataStore[i].filter.ref = NULL;
CanDataStore[i].filter.index = 0;
}
// Reset all event message slots
for (int i = 0; i < MAX_EVENT_STORAGE; i++) {
CanEventStore[i].canid = 0;
CanEventStore[i].eventCall = NULL;
CanEventStore[i].filter.ref = NULL;
CanEventStore[i].filter.index = 0;
}
// Reset all filter slots
for (int i = 0; i < MAX_FILTER_SLOTS; i++) {
CanFilterSlots[i].free = CANDATA_ALLFREE;
CanFilterSlots[i].fifo = CANDATA_FIFOX_UNDEFIEND;
CanFilterSlots[i].id[0] = 0;
CanFilterSlots[i].id[1] = 0;
}
}
/**
* Finds and returns an unused filter slot. If no unused slot is found, returns NULL.
*/
CanDataFilterRef CanData_unusedFilterSlot(CanDataSlotFifo reqest_fifo) {
CanDataFilterRef filterRef = {NULL, 0};
for (size_t i = 0; i < MAX_FILTER_SLOTS; i++) {
// find a slot with free some id
if (CanFilterSlots[i].free < CANDATA_FULL) {
// either the fifo settig matches or is undefined
if(CanFilterSlots[i].fifo == reqest_fifo || CanFilterSlots[i].fifo == CANDATA_FIFOX_UNDEFIEND)
filterRef.ref = &CanFilterSlots[i];
if (CanFilterSlots[i].fifo == CANDATA_FIFOX_UNDEFIEND) {
CanFilterSlots[i].fifo = reqest_fifo;
}
// Determine the index based on the 'free' field
switch (CanFilterSlots[i].free) {
case CANDATA_ALLFREE:
filterRef.index = 0;
CanFilterSlots[i].free = CANDATA_FREE1;
break;
case CANDATA_FREE1:
filterRef.index = 1;
CanFilterSlots[i].free = CANDATA_FULL;
break;
case CANDATA_FREE0:
filterRef.index = 0;
CanFilterSlots[i].free = CANDATA_FULL;
break;
default:
break;
}
break;
}
}
return filterRef;
}
void CanData_clearFilterSlot(CanDataFilterRef filter) {
// reset the filter can id
filter.ref->id[filter.index] = 0;
// set the slot as free
if(filter.index == 0) {
filter.ref->free = filter.ref->free & CANDATA_FREE0;
} else if( filter.index == 1) {
filter.ref->free = filter.ref->free & CANDATA_FREE1;
}
// if the filterslot is now fully free reset the fifo settings
if(filter.ref->free == CANDATA_ALLFREE) {
filter.ref->fifo = CANDATA_FIFOX_UNDEFIEND;
}
// finaly write new HW config
setup_StmCanFilter(filter.ref);
}
/**
* Finds and returns an unused data message slot. If no unused slot is found, returns NULL.
*/
CanDataMessageSlot * CanData_unusedDataSlot() {
for (size_t i = 0; i < MAX_DATA_STORAGE; i++) {
if (CanDataStore[i].msg.canid == 0) {
return &CanDataStore[i];
}
}
return NULL; // No unused slot found
}
/**
* Finds and returns an unused event slot. If no unused slot is found, returns NULL.
*/
CanDataEventSlot * CanData_unusedEventSlot() {
for (size_t i = 0; i < MAX_EVENT_STORAGE; i++) {
if (CanEventStore[i].canid == 0) {
return &CanEventStore[i];
}
}
return NULL; // No unused slot found
}
/**
* Registers a data message with given CanDataId. Returns true if registration is successful, false otherwise.
*/
bool CanData_regDataMsg(CanDataId canid) {
// check if we already have this canid to avoid duplicates
if(CanData_getDataMessage(canid) != NULL) {
return true; // but return true beause there is already a vaild entry for this canid
}
// Find an unused slot in the data store
CanDataMessageSlot *dataSlot = CanData_unusedDataSlot();
if (!dataSlot) {
return false; // No unused data slot available
}
// Find and configure an unused slot for the data message
CanDataFilterRef filter = CanData_unusedFilterSlot(CANDATA_FIFO0_DATA);
if (filter.ref == NULL) {
return false; // No unused filter slot available
}
// Configure the filter slot
filter.ref->id[filter.index] = canid;
// Set up the filter with the new settings
setup_StmCanFilter(filter.ref);
// Register the data message with the data slot
dataSlot->msg.canid = canid;
dataSlot->filter = filter; // Store the pointer to the filter slot
return true;
}
// Function to register a Set of ID for Data Messages using a Manual filter
size_t CanData_regDataManualMsg(const CanDataId* canid, size_t id_count, CLS_BSP_CAN_UniversalFilter * filter) {
// first check all id to be new
for (size_t i = 0; i < id_count; i++) {
if(CanData_getDataMessage(canid[i]) != NULL) {
return 0; // invalid operation one id is already used
}
}
// Find and configure one unused slot for the manual filter
CanDataFilterRef filterRef = CanData_unusedFilterSlot(CANDATA_FIFOX_MANUAL);
if (filterRef.ref == NULL) {
return 0; // No unused filter slot available
}
// setup the manual filters
filterRef.ref->fifo = CANDATA_FIFOX_MANUAL;
filterRef.ref->free = CANDATA_MANUAL;
setup_StmCanFilterManual(filterRef.ref, filter);
for (size_t i = 0; i < id_count; i++) {
// Find an unused slot in the data store
CanDataMessageSlot *dataSlot = CanData_unusedDataSlot();
if (!dataSlot) {
return i; // No unused data slot available
}
dataSlot->filter = filterRef;
dataSlot->filter.index = -1; // this idecates is a manual filter
}
return id_count;
}
/**
* Registers a event message with given CanDataId. Returns true if registration is successful, false otherwise.
*/
bool CanData_regEventMsg(CanDataId canid, EventCallback event_callback) {
// Check for vaild callback
if(event_callback == NULL) {
return false;
}
// Check if the canid is already registered
for (int i = 0; i < MAX_EVENT_STORAGE; i++) {
if (CanEventStore[i].canid == canid) {
return false; // The canid is already registered
}
}
// Find an unused slot in the event store
CanDataEventSlot *eventSlot = CanData_unusedEventSlot();
if (eventSlot == NULL) {
return false; // No unused event slot available
}
// Find and configure an unused slot for the data message
CanDataFilterRef filter = CanData_unusedFilterSlot(CANDATA_FIFO0_DATA);
if (filter.ref == NULL) {
return false; // No unused filter slot available
}
// Configure the filter slot
filter.ref->id[filter.index] = canid;
// Set up the filter with the new settings
setup_StmCanFilter(filter.ref);
// Register the event message with the event slot
eventSlot->canid = canid;
eventSlot->eventCall = event_callback;
eventSlot->filter = filter; // Store the pointer to the filter slot
return true;
}
// Function to remove a CAN ID from Event Messages Register
bool CanData_removeEvent(CanDataId canid) {
// Search for the event slot with the given CanDataId
for (size_t i = 0; i < MAX_EVENT_STORAGE; i++) {
if (CanEventStore[i].canid == canid) {
CanDataEventSlot * eventSlot = &CanEventStore[i];
CanDataFilterRef filter = eventSlot->filter;
// reset the CanDataEventSlot
eventSlot->canid =0;
eventSlot->eventCall = NULL;
eventSlot->filter.index =0;
eventSlot->filter.ref = NULL;
// reset the filter
CanData_clearFilterSlot(filter);
return true;
}
}
return false;
}
// Function to insert a Data Message into the array
void CanData_insertDataMessage(CanDataId canid, uint8_t* data, uint8_t data_length) {
if(data == NULL || data_length == 0 ) {
return;
}
// Search for the data slot with the given CanDataId
for (size_t i = 0; i < MAX_DATA_STORAGE; i++) {
if (CanDataStore[i].msg.canid == canid) {
// If found, update the data message in the slot
CanDataStore[i].msg.data_length = data_length;
memcpy(CanDataStore[i].msg.data, data, data_length);
return;
}
}
}
// Function to read stored Data Message based on CAN ID
// Returns a const pointer to the stored data or NULL if not found
const CanDataMessage* CanData_getDataMessage(CanDataId canid) {
// Search for the data message with the given CanDataId
for (size_t i = 0; i < MAX_DATA_STORAGE; i++) {
if (CanDataStore[i].msg.canid == canid) {
return &CanDataStore[i].msg; // Return a pointer to the found data message
}
}
return NULL; // No data message with the given CanDataId found
}
// Function to handle reception of Data Messages from FIFO0
void CanData_canFifo0RxCallback(CanDataId canid, uint8_t* data, uint8_t len) {
// Insert the data message into the data store
CanData_insertDataMessage(canid, data, len);
}
// Function to handle reception of Event Messages from FIFO1
void CanData_canFifo1RxCallback(CanDataId canid, uint8_t* data, uint8_t len) {
// Search for the event slot with the given CanDataId
for (size_t i = 0; i < MAX_EVENT_STORAGE; i++) {
if (CanEventStore[i].canid == canid) {
// If found, call the event callback with the received data
CanEventStore[i].eventCall(canid ,data, len);
return;
}
}
}

View File

@@ -0,0 +1,118 @@
/**
* @file CanDataHandler.h
* @brief CanDataHandler Module
*
* The CanDataHandler module is responsible for managing CAN data messages and event messages.
* It provides functionality to register CAN IDs for data and event messages, handle reception
* of these messages from FIFO buffers, insert data messages into an array, and retrieve stored
* data messages based on their CAN ID.
*
* The module maintains an internal data structure for data and event message slots, each of which
* is associated with a filter reference that points to a filter slot. A filter slot stores the
* CAN IDs and indicates the type of FIFO buffer and the number of free IDs in the slot.
*
* For event messages, a callback function can be registered to handle specific events associated
* with a CAN ID.
*/
#ifndef CANDATAHANDLER_H
#define CANDATAHANDLER_H
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include "CLS_BSP.h"
// Define the maximum length of data for a Data Message
#define MAX_DATA_LENGTH 8
typedef uint16_t CanDataId;
// Typedef for the event callback function
typedef void (*EventCallback)(CanDataId canid, uint8_t* data, uint8_t len);
// type of fifo that this slot uses
typedef enum {
CANDATA_FIFOX_UNDEFIEND = CLS_CAN_FILTER_DISABLE,
CANDATA_FIFO0_DATA = CLS_CAN_FILTER_TO_RXFIFO0,
CANDATA_FIFO1_EVENT = CLS_CAN_FILTER_TO_RXFIFO1,
CANDATA_FIFOX_MANUAL = 0x0f,
} CanDataSlotFifo;
// count of free ids in the slot
typedef enum {
CANDATA_ALLFREE = 0x00,
CANDATA_FREE1 = 0x01,
CANDATA_FREE0 = 0x02,
CANDATA_FULL = 0x03,
CANDATA_MANUAL = 0x0f,
} CanDataSlotFree;
// Define s structer for a used filter slot
typedef struct {
CanDataSlotFree free; // Number of free IDs in the slot
CanDataSlotFifo fifo; // Type of FIFO that this slot uses
CanDataId id[2]; // Array to store the two CAN IDs associated with this filter slot
} CanDataFilterSlot;
// Define a structure for a Data Message
typedef struct {
CanDataId canid;
uint8_t data[MAX_DATA_LENGTH];
uint8_t data_length;
} CanDataMessage;
typedef struct
{
CanDataFilterSlot * ref; // Reference to the filter slot
uint8_t index; // Index of the used CAN ID in the filter slot's id array
} CanDataFilterRef;
typedef struct {
CanDataMessage msg;
CanDataFilterRef filter; // Filter reference
} CanDataMessageSlot;
// Define a structure for a Event Message
typedef struct {
CanDataId canid;
EventCallback eventCall;
CanDataFilterRef filter; // Filter reference
} CanDataEventSlot;
// reset all internal structures
// does not reset CAN HW
void CanDataHandler_init(void);
// Function to register a CAN ID for Data Messages
bool CanData_regDataMsg(CanDataId canid);
// Function to register a Set of ID for Data Messages using a Manual filter
size_t CanData_regDataManualMsg(const CanDataId* canid, size_t id_count, CLS_BSP_CAN_UniversalFilter * filter);
// Function to register a CAN ID for Event Messages and associate it with a callback function
bool CanData_regEventMsg(CanDataId canid, EventCallback event_callback);
// Function to remove a CAN ID from Event Messages Register
bool CanData_removeEvent(CanDataId canid);
// Function to handle reception of Data Messages from FIFO0
void CanData_canFifo0RxCallback(CanDataId canid, uint8_t* data, uint8_t len);
// Function to handle reception of Event Messages from FIFO1
void CanData_canFifo1RxCallback(CanDataId canid, uint8_t* data, uint8_t len);
// Function to insert a Data Message into the array
void CanData_insertDataMessage(CanDataId canid, uint8_t* data, uint8_t data_length);
// Function to read stored Data Message based on CAN ID
// Returns a const pointer to the stored data or NULL if not found
const CanDataMessage* CanData_getDataMessage(CanDataId canid);
#endif // CANDATAHANDLER_H