First commit

This commit is contained in:
ggw
2026-04-24 19:51:22 -07:00
commit d853c57c16
2794 changed files with 2455857 additions and 0 deletions
@@ -0,0 +1,620 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file advanced_memory_manager.c
* @author MCD Application Team
* @brief Memory Manager
******************************************************************************
* @attention
*
* Copyright (c) 2022 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "stm_list.h"
#include "utilities_conf.h"
#include "advanced_memory_manager.h"
/* Private typedef -----------------------------------------------------------*/
/**
* @brief Virtual Memory information struct
*/
typedef struct __attribute__((packed, aligned(4))) VirtualMemoryInfo
{
/* Identifier of the Virtual Memory */
uint8_t Id;
/* Size required for this Virtual Memory buffer with a multiple of 32bits */
uint32_t RequiredSize;
/* Current occupation of the Virtual Memory buffer with a multiple of 32bits */
uint32_t OccupiedSize;
}VirtualMemoryInfo_t;
/* Private defines -----------------------------------------------------------*/
/* Defines that the module is not initialized */
#define NOT_INITIALIZED 0x00u
/* Defines that the module is initialized */
#define INITIALIZED 0x01u
/* Defines the bit to check for 32bits aligned values */
#define MASK_ALIGNED_32BITS 0x03u
/*
Defines the length of the Virtual Memory Header in 32bits
----------------------------------------
| +++ 8bits +++ | +++++++ 24bits +++++++ |
| VirtualMem ID | Buffer Size (n*32bits) |
----------------------------------------
*/
#define VIRTUAL_MEMORY_HEADER_SIZE 0x01
/* Position of the ID field in Virtual Memory Header */
#define VIRTUAL_MEMORY_HEADER_ID_POS 0x18
/* Mask of the ID field in Virtual Memory Header */
#define VIRTUAL_MEMORY_HEADER_ID_MASK 0xFF000000
/* Position of the Buffer Size field in Virtual Memory Header */
#define VIRTUAL_MEMORY_HEADER_BUFFER_SIZE_POS 0x00
/* Mask of the Buffer Size field in Virtual Memory Header */
#define VIRTUAL_MEMORY_HEADER_BUFFER_SIZE_MASK 0x00FFFFFF
/* Private macros ------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* AMM Initialized flag */
static uint8_t AmmInitialized = NOT_INITIALIZED;
/* AMM pool address */
static uint32_t * p_AmmPoolAddress;
/* AMM pool size */
static uint32_t AmmPoolSize;
/* AMM occupied shared pool size */
static uint32_t AmmOccupiedSharedPoolSize;
/* AMM needed virtual memory */
static uint32_t AmmRequiredVirtualMemorySize;
/* AMM virtual memory number */
static uint32_t AmmVirtualMemoryNumber;
/* List of Virtual Memories info */
static VirtualMemoryInfo_t * p_AmmVirtualMemoryList;
/* Handler of the Basic Memory Manager functions */
static AMM_BasicMemoryManagerFunctions_t AmmBmmFunctionsHandler;
/* Pointer on the first element of the pending callbacks */
static AMM_VirtualMemoryCallbackHeader_t AmmPendingCallback;
/* Pointer on the first element of the active callbacks */
static AMM_VirtualMemoryCallbackHeader_t AmmActiveCallback;
/* Global variables ----------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/**
* @brief Push a callback structure into the Pending FIFO
* @param p_CallbackElt: Pointer onto the callback to push
* @return None
*/
static inline void pushPending (AMM_VirtualMemoryCallbackFunction_t * const p_CallbackElt);
/**
* @brief Push the Pending callback(s) into the Active FIFO
* @return None
*/
static inline void passPendingToActive (void);
/**
* @brief Pop a callback structure from the Active FIFO
* @return Pointer onto the popped callback
*/
static inline AMM_VirtualMemoryCallbackFunction_t * popActive (void);
/* Functions Definition ------------------------------------------------------*/
AMM_Function_Error_t AMM_Init (const AMM_InitParameters_t * const p_InitParams)
{
AMM_Function_Error_t error = AMM_ERROR_NOK;
uint32_t neededPoolSize = 0x00;
/* Check if not already initialized */
if (AmmInitialized == INITIALIZED)
{
error = AMM_ERROR_ALREADY_INIT;
}
/* Check parameter null pointer */
else if (p_InitParams == NULL)
{
error = AMM_ERROR_BAD_POINTER;
}
/* Check Pool address null pointer */
else if (p_InitParams->p_PoolAddr == NULL)
{
error = AMM_ERROR_BAD_POOL_CONFIG;
}
/* Check if Pool address is 32bits aligned */
else if ((MASK_ALIGNED_32BITS & (uint32_t)p_InitParams->p_PoolAddr) != 0)
{
error = AMM_ERROR_BAD_POOL_CONFIG;
}
/* Check Pool size shall be non zero */
else if (p_InitParams->PoolSize == 0)
{
error = AMM_ERROR_BAD_POOL_CONFIG;
}
/* Check that Virtual memories can not be declared without a proper configuration list */
else if ((p_InitParams->VirtualMemoryNumber != 0x00) &&
(p_InitParams->p_VirtualMemoryConfigList == NULL))
{
error = AMM_ERROR_BAD_VIRTUAL_CONFIG;
}
else
{
neededPoolSize = p_InitParams->VirtualMemoryNumber * AMM_VIRTUAL_INFO_ELEMENT_SIZE;
/* Check the parameters relative to virtual memories */
for (uint32_t memIdx = 0x00;
(memIdx < p_InitParams->VirtualMemoryNumber) && (error == AMM_ERROR_NOK);
memIdx++)
{
/* Add the amount of needed space for this virtual memory */
neededPoolSize = neededPoolSize + p_InitParams->p_VirtualMemoryConfigList[memIdx].BufferSize;
/* Check the virtual memory ID. Shall not be zero */
if (p_InitParams->p_VirtualMemoryConfigList[memIdx].Id == 0)
{
error = AMM_ERROR_BAD_VIRTUAL_CONFIG;
}
/* Check if size is not zero */
else if (p_InitParams->p_VirtualMemoryConfigList[memIdx].BufferSize == 0)
{
error = AMM_ERROR_BAD_VIRTUAL_CONFIG;
}
/* Check if amount of needed memory has overlapped current pool size */
else if (p_InitParams->PoolSize < neededPoolSize)
{
error = AMM_ERROR_BAD_VIRTUAL_CONFIG;
}
else
{
/* Do nothing, all ok yet */
}
}
/* Check if parameters are still ok */
if (error == AMM_ERROR_NOK)
{
/* Init all private variables: Pool relative */
p_AmmPoolAddress = NULL;
AmmPoolSize = 0x00;
AmmOccupiedSharedPoolSize = 0x00;
AmmRequiredVirtualMemorySize = 0x00;
/* Init all private variables: Virtual Memory relative */
AmmVirtualMemoryNumber = 0x00;
p_AmmVirtualMemoryList = NULL;
/* Init all private variables: BMM relative */
AmmBmmFunctionsHandler.Init = NULL;
AmmBmmFunctionsHandler.Allocate = NULL;
AmmBmmFunctionsHandler.Free = NULL;
/* Init all private variables: Callbacks relative */
AmmPendingCallback.next = NULL;
AmmPendingCallback.prev = NULL;
AmmActiveCallback.next = NULL;
AmmActiveCallback.prev = NULL;
/* First get the Basic Memory Manager functions back */
AMM_RegisterBasicMemoryManager (&AmmBmmFunctionsHandler);
if ((AmmBmmFunctionsHandler.Init == NULL)
|| (AmmBmmFunctionsHandler.Allocate == NULL)
|| (AmmBmmFunctionsHandler.Free == NULL))
{
error = AMM_ERROR_BAD_BMM_REGISTRATION;
}
else
{
/* Store the pool info */
p_AmmPoolAddress = p_InitParams->p_PoolAddr;
AmmPoolSize = p_InitParams->PoolSize;
/* First init the Basic Memory Manager */
AmmBmmFunctionsHandler.Init (p_AmmPoolAddress,
AmmPoolSize);
/* Allocate memory for the virtual memories info */
p_AmmVirtualMemoryList = (VirtualMemoryInfo_t *)
(AmmBmmFunctionsHandler. Allocate (AMM_VIRTUAL_INFO_ELEMENT_SIZE
* p_InitParams->VirtualMemoryNumber));
/* Check if allocation is OK*/
if ((p_AmmVirtualMemoryList == NULL) && (p_InitParams->VirtualMemoryNumber > 0))
{
error = AMM_ERROR_BAD_BMM_ALLOCATION;
}
else
{
/* Init Critical section */
UTIL_SEQ_INIT_CRITICAL_SECTION ();
/* Init both pending and active list */
LST_init_head (&AmmPendingCallback);
LST_init_head (&AmmActiveCallback);
/* Keep going on init, fulfill the virtual memories info */
AmmVirtualMemoryNumber = p_InitParams->VirtualMemoryNumber;
/* Actualize actual shared pool occupied size */
AmmOccupiedSharedPoolSize = AmmOccupiedSharedPoolSize + (AMM_VIRTUAL_INFO_ELEMENT_SIZE
* AmmVirtualMemoryNumber);
for (uint32_t memIdx = 0x00;
memIdx < AmmVirtualMemoryNumber;
memIdx++)
{
p_AmmVirtualMemoryList[memIdx].Id = p_InitParams->p_VirtualMemoryConfigList[memIdx].Id;
p_AmmVirtualMemoryList[memIdx].RequiredSize = p_InitParams->p_VirtualMemoryConfigList[memIdx].BufferSize;
p_AmmVirtualMemoryList[memIdx].OccupiedSize = 0x00;
AmmRequiredVirtualMemorySize = AmmRequiredVirtualMemorySize + p_AmmVirtualMemoryList[memIdx].RequiredSize;
}
/* Set init flag */
AmmInitialized = INITIALIZED;
/* All info are stored and AMM is initialized */
error = AMM_ERROR_OK;
}
}
}
}
return error;
}
AMM_Function_Error_t AMM_DeInit (void)
{
AMM_Function_Error_t error = AMM_ERROR_NOK;
/* Check if initialized */
if (AmmInitialized == INITIALIZED)
{
/* Free resources */
AmmBmmFunctionsHandler.Free ((uint32_t *)p_AmmVirtualMemoryList);
/* Reset all the variables */
AmmBmmFunctionsHandler.Init = NULL;
AmmBmmFunctionsHandler.Allocate = NULL;
AmmBmmFunctionsHandler.Free = NULL;
p_AmmPoolAddress = 0x00;
AmmPoolSize = 0x00;
AmmOccupiedSharedPoolSize = 0x00;
AmmRequiredVirtualMemorySize = 0x00;
AmmVirtualMemoryNumber = 0x00;
/* Unset the flag */
AmmInitialized = 0x00;
error = AMM_ERROR_OK;
}
else
{
error = AMM_ERROR_NOT_INIT;
}
return error;
}
AMM_Function_Error_t AMM_Alloc (const uint8_t VirtualMemoryId,
const uint32_t BufferSize,
uint32_t ** pp_AllocBuffer,
AMM_VirtualMemoryCallbackFunction_t * const p_CallBackFunction)
{
AMM_Function_Error_t error = AMM_ERROR_NOK;
uint32_t selfAvailable = 0x00;
uint32_t * p_TmpAllocAddr = NULL;
if (AmmInitialized == NOT_INITIALIZED)
{
error = AMM_ERROR_NOT_INIT;
}
/* Check if buffer size is not zero */
else if (BufferSize == 0)
{
error = AMM_ERROR_BAD_ALLOCATION_SIZE;
}
/* Check if no virtual ID requested */
else if (VirtualMemoryId == AMM_NO_VIRTUAL_ID)
{
/* Enter critical section */
UTIL_SEQ_ENTER_CRITICAL_SECTION ();
/* Check for enough space in the shared pool */
if (BufferSize < (AmmPoolSize - AmmOccupiedSharedPoolSize - AmmRequiredVirtualMemorySize))
{
/* Try Allocation. Do not forget the header */
p_TmpAllocAddr = AmmBmmFunctionsHandler.Allocate (BufferSize + VIRTUAL_MEMORY_HEADER_SIZE);
/* Check if allocation is OK */
if (p_TmpAllocAddr != NULL)
{
/* Fulfill the header */
*p_TmpAllocAddr = (uint32_t)(((uint32_t)VirtualMemoryId << VIRTUAL_MEMORY_HEADER_ID_POS)
& VIRTUAL_MEMORY_HEADER_ID_MASK)
| ((BufferSize << VIRTUAL_MEMORY_HEADER_BUFFER_SIZE_POS)
& VIRTUAL_MEMORY_HEADER_BUFFER_SIZE_MASK);
/* Provide the right address to user, ie without the header */
*pp_AllocBuffer = (uint32_t *)(p_TmpAllocAddr + VIRTUAL_MEMORY_HEADER_SIZE);
/* Actualize the current memory occupation of the shared space */
AmmOccupiedSharedPoolSize = AmmOccupiedSharedPoolSize + BufferSize + VIRTUAL_MEMORY_HEADER_SIZE;
error = AMM_ERROR_OK;
}
else
{
/* Register the callback for a future retry */
pushPending (p_CallBackFunction);
error = AMM_ERROR_ALLOCATION_FAILED;
}
}
else
{
/* Register the callback for a future retry */
pushPending (p_CallBackFunction);
error = AMM_ERROR_BAD_ALLOCATION_SIZE;
}
/* Exit critical section */
UTIL_SEQ_EXIT_CRITICAL_SECTION ();
}
/* A specific ID is requested */
else
{
error = AMM_ERROR_UNKNOWN_ID;
/* Enter critical section */
UTIL_SEQ_ENTER_CRITICAL_SECTION ();
/* Check virtual memory info */
for (uint32_t memIdx = 0x00;
(memIdx < AmmVirtualMemoryNumber) && (error == AMM_ERROR_UNKNOWN_ID);
memIdx++)
{
/* Check if ID is known */
if (VirtualMemoryId == p_AmmVirtualMemoryList[memIdx].Id)
{
/* Check if all the reserved memory has been consumed */
if (p_AmmVirtualMemoryList[memIdx].OccupiedSize < p_AmmVirtualMemoryList[memIdx].RequiredSize)
{
/* Compute what is remaining */
selfAvailable = p_AmmVirtualMemoryList[memIdx].RequiredSize
- p_AmmVirtualMemoryList[memIdx].OccupiedSize;
}
/* Check if there is enough space in the shared pool plus in our virtual memory pool */
if (BufferSize < (AmmPoolSize - AmmOccupiedSharedPoolSize - AmmRequiredVirtualMemorySize + selfAvailable))
{
/* Try Allocation. Do not forget the header */
p_TmpAllocAddr = AmmBmmFunctionsHandler.Allocate ((BufferSize + VIRTUAL_MEMORY_HEADER_SIZE));
/* Check if allocation is OK */
if (p_TmpAllocAddr != NULL)
{
/* Fulfill the header */
*p_TmpAllocAddr = (uint32_t)(((uint32_t)VirtualMemoryId << VIRTUAL_MEMORY_HEADER_ID_POS)
& VIRTUAL_MEMORY_HEADER_ID_MASK)
| ((BufferSize << VIRTUAL_MEMORY_HEADER_BUFFER_SIZE_POS)
& VIRTUAL_MEMORY_HEADER_BUFFER_SIZE_MASK);
/* Provide the right address to user, ie without the header */
*pp_AllocBuffer = (uint32_t *)(p_TmpAllocAddr + VIRTUAL_MEMORY_HEADER_SIZE);
/* Actualize our current memory occupation */
p_AmmVirtualMemoryList[memIdx].OccupiedSize = p_AmmVirtualMemoryList[memIdx].OccupiedSize
+ BufferSize
+ VIRTUAL_MEMORY_HEADER_SIZE;
/* Check for overlapping the reserved memory */
if (p_AmmVirtualMemoryList[memIdx].RequiredSize < p_AmmVirtualMemoryList[memIdx].OccupiedSize)
{
/* Actualize the shared memory occupation */
AmmOccupiedSharedPoolSize = AmmOccupiedSharedPoolSize
+ BufferSize - selfAvailable
+ VIRTUAL_MEMORY_HEADER_SIZE;
}
error = AMM_ERROR_OK;
}
else
{
/* Register the callback for a future retry */
pushPending (p_CallBackFunction);
error = AMM_ERROR_ALLOCATION_FAILED;
}
}
else
{
/* Register the callback for a future retry */
pushPending (p_CallBackFunction);
error = AMM_ERROR_BAD_ALLOCATION_SIZE;
}
}
}
/* Exit critical section */
UTIL_SEQ_EXIT_CRITICAL_SECTION ();
}
return error;
}
AMM_Function_Error_t AMM_Free (uint32_t * const p_BufferAddr)
{
AMM_Function_Error_t error = AMM_ERROR_NOK;
uint8_t virtualId = 0x00;
uint32_t allocatedSize = 0x00;
uint32_t * p_TmpAllocAddr = NULL;
if (AmmInitialized == NOT_INITIALIZED)
{
error = AMM_ERROR_NOT_INIT;
}
else if (p_BufferAddr == NULL)
{
error = AMM_ERROR_BAD_POINTER;
}
else if ((MASK_ALIGNED_32BITS & (uint32_t)p_BufferAddr) != 0)
{
error = AMM_ERROR_NOT_ALIGNED;
}
/* Check if address is managed by this AMM */
else if ((p_BufferAddr > (p_AmmPoolAddress + AmmPoolSize))
|| (p_BufferAddr < p_AmmPoolAddress))
{
error = AMM_ERROR_OUT_OF_RANGE;
}
else
{
/* Enter critical section */
UTIL_SEQ_ENTER_CRITICAL_SECTION ();
/* First correct the address by adding the header */
p_TmpAllocAddr = (uint32_t *)(p_BufferAddr - VIRTUAL_MEMORY_HEADER_SIZE);
/* Get the virtual memory information */
virtualId = (*p_TmpAllocAddr & VIRTUAL_MEMORY_HEADER_ID_MASK) >> VIRTUAL_MEMORY_HEADER_ID_POS;
allocatedSize = (*p_TmpAllocAddr & VIRTUAL_MEMORY_HEADER_BUFFER_SIZE_MASK) >> VIRTUAL_MEMORY_HEADER_BUFFER_SIZE_POS;
/* Free the allocated memory */
AmmBmmFunctionsHandler.Free(p_TmpAllocAddr);
/* Update the occupation counters depending on the ID */
if (virtualId == AMM_NO_VIRTUAL_ID)
{
/* Update the occupation size */
AmmOccupiedSharedPoolSize = AmmOccupiedSharedPoolSize - allocatedSize - VIRTUAL_MEMORY_HEADER_SIZE;
error = AMM_ERROR_OK;
}
else
{
error = AMM_ERROR_UNKNOWN_ID;
for (uint32_t memIdx = 0x00;
(memIdx < AmmVirtualMemoryNumber) && (error == AMM_ERROR_UNKNOWN_ID);
memIdx++)
{
/* Check if it is the right ID */
if (virtualId == p_AmmVirtualMemoryList[memIdx].Id)
{
/* Check if reserved memory is overlapped */
if (p_AmmVirtualMemoryList[memIdx].RequiredSize < p_AmmVirtualMemoryList[memIdx].OccupiedSize)
{
/* Update the occupation size */
AmmOccupiedSharedPoolSize = AmmOccupiedSharedPoolSize
- (p_AmmVirtualMemoryList[memIdx].OccupiedSize
- p_AmmVirtualMemoryList[memIdx].RequiredSize);
}
/* Update the occupation size */
p_AmmVirtualMemoryList[memIdx].OccupiedSize = p_AmmVirtualMemoryList[memIdx].OccupiedSize
- allocatedSize
- VIRTUAL_MEMORY_HEADER_SIZE;
error = AMM_ERROR_OK;
}
}
}
/* Pop pending callbacks and add them to the active fifo */
passPendingToActive ();
/* Exit critical section */
UTIL_SEQ_EXIT_CRITICAL_SECTION ();
/* Ask the user task to proceed to a background process call */
AMM_ProcessRequest();
}
return error;
}
void AMM_BackgroundProcess (void)
{
AMM_VirtualMemoryCallbackFunction_t * p_tmpCallback = NULL;
do
{
/* Pop an active callback request */
p_tmpCallback = popActive();
if (p_tmpCallback != NULL)
{
/* Invoke the callback for an alloc retry */
p_tmpCallback->Callback();
}
}while (p_tmpCallback != NULL);
}
/* Private Functions Definition ------------------------------------------------------*/
void pushPending (AMM_VirtualMemoryCallbackFunction_t * const p_CallbackElt)
{
if (p_CallbackElt != NULL)
{
/* Add the new callback */
LST_insert_tail (&AmmPendingCallback, (tListNode *)p_CallbackElt);
}
}
void passPendingToActive (void)
{
AMM_VirtualMemoryCallbackFunction_t * p_TmpElt = NULL;
while (LST_is_empty (&AmmPendingCallback) == FALSE)
{
/* Remove the head element */
LST_remove_head (&AmmPendingCallback, (tListNode**)&p_TmpElt);
/* Add at the bottom */
LST_insert_tail (&AmmActiveCallback, (tListNode *)p_TmpElt);
}
}
AMM_VirtualMemoryCallbackFunction_t * popActive (void)
{
AMM_VirtualMemoryCallbackFunction_t * p_error = NULL;
if (LST_is_empty (&AmmActiveCallback) == FALSE)
{
/* Remove last element */
LST_remove_head (&AmmActiveCallback, (tListNode**)&p_error);
}
return p_error;
}
@@ -0,0 +1,236 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file advance_memory_manager.h
* @author MCD Application Team
* @brief Header for advance_memory_manager.c module
******************************************************************************
* @attention
*
* Copyright (c) 2022 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef ADVANCED_MEMORY_MANAGER_H
#define ADVANCED_MEMORY_MANAGER_H
/* Includes ------------------------------------------------------------------*/
#include "stm_list.h"
/* Exported defines -----------------------------------------------------------*/
/* Define for No Virtual Memory ID */
#define AMM_NO_VIRTUAL_ID 0x00u
/**
* @brief Size of a virtual memory information element in 32bits
*
* @details At initialization, the Advance Memory Manager allocate as many VM info element as there
* is Virtual Memory to manage.
* Thus user shall provide at the initialization more space for the pool.
*
* ie:
* - sizeOfDesiredPool = 8092
* - numberOfVirtualMemory = 3
* - actualSizeOfThePoolToGive = sizeOfDesiredPool + numberOfVirtualMemory * AMM_VIRTUAL_INFO_ELEMENT_SIZE
*/
#define AMM_VIRTUAL_INFO_ELEMENT_SIZE 0x3u
/* Exported types ------------------------------------------------------------*/
/* Redefine the header for chained list */
typedef tListNode AMM_VirtualMemoryCallbackHeader_t;
/* Function error enumeration */
typedef enum AMM_Function_Error
{
/* No error code */
AMM_ERROR_OK,
/* Error that occurred before any check */
AMM_ERROR_NOK,
/*Bad pointer error */
AMM_ERROR_BAD_POINTER,
/* Bad pool configuration error */
AMM_ERROR_BAD_POOL_CONFIG,
/* Bad virtual memory configuration error */
AMM_ERROR_BAD_VIRTUAL_CONFIG,
/* Bad BMM registration error */
AMM_ERROR_BAD_BMM_REGISTRATION,
/* Bad BMM allocation error */
AMM_ERROR_BAD_BMM_ALLOCATION,
/* Not aligned address error */
AMM_ERROR_NOT_ALIGNED,
/* Out of range error */
AMM_ERROR_OUT_OF_RANGE,
/* Unknown virtual memory manager ID error */
AMM_ERROR_UNKNOWN_ID,
/* Bad allocation size error */
AMM_ERROR_BAD_ALLOCATION_SIZE,
/* Allocation failed error */
AMM_ERROR_ALLOCATION_FAILED,
/* Already initialized AMM error */
AMM_ERROR_ALREADY_INIT,
/* Not initialized AMM error */
AMM_ERROR_NOT_INIT
} AMM_Function_Error_t;
/**
* @brief Virtual Memory configuration struct
*/
typedef struct AMM_VirtualMemoryConfig
{
/* ID of the Virtual Memory */
uint8_t Id;
/* Size of the Virtual Memory buffer with a multiple of 32bits.
ie: BufferSize = 4; TotalSize = BufferSize * 32bits
= 4 * 32bits
= 128 bits */
uint32_t BufferSize;
}AMM_VirtualMemoryConfig_t;
/**
* @brief Basic Memory Manager functions struct
*
* @details Structure that handles all the required functions of the Basic Memory Manager.
*/
typedef struct AMM_BasicMemoryManagerFunctions
{
/* Basic Memory Manager Init function - Shall be in bytes - */
void (* Init) (uint32_t * const p_PoolAddr, const uint32_t PoolSize);
/* Basic Memory Manager Allocate function - Shall be in bytes - */
uint32_t * (* Allocate) (const uint32_t BufferSize);
/* Basic Memory Manager Free function */
void (* Free) (uint32_t * const p_BufferAddr);
}AMM_BasicMemoryManagerFunctions_t;
/**
* @brief Advance Memory Manager init struct
*
* @details Structure that contains all the needed parameters to initialize the
* Advance Memory Manager.
*/
typedef struct AMM_InitParameters
{
/* Address of the pool of memory to manage */
uint32_t * p_PoolAddr;
/* Size of the pool with a multiple of 32bits.
ie: PoolSize = 4; TotalSize = PoolSize * 32bits
= 4 * 32bits
= 128 bits */
uint32_t PoolSize;
/* Number of Virtual Memory to create */
uint32_t VirtualMemoryNumber;
/* List of the Virtual Memory configurations */
AMM_VirtualMemoryConfig_t * p_VirtualMemoryConfigList;
}AMM_InitParameters_t;
/**
* @brief Virtual Memory Callback function struct
*/
typedef struct AMM_VirtualMemoryCallbackFunction
{
/* Next and previous callbacks in the list */
AMM_VirtualMemoryCallbackHeader_t Header;
/* Callback function pointer to invoke once memory has been freed */
void (* Callback) (void);
}AMM_VirtualMemoryCallbackFunction_t;
/* Exported constants --------------------------------------------------------*/
/* External variables --------------------------------------------------------*/
/* Exported macros -----------------------------------------------------------*/
/* Exported functions prototypes ---------------------------------------------*/
/**
* @brief Initialize the Advance Memory Manager Pool
* @param p_InitParams: Struct of init parameters
* @return Status of the initialization
* @retval AMM_Function_Error_t::AMM_ERROR_OK
* @retval AMM_Function_Error_t::AMM_ERROR_NOK
* @retval AMM_Function_Error_t::AMM_ERROR_ALREADY_INIT
* @retval AMM_Function_Error_t::AMM_ERROR_BAD_POINTER
* @retval AMM_Function_Error_t::AMM_ERROR_BAD_POOL_CONFIG
* @retval AMM_Function_Error_t::AMM_ERROR_BAD_VIRTUAL_CONFIG
* @retval AMM_Function_Error_t::AMM_ERROR_BAD_BMM_REGISTRATION
* @retval AMM_Function_Error_t::AMM_ERROR_BAD_BMM_ALLOCATION
*/
AMM_Function_Error_t AMM_Init (const AMM_InitParameters_t * const p_InitParams);
/**
* @brief DeInitialize the Advance Memory Manager Pool
* @details This function shall be called once every allocated memory has been freed
* @return Status of the initialization
* @retval AMM_Function_Error_t::AMM_ERROR_OK
* @retval AMM_Function_Error_t::AMM_ERROR_NOK
* @retval AMM_Function_Error_t::AMM_ERROR_NOT_INIT
*/
AMM_Function_Error_t AMM_DeInit (void);
/**
* @brief Allocate a buffer from the Advance Memory Manager Pool
* @param VirtualMemoryId: Virtual Memory Identifier - AMM_NO_VIRTUAL_ID Can be used -
* @param BufferSize: Size of the pool with a multiple of 32bits.
ie: BufferSize = 4; TotalSize = BufferSize * 32bits
= 4 * 32bits
= 128 bits
* @param p_CallBackFunction: Pointer onto the Callback to call in case of failure - Can be NULL -
* @param pp_AllocBuffer: Pointer onto the allocated buffer
* @return Status of the allocation
* @retval AMM_Function_Error_t::AMM_ERROR_OK
* @retval AMM_Function_Error_t::AMM_ERROR_NOK
* @retval AMM_Function_Error_t::AMM_ERROR_NOT_INIT
* @retval AMM_Function_Error_t::AMM_ERROR_BAD_POINTER
* @retval AMM_Function_Error_t::AMM_ERROR_UNKNOWN_ID
* @retval AMM_Function_Error_t::AMM_ERROR_BAD_ALLOCATION_SIZE
* @retval AMM_Function_Error_t::AMM_ERROR_ALLOCATION_FAILED
*/
AMM_Function_Error_t AMM_Alloc (const uint8_t VirtualMemoryId,
const uint32_t BufferSize,
uint32_t ** pp_AllocBuffer,
AMM_VirtualMemoryCallbackFunction_t * const p_CallBackFunction);
/**
* @brief Free the allocated buffer from the Advance Memory Manager Pool
* @param p_BufferAddr: Address of the buffer to free
* @return Status of the free
* @retval AMM_Function_Error_t::AMM_ERROR_OK
* @retval AMM_Function_Error_t::AMM_ERROR_NOK
* @retval AMM_Function_Error_t::AMM_ERROR_NOT_INIT
* @retval AMM_Function_Error_t::AMM_ERROR_BAD_POINTER
* @retval AMM_Function_Error_t::AMM_ERROR_NOT_ALIGNED
* @retval AMM_Function_Error_t::AMM_ERROR_OUT_OF_RANGE
* @retval AMM_Function_Error_t::AMM_ERROR_UNKNOWN_ID
*/
AMM_Function_Error_t AMM_Free (uint32_t * const p_BufferAddr);
/**
* @brief Background routine
* @details Background routine that aims to call registered callbacks for an allocation retry
* @return None
*/
void AMM_BackgroundProcess (void);
/* Exported functions to be implemented by the user if required ------------- */
/**
* @brief Register the Basic Memory Manager functions to use
* @param p_BasicMemoryManagerFunctions: Address of the basic memory manager functions
* @return None
*/
void AMM_RegisterBasicMemoryManager (AMM_BasicMemoryManagerFunctions_t * const p_BasicMemoryManagerFunctions);
/**
* @brief Request to application for a Background process run
* @return None
*/
void AMM_ProcessRequest (void);
#endif /* ADVANCED_MEMORY_MANAGER_H */
@@ -0,0 +1,360 @@
/**
******************************************************************************
* @file dbg_trace.c
* @author MCD Application Team
* @brief This file contains the Interface with BLE Drivers functions.
******************************************************************************
* @attention
*
* Copyright (c) 2018-2021 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "utilities_common.h"
#include "stm_queue.h"
#include "dbg_trace.h"
/* Definition of the function */
#if !defined(__GNUC__) /* SW4STM32 */
size_t __write(int handle, const unsigned char * buf, size_t bufSize);
#endif
/** @addtogroup TRACE
* @{
*/
/** @defgroup TRACE_LOG
* @brief TRACE Logging functions
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/** @defgroup TRACE Log private typedef
* @{
*/
/**
* @}
*/
/* Private defines -----------------------------------------------------------*/
/** @defgroup TRACE Log private defines
* @{
*/
/**
* @}
*/
/* Private macros ------------------------------------------------------------*/
/** @defgroup TRACE Log private macros
* @{
*/
/**
* @}
*/
/* Private variables ---------------------------------------------------------*/
/** @defgroup TRACE Log private variables
* @{
*/
#if (( CFG_DEBUG_TRACE_FULL != 0 ) || ( CFG_DEBUG_TRACE_LIGHT != 0 ))
#if (DBG_TRACE_USE_CIRCULAR_QUEUE != 0)
static queue_t MsgDbgTraceQueue;
static uint8_t MsgDbgTraceQueueBuff[DBG_TRACE_MSG_QUEUE_SIZE];
#endif
__IO ITStatus DbgTracePeripheralReady = SET;
#endif
/**
* @}
*/
/* Global variables ----------------------------------------------------------*/
/** @defgroup TRACE Log Global variable
* @{
*/
/**
* @}
*/
/* Private function prototypes -----------------------------------------------*/
/** @defgroup TRACE Log private function prototypes
* @{
*/
#if (( CFG_DEBUG_TRACE_FULL != 0 ) || ( CFG_DEBUG_TRACE_LIGHT != 0 ))
static void DbgTrace_TxCpltCallback(void);
#endif
/**
* @}
*/
/* Private Functions Definition ------------------------------------------------------*/
/** @defgroup TRACE Log Private function
* @{
*/
/* Functions Definition ------------------------------------------------------*/
/** @defgroup TRACE Log APIs
* @{
*/
/**
* @brief DbgTraceGetFileName: Return filename string extracted from full path information
* @param *fullPath Fullpath string (path + filename)
* @retval char* Pointer on filename string
*/
const char *DbgTraceGetFileName(const char *fullpath)
{
const char *ret = fullpath;
if (strrchr(fullpath, '\\') != NULL)
{
ret = strrchr(fullpath, '\\') + 1;
}
else if (strrchr(fullpath, '/') != NULL)
{
ret = strrchr(fullpath, '/') + 1;
}
return ret;
}
/**
* @brief DbgTraceBuffer: Output buffer content information to output Stream
* @param *pBuffer Pointer on buffer to be output
* @param u32Length buffer Size
* @paramt strFormat string as expected by "printf" function. Used to desrcibe buffer content information.
* @param ... Parameters to be "formatted" in strFormat string (if any)
* @retval None
*/
void DbgTraceBuffer(const void *pBuffer, uint32_t u32Length, const char *strFormat, ...)
{
va_list vaArgs;
uint32_t u32Index;
va_start(vaArgs, strFormat);
vprintf(strFormat, vaArgs);
va_end(vaArgs);
for (u32Index = 0; u32Index < u32Length; u32Index ++)
{
printf(" %02X", ((const uint8_t *) pBuffer)[u32Index]);
}
}
#if (( CFG_DEBUG_TRACE_FULL != 0 ) || ( CFG_DEBUG_TRACE_LIGHT != 0 ))
/**
* @brief DBG_TRACE USART Tx Transfer completed callback
* @param UartHandle: UART handle.
* @note Indicate the end of the transmission of a DBG_TRACE trace buffer to DBG_TRACE USART. If queue
* contains new trace data to transmit, start a new transmission.
* @retval None
*/
static void DbgTrace_TxCpltCallback(void)
{
#if (DBG_TRACE_USE_CIRCULAR_QUEUE != 0)
uint8_t* buf;
uint16_t bufSize;
BACKUP_PRIMASK();
DISABLE_IRQ(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/
/* Remove element just sent to UART */
CircularQueue_Remove(&MsgDbgTraceQueue,&bufSize);
/* Sense if new data to be sent */
buf=CircularQueue_Sense(&MsgDbgTraceQueue,&bufSize);
if ( buf != NULL)
{
RESTORE_PRIMASK();
DbgOutputTraces((uint8_t*)buf, bufSize, DbgTrace_TxCpltCallback);
}
else
{
DbgTracePeripheralReady = SET;
RESTORE_PRIMASK();
}
#else
BACKUP_PRIMASK();
DISABLE_IRQ(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/
DbgTracePeripheralReady = SET;
RESTORE_PRIMASK();
#endif
}
#endif
void DbgTraceInit( void )
{
#if (( CFG_DEBUG_TRACE_FULL != 0 ) || ( CFG_DEBUG_TRACE_LIGHT != 0 ))
DbgOutputInit();
#if (DBG_TRACE_USE_CIRCULAR_QUEUE != 0)
CircularQueue_Init(&MsgDbgTraceQueue, MsgDbgTraceQueueBuff, DBG_TRACE_MSG_QUEUE_SIZE, 0, CIRCULAR_QUEUE_SPLIT_IF_WRAPPING_FLAG);
#endif
#endif
return;
}
#if (( CFG_DEBUG_TRACE_FULL != 0 ) || ( CFG_DEBUG_TRACE_LIGHT != 0 ))
#if defined(__GNUC__) /* SW4STM32 (GCC) */
/**
* @brief _write: override the __write standard lib function to redirect printf to USART.
* @param handle output handle (STDIO, STDERR...)
* @param buf buffer to write
* @param bufsize buffer size
* @param ...: arguments to be formatted in format string
* @retval none
*/
size_t _write(int handle, const unsigned char * buf, size_t bufSize)
{
return ( DbgTraceWrite(handle, buf, bufSize) );
}
#else
/**
* @brief __write: override the _write standard lib function to redirect printf to USART.
* @param handle output handle (STDIO, STDERR...)
* @param buf buffer to write
* @param bufsize buffer size
* @param ...: arguments to be formatted in format string
* @retval none
*/
size_t __write(int handle, const unsigned char * buf, size_t bufSize)
{
return ( DbgTraceWrite(handle, buf, bufSize) );
}
#endif /* #if defined(__GNUC__) */
/**
* @brief Override the standard lib function to redirect printf to USART.
* @param handle output handle (STDIO, STDERR...)
* @param buf buffer to write
* @param bufsize buffer size
* @retval Number of elements written
*/
size_t DbgTraceWrite(int handle, const unsigned char * buf, size_t bufSize)
{
size_t chars_written = 0;
uint8_t* buffer;
BACKUP_PRIMASK();
/* Ignore flushes */
if ( handle == -1 )
{
chars_written = ( size_t ) 0;
}
/* Only allow stdout/stderr output */
else if ( ( handle != 1 ) && ( handle != 2 ) )
{
chars_written = ( size_t ) - 1;
}
/* Parameters OK, call the low-level character output routine */
else if (bufSize != 0)
{
chars_written = bufSize;
/* If queue emepty and TX free, send directly */
/* CS Start */
#if (DBG_TRACE_USE_CIRCULAR_QUEUE != 0)
DISABLE_IRQ(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/
buffer=CircularQueue_Add(&MsgDbgTraceQueue,(uint8_t*)buf, bufSize,1);
if (buffer && DbgTracePeripheralReady)
{
DbgTracePeripheralReady = RESET;
RESTORE_PRIMASK();
DbgOutputTraces((uint8_t*)buffer, bufSize, DbgTrace_TxCpltCallback);
}
else
{
RESTORE_PRIMASK();
}
#else
DISABLE_IRQ(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/
DbgTracePeripheralReady = RESET;
RESTORE_PRIMASK();
DbgOutputTraces((uint8_t*)buf, bufSize, DbgTrace_TxCpltCallback);
while (!DbgTracePeripheralReady);
#endif
/* CS END */
}
return ( chars_written );
}
#if defined ( __CC_ARM ) || defined (__ARMCC_VERSION) /* Keil */
/**
Called from assert() and prints a message on stderr and calls abort().
\param[in] expr assert expression that was not TRUE
\param[in] file source file of the assertion
\param[in] line source line of the assertion
*/
__attribute__((weak,noreturn))
void __aeabi_assert (const char *expr, const char *file, int line) {
char str[12], *p;
fputs("*** assertion failed: ", stderr);
fputs(expr, stderr);
fputs(", file ", stderr);
fputs(file, stderr);
fputs(", line ", stderr);
p = str + sizeof(str);
*--p = '\0';
*--p = '\n';
while (line > 0) {
*--p = '0' + (line % 10);
line /= 10;
}
fputs(p, stderr);
abort();
}
/* For KEIL re-implement our own version of fputc */
int fputc(int ch, FILE *f)
{
/* temp char avoids endianness issue */
char tempch = ch;
/* Write one character to Debug Circular Queue */
DbgTraceWrite(1U, (const unsigned char *) &tempch, 1);
return ch;
}
#endif /* #if defined ( __CC_ARM ) */
#endif /* #if (( CFG_DEBUG_TRACE_FULL != 0 ) || ( CFG_DEBUG_TRACE_LIGHT != 0 )) */
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
@@ -0,0 +1,103 @@
/**
******************************************************************************
* @file dbg_trace.h
* @author MCD Application Team
* @brief Header for dbg_trace.c
******************************************************************************
* @attention
*
* Copyright (c) 2018-2021 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __DBG_TRACE_H
#define __DBG_TRACE_H
#ifdef __cplusplus
extern "C"
{
#endif
/* Exported types ------------------------------------------------------------*/
/* External variables --------------------------------------------------------*/
/* Exported macros -----------------------------------------------------------*/
#if ( ( CFG_DEBUG_TRACE_FULL != 0 ) || ( CFG_DEBUG_TRACE_LIGHT != 0 ) )
#define PRINT_LOG_BUFF_DBG(...) DbgTraceBuffer(__VA_ARGS__)
#if ( CFG_DEBUG_TRACE_FULL != 0 )
#define PRINT_MESG_DBG(...) do{printf("\r\n [%s][%s][%d] ", DbgTraceGetFileName(__FILE__),__FUNCTION__,__LINE__);printf(__VA_ARGS__);}while(0);
#else
#define PRINT_MESG_DBG printf
#endif
#else
#define PRINT_LOG_BUFF_DBG(...)
#define PRINT_MESG_DBG(...)
#endif
#define PRINT_NO_MESG(...)
/* Exported functions ------------------------------------------------------- */
/**
* @brief Request the user to initialize the peripheral to output traces
*
* @param None
* @retval None
*/
extern void DbgOutputInit( void );
/**
* @brief Request the user to sent the traces on the output peripheral
*
* @param p_data: Address of the buffer to be sent
* @param size: Size of the data to be sent
* @param cb: Function to be called when the data has been sent
* @retval None
*/
extern void DbgOutputTraces( uint8_t *p_data, uint16_t size, void (*cb)(void) );
/**
* @brief DbgTraceInit Initialize Logging feature.
*
* @param: None
* @retval: None
*/
void DbgTraceInit( void );
/**********************************************************************************************************************/
/** This function outputs into the log the buffer (in hex) and the provided format string and arguments.
***********************************************************************************************************************
*
* @param pBuffer Buffer to be output into the logs.
* @param u32Length Length of the buffer, in bytes.
* @param strFormat The format string in printf() style.
* @param ... Arguments of the format string.
*
**********************************************************************************************************************/
void DbgTraceBuffer( const void *pBuffer , uint32_t u32Length , const char *strFormat , ... );
const char *DbgTraceGetFileName( const char *fullpath );
/**
* @brief Override the standard lib function to redirect printf to USART.
* @param handle output handle (STDIO, STDERR...)
* @param buf buffer to write
* @param bufsize buffer size
* @retval Number of elements written
*/
size_t DbgTraceWrite(int handle, const unsigned char * buf, size_t bufSize);
#ifdef __cplusplus
}
#endif
#endif /*__DBG_TRACE_H */
@@ -0,0 +1,233 @@
/**
******************************************************************************
* @file fmm.c
* @author MCD Application Team
* @brief Fifo based Memory Manager
******************************************************************************
* @attention
*
* Copyright (c) 2018-2021 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "common.h"
#include "fmm.h"
/* Private typedef -----------------------------------------------------------*/
typedef enum
{
FREE,
RESERVED,
CLOSED
} BufferStatus_e;
typedef PACKED_STRUCT {
uint8_t BufferStatus;
FMM_Mem_Id MemId;
uint16_t BufferSize;
} TL_PacketHeader_t;
typedef struct{
TL_PacketHeader_t pHeadMemory;
TL_PacketHeader_t pEndMemory;
TL_PacketHeader_t pCurFreeMemory;
pFMM_Callback Callback;
uint16_t MemReqCallback;
uint16_t CurFreeSize;
uint16_t HeadFreeSize;
} MemManager_t;
/* Private defines -----------------------------------------------------------*/
/* Private macros ------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
MemManager_t MemManager[FMM_MGR_NBR];
/* Global variables ----------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
static uint16_t GetMemAvailable( FMM_Mem_Id Mem_id );
static void CheckCallback( FMM_Mem_Id Mem_id );
static void UpdatePtr( FMM_Mem_Id Mem_id, TL_PacketHeader_t *pPtr, uint16_t *pFreeSizeValue );
/* Functions Definition ------------------------------------------------------*/
FMM_Init( FMM_Mem_Id Mem_id, pFMM_MemAdd pMemAdd, uint16_t MemSize )
{
MemManager[Mem_id].pCurFreeMemory.BufferStatus = FREE;
MemManager[Mem_id].pHeadMemory = pMemAdd;
MemManager[Mem_id].pEndMemory = ((uint8_t*)pMemAdd) + 4*DIVF( MemSize, 4 );
MemManager[Mem_id].pCurFreeMemory = pMemAdd;
MemManager[Mem_id].CurFreeSize = ( 4*DIVF( MemSize, 4 ) - sizeof(TL_PacketHeader_t) );
MemManager[Mem_id].HeadFreeSize = 0;
MemManager[Mem_id].pCurFreeMemory.MemId = Mem_id;
MemManager[Mem_id].MemReqCallback = 0;
return;
}
void FMM_ReleaseBuffer( pFMM_MemAdd pMemAdd )
{
TL_PacketHeader_t *pbuffer;
FMM_Mem_Id mem_id;
uint8_t *pend_head_mem;
pbuffer = ((TL_PacketHeader_t *)pMemAdd) - 1;
mem_id = pbuffer->MemId;
pbuffer->BufferStatus = FREE;
UpdatePtr( mem_id, MemManager[mem_id].pHeadMemory, MemManager[mem_id].HeadFreeSize );
pend_head_mem = ((uint8_t*)MemManager[mem_id].pHeadMemory) + MemManager[mem_id].HeadFreeSize + sizeof( TL_PacketHeader_t );
if (pend_head_mem == ((uint8_t*)MemManager[mem_id].pEndMemory))
{
MemManager[mem_id].HeadFreeSize = 0;
MemManager[mem_id].CurFreeSize = (MemManager[mem_id].pHeadMemory - MemManager[mem_id].pEndMemory) - 1;
MemManager[mem_id].pCurFreeMemory = MemManager[mem_id].pHeadMemory;
if (MemManager[mem_id].MemReqCallback)
{
MemManager[mem_id].MemReqCallback = 0;
FMM_Notification(MemManager[mem_id].Callback);
}
}
else
{
UpdatePtr( mem_id, MemManager[mem_id].pCurFreeMemory, MemManager[mem_id].CurFreeSize );
CheckCallback( mem_id );
}
return;
}
pFMM_MemAdd FMM_GetBuffer( FMM_Mem_Id Mem_id, uint16_t Size, pFMM_Callback Callback )
{
pFMM_MemAdd retvalue;
if( ( 4*DIVC( Size, 4 ) ) <= GetMemAvailable( Mem_id ))
{
if ( MemManager[Mem_id].pCurFreeMemory.BufferStatus != FREE )
{
FMM_UpdateBufferSize( MemManager[Mem_id].pCurFreeMemory, MemManager[Mem_id].pCurFreeMemory.BufferSize);
}
MemManager[Mem_id].pCurFreeMemory.BufferStatus = RESERVED;
MemManager[Mem_id].pCurFreeMemory.BufferSize = ( 4*DIVC( Size, 4 ) );
MemManager[Mem_id].CurFreeSize -= ( 4*DIVC( Size, 4 ) );
retvalue = (pFMM_MemAdd)(MemManager[Mem_id].pCurFreeMemory + 1) ;
}
else
{
MemManager[Mem_id].MemReqCallback = ( 4*DIVC( Size, 4 ) );
MemManager[Mem_id].Callback = Callback;
retvalue = 0;
}
return ( retvalue);
}
void FMM_UpdateBufferSize( pFMM_MemAdd pMemAdd, uint16_t Size)
{
TL_PacketHeader_t *pbuffer;
FMM_Mem_Id mem_id;
pbuffer = ((TL_PacketHeader_t *)pMemAdd) - 1;
mem_id = pbuffer->MemId;
if(pbuffer->BufferStatus == RESERVED)
{
pbuffer->BufferStatus = CLOSED;
MemManager[mem_id].CurFreeSize += (pbuffer->BufferSize + ( (4*DIVC( Size, 4 ) ));
pbuffer->BufferSize = ( 4*DIVC( Size, 4 ) );
if(MemManager[mem_id].CurFreeSize)
{
(uint8_t*)MemManager[mem_id].pCurFreeMemory += ( 4*DIVC( Size, 4 ) );
MemManager[mem_id].pCurFreeMemory.BufferStatus = FREE;
}
else
{
MemManager[mem_id].pCurFreeMemory = MemManager[mem_id].pHeadMemory;
MemManager[mem_id].CurFreeSize = MemManager[mem_id].HeadFreeSize;
MemManager[mem_id].HeadFreeSize = 0;
}
}
return;
}
/**********************************************************************************************************************/
static uint16_t GetMemAvailable( FMM_Mem_Id Mem_id )
{
uint16_t ret_size;
uint8_t *pend_cur_free_mem;
pend_cur_free_mem = ((uint8_t*)MemManager[Mem_id].pCurFreeMemory) + MemManager[Mem_id].CurFreeSize + sizeof( TL_PacketHeader_t );
if (pend_cur_free_mem == ((uint8_t*)MemManager[Mem_id].pEndMemory))
{
ret_size = MAX( MemManager[Mem_id].CurFreeSize, MemManager[Mem_id].HeadFreeSize );
}
else
{
ret_size = MemManager[Mem_id].CurFreeSize;
}
return ( ret_size );
}
static void CheckCallback( FMM_Mem_Id Mem_id )
{
uint16_t mem_available;
if(MemManager[Mem_id].MemReqCallback)
{
mem_available = GetMemAvailable( Mem_id );
if(MemManager[Mem_id].MemReqCallback <= mem_available)
{
MemManager[Mem_id].MemReqCallback = 0;
FMM_Notification(MemManager[Mem_id].Callback);
}
}
return;
}
static void UpdatePtr( FMM_Mem_Id Mem_id, TL_PacketHeader_t *pPtr, uint16_t *pFreeSizeValue )
{
TL_PacketHeader_t *pmem;
uint8_t update_done = FALSE;
while(update_done == FALSE)
{
(uint8_t*)pmem = ((uint8_t*)pPtr) + (*pFreeSizeValue);
if ((pmem + sizeof( TL_PacketHeader_t )) != ((uint8_t*)MemManager[Mem_id].pEndMemory))
{
if(pmem->BufferStatus == FREE)
{
(*pFreeSizeValue) += pmem->BufferSize;
}
else
{
update_done = TRUE;
}
}
else
{
update_done = TRUE;
}
}
return;
}
@@ -0,0 +1,43 @@
/**
******************************************************************************
* @file fmm.h
* @author MCD Application Team
* @brief Header for Fifo based Memory Manager
******************************************************************************
* @attention
*
* Copyright (c) 2018-2021 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __FMM_H
#define __FMM_H
/* Includes ------------------------------------------------------------------*/
/* Exported defines -----------------------------------------------------------*/
/* Exported types ------------------------------------------------------------*/
typedef uint8_t FMM_Mem_Id;
typedef uint32_t* pFMM_MemAdd;
typedef void ( *pFMM_Callback )( void );
/* Exported constants --------------------------------------------------------*/
/* External variables --------------------------------------------------------*/
/* Exported macros -----------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
FMM_Init( FMM_Mem_Id Mem_id, pFMM_MemAdd pMemAdd, uint16_t MemSize );
pFMM_MemAdd FMM_GetBuffer( FMM_Mem_Id Mem_id, uint16_t Size, pFMM_Callback Callback );
void FMM_UpdateBufferSize( pFMM_MemAdd pMemAdd, uint16_t Size);
void FMM_ReleaseBuffer( pFMM_MemAdd pMemAdd );
void FMM_Notification( pFMM_Callback pCallback );
#endif /*__FMM_H */
@@ -0,0 +1,494 @@
/*
* FreeRTOS Kernel V10.4.1
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/*
* A sample implementation of pvPortMalloc() and vPortFree() that combines
* (coalescences) adjacent memory blocks as they are freed, and in so doing
* limits memory fragmentation.
*
* See heap_1.c, heap_2.c and heap_3.c for alternative implementations, and the
* memory management pages of https://www.FreeRTOS.org for more information.
*/
#include <stdlib.h>
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
* all the API functions to use the MPU wrappers. That should only be done when
* task.h is included from an application file. */
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
#include "FreeRTOS.h"
#include "task.h"
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 0 )
#error This file must not be used if configSUPPORT_DYNAMIC_ALLOCATION is 0
#endif
/* Block sizes must not get too small. */
#define heapMINIMUM_BLOCK_SIZE ( ( size_t ) ( xHeapStructSize << 1 ) )
/* Assumes 8bit bytes! */
#define heapBITS_PER_BYTE ( ( size_t ) 8 )
/* Allocate the memory for the heap. */
#if ( configAPPLICATION_ALLOCATED_HEAP == 1 )
/* The application writer has already defined the array used for the RTOS
* heap - probably so it can be placed in a special segment or address. */
extern uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
#else
PRIVILEGED_DATA static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
#endif /* configAPPLICATION_ALLOCATED_HEAP */
/* Define the linked list structure. This is used to link free blocks in order
* of their memory address. */
typedef struct A_BLOCK_LINK
{
struct A_BLOCK_LINK * pxNextFreeBlock; /*<< The next free block in the list. */
size_t xBlockSize; /*<< The size of the free block. */
} BlockLink_t;
/*-----------------------------------------------------------*/
/*
* Inserts a block of memory that is being freed into the correct position in
* the list of free memory blocks. The block being freed will be merged with
* the block in front it and/or the block behind it if the memory blocks are
* adjacent to each other.
*/
static void prvInsertBlockIntoFreeList( BlockLink_t * pxBlockToInsert ) PRIVILEGED_FUNCTION;
/*
* Called automatically to setup the required heap structures the first time
* pvPortMalloc() is called.
*/
static void prvHeapInit( void ) PRIVILEGED_FUNCTION;
/*-----------------------------------------------------------*/
/* The size of the structure placed at the beginning of each allocated memory
* block must by correctly byte aligned. */
static const size_t xHeapStructSize = ( sizeof( BlockLink_t ) + ( ( size_t ) ( portBYTE_ALIGNMENT - 1 ) ) ) & ~( ( size_t ) portBYTE_ALIGNMENT_MASK );
/* Create a couple of list links to mark the start and end of the list. */
PRIVILEGED_DATA static BlockLink_t xStart, * pxEnd = NULL;
/* Keeps track of the number of calls to allocate and free memory as well as the
* number of free bytes remaining, but says nothing about fragmentation. */
PRIVILEGED_DATA static size_t xFreeBytesRemaining = 0U;
PRIVILEGED_DATA static size_t xMinimumEverFreeBytesRemaining = 0U;
PRIVILEGED_DATA static size_t xNumberOfSuccessfulAllocations = 0;
PRIVILEGED_DATA static size_t xNumberOfSuccessfulFrees = 0;
/* Gets set to the top bit of an size_t type. When this bit in the xBlockSize
* member of an BlockLink_t structure is set then the block belongs to the
* application. When the bit is free the block is still part of the free heap
* space. */
PRIVILEGED_DATA static size_t xBlockAllocatedBit = 0;
/*-----------------------------------------------------------*/
void * pvPortMalloc( size_t xWantedSize )
{
BlockLink_t * pxBlock, * pxPreviousBlock, * pxNewBlockLink;
void * pvReturn = NULL;
vTaskSuspendAll();
{
/* If this is the first call to malloc then the heap will require
* initialisation to setup the list of free blocks. */
if( pxEnd == NULL )
{
prvHeapInit();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* Check the requested block size is not so large that the top bit is
* set. The top bit of the block size member of the BlockLink_t structure
* is used to determine who owns the block - the application or the
* kernel, so it must be free. */
if( ( xWantedSize & xBlockAllocatedBit ) == 0 )
{
/* The wanted size is increased so it can contain a BlockLink_t
* structure in addition to the requested amount of bytes. */
if( xWantedSize > 0 )
{
xWantedSize += xHeapStructSize;
/* Ensure that blocks are always aligned to the required number
* of bytes. */
if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0x00 )
{
/* Byte alignment required. */
xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );
configASSERT( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) == 0 );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining ) )
{
/* Traverse the list from the start (lowest address) block until
* one of adequate size is found. */
pxPreviousBlock = &xStart;
pxBlock = xStart.pxNextFreeBlock;
while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) )
{
pxPreviousBlock = pxBlock;
pxBlock = pxBlock->pxNextFreeBlock;
}
/* If the end marker was reached then a block of adequate size
* was not found. */
if( pxBlock != pxEnd )
{
/* Return the memory space pointed to - jumping over the
* BlockLink_t structure at its start. */
pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + xHeapStructSize );
/* This block is being returned for use so must be taken out
* of the list of free blocks. */
pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;
/* If the block is larger than required it can be split into
* two. */
if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE )
{
/* This block is to be split into two. Create a new
* block following the number of bytes requested. The void
* cast is used to prevent byte alignment warnings from the
* compiler. */
pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize );
configASSERT( ( ( ( size_t ) pxNewBlockLink ) & portBYTE_ALIGNMENT_MASK ) == 0 );
/* Calculate the sizes of two blocks split from the
* single block. */
pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;
pxBlock->xBlockSize = xWantedSize;
/* Insert the new block into the list of free blocks. */
prvInsertBlockIntoFreeList( pxNewBlockLink );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
xFreeBytesRemaining -= pxBlock->xBlockSize;
if( xFreeBytesRemaining < xMinimumEverFreeBytesRemaining )
{
xMinimumEverFreeBytesRemaining = xFreeBytesRemaining;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* The block is being returned - it is allocated and owned
* by the application and has no "next" block. */
pxBlock->xBlockSize |= xBlockAllocatedBit;
pxBlock->pxNextFreeBlock = NULL;
xNumberOfSuccessfulAllocations++;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
traceMALLOC( pvReturn, xWantedSize );
}
( void ) xTaskResumeAll();
#if ( configUSE_MALLOC_FAILED_HOOK == 1 )
{
if( pvReturn == NULL )
{
extern void vApplicationMallocFailedHook( void );
vApplicationMallocFailedHook();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#endif /* if ( configUSE_MALLOC_FAILED_HOOK == 1 ) */
configASSERT( ( ( ( size_t ) pvReturn ) & ( size_t ) portBYTE_ALIGNMENT_MASK ) == 0 );
return pvReturn;
}
/*-----------------------------------------------------------*/
void vPortFree( void * pv )
{
uint8_t * puc = ( uint8_t * ) pv;
BlockLink_t * pxLink;
if( pv != NULL )
{
/* The memory being freed will have an BlockLink_t structure immediately
* before it. */
puc -= xHeapStructSize;
/* This casting is to keep the compiler from issuing warnings. */
pxLink = ( void * ) puc;
/* Check the block is actually allocated. */
configASSERT( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 );
configASSERT( pxLink->pxNextFreeBlock == NULL );
if( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 )
{
if( pxLink->pxNextFreeBlock == NULL )
{
/* The block is being returned to the heap - it is no longer
* allocated. */
pxLink->xBlockSize &= ~xBlockAllocatedBit;
vTaskSuspendAll();
{
/* Add this block to the list of free blocks. */
xFreeBytesRemaining += pxLink->xBlockSize;
traceFREE( pv, pxLink->xBlockSize );
prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) );
xNumberOfSuccessfulFrees++;
}
( void ) xTaskResumeAll();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
}
/*-----------------------------------------------------------*/
size_t xPortGetFreeHeapSize( void )
{
return xFreeBytesRemaining;
}
/*-----------------------------------------------------------*/
size_t xPortGetMinimumEverFreeHeapSize( void )
{
return xMinimumEverFreeBytesRemaining;
}
/*-----------------------------------------------------------*/
void vPortInitialiseBlocks( void )
{
/* This just exists to keep the linker quiet. */
}
/*-----------------------------------------------------------*/
static void prvHeapInit( void ) /* PRIVILEGED_FUNCTION */
{
BlockLink_t * pxFirstFreeBlock;
uint8_t * pucAlignedHeap;
size_t uxAddress;
size_t xTotalHeapSize = configTOTAL_HEAP_SIZE;
/* Ensure the heap starts on a correctly aligned boundary. */
uxAddress = ( size_t ) ucHeap;
if( ( uxAddress & portBYTE_ALIGNMENT_MASK ) != 0 )
{
uxAddress += ( portBYTE_ALIGNMENT - 1 );
uxAddress &= ~( ( size_t ) portBYTE_ALIGNMENT_MASK );
xTotalHeapSize -= uxAddress - ( size_t ) ucHeap;
}
pucAlignedHeap = ( uint8_t * ) uxAddress;
/* xStart is used to hold a pointer to the first item in the list of free
* blocks. The void cast is used to prevent compiler warnings. */
xStart.pxNextFreeBlock = ( void * ) pucAlignedHeap;
xStart.xBlockSize = ( size_t ) 0;
/* pxEnd is used to mark the end of the list of free blocks and is inserted
* at the end of the heap space. */
uxAddress = ( ( size_t ) pucAlignedHeap ) + xTotalHeapSize;
uxAddress -= xHeapStructSize;
uxAddress &= ~( ( size_t ) portBYTE_ALIGNMENT_MASK );
pxEnd = ( void * ) uxAddress;
pxEnd->xBlockSize = 0;
pxEnd->pxNextFreeBlock = NULL;
/* To start with there is a single free block that is sized to take up the
* entire heap space, minus the space taken by pxEnd. */
pxFirstFreeBlock = ( void * ) pucAlignedHeap;
pxFirstFreeBlock->xBlockSize = uxAddress - ( size_t ) pxFirstFreeBlock;
pxFirstFreeBlock->pxNextFreeBlock = pxEnd;
/* Only one block exists - and it covers the entire usable heap space. */
xMinimumEverFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;
xFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;
/* Work out the position of the top bit in a size_t variable. */
xBlockAllocatedBit = ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 );
}
/*-----------------------------------------------------------*/
static void prvInsertBlockIntoFreeList( BlockLink_t * pxBlockToInsert ) /* PRIVILEGED_FUNCTION */
{
BlockLink_t * pxIterator;
uint8_t * puc;
/* Iterate through the list until a block is found that has a higher address
* than the block being inserted. */
for( pxIterator = &xStart; pxIterator->pxNextFreeBlock < pxBlockToInsert; pxIterator = pxIterator->pxNextFreeBlock )
{
/* Nothing to do here, just iterate to the right position. */
}
/* Do the block being inserted, and the block it is being inserted after
* make a contiguous block of memory? */
puc = ( uint8_t * ) pxIterator;
if( ( puc + pxIterator->xBlockSize ) == ( uint8_t * ) pxBlockToInsert )
{
pxIterator->xBlockSize += pxBlockToInsert->xBlockSize;
pxBlockToInsert = pxIterator;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* Do the block being inserted, and the block it is being inserted before
* make a contiguous block of memory? */
puc = ( uint8_t * ) pxBlockToInsert;
if( ( puc + pxBlockToInsert->xBlockSize ) == ( uint8_t * ) pxIterator->pxNextFreeBlock )
{
if( pxIterator->pxNextFreeBlock != pxEnd )
{
/* Form one big block from the two blocks. */
pxBlockToInsert->xBlockSize += pxIterator->pxNextFreeBlock->xBlockSize;
pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock->pxNextFreeBlock;
}
else
{
pxBlockToInsert->pxNextFreeBlock = pxEnd;
}
}
else
{
pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock;
}
/* If the block being inserted plugged a gab, so was merged with the block
* before and the block after, then it's pxNextFreeBlock pointer will have
* already been set, and should not be set here as that would make it point
* to itself. */
if( pxIterator != pxBlockToInsert )
{
pxIterator->pxNextFreeBlock = pxBlockToInsert;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
/*-----------------------------------------------------------*/
void vPortGetHeapStats( HeapStats_t * pxHeapStats )
{
BlockLink_t * pxBlock;
size_t xBlocks = 0, xMaxSize = 0, xMinSize = portMAX_DELAY; /* portMAX_DELAY used as a portable way of getting the maximum value. */
vTaskSuspendAll();
{
pxBlock = xStart.pxNextFreeBlock;
/* pxBlock will be NULL if the heap has not been initialised. The heap
* is initialised automatically when the first allocation is made. */
if( pxBlock != NULL )
{
do
{
/* Increment the number of blocks and record the largest block seen
* so far. */
xBlocks++;
if( pxBlock->xBlockSize > xMaxSize )
{
xMaxSize = pxBlock->xBlockSize;
}
if( pxBlock->xBlockSize < xMinSize )
{
xMinSize = pxBlock->xBlockSize;
}
/* Move to the next block in the chain until the last block is
* reached. */
pxBlock = pxBlock->pxNextFreeBlock;
} while( pxBlock != pxEnd );
}
}
( void ) xTaskResumeAll();
pxHeapStats->xSizeOfLargestFreeBlockInBytes = xMaxSize;
pxHeapStats->xSizeOfSmallestFreeBlockInBytes = xMinSize;
pxHeapStats->xNumberOfFreeBlocks = xBlocks;
taskENTER_CRITICAL();
{
pxHeapStats->xAvailableHeapSpaceInBytes = xFreeBytesRemaining;
pxHeapStats->xNumberOfSuccessfulAllocations = xNumberOfSuccessfulAllocations;
pxHeapStats->xNumberOfSuccessfulFrees = xNumberOfSuccessfulFrees;
pxHeapStats->xMinimumEverFreeBytesRemaining = xMinimumEverFreeBytesRemaining;
}
taskEXIT_CRITICAL();
}
@@ -0,0 +1,292 @@
/**
******************************************************************************
* @file memory_manager.c
* @author MCD Application Team
* @brief Memory Manager
******************************************************************************
* @attention
*
* Copyright (c) 2018-2021 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "utilities_common.h"
#include "memory_manager.h"
#include "stm_list.h"
/* Private typedef -----------------------------------------------------------*/
/* Private defines -----------------------------------------------------------*/
/**
* The average timing is @32Mhz :
* Legacy MM
* + Alloc = 3.5us
* + Free = 2.5us
* New MM
* + Alloc = 6.5us
* + Free = 4.5us
*/
#define USE_NEW_MM 1
/* Private macros ------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
#if(USE_NEW_MM == 0)
#pragma default_variable_attributes = @"MM_CONTEXT"
static uint8_t QueueSize;
static tListNode BufferPool;
static MM_pCb_t BufferFreeCb;
static uint8_t *p_StartPoolAdd;
static uint8_t *p_EndPoolAdd;
#pragma default_variable_attributes =
/* Global variables ----------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Functions Definition ------------------------------------------------------*/
/**
* @brief Initialize the Pools
* @param p_pool: The pool of memory to manage
* @param pool_size: The size of the pool
* @param elt_size: The size of one element in the pool
* @retval None
*/
void MM_Init(uint8_t *p_pool, uint32_t pool_size, uint32_t elt_size)
{
uint32_t elt_size_corrected;
QueueSize = 0;
elt_size_corrected = 4*DIVC( elt_size, 4 );
/**
* Save the first and last address of the pool of memory
*/
p_StartPoolAdd = p_pool;
p_EndPoolAdd = p_pool + pool_size - 1;
/**
* Initialize list
*/
LST_init_head (&BufferPool);
/**
* Initialize the queue
*/
while(pool_size >= elt_size_corrected)
{
LST_insert_tail(&BufferPool, (tListNode *)p_pool);
p_pool += elt_size_corrected;
QueueSize++;
pool_size -= elt_size_corrected;
}
return;
}
/**
* @brief Provide a buffer
* @note The buffer allocated to the user shall be at least sizeof(tListNode) bytes
* to store the memory manager chaining information
*
* @param size: The size of the buffer requested
* @param cb: The callback to be called when a buffer is made available later on
* if there is no buffer currently available when this API is called
* @retval The buffer address when available or NULL when there is no buffer
*/
MM_pBufAdd_t MM_GetBuffer( uint32_t size, MM_pCb_t cb )
{
MM_pBufAdd_t buffer_address;
uint32_t primask_bit;
uint8_t allocation_exit = FALSE;
while( allocation_exit == FALSE )
{
primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */
__disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/
if ( QueueSize )
{
QueueSize--;
LST_remove_head( &BufferPool, ( tListNode ** )&buffer_address );
if((buffer_address >= p_StartPoolAdd) && (buffer_address <= (p_EndPoolAdd - size + 1)))
{
/* The buffer is in a valid range */
BufferFreeCb = 0;
allocation_exit = TRUE;
}
else
{
/**
* The buffer is not in a valid range.
* Keep the reference out of the memory pool and try again
*/
}
}
else
{
BufferFreeCb = cb;
buffer_address = 0;
allocation_exit = TRUE;
}
__set_PRIMASK( primask_bit ); /**< Restore PRIMASK bit*/
}
return buffer_address;
}
/**
* @brief Release a buffer
* @param p_buffer: The data buffer address
* @retval None
*/
void MM_ReleaseBuffer( MM_pBufAdd_t p_buffer )
{
uint32_t primask_bit;
if((p_buffer >= p_StartPoolAdd) && (p_buffer <= p_EndPoolAdd))
{
primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */
__disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/
LST_insert_tail( &BufferPool, ( tListNode * )p_buffer );
QueueSize++;
__set_PRIMASK( primask_bit ); /**< Restore PRIMASK bit*/
if( BufferFreeCb )
{
/**
* The application is waiting for a free buffer
*/
BufferFreeCb();
}
}
return;
}
#else
#include "stm32_mm.h"
#pragma default_variable_attributes = @"MM_CONTEXT"
static uint8_t *p_StartPoolAdd;
static uint8_t *p_EndPoolAdd;
static MM_pCb_t BufferFreeCb;
#pragma default_variable_attributes =
/* Functions Definition ------------------------------------------------------*/
void MM_Init(uint8_t *p_pool, uint32_t pool_size, uint32_t elt_size)
{
/**
* Save the first and last address of the pool of memory
*/
p_StartPoolAdd = p_pool;
p_EndPoolAdd = p_pool + pool_size - 1;
UTIL_MM_Init(p_pool, pool_size);
return;
}
/**
* @brief Provide a buffer
* @note The buffer allocated to the user shall be at least sizeof(tListNode) bytes
* to store the memory manager chaining information
* During execution, this API shall not be interrupted with a call to either
* MM_GetBuffer() or MM_ReleaseBuffer()
* MM_GetBuffer() is called only from background so this will never happen
* MM_ReleaseBuffer() is called from IPCC interrupt. Masking IPCC interrupt is
* enough to comply to the requirement
* Note that the primask bit cannot be used as the length of the critical section is too long compare to
* the maximum latency of the BLE Irq. Therefore, the BLE Irq shall not be masked.
*
* @param size: The size of the buffer requested
* @param cb: The callback to be called when a buffer is made available later on
* if there is no buffer currently available when this API is called
* @retval The buffer address when available or NULL when there is no buffer
*/
MM_pBufAdd_t MM_GetBuffer( uint32_t size, MM_pCb_t cb )
{
MM_pBufAdd_t buffer_address;
uint32_t nvic_ipcc_status;
uint8_t allocation_exit = FALSE;
while( allocation_exit == FALSE )
{
nvic_ipcc_status = NVIC_GetEnableIRQ(IPCC_C2_RX_C2_TX_HSEM_IRQn); /**< backup IPCC just in case it has been disabled by the user */
NVIC_DisableIRQ(IPCC_C2_RX_C2_TX_HSEM_IRQn);
buffer_address = (MM_pBufAdd_t)UTIL_MM_GetBuffer( size );
if(nvic_ipcc_status != 0)
{
NVIC_EnableIRQ(IPCC_C2_RX_C2_TX_HSEM_IRQn);
}
if(buffer_address != 0)
{
if((buffer_address >= p_StartPoolAdd) && (buffer_address <= (p_EndPoolAdd - size + 1)))
{
/* The buffer is in a valid range */
BufferFreeCb = 0;
allocation_exit = TRUE;
}
else
{
/**
* The buffer is not in a valid range.
* Keep the reference out of the memory pool and try again
*/
}
}
else
{
BufferFreeCb = cb;
allocation_exit = TRUE;
}
}
return buffer_address;
}
/**
* @brief Release a buffer
* During execution, this API shall not be interrupted with a call to either
* MM_GetBuffer() or MM_ReleaseBuffer()
* MM_GetBuffer() is called only from background so this will never happen
* MM_ReleaseBuffer() is called from IPCC interrupt so it cannot be nested.
* There is no need of a critical section
* Note that anyway, the primask bit cannot be used as the length of the critical section
* is too long compare to the maximum latency of the BLE Irq. Therefore, the BLE Irq shall not be masked.
*
* @param p_buffer: The data buffer address
* @retval None
*/
void MM_ReleaseBuffer( MM_pBufAdd_t p_buffer )
{
if((p_buffer >= p_StartPoolAdd) && (p_buffer <= p_EndPoolAdd))
{
UTIL_MM_ReleaseBuffer( p_buffer );
if( BufferFreeCb )
{
/**
* The application is waiting for a free buffer
*/
BufferFreeCb();
}
}
return;
}
#endif
@@ -0,0 +1,42 @@
/**
******************************************************************************
* @file memory_manager.h
* @author MCD Application Team
* @brief Header for memory_manager.c module
******************************************************************************
* @attention
*
* Copyright (c) 2018-2021 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __MEMORY_MANAGER_H
#define __MEMORY_MANAGER_H
/* Includes ------------------------------------------------------------------*/
/* Exported defines -----------------------------------------------------------*/
/* Exported types ------------------------------------------------------------*/
typedef void (*MM_pCb_t)( void );
typedef uint8_t (*MM_pBufAdd_t);
/* Exported constants --------------------------------------------------------*/
/* External variables --------------------------------------------------------*/
/* Exported macros -----------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
void MM_Init(uint8_t *p_pool, uint32_t pool_size, uint32_t elt_size);
MM_pBufAdd_t MM_GetBuffer(uint32_t size, MM_pCb_t cb );
void MM_ReleaseBuffer( MM_pBufAdd_t p_buffer );
/* Exported functions to be implemented by the user if required ------------- */
#endif /*__MEMORY_MANAGER_H */
@@ -0,0 +1,52 @@
/**
******************************************************************************
* @file otp.c
* @author MCD Application Team
* @brief OTP manager
******************************************************************************
* @attention
*
* Copyright (c) 2018-2021 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "utilities_common.h"
#include "otp.h"
/* Private typedef -----------------------------------------------------------*/
/* Private defines -----------------------------------------------------------*/
/* Private macros ------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Global variables ----------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Functions Definition ------------------------------------------------------*/
uint8_t * OTP_Read( uint8_t id )
{
uint8_t *p_id;
p_id = (uint8_t*)(CFG_OTP_END_ADRESS - 7) ;
while( ((*( p_id + 7 )) != id) && ( p_id != (uint8_t*)CFG_OTP_BASE_ADDRESS) )
{
p_id -= 8 ;
}
if((*( p_id + 7 )) != id)
{
p_id = 0 ;
}
return p_id ;
}
@@ -0,0 +1,65 @@
/**
******************************************************************************
* @file otp.h
* @author MCD Application Team
* @brief OTP manager interface
******************************************************************************
* @attention
*
* Copyright (c) 2018-2021 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __OTP_H
#define __OTP_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "utilities_common.h"
/* Exported types ------------------------------------------------------------*/
typedef PACKED_STRUCT
{
uint8_t bd_address[6];
uint8_t hse_tuning;
uint8_t id;
} OTP_ID0_t;
/* Exported constants --------------------------------------------------------*/
/* External variables --------------------------------------------------------*/
/* Exported macros -----------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
/**
* @brief This API return the address (64 bits aligned) of the ID parameter in the OTP
* It returns the first ID declaration found from the higher address down to the base address
* The user shall fill the OTP from the base address to the top of the OTP so that the more recent
* declaration is returned by the API
* The OTP manager handles only 64bits parameter
* | Id | Parameter |
* | 8bits | 58bits |
* | MSB | LSB |
*
* @param id: ID of the parameter to read from OTP
* @retval Address of the ID in the OTP - returns 0 when no ID found
*/
uint8_t * OTP_Read( uint8_t id );
#ifdef __cplusplus
}
#endif
#endif /*__OTP_H */
@@ -0,0 +1,649 @@
/*
* FreeRTOS Kernel V10.4.1
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/**
******************************************************************************
* @file stm32_mm.c
* @author MCD Application Team
* @brief Memory Manager Utility
******************************************************************************
* @attention
*
* Copyright (c) 2018-2021 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/*
* A sample implementation of pvPortMalloc() and vPortFree() that combines
* (coalescences) adjacent memory blocks as they are freed, and in so doing
* limits memory fragmentation.
*
* See heap_1.c, heap_2.c and heap_3.c for alternative implementations, and the
* memory management pages of https://www.FreeRTOS.org for more information.
*/
#if (KEEP_ORIGINAL_CODE_FROM_FREERTOS != 0)
#include <stdlib.h>
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
* all the API functions to use the MPU wrappers. That should only be done when
* task.h is included from an application file. */
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
#include "FreeRTOS.h"
#include "task.h"
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 0 )
#error This file must not be used if configSUPPORT_DYNAMIC_ALLOCATION is 0
#endif
#else
#include "utilities_common.h"
#include "stm32_mm.h"
#undef PRIVILEGED_DATA
#define PRIVILEGED_DATA
#undef PRIVILEGED_FUNCTION
#define PRIVILEGED_FUNCTION
#undef portBYTE_ALIGNMENT
#define portBYTE_ALIGNMENT (8)
#undef portBYTE_ALIGNMENT_MASK
#if portBYTE_ALIGNMENT == 8
#define portBYTE_ALIGNMENT_MASK ( 0x0007 )
#endif
#if portBYTE_ALIGNMENT == 4
#define portBYTE_ALIGNMENT_MASK ( 0x0003 )
#endif
/* No test marker by default. */
#undef mtCOVERAGE_TEST_MARKER
#define mtCOVERAGE_TEST_MARKER()
#undef configASSERT
#define configASSERT( x )
/* No tracing by default. */
#undef traceMALLOC
#define traceMALLOC( pvReturn, xWantedSize )
#undef traceFREE
#define traceFREE( pvAddress, uiSize )
#undef vTaskSuspendAll
#define vTaskSuspendAll()
#undef xTaskResumeAll
#define xTaskResumeAll() (0)
#endif /* (KEEP_ORIGINAL_CODE_FROM_FREERTOS != 0) */
/* Block sizes must not get too small. */
#define heapMINIMUM_BLOCK_SIZE ( ( size_t ) ( xHeapStructSize << 1 ) )
/* Assumes 8bit bytes! */
#define heapBITS_PER_BYTE ( ( size_t ) 8 )
#if (KEEP_ORIGINAL_CODE_FROM_FREERTOS != 0)
/* Allocate the memory for the heap. */
#if ( configAPPLICATION_ALLOCATED_HEAP == 1 )
/* The application writer has already defined the array used for the RTOS
* heap - probably so it can be placed in a special segment or address. */
extern uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
#else
PRIVILEGED_DATA static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
#endif /* configAPPLICATION_ALLOCATED_HEAP */
#endif /* (KEEP_ORIGINAL_CODE_FROM_FREERTOS != 0) */
/* Define the linked list structure. This is used to link free blocks in order
* of their memory address. */
typedef struct A_BLOCK_LINK
{
struct A_BLOCK_LINK * pxNextFreeBlock; /*<< The next free block in the list. */
size_t xBlockSize; /*<< The size of the free block. */
} BlockLink_t;
#if ((KEEP_ORIGINAL_CODE_FROM_FREERTOS == 0) && (__CORTEX_M < 4))
static BlockLink_t * pFirstValidAddress;
static BlockLink_t * pLastValidAddress;
#endif /* (KEEP_ORIGINAL_CODE_FROM_FREERTOS == 0) && (__CORTEX_M < 4) */
/*-----------------------------------------------------------*/
/*
* Inserts a block of memory that is being freed into the correct position in
* the list of free memory blocks. The block being freed will be merged with
* the block in front it and/or the block behind it if the memory blocks are
* adjacent to each other.
*/
static void prvInsertBlockIntoFreeList( BlockLink_t * pxBlockToInsert ) PRIVILEGED_FUNCTION;
/*
* Called automatically to setup the required heap structures the first time
* pvPortMalloc() is called.
*/
#if (KEEP_ORIGINAL_CODE_FROM_FREERTOS != 0)
static void prvHeapInit( void ) PRIVILEGED_FUNCTION;
#endif /* (KEEP_ORIGINAL_CODE_FROM_FREERTOS != 0) */
#if ((KEEP_ORIGINAL_CODE_FROM_FREERTOS == 0) && (__CORTEX_M < 4))
static void CheckIntegrity( BlockLink_t * pAddressToCheck );
#endif /* (KEEP_ORIGINAL_CODE_FROM_FREERTOS == 0) && (__CORTEX_M < 4) */
/*-----------------------------------------------------------*/
/* The size of the structure placed at the beginning of each allocated memory
* block must by correctly byte aligned. */
static const size_t xHeapStructSize = ( sizeof( BlockLink_t ) + ( ( size_t ) ( portBYTE_ALIGNMENT - 1 ) ) ) & ~( ( size_t ) portBYTE_ALIGNMENT_MASK );
/* Create a couple of list links to mark the start and end of the list. */
PRIVILEGED_DATA static BlockLink_t xStart, * pxEnd = NULL;
/* Keeps track of the number of calls to allocate and free memory as well as the
* number of free bytes remaining, but says nothing about fragmentation. */
PRIVILEGED_DATA static size_t xFreeBytesRemaining = 0U;
PRIVILEGED_DATA static size_t xMinimumEverFreeBytesRemaining = 0U;
PRIVILEGED_DATA static size_t xNumberOfSuccessfulAllocations = 0;
PRIVILEGED_DATA static size_t xNumberOfSuccessfulFrees = 0;
/* Gets set to the top bit of an size_t type. When this bit in the xBlockSize
* member of an BlockLink_t structure is set then the block belongs to the
* application. When the bit is free the block is still part of the free heap
* space. */
PRIVILEGED_DATA static size_t xBlockAllocatedBit = 0;
/*-----------------------------------------------------------*/
#if (KEEP_ORIGINAL_CODE_FROM_FREERTOS == 0)
void * UTIL_MM_GetBuffer( size_t xWantedSize )
#else
void * pvPortMalloc( size_t xWantedSize )
#endif /* (KEEP_ORIGINAL_CODE_FROM_FREERTOS == 0) */
{
BlockLink_t * pxBlock, * pxPreviousBlock, * pxNewBlockLink;
void * pvReturn = NULL;
vTaskSuspendAll();
{
/* If this is the first call to malloc then the heap will require
* initialisation to setup the list of free blocks. */
#if (KEEP_ORIGINAL_CODE_FROM_FREERTOS != 0)
if( pxEnd == NULL )
{
prvHeapInit();
}
else
#endif /* (KEEP_ORIGINAL_CODE_FROM_FREERTOS != 0) */
{
mtCOVERAGE_TEST_MARKER();
}
/* Check the requested block size is not so large that the top bit is
* set. The top bit of the block size member of the BlockLink_t structure
* is used to determine who owns the block - the application or the
* kernel, so it must be free. */
if( ( xWantedSize & xBlockAllocatedBit ) == 0 )
{
/* The wanted size is increased so it can contain a BlockLink_t
* structure in addition to the requested amount of bytes. */
if( xWantedSize > 0 )
{
xWantedSize += xHeapStructSize;
/* Ensure that blocks are always aligned to the required number
* of bytes. */
if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0x00 )
{
/* Byte alignment required. */
xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );
configASSERT( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) == 0 );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining ) )
{
/* Traverse the list from the start (lowest address) block until
* one of adequate size is found. */
pxPreviousBlock = &xStart;
pxBlock = xStart.pxNextFreeBlock;
while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) )
{
pxPreviousBlock = pxBlock;
pxBlock = pxBlock->pxNextFreeBlock;
}
/* If the end marker was reached then a block of adequate size
* was not found. */
if( pxBlock != pxEnd )
{
#if ((KEEP_ORIGINAL_CODE_FROM_FREERTOS == 0) && (__CORTEX_M < 4))
CheckIntegrity( pxBlock );
CheckIntegrity( pxPreviousBlock );
#endif /* (KEEP_ORIGINAL_CODE_FROM_FREERTOS == 0) && (__CORTEX_M < 4) */
/* Return the memory space pointed to - jumping over the
* BlockLink_t structure at its start. */
pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + xHeapStructSize );
/* This block is being returned for use so must be taken out
* of the list of free blocks. */
pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;
/* If the block is larger than required it can be split into
* two. */
if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE )
{
/* This block is to be split into two. Create a new
* block following the number of bytes requested. The void
* cast is used to prevent byte alignment warnings from the
* compiler. */
pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize );
configASSERT( ( ( ( size_t ) pxNewBlockLink ) & portBYTE_ALIGNMENT_MASK ) == 0 );
#if ((KEEP_ORIGINAL_CODE_FROM_FREERTOS == 0) && (__CORTEX_M < 4))
CheckIntegrity( pxNewBlockLink );
#endif /* (KEEP_ORIGINAL_CODE_FROM_FREERTOS == 0) && (__CORTEX_M < 4) */
/* Calculate the sizes of two blocks split from the
* single block. */
pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;
pxBlock->xBlockSize = xWantedSize;
/* Insert the new block into the list of free blocks. */
prvInsertBlockIntoFreeList( pxNewBlockLink );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
xFreeBytesRemaining -= pxBlock->xBlockSize;
if( xFreeBytesRemaining < xMinimumEverFreeBytesRemaining )
{
xMinimumEverFreeBytesRemaining = xFreeBytesRemaining;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* The block is being returned - it is allocated and owned
* by the application and has no "next" block. */
pxBlock->xBlockSize |= xBlockAllocatedBit;
pxBlock->pxNextFreeBlock = NULL;
xNumberOfSuccessfulAllocations++;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
traceMALLOC( pvReturn, xWantedSize );
}
( void ) xTaskResumeAll();
#if ( configUSE_MALLOC_FAILED_HOOK == 1 )
{
if( pvReturn == NULL )
{
extern void vApplicationMallocFailedHook( void );
vApplicationMallocFailedHook();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#endif /* if ( configUSE_MALLOC_FAILED_HOOK == 1 ) */
configASSERT( ( ( ( size_t ) pvReturn ) & ( size_t ) portBYTE_ALIGNMENT_MASK ) == 0 );
return pvReturn;
}
/*-----------------------------------------------------------*/
#if (KEEP_ORIGINAL_CODE_FROM_FREERTOS == 0)
void UTIL_MM_ReleaseBuffer( void * pv )
#else
void vPortFree( void * pv )
#endif /* (KEEP_ORIGINAL_CODE_FROM_FREERTOS == 0) */
{
uint8_t * puc = ( uint8_t * ) pv;
BlockLink_t * pxLink;
if( pv != NULL )
{
/* The memory being freed will have an BlockLink_t structure immediately
* before it. */
puc -= xHeapStructSize;
/* This casting is to keep the compiler from issuing warnings. */
pxLink = ( void * ) puc;
#if ((KEEP_ORIGINAL_CODE_FROM_FREERTOS == 0) && (__CORTEX_M < 4))
CheckIntegrity( pxLink );
#endif /* (KEEP_ORIGINAL_CODE_FROM_FREERTOS == 0) && (__CORTEX_M < 4) */
/* Check the block is actually allocated. */
configASSERT( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 );
configASSERT( pxLink->pxNextFreeBlock == NULL );
if( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 )
{
if( pxLink->pxNextFreeBlock == NULL )
{
/* The block is being returned to the heap - it is no longer
* allocated. */
pxLink->xBlockSize &= ~xBlockAllocatedBit;
vTaskSuspendAll();
{
/* Add this block to the list of free blocks. */
xFreeBytesRemaining += pxLink->xBlockSize;
traceFREE( pv, pxLink->xBlockSize );
prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) );
xNumberOfSuccessfulFrees++;
}
( void ) xTaskResumeAll();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
}
/*-----------------------------------------------------------*/
#if (KEEP_ORIGINAL_CODE_FROM_FREERTOS != 0)
size_t xPortGetFreeHeapSize( void )
{
return xFreeBytesRemaining;
}
/*-----------------------------------------------------------*/
size_t xPortGetMinimumEverFreeHeapSize( void )
{
return xMinimumEverFreeBytesRemaining;
}
/*-----------------------------------------------------------*/
void vPortInitialiseBlocks( void )
{
/* This just exists to keep the linker quiet. */
}
/*-----------------------------------------------------------*/
#endif /* (KEEP_ORIGINAL_CODE_FROM_FREERTOS != 0) */
#if (KEEP_ORIGINAL_CODE_FROM_FREERTOS != 0)
static void prvHeapInit( void ) /* PRIVILEGED_FUNCTION */
#else
void UTIL_MM_Init(uint8_t *p_pool, uint32_t pool_size)
#endif /* (KEEP_ORIGINAL_CODE_FROM_FREERTOS != 0) */
{
BlockLink_t * pxFirstFreeBlock;
uint8_t * pucAlignedHeap;
size_t uxAddress;
#if (KEEP_ORIGINAL_CODE_FROM_FREERTOS != 0)
size_t xTotalHeapSize = configTOTAL_HEAP_SIZE;
#else
size_t xTotalHeapSize;
xTotalHeapSize = pool_size;
#if (__CORTEX_M < 4)
pFirstValidAddress = (BlockLink_t *) p_pool;
pLastValidAddress = (BlockLink_t *)((uint32_t)p_pool + pool_size - 1 - sizeof( BlockLink_t ));
#endif /* (__CORTEX_M < 4) */
#endif /* (KEEP_ORIGINAL_CODE_FROM_FREERTOS != 0) */
/* Ensure the heap starts on a correctly aligned boundary. */
#if (KEEP_ORIGINAL_CODE_FROM_FREERTOS != 0)
uxAddress = ( size_t ) ucHeap;
#else
uxAddress = ( size_t ) p_pool;
#endif /* (KEEP_ORIGINAL_CODE_FROM_FREERTOS != 0) */
if( ( uxAddress & portBYTE_ALIGNMENT_MASK ) != 0 )
{
uxAddress += ( portBYTE_ALIGNMENT - 1 );
uxAddress &= ~( ( size_t ) portBYTE_ALIGNMENT_MASK );
#if (KEEP_ORIGINAL_CODE_FROM_FREERTOS != 0)
xTotalHeapSize -= uxAddress - ( size_t ) ucHeap;
#else
xTotalHeapSize -= uxAddress - ( size_t ) p_pool;
#endif /* (KEEP_ORIGINAL_CODE_FROM_FREERTOS != 0) */
}
pucAlignedHeap = ( uint8_t * ) uxAddress;
/* xStart is used to hold a pointer to the first item in the list of free
* blocks. The void cast is used to prevent compiler warnings. */
xStart.pxNextFreeBlock = ( void * ) pucAlignedHeap;
xStart.xBlockSize = ( size_t ) 0;
/* pxEnd is used to mark the end of the list of free blocks and is inserted
* at the end of the heap space. */
uxAddress = ( ( size_t ) pucAlignedHeap ) + xTotalHeapSize;
uxAddress -= xHeapStructSize;
uxAddress &= ~( ( size_t ) portBYTE_ALIGNMENT_MASK );
pxEnd = ( void * ) uxAddress;
pxEnd->xBlockSize = 0;
pxEnd->pxNextFreeBlock = NULL;
/* To start with there is a single free block that is sized to take up the
* entire heap space, minus the space taken by pxEnd. */
pxFirstFreeBlock = ( void * ) pucAlignedHeap;
pxFirstFreeBlock->xBlockSize = uxAddress - ( size_t ) pxFirstFreeBlock;
pxFirstFreeBlock->pxNextFreeBlock = pxEnd;
/* Only one block exists - and it covers the entire usable heap space. */
xMinimumEverFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;
xFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;
/* Work out the position of the top bit in a size_t variable. */
xBlockAllocatedBit = ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 );
}
/*-----------------------------------------------------------*/
static void prvInsertBlockIntoFreeList( BlockLink_t * pxBlockToInsert ) /* PRIVILEGED_FUNCTION */
{
BlockLink_t * pxIterator;
uint8_t * puc;
/* Iterate through the list until a block is found that has a higher address
* than the block being inserted. */
for( pxIterator = &xStart; pxIterator->pxNextFreeBlock < pxBlockToInsert; pxIterator = pxIterator->pxNextFreeBlock )
{
/* Nothing to do here, just iterate to the right position. */
}
#if ((KEEP_ORIGINAL_CODE_FROM_FREERTOS == 0) && (__CORTEX_M < 4))
CheckIntegrity( pxIterator );
#endif /* (KEEP_ORIGINAL_CODE_FROM_FREERTOS == 0) && (__CORTEX_M < 4) */
/* Do the block being inserted, and the block it is being inserted after
* make a contiguous block of memory? */
puc = ( uint8_t * ) pxIterator;
if( ( puc + pxIterator->xBlockSize ) == ( uint8_t * ) pxBlockToInsert )
{
pxIterator->xBlockSize += pxBlockToInsert->xBlockSize;
pxBlockToInsert = pxIterator;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
#if ((KEEP_ORIGINAL_CODE_FROM_FREERTOS == 0) && (__CORTEX_M < 4))
CheckIntegrity( pxBlockToInsert );
#endif /* (KEEP_ORIGINAL_CODE_FROM_FREERTOS == 0) && (__CORTEX_M < 4) */
/* Do the block being inserted, and the block it is being inserted before
* make a contiguous block of memory? */
puc = ( uint8_t * ) pxBlockToInsert;
if( ( puc + pxBlockToInsert->xBlockSize ) == ( uint8_t * ) pxIterator->pxNextFreeBlock )
{
if( pxIterator->pxNextFreeBlock != pxEnd )
{
/* Form one big block from the two blocks. */
pxBlockToInsert->xBlockSize += pxIterator->pxNextFreeBlock->xBlockSize;
pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock->pxNextFreeBlock;
}
else
{
pxBlockToInsert->pxNextFreeBlock = pxEnd;
}
}
else
{
pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock;
}
/* If the block being inserted plugged a gab, so was merged with the block
* before and the block after, then it's pxNextFreeBlock pointer will have
* already been set, and should not be set here as that would make it point
* to itself. */
if( pxIterator != pxBlockToInsert )
{
pxIterator->pxNextFreeBlock = pxBlockToInsert;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
/*-----------------------------------------------------------*/
#if (KEEP_ORIGINAL_CODE_FROM_FREERTOS != 0)
void vPortGetHeapStats( HeapStats_t * pxHeapStats )
{
BlockLink_t * pxBlock;
size_t xBlocks = 0, xMaxSize = 0, xMinSize = portMAX_DELAY; /* portMAX_DELAY used as a portable way of getting the maximum value. */
vTaskSuspendAll();
{
pxBlock = xStart.pxNextFreeBlock;
/* pxBlock will be NULL if the heap has not been initialised. The heap
* is initialised automatically when the first allocation is made. */
if( pxBlock != NULL )
{
do
{
/* Increment the number of blocks and record the largest block seen
* so far. */
xBlocks++;
if( pxBlock->xBlockSize > xMaxSize )
{
xMaxSize = pxBlock->xBlockSize;
}
if( pxBlock->xBlockSize < xMinSize )
{
xMinSize = pxBlock->xBlockSize;
}
/* Move to the next block in the chain until the last block is
* reached. */
pxBlock = pxBlock->pxNextFreeBlock;
} while( pxBlock != pxEnd );
}
}
( void ) xTaskResumeAll();
pxHeapStats->xSizeOfLargestFreeBlockInBytes = xMaxSize;
pxHeapStats->xSizeOfSmallestFreeBlockInBytes = xMinSize;
pxHeapStats->xNumberOfFreeBlocks = xBlocks;
taskENTER_CRITICAL();
{
pxHeapStats->xAvailableHeapSpaceInBytes = xFreeBytesRemaining;
pxHeapStats->xNumberOfSuccessfulAllocations = xNumberOfSuccessfulAllocations;
pxHeapStats->xNumberOfSuccessfulFrees = xNumberOfSuccessfulFrees;
pxHeapStats->xMinimumEverFreeBytesRemaining = xMinimumEverFreeBytesRemaining;
}
taskEXIT_CRITICAL();
}
#endif /* (KEEP_ORIGINAL_CODE_FROM_FREERTOS != 0) */
#if ((KEEP_ORIGINAL_CODE_FROM_FREERTOS == 0) && (__CORTEX_M < 4))
/**
* When the pool of memory can be written by a non secure firmware, it may corrupt the metadata
* used by the memory manager to make the secure firmware to write at non expected address
* The purpose of this API is to make sure the secure firmware writes the metada in a location
* within the memory pool.
* There is no objective to ensure the memory will keep running fine as anyway the meta data
* are corrupted. The only goal is to ensure the secure firmware is not writing data at an
* address that may break the security.
*/
static void CheckIntegrity( BlockLink_t * pAddressToCheck )
{
/**
* In some cases, the pointer is initialized to the local structure address xStart
* In that case, it is easier to run the check here every time instead of trying
* to check this when needed in the implementation before calling CheckIntegrity()
*/
if(pAddressToCheck != &xStart)
{
if ((pAddressToCheck < pFirstValidAddress) || (pAddressToCheck > pLastValidAddress))
{
while(1);
NVIC_SystemReset( );
}
}
return;
}
#endif /* (KEEP_ORIGINAL_CODE_FROM_FREERTOS == 0) && (__CORTEX_M < 4) */
@@ -0,0 +1,62 @@
/**
******************************************************************************
* @file stm32_mm.h
* @author MCD Application Team
* @brief Header for stm32_mm.c module
******************************************************************************
* @attention
*
* Copyright (c) 2018-2021 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef STM32_MM_H
#define STM32_MM_H
/* Includes ------------------------------------------------------------------*/
/* Exported defines -----------------------------------------------------------*/
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* External variables --------------------------------------------------------*/
/* Exported macros -----------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
/**
* @brief Initialize the Pool
* @param p_pool: The pool of memory to manage
* @param pool_size: The size of the pool
* @retval None
*/
void UTIL_MM_Init(uint8_t *p_pool, uint32_t pool_size);
/**
* @brief Provide a buffer
* @note The buffer allocated to the user shall be at least sizeof(tListNode) bytes
* to store the memory manager chaining information
*
* @param xWantedSize: The size of the buffer requested
* @retval The buffer address when available or NULL when there is no buffer
*/
void * UTIL_MM_GetBuffer(size_t xWantedSize);
/**
* @brief Release a buffer
* @param pv: The data buffer address
* @retval None
*/
void UTIL_MM_ReleaseBuffer( void * pv );
/* Exported functions to be implemented by the user if required ------------- */
#endif /* STM32_MM_H */
@@ -0,0 +1,207 @@
/**
******************************************************************************
* @file stm_list.c
* @author MCD Application Team
* @brief TCircular Linked List Implementation.
******************************************************************************
* @attention
*
* Copyright (c) 2018-2021 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/******************************************************************************
* Include Files
******************************************************************************/
#include "utilities_common.h"
#include "stm_list.h"
/******************************************************************************
* Function Definitions
******************************************************************************/
void LST_init_head (tListNode * listHead)
{
listHead->next = listHead;
listHead->prev = listHead;
}
uint8_t LST_is_empty (tListNode * listHead)
{
uint32_t primask_bit;
uint8_t return_value;
primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */
__disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/
if(listHead->next == listHead)
{
return_value = TRUE;
}
else
{
return_value = FALSE;
}
__set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/
return return_value;
}
void LST_insert_head (tListNode * listHead, tListNode * node)
{
uint32_t primask_bit;
primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */
__disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/
node->next = listHead->next;
node->prev = listHead;
listHead->next = node;
(node->next)->prev = node;
__set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/
}
void LST_insert_tail (tListNode * listHead, tListNode * node)
{
uint32_t primask_bit;
primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */
__disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/
node->next = listHead;
node->prev = listHead->prev;
listHead->prev = node;
(node->prev)->next = node;
__set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/
}
void LST_remove_node (tListNode * node)
{
uint32_t primask_bit;
primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */
__disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/
(node->prev)->next = node->next;
(node->next)->prev = node->prev;
__set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/
}
void LST_remove_head (tListNode * listHead, tListNode ** node )
{
uint32_t primask_bit;
primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */
__disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/
*node = listHead->next;
LST_remove_node (listHead->next);
__set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/
}
void LST_remove_tail (tListNode * listHead, tListNode ** node )
{
uint32_t primask_bit;
primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */
__disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/
*node = listHead->prev;
LST_remove_node (listHead->prev);
__set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/
}
void LST_insert_node_after (tListNode * node, tListNode * ref_node)
{
uint32_t primask_bit;
primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */
__disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/
node->next = ref_node->next;
node->prev = ref_node;
ref_node->next = node;
(node->next)->prev = node;
__set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/
}
void LST_insert_node_before (tListNode * node, tListNode * ref_node)
{
uint32_t primask_bit;
primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */
__disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/
node->next = ref_node;
node->prev = ref_node->prev;
ref_node->prev = node;
(node->prev)->next = node;
__set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/
}
int LST_get_size (tListNode * listHead)
{
int size = 0;
tListNode * temp;
uint32_t primask_bit;
primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */
__disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/
temp = listHead->next;
while (temp != listHead)
{
size++;
temp = temp->next;
}
__set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/
return (size);
}
void LST_get_next_node (tListNode * ref_node, tListNode ** node)
{
uint32_t primask_bit;
primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */
__disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/
*node = ref_node->next;
__set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/
}
void LST_get_prev_node (tListNode * ref_node, tListNode ** node)
{
uint32_t primask_bit;
primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */
__disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/
*node = ref_node->prev;
__set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/
}
@@ -0,0 +1,63 @@
/**
******************************************************************************
* @file stm_list.h
* @author MCD Application Team
* @brief Header file for linked list library.
******************************************************************************
* @attention
*
* Copyright (c) 2018-2021 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#ifndef _STM_LIST_H_
#define _STM_LIST_H_
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32_wpan_common.h"
typedef PACKED_STRUCT _tListNode {
struct _tListNode * next;
struct _tListNode * prev;
} tListNode;
void LST_init_head (tListNode * listHead);
uint8_t LST_is_empty (tListNode * listHead);
void LST_insert_head (tListNode * listHead, tListNode * node);
void LST_insert_tail (tListNode * listHead, tListNode * node);
void LST_remove_node (tListNode * node);
void LST_remove_head (tListNode * listHead, tListNode ** node );
void LST_remove_tail (tListNode * listHead, tListNode ** node );
void LST_insert_node_after (tListNode * node, tListNode * ref_node);
void LST_insert_node_before (tListNode * node, tListNode * ref_node);
int LST_get_size (tListNode * listHead);
void LST_get_next_node (tListNode * ref_node, tListNode ** node);
void LST_get_prev_node (tListNode * ref_node, tListNode ** node);
#ifdef __cplusplus
}
#endif
#endif /* _STM_LIST_H_ */
@@ -0,0 +1,383 @@
/**
******************************************************************************
* @file stm_queue.c
* @author MCD Application Team
* @brief Queue management
******************************************************************************
* @attention
*
* Copyright (c) 2018-2021 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
/* Includes ------------------------------------------------------------------*/
#include "utilities_common.h"
#include "stm_queue.h"
/* Private define ------------------------------------------------------------*/
/* Private typedef -------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
#define MOD(X,Y) (((X) >= (Y)) ? ((X)-(Y)) : (X))
/* Private variables ---------------------------------------------------------*/
/* Global variables ----------------------------------------------------------*/
/* Extern variables ----------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/* Public functions ----------------------------------------------------------*/
/**
* @brief Initilaiilze queue structure .
* @note This function is used to initialize the global queue structure.
* @param q: pointer on queue structure to be initialised
* @param queueBuffer: pointer on Queue Buffer
* @param queueSize: Size of Queue Buffer
* @param elementSize: Size of an element in the queue. if =0, the queue will manage variable sizze elements
* @retval always 0
*/
int CircularQueue_Init(queue_t *q, uint8_t* queueBuffer, uint32_t queueSize, uint16_t elementSize, uint8_t optionFlags)
{
q->qBuff = queueBuffer;
q->first = 0;
q->last = 0; /* queueSize-1; */
q->byteCount = 0;
q->elementCount = 0;
q->queueMaxSize = queueSize;
q->elementSize = elementSize;
q->optionFlags = optionFlags;
if ((optionFlags & CIRCULAR_QUEUE_SPLIT_IF_WRAPPING_FLAG) && q-> elementSize)
{
/* can not deal with splitting at the end of buffer with fixed size element */
return -1;
}
return 0;
}
/**
* @brief Add element to the queue .
* @note This function is used to add one or more element(s) to the Circular Queue .
* @param q: pointer on queue structure to be handled
* @param X; pointer on element(s) to be added
* @param elementSize: Size of element to be added to the queue. Only used if the queue manage variable size elements
* @param nbElements: number of elements in the in buffer pointed by x
* @retval pointer on last element just added to the queue, NULL if the element to be added do not fit in the queue (too big)
*/
uint8_t* CircularQueue_Add(queue_t *q, uint8_t* x, uint16_t elementSize, uint32_t nbElements)
{
uint8_t* ptr = NULL; /* fct return ptr to the element freshly added, if no room fct return NULL */
uint16_t curElementSize = 0; /* the size of the element currently stored at q->last position */
uint8_t elemSizeStorageRoom = 0 ; /* Indicate the header (which contain only size) of element in case of varaibale size element (q->elementsize == 0) */
uint32_t curBuffPosition; /* the current position in the queue buffer */
uint32_t i; /* loop counter */
uint32_t NbBytesToCopy = 0, NbCopiedBytes = 0 ; /* Indicators for copying bytes in queue */
uint32_t eob_free_size; /* Eof End of Quque Buffer Free Size */
uint8_t wrap_will_occur = 0; /* indicate if a wrap around will occurs */
uint8_t wrapped_element_eob_size; /* In case of Wrap around, indicate size of parta of element that fit at thened of the queuue buffer */
uint16_t overhead = 0; /* In case of CIRCULAR_QUEUE_SPLIT_IF_WRAPPING_FLAG or CIRCULAR_QUEUE_NO_WRAP_FLAG options,
indcate the size overhead that will be generated by adding the element with wrap management (split or no wrap ) */
elemSizeStorageRoom = (q->elementSize == 0) ? 2 : 0;
/* retrieve the size of last element sored: the value stored at the beginning of the queue element if element size is variable otherwise take it from fixed element Size member */
if (q->byteCount)
{
curElementSize = (q->elementSize == 0) ? q->qBuff[q->last] + ((q->qBuff[MOD((q->last+1), q->queueMaxSize)])<<8) + 2 : q->elementSize;
}
/* if queue element have fixed size , reset the elementSize arg with fixed element size value */
if (q->elementSize > 0)
{
elementSize = q->elementSize;
}
eob_free_size = (q->last >= q->first) ? q->queueMaxSize - (q->last + curElementSize) : 0;
/* check how many bytes of wrapped element (if anay) are at end of buffer */
wrapped_element_eob_size = (((elementSize + elemSizeStorageRoom )*nbElements) < eob_free_size) ? 0 : (eob_free_size % (elementSize + elemSizeStorageRoom));
wrap_will_occur = wrapped_element_eob_size > elemSizeStorageRoom;
overhead = (wrap_will_occur && (q->optionFlags & CIRCULAR_QUEUE_NO_WRAP_FLAG)) ? wrapped_element_eob_size : overhead;
overhead = (wrap_will_occur && (q->optionFlags & CIRCULAR_QUEUE_SPLIT_IF_WRAPPING_FLAG)) ? elemSizeStorageRoom : overhead;
/* Store now the elements if ennough room for all elements */
if (elementSize && ((q->byteCount + ((elementSize + elemSizeStorageRoom )*nbElements) + overhead) <= q->queueMaxSize))
{
/* loop to add all elements */
for (i=0; i < nbElements; i++)
{
q->last = MOD ((q->last + curElementSize),q->queueMaxSize);
curBuffPosition = q->last;
/* store the element */
/* store first the element size if element size is variable */
if (q->elementSize == 0)
{
q->qBuff[curBuffPosition++]= elementSize & 0xFF;
curBuffPosition = MOD(curBuffPosition, q->queueMaxSize);
q->qBuff[curBuffPosition++]= (elementSize & 0xFF00) >> 8 ;
curBuffPosition = MOD(curBuffPosition, q->queueMaxSize);
q->byteCount += 2;
}
/* Identify number of bytes of copy takeing account possible wrap, in this case NbBytesToCopy will contains size that fit at end of the queue buffer */
NbBytesToCopy = MIN((q->queueMaxSize-curBuffPosition),elementSize);
/* check if no wrap (NbBytesToCopy == elementSize) or if Wrap and no spsicf option;
In this case part of data will copied at the end of the buffer and the rest a the beginning */
if ((NbBytesToCopy == elementSize) || ((NbBytesToCopy < elementSize) && (q->optionFlags == CIRCULAR_QUEUE_NO_FLAG)))
{
/* Copy First part (or emtire buffer ) from current position up to the end of the buffer queue (or before if enough room) */
memcpy(&q->qBuff[curBuffPosition],&x[i*elementSize],NbBytesToCopy);
/* Adjust bytes count */
q->byteCount += NbBytesToCopy;
/* Wrap */
curBuffPosition = 0;
/* set NbCopiedBytes bytes with ampount copied */
NbCopiedBytes = NbBytesToCopy;
/* set the rest to copy if wrao , if no wrap will be 0 */
NbBytesToCopy = elementSize - NbBytesToCopy;
/* set the current element Size, will be used to calaculate next last position at beginning of loop */
curElementSize = (elementSize) + elemSizeStorageRoom ;
}
else if (NbBytesToCopy) /* We have a wrap to manage */
{
/* case of CIRCULAR_QUEUE_NO_WRAP_FLAG option */
if (q->optionFlags & CIRCULAR_QUEUE_NO_WRAP_FLAG)
{
/* if element size are variable and NO_WRAP option, Invalidate end of buffer setting 0xFFFF size*/
if (q->elementSize == 0)
{
q->qBuff[curBuffPosition-2] = 0xFF;
q->qBuff[curBuffPosition-1] = 0xFF;
}
q->byteCount += NbBytesToCopy; /* invalid data at the end of buffer are take into account in byteCount */
/* No bytes coped a the end of buffer */
NbCopiedBytes = 0;
/* all element to be copied at the begnning of buffer */
NbBytesToCopy = elementSize;
/* Wrap */
curBuffPosition = 0;
/* if variable size element, invalidate end of buffer setting OxFFFF in element header (size) */
if (q->elementSize == 0)
{
q->qBuff[curBuffPosition++] = NbBytesToCopy & 0xFF;
q->qBuff[curBuffPosition++] = (NbBytesToCopy & 0xFF00) >> 8 ;
q->byteCount += 2;
}
}
/* case of CIRCULAR_QUEUE_SPLIT_IF_WRAPPING_FLAG option */
else if (q->optionFlags & CIRCULAR_QUEUE_SPLIT_IF_WRAPPING_FLAG)
{
if (q->elementSize == 0)
{
/* reset the size of current element to the nb bytes fitting at the end of buffer */
q->qBuff[curBuffPosition-2] = NbBytesToCopy & 0xFF;
q->qBuff[curBuffPosition-1] = (NbBytesToCopy & 0xFF00) >> 8 ;
/* copy the bytes */
memcpy(&q->qBuff[curBuffPosition],&x[i*elementSize],NbBytesToCopy);
q->byteCount += NbBytesToCopy;
/* set the number of copied bytes */
NbCopiedBytes = NbBytesToCopy;
/* set rest of data to be copied to begnning of buffer */
NbBytesToCopy = elementSize - NbBytesToCopy;
/* one element more dur to split in 2 elements */
q->elementCount++;
/* Wrap */
curBuffPosition = 0;
/* Set new size for rest of data */
q->qBuff[curBuffPosition++] = NbBytesToCopy & 0xFF;
q->qBuff[curBuffPosition++] = (NbBytesToCopy & 0xFF00) >> 8 ;
q->byteCount += 2;
}
else
{
/* Should not occur */
/* can not manage split Flag on Fixed size element */
/* Buffer is corrupted */
return NULL;
}
}
curElementSize = (NbBytesToCopy) + elemSizeStorageRoom ;
q->last = 0;
}
/* some remaining byte to copy */
if (NbBytesToCopy)
{
memcpy(&q->qBuff[curBuffPosition],&x[(i*elementSize)+NbCopiedBytes],NbBytesToCopy);
q->byteCount += NbBytesToCopy;
}
/* One more element */
q->elementCount++;
}
ptr = q->qBuff + (MOD((q->last+elemSizeStorageRoom ),q->queueMaxSize));
}
/* for Breakpoint only...to remove */
else
{
return NULL;
}
return ptr;
}
/**
* @brief Remove element from the queue and copy it in provided buffer
* @note This function is used to remove and element from the Circular Queue .
* @param q: pointer on queue structure to be handled
* @param elementSize: Pointer to return Size of element to be removed
* @param buffer: destination buffer where to copy element
* @retval Pointer on removed element. NULL if queue was empty
*/
uint8_t* CircularQueue_Remove_Copy(queue_t *q, uint16_t* elementSize, uint8_t* buffer)
{
return NULL;
}
/**
* @brief Remove element from the queue.
* @note This function is used to remove and element from the Circular Queue .
* @param q: pointer on queue structure to be handled
* @param elementSize: Pointer to return Size of element to be removed (ignored if NULL)
* @retval Pointer on removed element. NULL if queue was empty
*/
uint8_t* CircularQueue_Remove(queue_t *q, uint16_t* elementSize)
{
uint8_t elemSizeStorageRoom = 0;
uint8_t* ptr= NULL;
elemSizeStorageRoom = (q->elementSize == 0) ? 2 : 0;
uint16_t eltSize = 0;
if (q->byteCount > 0)
{
/* retrieve element Size */
eltSize = (q->elementSize == 0) ? q->qBuff[q->first] + ((q->qBuff[MOD((q->first+1), q->queueMaxSize)])<<8) : q->elementSize;
if ((q->optionFlags & CIRCULAR_QUEUE_NO_WRAP_FLAG) && !(q->optionFlags & CIRCULAR_QUEUE_SPLIT_IF_WRAPPING_FLAG))
{
if (((eltSize == 0xFFFF) && q->elementSize == 0 ) ||
((q->first > q->last) && q->elementSize && ((q->queueMaxSize - q->first) < q->elementSize)))
{
/* all data from current position up to the end of buffer are invalid */
q->byteCount -= (q->queueMaxSize - q->first);
/* Adjust first element pos */
q->first = 0;
/* retrieve the right size after the wrap [if variable size element] */
eltSize = (q->elementSize == 0) ? q->qBuff[q->first] + ((q->qBuff[MOD((q->first+1), q->queueMaxSize)])<<8) : q->elementSize;
}
}
/* retrieve element */
ptr = q->qBuff + (MOD((q->first + elemSizeStorageRoom), q->queueMaxSize));
/* adjust byte count */
q->byteCount -= (eltSize + elemSizeStorageRoom) ;
/* Adjust q->first */
if (q->byteCount > 0)
{
q->first = MOD((q->first+ eltSize + elemSizeStorageRoom ), q->queueMaxSize);
}
/* adjust element count */
--q->elementCount;
}
if (elementSize != NULL)
{
*elementSize = eltSize;
}
return ptr;
}
/**
* @brief "Sense" first element of the queue, without removing it and copy it in provided buffer
* @note This function is used to return a pointer on the first element of the queue without removing it.
* @param q: pointer on queue structure to be handled
* @param elementSize: Pointer to return Size of element to be removed
* @param buffer: destination buffer where to copy element
* @retval Pointer on sensed element. NULL if queue was empty
*/
uint8_t* CircularQueue_Sense_Copy(queue_t *q, uint16_t* elementSize, uint8_t* buffer)
{
return NULL;
}
/**
* @brief "Sense" first element of the queue, without removing it.
* @note This function is used to return a pointer on the first element of the queue without removing it.
* @param q: pointer on queue structure to be handled
* @param elementSize: Pointer to return Size of element to be removed (ignored if NULL)
* @retval Pointer on sensed element. NULL if queue was empty
*/
uint8_t* CircularQueue_Sense(queue_t *q, uint16_t* elementSize)
{
uint8_t elemSizeStorageRoom = 0;
uint8_t* x= NULL;
elemSizeStorageRoom = (q->elementSize == 0) ? 2 : 0;
uint16_t eltSize = 0;
uint32_t FirstElemetPos = 0;
if (q->byteCount > 0)
{
FirstElemetPos = q->first;
eltSize = (q->elementSize == 0) ? q->qBuff[q->first] + ((q->qBuff[MOD((q->first+1), q->queueMaxSize)])<<8) : q->elementSize;
if ((q->optionFlags & CIRCULAR_QUEUE_NO_WRAP_FLAG) && !(q->optionFlags & CIRCULAR_QUEUE_SPLIT_IF_WRAPPING_FLAG))
{
if (((eltSize == 0xFFFF) && q->elementSize == 0 ) ||
((q->first > q->last) && q->elementSize && ((q->queueMaxSize - q->first) < q->elementSize)))
{
/* all data from current position up to the end of buffer are invalid */
FirstElemetPos = 0; /* wrap to the begiining of buffer */
/* retrieve the right size after the wrap [if variable size element] */
eltSize = (q->elementSize == 0) ? q->qBuff[FirstElemetPos]+ ((q->qBuff[MOD((FirstElemetPos+1), q->queueMaxSize)])<<8) : q->elementSize;
}
}
/* retrieve element */
x = q->qBuff + (MOD((FirstElemetPos + elemSizeStorageRoom), q->queueMaxSize));
}
if (elementSize != NULL)
{
*elementSize = eltSize;
}
return x;
}
/**
* @brief Check if queue is empty.
* @note This function is used to to check if the queue is empty.
* @param q: pointer on queue structure to be handled
* @retval TRUE (!0) if the queue is empyu otherwise FALSE (0)
*/
int CircularQueue_Empty(queue_t *q)
{
int ret=FALSE;
if (q->byteCount <= 0)
{
ret=TRUE;
}
return ret;
}
int CircularQueue_NbElement(queue_t *q)
{
return q->elementCount;
}
@@ -0,0 +1,59 @@
/**
******************************************************************************
* @file stm_queue.h
* @author MCD Application Team
* @brief Header for stm_queue.c
******************************************************************************
* @attention
*
* Copyright (c) 2018-2021 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM_QUEUE_H
#define __STM_QUEUE_H
/* Includes ------------------------------------------------------------------*/
/* Exported define -----------------------------------------------------------*/
/* Options flags */
#define CIRCULAR_QUEUE_NO_FLAG 0
#define CIRCULAR_QUEUE_NO_WRAP_FLAG 1
#define CIRCULAR_QUEUE_SPLIT_IF_WRAPPING_FLAG 2
/* Exported types ------------------------------------------------------------*/
typedef struct {
uint8_t* qBuff; /* queue buffer, , provided by init fct */
uint32_t queueMaxSize; /* size of the queue, provided by init fct (in bytes)*/
uint16_t elementSize; /* -1 variable. If variable element size the size is stored in the 4 first of the queue element */
uint32_t first; /* position of first element */
uint32_t last; /* position of last element */
uint32_t byteCount; /* number of bytes in the queue */
uint32_t elementCount; /* number of element in the queue */
uint8_t optionFlags; /* option to enable specific features */
} queue_t;
/* Exported constants --------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
int CircularQueue_Init(queue_t *q, uint8_t* queueBuffer, uint32_t queueSize, uint16_t elementSize, uint8_t optionlags);
uint8_t* CircularQueue_Add(queue_t *q, uint8_t* x, uint16_t elementSize, uint32_t nbElements);
uint8_t* CircularQueue_Remove(queue_t *q, uint16_t* elementSize);
uint8_t* CircularQueue_Sense(queue_t *q, uint16_t* elementSize);
int CircularQueue_Empty(queue_t *q);
int CircularQueue_NbElement(queue_t *q);
uint8_t* CircularQueue_Remove_Copy(queue_t *q, uint16_t* elementSize, uint8_t* buffer);
uint8_t* CircularQueue_Sense_Copy(queue_t *q, uint16_t* elementSize, uint8_t* buffer);
#endif /* __STM_QUEUE_H */
@@ -0,0 +1,159 @@
/**
******************************************************************************
* @file utilities_common.h
* @author MCD Application Team
* @brief Common file to utilities
******************************************************************************
* @attention
*
* Copyright (c) 2018-2021 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __UTILITIES_COMMON_H
#define __UTILITIES_COMMON_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "app_conf.h"
/* -------------------------------- *
* Basic definitions *
* -------------------------------- */
#undef NULL
#define NULL 0
#undef FALSE
#define FALSE 0
#undef TRUE
#define TRUE (!0)
/* -------------------------------- *
* Critical Section definition *
* -------------------------------- */
#undef BACKUP_PRIMASK
#define BACKUP_PRIMASK() uint32_t primask_bit= __get_PRIMASK()
#undef DISABLE_IRQ
#define DISABLE_IRQ() __disable_irq()
#undef RESTORE_PRIMASK
#define RESTORE_PRIMASK() __set_PRIMASK(primask_bit)
/* -------------------------------- *
* Macro delimiters *
* -------------------------------- */
#undef M_BEGIN
#define M_BEGIN do {
#undef M_END
#define M_END } while(0)
/* -------------------------------- *
* Some useful macro definitions *
* -------------------------------- */
#undef MAX
#define MAX( x, y ) (((x)>(y))?(x):(y))
#undef MIN
#define MIN( x, y ) (((x)<(y))?(x):(y))
#undef MODINC
#define MODINC( a, m ) M_BEGIN (a)++; if ((a)>=(m)) (a)=0; M_END
#undef MODDEC
#define MODDEC( a, m ) M_BEGIN if ((a)==0) (a)=(m); (a)--; M_END
#undef MODADD
#define MODADD( a, b, m ) M_BEGIN (a)+=(b); if ((a)>=(m)) (a)-=(m); M_END
#undef MODSUB
#define MODSUB( a, b, m ) MODADD( a, (m)-(b), m )
#undef ALIGN
#ifdef WIN32
#define ALIGN(n)
#else
#define ALIGN(n) __attribute__((aligned(n)))
#endif
#undef PAUSE
#define PAUSE( t ) M_BEGIN \
volatile int _i; \
for ( _i = t; _i > 0; _i -- ); \
M_END
#undef DIVF
#define DIVF( x, y ) ((x)/(y))
#undef DIVC
#define DIVC( x, y ) (((x)+(y)-1)/(y))
#undef DIVR
#define DIVR( x, y ) (((x)+((y)/2))/(y))
#undef SHRR
#define SHRR( x, n ) ((((x)>>((n)-1))+1)>>1)
#undef BITN
#define BITN( w, n ) (((w)[(n)/32] >> ((n)%32)) & 1)
#undef BITNSET
#define BITNSET( w, n, b ) M_BEGIN (w)[(n)/32] |= ((U32)(b))<<((n)%32); M_END
/* -------------------------------- *
* Section attribute *
* -------------------------------- */
#define PLACE_IN_SECTION( __x__ ) __attribute__((section (__x__)))
/* ----------------------------------- *
* Packed usage (compiler dependent) *
* ----------------------------------- */
#undef PACKED__
#undef PACKED_STRUCT
#if defined ( __CC_ARM )
#if defined ( __GNUC__ )
/* GNU extension */
#define PACKED__ __attribute__((packed))
#define PACKED_STRUCT struct PACKED__
#elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050U)
#define PACKED__ __attribute__((packed))
#define PACKED_STRUCT struct PACKED__
#else
#define PACKED__(TYPE) __packed TYPE
#define PACKED_STRUCT PACKED__(struct)
#endif
#elif defined ( __GNUC__ )
#define PACKED__ __attribute__((packed))
#define PACKED_STRUCT struct PACKED__
#elif defined (__ICCARM__)
#define PACKED_STRUCT __packed struct
#else
#define PACKED_STRUCT __packed struct
#endif
#ifdef __cplusplus
}
#endif
#endif /*__UTILITIES_COMMON_H */