First commit
This commit is contained in:
@@ -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 */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user