commit 23eef2d46c01848878b00453ee7a96a9af5884ff Author: Oliver Walter Date: Mon Feb 5 19:49:37 2024 +0100 Initial commit 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