From 23eef2d46c01848878b00453ee7a96a9af5884ff Mon Sep 17 00:00:00 2001 From: Oliver Walter Date: Mon, 5 Feb 2024 19:49:37 +0100 Subject: [PATCH] Initial commit --- CLS.c | 33 +++++ CLS.h | 9 ++ CLSAddress.h | 64 +++++++++ CLSFirmware.c | 110 +++++++++++++++ CLSFirmware.h | 0 CMakeLists.txt | 21 +++ CanDataHandler.c | 345 +++++++++++++++++++++++++++++++++++++++++++++++ CanDataHandler.h | 118 ++++++++++++++++ 8 files changed, 700 insertions(+) create mode 100644 CLS.c create mode 100644 CLS.h create mode 100644 CLSAddress.h create mode 100644 CLSFirmware.c create mode 100644 CLSFirmware.h create mode 100644 CMakeLists.txt create mode 100644 CanDataHandler.c create mode 100644 CanDataHandler.h diff --git a/CLS.c b/CLS.c new file mode 100644 index 0000000..8ef939c --- /dev/null +++ b/CLS.c @@ -0,0 +1,33 @@ +#include "CLS_BSP.h" +#include "CLS.h" +#include "CLSAddress.h" +#include "cmsis_os2.h" + +osTimerId_t CLS_HeatbeatTimerId; // Timer ID +static uint8_t cls_hartbeat_counter = 0; +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); + + +void CLS_Heatbeat(void *argument) { + // Code to be executed every 500ms + cls_hartbeat_counter++; + CLS_BSP_CAN_AddMessageToSend(&cls_hartbeat_header, &cls_hartbeat_counter); +} + + + +void CLS_Init(void) { + osTimerAttr_t timerAttr; + timerAttr.name = "CLS_Heatbeat"; + timerAttr.attr_bits = 0U; + timerAttr.cb_mem = NULL; + timerAttr.cb_size = 0U; + + + CLS_HeatbeatTimerId = osTimerNew((osTimerFunc_t)CLS_Heatbeat, osTimerPeriodic, NULL, &timerAttr); + if (CLS_HeatbeatTimerId != NULL) { // Timer object created + if (osTimerStart(CLS_HeatbeatTimerId, 500) == osOK) { // Timer started + // Timer started successfully + } + } +} \ No newline at end of file diff --git a/CLS.h b/CLS.h new file mode 100644 index 0000000..d0e3f1a --- /dev/null +++ b/CLS.h @@ -0,0 +1,9 @@ +#pragma once + +#define CLS_DEVICE_MASTER 0x11 +#define CLS_SLAVE_AR(n) n + +#define CLS_DEVICE CLS_DEVICE_MASTER + + +void CLS_Init(void); diff --git a/CLSAddress.h b/CLSAddress.h new file mode 100644 index 0000000..22f0fc0 --- /dev/null +++ b/CLSAddress.h @@ -0,0 +1,64 @@ +#pragma once + +#include + +typedef enum { + CLS_CODE_0 = 0, // 0b000 + CLS_CODE_FIMWARE = 1, // 0b001 + CLS_CODE_2 = 2, // 0b010 + CLS_CODE_MESSAGE = 3, // 0b011 + CLS_CODE_4 = 4, // 0b100 + CLS_CODE_5 = 5, // 0b101 + CLS_CODE_STATUS = 6, // 0b110 + CLS_CODE_CONFIG = 7 // 0b111 +} CLSMessageCode; + +typedef enum { + CLS_CHANNEL1 = 0, // 0b000 + CLS_CHANNEL2 = 1, // 0b001 + CLS_CHANNEL3 = 2, // 0b010 + CLS_CHANNEL4 = 3, // 0b011 + CLS_CHANNEL5 = 4, // 0b100 + CLS_CHANNEL6 = 5, // 0b101 + CLS_CHANNEL7 = 6, // 0b110 + CLS_CHANNEL8 = 7 // 0b111 +} CLSChannel; + + +typedef enum { + CLS_CH_FW_MOSI = 0, // 0b000 + CLS_CH_FW_MISO = 1, // 0b001 + CLS_CH_FW_MASTER_CONTROL = 2, // 0b010 + CLS_CH_FW_SLAVE_FEEDBACK = 3, // 0b011 + CLS_CH_FW_4 = 4, // 0b100 + CLS_CH_FW_5 = 5, // 0b101 + CLS_CH_FW_6 = 6, // 0b110 + CLS_CH_FW_BOOTCALL = 7 // 0b111 +} CLSChannelFirmware; + + +typedef enum { + CLS_CH_STA_HEATBEAT = 0, // 0b000 + CLS_CH_STA_1 = 1, // 0b001 + CLS_CH_STA_2 = 2, // 0b010 + CLS_CH_STA_3 = 3, // 0b011 + CLS_CH_STA_4 = 4, // 0b100 + CLS_CH_STA_5 = 5, // 0b101 + CLS_CH_STA_6 = 6, // 0b110 + CLS_CH_STA_7 = 7 // 0b111 +} CLSChannelStatus; + + +typedef struct { + CLSMessageCode code : 3; + uint8_t device : 5; + CLSChannel channel : 3; +} CLSAddress; + + +#define GENERATE_CLS_ADDRESS(type, device, channel) \ + ((uint16_t)(((type) << 8) | ((device) << 3) | (channel)) & 0x7ff) + +inline uint16_t generateCLSAddress(CLSMessageCode type, uint8_t device, CLSChannel channel) { + return ((type << 8) | (device << 3) | channel) & 0x7ff; +} \ No newline at end of file diff --git a/CLSFirmware.c b/CLSFirmware.c new file mode 100644 index 0000000..7588146 --- /dev/null +++ b/CLSFirmware.c @@ -0,0 +1,110 @@ +#include "CanDataHandler.h" +#include "cmsis_os2.h" +#include "FreeRTOS.h" + + +// Memory for the task +StaticTask_t CLS_FW_Task_cb; +uint32_t CLS_FW_Task_stk[512]; +// Attributes for the task +osThreadId_t CLS_FW_Task_id; +const osThreadAttr_t CLS_FW_Task_attr = { + .name = "CLS_FW_Task", + .attr_bits = 0U, + .cb_mem = &CLS_FW_Task_cb, + .cb_size = sizeof(CLS_FW_Task_cb), + .stack_mem = CLS_FW_Task_stk, + .stack_size = sizeof(CLS_FW_Task_stk), + .priority = osPriorityNormal, + .reserved = 0U +}; + +void wait_for_start_callback() { + osThreadFlagsSet(CLS_FW_Task_id, 1); +} + +void wait_for_start_enter() { + // CanData_regEventMsg(...) // wait_for_start_callback // MessageCode::Firmware(FirmwareChannel::SlaveOutMasterIn); +} + + +void wait_for_start() { + //osWaitForNotify // add timeout with eeror + //wait_for_start_exit() + //goto running +} + +void wait_for_start_exit() { + //CanData_removeEvent(...) + //f_lseek(&SDFile,0); or Open file + // frame.counter = 0; +} + + + + +void running_callback_error() { + // lock the file + // reset the file + // reset the packcount + // unlock the filec +} + +void running_callback_ack() { + //osNotify +} + +void running_enter() { + // CanData_regEventMsg(...) // running_callback_error // MessageCode::Firmware(FirmwareChannel::SlaveOutMasterIn); + // CanData_regEventMsg(...) //running_callback_ack // MessageCode::Firmware(FirmwareChannel::SlaveFeedback); +} + + +void running() { + + //4x + // -- read file upto 4 bytes + // -- send bytes can + // -- if eof -> exit() + // wait for Notify ack and repeat ^^ + +} + +void running_exit() { + // send DONE PACK + + //CanData_removeEvent(...) + //CanData_removeEvent(...) + + // we are done task exit +} + + +typedef struct { + char name[16]; + uint8_t device; +} CLSFirmwareUpdateArgs; + +void CLSFirmwareUpdateTask_func(void *argument); + +void CLSFirmwareUpdateTask_start(CLSFirmwareUpdateArgs args) { + // Task functionality here + + // check CLS_FW_Task_id is null or stopped + // osThreadGetState + CLS_FW_Task_id = osThreadNew(CLSFirmwareUpdateTask_func, NULL, &CLS_FW_Task_attr); +} + + +void CLSFirmwareUpdateTask_func(void *argument) { + + wait_for_start_enter(); + wait_for_start(); + wait_for_start_exit(); + + running_enter(); + running(); + running_exit(); + + osThreadExit(); +} \ No newline at end of file diff --git a/CLSFirmware.h b/CLSFirmware.h new file mode 100644 index 0000000..e69de29 diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..396428a --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 3.12) + +project(CLS C) + +add_library(${PROJECT_NAME} STATIC "") + +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} PRIVATE CLS_BSP) \ No newline at end of file diff --git a/CanDataHandler.c b/CanDataHandler.c new file mode 100644 index 0000000..6f851f5 --- /dev/null +++ b/CanDataHandler.c @@ -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; + } + } +} diff --git a/CanDataHandler.h b/CanDataHandler.h new file mode 100644 index 0000000..4597a11 --- /dev/null +++ b/CanDataHandler.h @@ -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 +#include +#include +#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 \ No newline at end of file