This commit is contained in:
xavie
2025-12-05 17:08:34 +01:00
commit 6ff7181a1e
348 changed files with 308857 additions and 0 deletions

View File

@@ -0,0 +1,831 @@
/**
******************************************************************************
* @file stm32_adv_trace.c
* @author MCD Application Team
* @brief This file contains the advanced trace utility functions.
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32_adv_trace.h"
#include "stdarg.h"
#include "stdio.h"
/** @addtogroup ADV_TRACE
* @{
*/
/* Private defines -----------------------------------------------------------*/
/** @defgroup ADV_TRACE_Private_defines ADV_TRACE Privates defines
* @{
*/
/**
* @brief memory address of the trace buffer location.
* This define can be used, to change the buffer location.
*
*/
#if !defined(UTIL_ADV_TRACE_MEMLOCATION)
#define UTIL_ADV_TRACE_MEMLOCATION
#endif
#if defined(UTIL_ADV_TRACE_OVERRUN)
/**
* @brief List the overrun status.
* list of the overrun status used to handle the overrun trace evacuation.
*
* @note only valid if UTIL_ADV_TRACE_OVERRUN has been enabled inside utilities conf
*/
typedef enum {
TRACE_OVERRUN_NONE = 0, /*!<overrun status none. */
TRACE_OVERRUN_INDICATION, /*!<overrun status an indication shall be sent. */
TRACE_OVERRUN_TRANSFERT, /*!<overrun status data transfer ongoing. */
TRACE_OVERRUN_EXECUTED, /*!<overrun status data transfer complete. */
} TRACE_OVERRUN_STATUS;
#endif
#if defined(UTIL_ADV_TRACE_UNCHUNK_MODE)
/**
* @brief List the unchunk status.
* list of the unchunk status used to handle the unchunk case.
*
* @note only valid if UTIL_ADV_TRACE_UNCHUNK_MODE has been enabled inside utilities conf
*/
typedef enum {
TRACE_UNCHUNK_NONE = 0, /*!<unchunk status none. */
TRACE_UNCHUNK_DETECTED, /*!<unchunk status an unchunk has been detected. */
TRACE_UNCHUNK_TRANSFER /*!<unchunk status an unchunk transfer is ongoing. */
} TRACE_UNCHUNK_STATUS;
#endif
/**
* @}
*/
/**
* @brief advanced macro to override to enable debug mode
*/
#ifndef UTIL_ADV_TRACE_DEBUG
#define UTIL_ADV_TRACE_DEBUG(...)
#endif
/* Private macros ------------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/** @defgroup ADV_TRACE_private_typedef ADV_TRACE private typedef
* @{
*/
/**
* @brief ADV_TRACE_Context.
* this structure contains all the data to handle the trace context.
*
* @note some part of the context are depend with the selected switch inside the configuration file
* UTIL_ADV_TRACE_UNCHUNK_MODE, UTIL_ADV_TRACE_OVERRUN, UTIL_ADV_TRACE_CONDITIONNAL
*/
typedef struct {
#if defined(UTIL_ADV_TRACE_UNCHUNK_MODE)
uint16_t unchunk_enabled; /*!<unchunk enable. */
TRACE_UNCHUNK_STATUS unchunk_status; /*!<unchunk transfer status. */
#endif
#if defined(UTIL_ADV_TRACE_OVERRUN)
TRACE_OVERRUN_STATUS OverRunStatus; /*!<overrun status. */
cb_overrun *overrun_func; /*!<overrun function */
#endif
#if defined(UTIL_ADV_TRACE_CONDITIONNAL)
cb_timestamp *timestamp_func; /*!<ptr of function used to insert time stamp. */
uint8_t CurrentVerboseLevel; /*!<verbose level used. */
uint32_t RegionMask; /*!<mask of the enabled region. */
#endif
uint16_t TraceRdPtr; /*!<read pointer the trace system. */
uint16_t TraceWrPtr; /*!<write pointer the trace system. */
uint16_t TraceSentSize; /*!<size of the latest transfer. */
uint16_t TraceLock; /*!<lock counter of the trace system. */
} ADV_TRACE_Context;
/**
* @}
*/
/* Private variables ---------------------------------------------------------*/
/** @defgroup ADV_TRACE_private_variable ADV_TRACE private variable
* private variable of the advanced trace system.
* @{
*/
/**
* @brief trace context
* this variable contains all the internal data of the advanced trace system.
*/
static ADV_TRACE_Context ADV_TRACE_Ctx;
static UTIL_ADV_TRACE_MEMLOCATION uint8_t ADV_TRACE_Buffer[UTIL_ADV_TRACE_FIFO_SIZE];
#if defined(UTIL_ADV_TRACE_CONDITIONNAL) && defined(UTIL_ADV_TRACE_UNCHUNK_MODE)
/**
* @brief temporary buffer used by UTIL_ADV_TRACE_COND_FSend
* a temporary buffers variable used to evaluate a formatted string size.
*/
static uint8_t sztmp[UTIL_ADV_TRACE_TMP_BUF_SIZE];
#endif
/**
* @}
*/
/* Private function prototypes -----------------------------------------------*/
/** @defgroup ADV_TRACE_private_function ADV_TRACE private function
*
* @{
*/
static void TRACE_TxCpltCallback(void *Ptr);
static int16_t TRACE_AllocateBufer(uint16_t Size, uint16_t *Pos);
static UTIL_ADV_TRACE_Status_t TRACE_Send(void);
static void TRACE_Lock(void);
static void TRACE_UnLock(void);
static uint32_t TRACE_IsLocked(void);
/**
* @}
*/
/* Functions Definition ------------------------------------------------------*/
/** @addtogroup ADV_TRACE_exported_function
* @{
*/
UTIL_ADV_TRACE_Status_t UTIL_ADV_TRACE_Init(void)
{
/* initialize the Ptr for Read/Write */
(void)UTIL_ADV_TRACE_MEMSET8(&ADV_TRACE_Ctx, 0x0, sizeof(ADV_TRACE_Context));
(void)UTIL_ADV_TRACE_MEMSET8(&ADV_TRACE_Buffer, 0x0, sizeof(ADV_TRACE_Buffer));
#if defined(UTIL_ADV_TRACE_UNCHUNK_MODE)
UTIL_ADV_TRACE_DEBUG("\nUNCHUNK_MODE\n");
#endif
/* Allocate Lock resource */
UTIL_ADV_TRACE_INIT_CRITICAL_SECTION();
/* Initialize the Low Level interface */
return UTIL_TraceDriver.Init(TRACE_TxCpltCallback);
}
UTIL_ADV_TRACE_Status_t UTIL_ADV_TRACE_DeInit(void)
{
/* Un-initialize the Low Level interface */
return UTIL_TraceDriver.DeInit();
}
uint8_t UTIL_ADV_TRACE_IsBufferEmpty(void)
{
/* check of the buffer is empty */
if(ADV_TRACE_Ctx.TraceWrPtr == ADV_TRACE_Ctx.TraceRdPtr)
return 1;
return 0;
}
UTIL_ADV_TRACE_Status_t UTIL_ADV_TRACE_StartRxProcess(void (*UserCallback)(uint8_t *PData, uint16_t Size, uint8_t Error))
{
/* start the RX process */
return UTIL_TraceDriver.StartRx(UserCallback);
}
#if defined(UTIL_ADV_TRACE_CONDITIONNAL)
UTIL_ADV_TRACE_Status_t UTIL_ADV_TRACE_COND_FSend(uint32_t VerboseLevel, uint32_t Region, uint32_t TimeStampState, const char *strFormat, ...)
{
va_list vaArgs;
#if defined(UTIL_ADV_TRACE_UNCHUNK_MODE)
uint8_t buf[UTIL_ADV_TRACE_TMP_MAX_TIMESTMAP_SIZE];
uint16_t timestamp_size = 0u;
uint16_t writepos;
uint16_t idx;
#else
uint8_t buf[UTIL_ADV_TRACE_TMP_BUF_SIZE+UTIL_ADV_TRACE_TMP_MAX_TIMESTMAP_SIZE];
#endif
uint16_t buff_size = 0u;
/* check verbose level */
if(!(ADV_TRACE_Ctx.CurrentVerboseLevel >= VerboseLevel))
{
return UTIL_ADV_TRACE_GIVEUP;
}
if((Region & ADV_TRACE_Ctx.RegionMask) != Region)
{
return UTIL_ADV_TRACE_REGIONMASKED;
}
#if defined(UTIL_ADV_TRACE_UNCHUNK_MODE)
if((ADV_TRACE_Ctx.timestamp_func != NULL) && (TimeStampState != 0u))
{
ADV_TRACE_Ctx.timestamp_func(buf,&timestamp_size);
}
va_start( vaArgs, strFormat);
buff_size =(uint16_t)UTIL_ADV_TRACE_VSNPRINTF((char *)sztmp,UTIL_ADV_TRACE_TMP_BUF_SIZE, strFormat, vaArgs);
TRACE_Lock();
/* if allocation is ok, write data into the buffer */
if (TRACE_AllocateBufer((buff_size+timestamp_size),&writepos) != -1)
{
#if defined(UTIL_ADV_TRACE_OVERRUN)
UTIL_ADV_TRACE_ENTER_CRITICAL_SECTION();
if(ADV_TRACE_Ctx.OverRunStatus == TRACE_OVERRUN_EXECUTED)
{
/* clear the over run */
ADV_TRACE_Ctx.OverRunStatus = TRACE_OVERRUN_NONE;
}
UTIL_ADV_TRACE_EXIT_CRITICAL_SECTION();
#endif
/* copy the timestamp */
for (idx = 0u; idx < timestamp_size; idx++)
{
ADV_TRACE_Buffer[writepos] = buf[idx];
writepos = writepos + 1u;
}
/* copy the data */
(void)UTIL_ADV_TRACE_VSNPRINTF((char *)(&ADV_TRACE_Buffer[writepos]), UTIL_ADV_TRACE_TMP_BUF_SIZE, strFormat, vaArgs);
va_end(vaArgs);
TRACE_UnLock();
return TRACE_Send();
}
va_end(vaArgs);
TRACE_UnLock();
#if defined(UTIL_ADV_TRACE_OVERRUN)
UTIL_ADV_TRACE_ENTER_CRITICAL_SECTION();
if((ADV_TRACE_Ctx.OverRunStatus == TRACE_OVERRUN_NONE ) && (NULL != ADV_TRACE_Ctx.overrun_func))
{
UTIL_ADV_TRACE_DEBUG("UTIL_ADV_TRACE_Send:TRACE_OVERRUN_INDICATION");
ADV_TRACE_Ctx.OverRunStatus = TRACE_OVERRUN_INDICATION;
}
UTIL_ADV_TRACE_EXIT_CRITICAL_SECTION();
#endif
return UTIL_ADV_TRACE_MEM_FULL;
#else
if((ADV_TRACE_Ctx.timestamp_func != NULL) && (TimeStampState != 0u))
{
ADV_TRACE_Ctx.timestamp_func(buf,&buff_size);
}
va_start(vaArgs, strFormat);
buff_size += (uint16_t) UTIL_ADV_TRACE_VSNPRINTF((char* )(buf + buff_size), UTIL_ADV_TRACE_TMP_BUF_SIZE, strFormat, vaArgs);
va_end(vaArgs);
return UTIL_ADV_TRACE_Send(buf, buff_size);
#endif
}
#endif
UTIL_ADV_TRACE_Status_t UTIL_ADV_TRACE_FSend(const char *strFormat, ...)
{
uint8_t buf[UTIL_ADV_TRACE_TMP_BUF_SIZE];
va_list vaArgs;
va_start(vaArgs, strFormat);
uint16_t bufSize = (uint16_t) UTIL_ADV_TRACE_VSNPRINTF((char* )buf, UTIL_ADV_TRACE_TMP_BUF_SIZE, strFormat, vaArgs);
va_end(vaArgs);
return UTIL_ADV_TRACE_Send(buf, bufSize);
}
#if defined(UTIL_ADV_TRACE_CONDITIONNAL)
UTIL_ADV_TRACE_Status_t UTIL_ADV_TRACE_COND_ZCSend_Allocation(uint32_t VerboseLevel, uint32_t Region, uint32_t TimeStampState, uint16_t length, uint8_t **pData, uint16_t *FifoSize, uint16_t *WritePos)
{
UTIL_ADV_TRACE_Status_t ret = UTIL_ADV_TRACE_OK;
uint16_t writepos;
uint8_t timestamp_ptr[UTIL_ADV_TRACE_TMP_MAX_TIMESTMAP_SIZE];
uint16_t timestamp_size = 0u;
/* check verbose level */
if(!(ADV_TRACE_Ctx.CurrentVerboseLevel >= VerboseLevel))
{
return UTIL_ADV_TRACE_GIVEUP;
}
if((Region & ADV_TRACE_Ctx.RegionMask) != Region)
{
return UTIL_ADV_TRACE_REGIONMASKED;
}
if((ADV_TRACE_Ctx.timestamp_func != NULL) && (TimeStampState != 0u))
{
ADV_TRACE_Ctx.timestamp_func(timestamp_ptr, &timestamp_size);
}
TRACE_Lock();
/* if allocation is ok, write data into the buffer */
if (TRACE_AllocateBufer(length+timestamp_size, &writepos) != -1)
{
/* fill time stamp information */
for (uint16_t index = 0u; index < timestamp_size; index++)
{
ADV_TRACE_Buffer[writepos] = timestamp_ptr[index];
writepos = (uint16_t) ((writepos + 1u) % UTIL_ADV_TRACE_FIFO_SIZE);
}
/*user fill */
*pData = ADV_TRACE_Buffer;
*FifoSize = (uint16_t) UTIL_ADV_TRACE_FIFO_SIZE;
*WritePos = writepos;
}
else
{
TRACE_UnLock();
ret = UTIL_ADV_TRACE_MEM_FULL;
}
return ret;
}
UTIL_ADV_TRACE_Status_t UTIL_ADV_TRACE_COND_ZCSend_Finalize(void)
{
return UTIL_ADV_TRACE_ZCSend_Finalize();
}
#endif
UTIL_ADV_TRACE_Status_t UTIL_ADV_TRACE_ZCSend_Allocation(uint16_t Length, uint8_t **pData, uint16_t *FifoSize, uint16_t *WritePos)
{
UTIL_ADV_TRACE_Status_t ret = UTIL_ADV_TRACE_OK;
uint16_t writepos;
TRACE_Lock();
/* if allocation is ok, write data into the buffer */
if (TRACE_AllocateBufer(Length,&writepos) != -1)
{
/*user fill */
*pData = ADV_TRACE_Buffer;
*FifoSize = UTIL_ADV_TRACE_FIFO_SIZE;
*WritePos = (uint16_t)writepos;
}
else
{
TRACE_UnLock();
ret = UTIL_ADV_TRACE_MEM_FULL;
}
return ret;
}
UTIL_ADV_TRACE_Status_t UTIL_ADV_TRACE_ZCSend_Finalize(void)
{
TRACE_UnLock();
return TRACE_Send();
}
#if defined(UTIL_ADV_TRACE_CONDITIONNAL)
UTIL_ADV_TRACE_Status_t UTIL_ADV_TRACE_COND_Send(uint32_t VerboseLevel, uint32_t Region, uint32_t TimeStampState, const uint8_t *pData, uint16_t Length)
{
UTIL_ADV_TRACE_Status_t ret;
uint16_t writepos;
uint32_t idx;
uint8_t timestamp_ptr[UTIL_ADV_TRACE_TMP_MAX_TIMESTMAP_SIZE];
uint16_t timestamp_size = 0u;
/* check verbose level */
if(!(ADV_TRACE_Ctx.CurrentVerboseLevel >= VerboseLevel))
{
return UTIL_ADV_TRACE_GIVEUP;
}
if((Region & ADV_TRACE_Ctx.RegionMask) != Region)
{
return UTIL_ADV_TRACE_REGIONMASKED;
}
if((ADV_TRACE_Ctx.timestamp_func != NULL) && (TimeStampState != 0u))
{
ADV_TRACE_Ctx.timestamp_func(timestamp_ptr, &timestamp_size);
}
TRACE_Lock();
/* if allocation is ok, write data into the buffer */
if (TRACE_AllocateBufer(Length + timestamp_size, &writepos) != -1)
{
/* fill time stamp information */
for (idx = 0; idx < timestamp_size; idx++)
{
ADV_TRACE_Buffer[writepos] = timestamp_ptr[idx];
writepos = (uint16_t) ((writepos + 1u) % UTIL_ADV_TRACE_FIFO_SIZE);
}
for (idx = 0u; idx < Length; idx++)
{
ADV_TRACE_Buffer[writepos] = pData[idx];
writepos = (uint16_t) ((writepos + 1u) % UTIL_ADV_TRACE_FIFO_SIZE);
}
TRACE_UnLock();
ret = TRACE_Send();
}
else
{
TRACE_UnLock();
ret = UTIL_ADV_TRACE_MEM_FULL;
}
return ret;
}
#endif
UTIL_ADV_TRACE_Status_t UTIL_ADV_TRACE_Send(const uint8_t *pData, uint16_t Length)
{
UTIL_ADV_TRACE_Status_t ret;
uint16_t writepos;
uint32_t idx;
TRACE_Lock();
/* if allocation is ok, write data into the buffer */
if (TRACE_AllocateBufer(Length,&writepos) != -1)
{
/* initialize the Ptr for Read/Write */
for (idx = 0u; idx < Length; idx++)
{
ADV_TRACE_Buffer[writepos] = pData[idx];
writepos = (uint16_t) ((writepos + 1u) % UTIL_ADV_TRACE_FIFO_SIZE);
}
TRACE_UnLock();
ret = TRACE_Send();
}
else
{
TRACE_UnLock();
ret = UTIL_ADV_TRACE_MEM_FULL;
}
return ret;
}
#if defined(UTIL_ADV_TRACE_OVERRUN)
void UTIL_ADV_TRACE_RegisterOverRunFunction(cb_overrun *cb)
{
ADV_TRACE_Ctx.overrun_func = *cb;
}
#endif
#if defined(UTIL_ADV_TRACE_CONDITIONNAL)
void UTIL_ADV_TRACE_RegisterTimeStampFunction(cb_timestamp *cb)
{
ADV_TRACE_Ctx.timestamp_func = *cb;
}
void UTIL_ADV_TRACE_SetVerboseLevel(uint8_t Level)
{
ADV_TRACE_Ctx.CurrentVerboseLevel = Level;
}
uint8_t UTIL_ADV_TRACE_GetVerboseLevel(void)
{
return ADV_TRACE_Ctx.CurrentVerboseLevel;
}
void UTIL_ADV_TRACE_SetRegion(uint32_t Region)
{
ADV_TRACE_Ctx.RegionMask |= Region;
}
uint32_t UTIL_ADV_TRACE_GetRegion(void)
{
return ADV_TRACE_Ctx.RegionMask;
}
void UTIL_ADV_TRACE_ResetRegion(uint32_t Region)
{
ADV_TRACE_Ctx.RegionMask &= ~Region;
}
#endif
__WEAK void UTIL_ADV_TRACE_PreSendHook(void)
{
}
__WEAK void UTIL_ADV_TRACE_PostSendHook(void)
{
}
/**
* @}
*/
/** @addtogroup ADV_TRACE_private_function
* @{
*/
/**
* @brief send the data of the trace to low layer
* @retval Status based on @ref UTIL_ADV_TRACE_Status_t
*/
static UTIL_ADV_TRACE_Status_t TRACE_Send(void)
{
UTIL_ADV_TRACE_Status_t ret = UTIL_ADV_TRACE_OK;
uint8_t *ptr = NULL;
UTIL_ADV_TRACE_ENTER_CRITICAL_SECTION();
if(TRACE_IsLocked() == 0u)
{
TRACE_Lock();
if(ADV_TRACE_Ctx.TraceRdPtr != ADV_TRACE_Ctx.TraceWrPtr)
{
#ifdef UTIL_ADV_TRACE_UNCHUNK_MODE
if(TRACE_UNCHUNK_DETECTED == ADV_TRACE_Ctx.unchunk_status)
{
ADV_TRACE_Ctx.TraceSentSize = (uint16_t) (ADV_TRACE_Ctx.unchunk_enabled - ADV_TRACE_Ctx.TraceRdPtr);
ADV_TRACE_Ctx.unchunk_status = TRACE_UNCHUNK_TRANSFER;
ADV_TRACE_Ctx.unchunk_enabled = 0;
UTIL_ADV_TRACE_DEBUG("\nTRACE_TxCpltCallback::unchunk start(%d,%d)\n", ADV_TRACE_Ctx.unchunk_enabled, ADV_TRACE_Ctx.TraceRdPtr);
if(0u == ADV_TRACE_Ctx.TraceSentSize)
{
ADV_TRACE_Ctx.unchunk_status = TRACE_UNCHUNK_NONE;
ADV_TRACE_Ctx.TraceRdPtr = 0;
}
}
if(TRACE_UNCHUNK_NONE == ADV_TRACE_Ctx.unchunk_status)
{
#endif
if(ADV_TRACE_Ctx.TraceWrPtr > ADV_TRACE_Ctx.TraceRdPtr)
{
ADV_TRACE_Ctx.TraceSentSize = ADV_TRACE_Ctx.TraceWrPtr - ADV_TRACE_Ctx.TraceRdPtr;
}
else /* TraceRdPtr > TraceWrPtr */
{
ADV_TRACE_Ctx.TraceSentSize = UTIL_ADV_TRACE_FIFO_SIZE - ADV_TRACE_Ctx.TraceRdPtr;
}
#ifdef UTIL_ADV_TRACE_UNCHUNK_MODE
}
#endif
ptr = &ADV_TRACE_Buffer[ADV_TRACE_Ctx.TraceRdPtr];
UTIL_ADV_TRACE_EXIT_CRITICAL_SECTION();
UTIL_ADV_TRACE_PreSendHook();
UTIL_ADV_TRACE_DEBUG("\n--TRACE_Send(%d-%d)--\n", ADV_TRACE_Ctx.TraceRdPtr, ADV_TRACE_Ctx.TraceSentSize);
ret = UTIL_TraceDriver.Send(ptr, ADV_TRACE_Ctx.TraceSentSize);
}
else
{
TRACE_UnLock();
UTIL_ADV_TRACE_EXIT_CRITICAL_SECTION();
}
}
else
{
UTIL_ADV_TRACE_EXIT_CRITICAL_SECTION();
}
return ret;
}
/**
* @brief Tx callback called by the low layer level to inform a transfer complete
* @param Ptr pointer not used only for HAL compatibility
* @retval none
*/
static void TRACE_TxCpltCallback(void *Ptr)
{
uint8_t *ptr = NULL;
UTIL_ADV_TRACE_ENTER_CRITICAL_SECTION();
#if defined(UTIL_ADV_TRACE_OVERRUN)
if(ADV_TRACE_Ctx.OverRunStatus == TRACE_OVERRUN_TRANSFERT)
{
ADV_TRACE_Ctx.OverRunStatus = TRACE_OVERRUN_EXECUTED;
UTIL_ADV_TRACE_DEBUG("\n--TRACE_Send overrun complete--\n");
ADV_TRACE_Ctx.TraceSentSize = 0u;
}
#endif
#if defined(UTIL_ADV_TRACE_UNCHUNK_MODE)
if(TRACE_UNCHUNK_TRANSFER == ADV_TRACE_Ctx.unchunk_status)
{
ADV_TRACE_Ctx.unchunk_status = TRACE_UNCHUNK_NONE;
ADV_TRACE_Ctx.TraceRdPtr = 0;
UTIL_ADV_TRACE_DEBUG("\nTRACE_TxCpltCallback::unchunk complete\n");
}
else
{
ADV_TRACE_Ctx.TraceRdPtr = (ADV_TRACE_Ctx.TraceRdPtr + ADV_TRACE_Ctx.TraceSentSize) % UTIL_ADV_TRACE_FIFO_SIZE;
}
#else
ADV_TRACE_Ctx.TraceRdPtr = (ADV_TRACE_Ctx.TraceRdPtr + ADV_TRACE_Ctx.TraceSentSize) % UTIL_ADV_TRACE_FIFO_SIZE;
#endif
#if defined(UTIL_ADV_TRACE_OVERRUN)
if(ADV_TRACE_Ctx.OverRunStatus == TRACE_OVERRUN_INDICATION)
{
uint8_t *ptr = NULL;
ADV_TRACE_Ctx.OverRunStatus = TRACE_OVERRUN_TRANSFERT;
UTIL_ADV_TRACE_EXIT_CRITICAL_SECTION();
ADV_TRACE_Ctx.overrun_func(&ptr, &ADV_TRACE_Ctx.TraceSentSize);
UTIL_ADV_TRACE_DEBUG("\n--Driver_Send overrun(%d)--\n", ADV_TRACE_Ctx.TraceSentSize);
UTIL_TraceDriver.Send(ptr, ADV_TRACE_Ctx.TraceSentSize);
return;
}
#endif
if((ADV_TRACE_Ctx.TraceRdPtr != ADV_TRACE_Ctx.TraceWrPtr) && (1u == ADV_TRACE_Ctx.TraceLock))
{
#ifdef UTIL_ADV_TRACE_UNCHUNK_MODE
if(TRACE_UNCHUNK_DETECTED == ADV_TRACE_Ctx.unchunk_status)
{
ADV_TRACE_Ctx.TraceSentSize = ADV_TRACE_Ctx.unchunk_enabled - ADV_TRACE_Ctx.TraceRdPtr;
ADV_TRACE_Ctx.unchunk_status = TRACE_UNCHUNK_TRANSFER;
ADV_TRACE_Ctx.unchunk_enabled = 0;
UTIL_ADV_TRACE_DEBUG("\nTRACE_TxCpltCallback::unchunk start(%d,%d)\n", ADV_TRACE_Ctx.unchunk_enabled, ADV_TRACE_Ctx.TraceRdPtr);
if(0u == ADV_TRACE_Ctx.TraceSentSize)
{
/* this case occurs when an ongoing write aligned the Rd position with chunk position */
/* in that case the unchunk is forgot */
ADV_TRACE_Ctx.unchunk_status = TRACE_UNCHUNK_NONE;
ADV_TRACE_Ctx.TraceRdPtr = 0;
}
}
if(TRACE_UNCHUNK_NONE == ADV_TRACE_Ctx.unchunk_status)
{
#endif
if(ADV_TRACE_Ctx.TraceWrPtr > ADV_TRACE_Ctx.TraceRdPtr)
{
ADV_TRACE_Ctx.TraceSentSize = ADV_TRACE_Ctx.TraceWrPtr - ADV_TRACE_Ctx.TraceRdPtr;
}
else /* TraceRdPtr > TraceWrPtr */
{
ADV_TRACE_Ctx.TraceSentSize = UTIL_ADV_TRACE_FIFO_SIZE - ADV_TRACE_Ctx.TraceRdPtr;
}
#ifdef UTIL_ADV_TRACE_UNCHUNK_MODE
}
#endif
ptr = &ADV_TRACE_Buffer[ADV_TRACE_Ctx.TraceRdPtr];
UTIL_ADV_TRACE_EXIT_CRITICAL_SECTION();
UTIL_ADV_TRACE_DEBUG("\n--TRACE_Send(%d-%d)--\n", ADV_TRACE_Ctx.TraceRdPtr, ADV_TRACE_Ctx.TraceSentSize);
UTIL_TraceDriver.Send(ptr, ADV_TRACE_Ctx.TraceSentSize);
}
else
{
UTIL_ADV_TRACE_EXIT_CRITICAL_SECTION();
UTIL_ADV_TRACE_PostSendHook();
TRACE_UnLock();
}
}
/**
* @brief allocate space inside the buffer to push data
* @param Size to allocate within fifo
* @param Pos position within the fifo
* @retval write position inside the buffer is -1 no space available.
*/
static int16_t TRACE_AllocateBufer(uint16_t Size, uint16_t *Pos)
{
uint16_t freesize;
int16_t ret = -1;
UTIL_ADV_TRACE_ENTER_CRITICAL_SECTION();
if(ADV_TRACE_Ctx.TraceWrPtr == ADV_TRACE_Ctx.TraceRdPtr)
{
#ifdef UTIL_ADV_TRACE_UNCHUNK_MODE
freesize = (uint16_t)(UTIL_ADV_TRACE_FIFO_SIZE - ADV_TRACE_Ctx.TraceWrPtr);
if((Size >= freesize) && (ADV_TRACE_Ctx.TraceRdPtr > Size))
{
ADV_TRACE_Ctx.unchunk_status = TRACE_UNCHUNK_DETECTED;
ADV_TRACE_Ctx.unchunk_enabled = ADV_TRACE_Ctx.TraceWrPtr;
freesize = ADV_TRACE_Ctx.TraceRdPtr;
ADV_TRACE_Ctx.TraceWrPtr = 0;
}
#else
/* need to add buffer full management*/
freesize = (int16_t)UTIL_ADV_TRACE_FIFO_SIZE;
#endif
}
else
{
#ifdef UTIL_ADV_TRACE_UNCHUNK_MODE
if (ADV_TRACE_Ctx.TraceWrPtr > ADV_TRACE_Ctx.TraceRdPtr)
{
freesize = (uint16_t)(UTIL_ADV_TRACE_FIFO_SIZE - ADV_TRACE_Ctx.TraceWrPtr);
if((Size >= freesize) && (ADV_TRACE_Ctx.TraceRdPtr > Size))
{
ADV_TRACE_Ctx.unchunk_status = TRACE_UNCHUNK_DETECTED;
ADV_TRACE_Ctx.unchunk_enabled = ADV_TRACE_Ctx.TraceWrPtr;
freesize = ADV_TRACE_Ctx.TraceRdPtr;
ADV_TRACE_Ctx.TraceWrPtr = 0;
}
}
else
{
freesize = (uint16_t)(ADV_TRACE_Ctx.TraceRdPtr - ADV_TRACE_Ctx.TraceWrPtr);
}
#else
if (ADV_TRACE_Ctx.TraceWrPtr > ADV_TRACE_Ctx.TraceRdPtr)
{
freesize = UTIL_ADV_TRACE_FIFO_SIZE - ADV_TRACE_Ctx.TraceWrPtr + ADV_TRACE_Ctx.TraceRdPtr;
}
else
{
freesize = ADV_TRACE_Ctx.TraceRdPtr - ADV_TRACE_Ctx.TraceWrPtr;
}
#endif
}
if(freesize > Size)
{
*Pos = ADV_TRACE_Ctx.TraceWrPtr;
ADV_TRACE_Ctx.TraceWrPtr = (ADV_TRACE_Ctx.TraceWrPtr + Size) % UTIL_ADV_TRACE_FIFO_SIZE;
ret = 0;
#if defined(UTIL_ADV_TRACE_OVERRUN)
if(ADV_TRACE_Ctx.OverRunStatus == TRACE_OVERRUN_EXECUTED)
{
/* clear the over run */
ADV_TRACE_Ctx.OverRunStatus = TRACE_OVERRUN_NONE;
}
#endif
#ifdef UTIL_ADV_TRACE_UNCHUNK_MODE
UTIL_ADV_TRACE_DEBUG("\n--TRACE_AllocateBufer(%d-%d-%d::%d-%d)--\n", freesize - Size, Size, ADV_TRACE_Ctx.unchunk_enabled, ADV_TRACE_Ctx.TraceRdPtr, ADV_TRACE_Ctx.TraceWrPtr);
#else
UTIL_ADV_TRACE_DEBUG("\n--TRACE_AllocateBufer(%d-%d::%d-%d)--\n",freesize - Size, Size, ADV_TRACE_Ctx.TraceRdPtr, ADV_TRACE_Ctx.TraceWrPtr);
#endif
}
#if defined(UTIL_ADV_TRACE_OVERRUN)
else
{
if((ADV_TRACE_Ctx.OverRunStatus == TRACE_OVERRUN_NONE) && (NULL != ADV_TRACE_Ctx.overrun_func))
{
UTIL_ADV_TRACE_DEBUG(":TRACE_OVERRUN_INDICATION");
ADV_TRACE_Ctx.OverRunStatus = TRACE_OVERRUN_INDICATION;
}
}
#endif
UTIL_ADV_TRACE_EXIT_CRITICAL_SECTION();
return ret;
}
/**
* @brief Lock the trace buffer.
* @retval None.
*/
static void TRACE_Lock(void)
{
UTIL_ADV_TRACE_ENTER_CRITICAL_SECTION();
ADV_TRACE_Ctx.TraceLock++;
UTIL_ADV_TRACE_EXIT_CRITICAL_SECTION();
}
/**
* @brief UnLock the trace buffer.
* @retval None.
*/
static void TRACE_UnLock(void)
{
UTIL_ADV_TRACE_ENTER_CRITICAL_SECTION();
ADV_TRACE_Ctx.TraceLock--;
UTIL_ADV_TRACE_EXIT_CRITICAL_SECTION();
}
/**
* @brief UnLock the trace buffer.
* @retval None.
*/
static uint32_t TRACE_IsLocked(void)
{
return (ADV_TRACE_Ctx.TraceLock == 0u? 0u: 1u);
}
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@@ -0,0 +1,65 @@
/**
******************************************************************************
* @file stm32_mem.c
* @author MCD Application Team
* @brief standard memory operation
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stdint.h"
#include "stm32_mem.h"
/* Private typedef -----------------------------------------------------------*/
/* Private defines -----------------------------------------------------------*/
/* Private macros ------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Global variables ----------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Functions Definition ------------------------------------------------------*/
void UTIL_MEM_cpy_8( void *dst, const void *src, uint16_t size )
{
uint8_t* dst8= (uint8_t *) dst;
uint8_t* src8= (uint8_t *) src;
while( size-- )
{
*dst8++ = *src8++;
}
}
void UTIL_MEM_cpyr_8( void *dst, const void *src, uint16_t size )
{
uint8_t* dst8= (uint8_t *) dst;
uint8_t* src8= (uint8_t *) src;
dst8 = dst8 + ( size - 1 );
while( size-- )
{
*dst8-- = *src8++;
}
}
void UTIL_MEM_set_8( void *dst, uint8_t value, uint16_t size )
{
uint8_t* dst8= (uint8_t *) dst;
while( size-- )
{
*dst8++ = value;
}
}
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@@ -0,0 +1,512 @@
/**
******************************************************************************
* @file stm32_seq.c
* @author MCD Application Team
* @brief Simple sequencer implementation
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32_seq.h"
#include "utilities_conf.h"
/** @addtogroup SEQUENCER
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/** @defgroup SEQUENCER_Private_type SEQUENCER private type
* @{
*/
/**
* @brief structure used to manage task scheduling
*/
typedef struct
{
uint32_t priority; /*!<bit field of the enabled task. */
uint32_t round_robin; /*!<mask on the allowed task to be running. */
} UTIL_SEQ_Priority_t;
/**
* @}
*/
/* Private defines -----------------------------------------------------------*/
/** @defgroup SEQUENCER_Private_define SEQUENCER private defines
* @{
*/
/**
* @brief macro used to enter the critical section before calling the IDLE function
* @note in a basic configuration shall be identical to the macro
* UTIL_SEQ_ENTER_CRITICAL_SECTION. The redefinition of this macro will allow
* to perform specific operation
*/
#ifndef UTIL_SEQ_ENTER_CRITICAL_SECTION_IDLE
#define UTIL_SEQ_ENTER_CRITICAL_SECTION_IDLE( ) UTIL_SEQ_ENTER_CRITICAL_SECTION( )
#endif
/**
* @brief macro used to exit the critical section when exiting the IDLE function
* @note the behavior of the macro shall be symmetrical with the macro
* UTIL_SEQ_ENTER_CRITICAL_SECTION_IDLE
*/
#ifndef UTIL_SEQ_EXIT_CRITICAL_SECTION_IDLE
#define UTIL_SEQ_EXIT_CRITICAL_SECTION_IDLE( ) UTIL_SEQ_EXIT_CRITICAL_SECTION( )
#endif
/**
* @brief define to represent no task running
*/
#define UTIL_SEQ_NOTASKRUNNING (0xFFFFFFFFU)
/**
* @brief define to represent no bit set inside uint32_t mapping
*/
#define UTIL_SEQ_NO_BIT_SET (0U)
/**
* @brief define to represent all bits set inside uint32_t mapping
*/
#define UTIL_SEQ_ALL_BIT_SET (~0U)
/**
* @brief default number of task is default 32 (maximum), can be reduced by redefining in utilities_conf.h
*/
#ifndef UTIL_SEQ_CONF_TASK_NBR
#define UTIL_SEQ_CONF_TASK_NBR (32)
#endif
#if UTIL_SEQ_CONF_TASK_NBR > 32
#error "UTIL_SEQ_CONF_PRIO_NBR must be less of equal then 32"
#endif
/**
* @brief default value of priority number.
*/
#ifndef UTIL_SEQ_CONF_PRIO_NBR
#define UTIL_SEQ_CONF_PRIO_NBR (2)
#endif
/**
* @brief default memset function.
*/
#ifndef UTIL_SEQ_MEMSET8
#define UTIL_SEQ_MEMSET8( dest, value, size ) UTILS_MEMSET8( dest, value, size )
#endif
/**
* @}
*/
/* Private variables ---------------------------------------------------------*/
/** @defgroup SEQUENCER_Private_varaible SEQUENCER private variables
* @{
*/
/**
* @brief task set.
*/
static UTIL_SEQ_bm_t TaskSet;
/**
* @brief task mask.
*/
static UTIL_SEQ_bm_t TaskMask = UTIL_SEQ_ALL_BIT_SET;
/**
* @brief super mask.
*/
static UTIL_SEQ_bm_t SuperMask = UTIL_SEQ_ALL_BIT_SET;
/**
* @brief evt set mask.
*/
static UTIL_SEQ_bm_t EvtSet = UTIL_SEQ_NO_BIT_SET;
/**
* @brief evt expected mask.
*/
static UTIL_SEQ_bm_t EvtWaited = UTIL_SEQ_NO_BIT_SET;
/**
* @brief current task id.
*/
static uint32_t CurrentTaskIdx = 0U;
/**
* @brief task function registered.
*/
static void (*TaskCb[UTIL_SEQ_CONF_TASK_NBR])( void );
/**
* @brief task prio management.
*/
static UTIL_SEQ_Priority_t TaskPrio[UTIL_SEQ_CONF_PRIO_NBR];
/**
* @}
*/
/* Private function prototypes -----------------------------------------------*/
/** @defgroup SEQUENCER_Private_function SEQUENCER private functions
* @{
*/
uint8_t SEQ_BitPosition(uint32_t Value);
/**
* @}
*/
/* Functions Definition ------------------------------------------------------*/
/** @addtogroup SEQUENCER_Exported_function SEQUENCER exported functions
* @{
*/
void UTIL_SEQ_Init( void )
{
TaskSet = UTIL_SEQ_NO_BIT_SET;
TaskMask = UTIL_SEQ_ALL_BIT_SET;
SuperMask = UTIL_SEQ_ALL_BIT_SET;
EvtSet = UTIL_SEQ_NO_BIT_SET;
EvtWaited = UTIL_SEQ_NO_BIT_SET;
CurrentTaskIdx = 0U;
(void)UTIL_SEQ_MEMSET8(TaskCb, 0, sizeof(TaskCb));
(void)UTIL_SEQ_MEMSET8(TaskPrio, 0, sizeof(TaskPrio));
UTIL_SEQ_INIT_CRITICAL_SECTION( );
}
void UTIL_SEQ_DeInit( void )
{
}
/**
* This function can be nested.
* That is the reason why many variables that are used only in that function are declared static.
* Note: These variables could have been declared static in the function.
*/
void UTIL_SEQ_Run( UTIL_SEQ_bm_t Mask_bm )
{
uint32_t counter;
UTIL_SEQ_bm_t current_task_set;
UTIL_SEQ_bm_t super_mask_backup;
/**
* When this function is nested, the mask to be applied cannot be larger than the first call
* The mask is always getting smaller and smaller
* A copy is made of the mask set by UTIL_SEQ_Run() in case it is called again in the task
*/
super_mask_backup = SuperMask;
SuperMask &= Mask_bm;
/**
* There are two independent mask to check:
* TaskMask that comes from UTIL_SEQ_PauseTask() / UTIL_SEQ_ResumeTask
* SuperMask that comes from UTIL_SEQ_Run
* If the waited event is there, exit from UTIL_SEQ_Run() to return to the
* waiting task
*/
while(((TaskSet & TaskMask & SuperMask) != 0U) && ((EvtSet & EvtWaited)==0U))
{
counter = 0U;
/**
* When a flag is set, the associated bit is set in TaskPrio[counter].priority mask depending
* on the priority parameter given from UTIL_SEQ_SetTask()
* The while loop is looking for a flag set from the highest priority maskr to the lower
*/
while((TaskPrio[counter].priority & TaskMask & SuperMask)== 0U)
{
counter++;
}
current_task_set = TaskPrio[counter].priority & TaskMask & SuperMask;
/**
* The round_robin register is a mask of allowed flags to be evaluated.
* The concept is to make sure that on each round on UTIL_SEQ_Run(), if two same flags are always set,
* the sequencer does not run always only the first one.
* When a task has been executed, The flag is removed from the round_robin mask.
* If on the next UTIL_SEQ_RUN(), the two same flags are set again, the round_robin mask will mask out the first flag
* so that the second one can be executed.
* Note that the first flag is not removed from the list of pending task but just masked by the round_robin mask
*
* In the check below, the round_robin mask is reitialize in case all pending tasks haven been executed at least once
*/
if ((TaskPrio[counter].round_robin & current_task_set) == 0U)
{
TaskPrio[counter].round_robin = UTIL_SEQ_ALL_BIT_SET;
}
/** Read the flag index of the task to be executed
* Once the index is read, the associated task will be executed even though a higher priority stack is requested
* before task execution.
*/
CurrentTaskIdx = (SEQ_BitPosition(current_task_set & TaskPrio[counter].round_robin));
/** remove from the roun_robin mask the task that has been selected to be executed */
TaskPrio[counter].round_robin &= ~(1U << CurrentTaskIdx);
UTIL_SEQ_ENTER_CRITICAL_SECTION( );
/** remove from the list or pending task the one that has been selected to be executed */
TaskSet &= ~(1U << CurrentTaskIdx);
/** remove from all priority mask the task that has been selected to be executed */
for (counter = UTIL_SEQ_CONF_PRIO_NBR; counter != 0U; counter--)
{
TaskPrio[counter - 1U].priority &= ~(1U << CurrentTaskIdx);
}
UTIL_SEQ_EXIT_CRITICAL_SECTION( );
/** Execute the task */
TaskCb[CurrentTaskIdx]( );
}
/* the set of CurrentTaskIdx to no task running allows to call WaitEvt in the Pre/Post ilde context */
CurrentTaskIdx = UTIL_SEQ_NOTASKRUNNING;
UTIL_SEQ_PreIdle( );
UTIL_SEQ_ENTER_CRITICAL_SECTION_IDLE( );
if (!(((TaskSet & TaskMask & SuperMask) != 0U) || ((EvtSet & EvtWaited)!= 0U)))
{
UTIL_SEQ_Idle( );
}
UTIL_SEQ_EXIT_CRITICAL_SECTION_IDLE( );
UTIL_SEQ_PostIdle( );
/** restore the mask from UTIL_SEQ_Run() */
SuperMask = super_mask_backup;
return;
}
void UTIL_SEQ_RegTask(UTIL_SEQ_bm_t TaskId_bm, uint32_t Flags, void (*Task)( void ))
{
UTIL_SEQ_ENTER_CRITICAL_SECTION();
TaskCb[SEQ_BitPosition(TaskId_bm)] = Task;
UTIL_SEQ_EXIT_CRITICAL_SECTION();
return;
}
void UTIL_SEQ_SetTask( UTIL_SEQ_bm_t TaskId_bm , uint32_t Task_Prio )
{
UTIL_SEQ_ENTER_CRITICAL_SECTION( );
TaskSet |= TaskId_bm;
TaskPrio[Task_Prio].priority |= TaskId_bm;
UTIL_SEQ_EXIT_CRITICAL_SECTION( );
return;
}
uint32_t UTIL_SEQ_IsSchedulableTask( UTIL_SEQ_bm_t TaskId_bm)
{
uint32_t _status;
UTIL_SEQ_ENTER_CRITICAL_SECTION();
_status = ((TaskSet & TaskMask & SuperMask & TaskId_bm) == TaskId_bm)? 1U: 0U;
UTIL_SEQ_EXIT_CRITICAL_SECTION();
return _status;
}
void UTIL_SEQ_PauseTask( UTIL_SEQ_bm_t TaskId_bm )
{
UTIL_SEQ_ENTER_CRITICAL_SECTION( );
TaskMask &= (~TaskId_bm);
UTIL_SEQ_EXIT_CRITICAL_SECTION( );
return;
}
uint32_t UTIL_SEQ_IsPauseTask( UTIL_SEQ_bm_t TaskId_bm )
{
uint32_t _status;
UTIL_SEQ_ENTER_CRITICAL_SECTION( );
_status = ((TaskMask & TaskId_bm) == TaskId_bm) ? 0:1;
UTIL_SEQ_EXIT_CRITICAL_SECTION( );
return _status;
}
void UTIL_SEQ_ResumeTask( UTIL_SEQ_bm_t TaskId_bm )
{
UTIL_SEQ_ENTER_CRITICAL_SECTION( );
TaskMask |= TaskId_bm;
UTIL_SEQ_EXIT_CRITICAL_SECTION( );
return;
}
void UTIL_SEQ_SetEvt( UTIL_SEQ_bm_t EvtId_bm )
{
UTIL_SEQ_ENTER_CRITICAL_SECTION( );
EvtSet |= EvtId_bm;
UTIL_SEQ_EXIT_CRITICAL_SECTION( );
return;
}
void UTIL_SEQ_ClrEvt( UTIL_SEQ_bm_t EvtId_bm )
{
UTIL_SEQ_ENTER_CRITICAL_SECTION( );
EvtSet &= (~EvtId_bm);
UTIL_SEQ_EXIT_CRITICAL_SECTION( );
return;
}
void UTIL_SEQ_WaitEvt(UTIL_SEQ_bm_t EvtId_bm)
{
UTIL_SEQ_bm_t event_waited_id_backup;
UTIL_SEQ_bm_t current_task_idx;
UTIL_SEQ_bm_t wait_task_idx;
/** store in local the current_task_id_bm as the global variable CurrentTaskIdx
* may be overwritten in case there are nested call of UTIL_SEQ_Run()
*/
current_task_idx = CurrentTaskIdx;
if(UTIL_SEQ_NOTASKRUNNING == CurrentTaskIdx)
{
wait_task_idx = 0;
}
else
{
wait_task_idx = 1 << CurrentTaskIdx;
}
/** backup the event id that was currently waited */
event_waited_id_backup = EvtWaited;
EvtWaited = EvtId_bm;
/**
* wait for the new event
* note: that means that if the previous waited event occurs, it will not exit
* the while loop below.
* The system is waiting only for the last waited event.
* When it will go out, it will wait again from the previous one.
* It case it occurs while waiting for the second one, the while loop will exit immediately
*/
while ((EvtSet & EvtWaited) == 0U)
{
UTIL_SEQ_EvtIdle(wait_task_idx, EvtWaited);
}
/**
* Restore the CurrentTaskIdx that may have been modified by call of UTIL_SEQ_Run() from UTIL_SEQ_EvtIdle()
* This is required so that a second call of UTIL_SEQ_WaitEvt() in the same process pass the correct current_task_id_bm
* in the call of UTIL_SEQ_EvtIdle()
*/
CurrentTaskIdx = current_task_idx;
EvtSet &= (~EvtWaited);
EvtWaited = event_waited_id_backup;
return;
}
UTIL_SEQ_bm_t UTIL_SEQ_IsEvtPend( void )
{
return (EvtSet & EvtWaited);
}
__WEAK void UTIL_SEQ_EvtIdle( UTIL_SEQ_bm_t TaskId_bm, UTIL_SEQ_bm_t EvtWaited_bm )
{
UTIL_SEQ_Run(~TaskId_bm);
return;
}
__WEAK void UTIL_SEQ_Idle( void )
{
return;
}
__WEAK void UTIL_SEQ_PreIdle( void )
{
/**
* Unless specified by the application, there is nothing to be done
*/
return;
}
__WEAK void UTIL_SEQ_PostIdle( void )
{
/**
* Unless specified by the application, there is nothing to be done
*/
return;
}
/**
* @}
*/
/** @addtogroup SEQUENCER_Private_function
* @{
*/
#if( __CORTEX_M == 0)
static const uint8_t SEQ_clz_table_4bit[16] = { 4U, 3U, 2U, 2U, 1U, 1U, 1U, 1U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U };
/**
* @brief return the position of the first bit set to 1
* @param Value 32 bit value
* @retval bit position
*/
uint8_t SEQ_BitPosition(uint32_t Value)
{
uint8_t n = 0U;
if ((Value & 0xFFFF0000U) == 0U) { n = 16U; Value <<= 16U; }
if ((Value & 0xFF000000U) == 0U) { n += 8U; Value <<= 8U; }
if ((Value & 0xF0000000U) == 0U) { n += 4U; Value <<= 4U; }
n += SEQ_clz_table_4bit[Value >> (32-4)];
return (uint8_t)(31U-n);
}
#else
/**
* @brief return the position of the first bit set to 1
* @param Value 32 bit value
* @retval bit position
*/
uint8_t SEQ_BitPosition(uint32_t Value)
{
return (uint8_t)(31 -__CLZ( Value ));
}
#endif
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@@ -0,0 +1,500 @@
/*!
* \file systime.c
*
* \brief System time functions implementation.
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013-2018 Semtech - STMicroelectronics
*
* \endcode
*
* \author Miguel Luis ( Semtech )
*
* \author Gregory Cristian ( Semtech )
*
* \author MCD Application Team ( STMicroelectronics International )
*/
/**
******************************************************************************
* @file stm32_systime.c
* @author MCD Application Team
* @brief System time functions implementation
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include <stdio.h>
#include "stm32_systime.h"
/** @addtogroup SYS_TIME
* @{
*/
/* Private defines -----------------------------------------------------------*/
/**
* @defgroup SYS_TIME_private_defines SYS_TIME private defines
* @{
*/
/**
* @brief number of day in leap year up to the end of February
*
*/
#define END_OF_FEBRUARY_LEAP 60 //31+29
/**
* @brief number of day in leap year up to the end of july
*
*/
#define END_OF_JULY_LEAP 213 //31+29+...
/**
* @brief number of day in normal year up to the end of February
*
*/
#define END_OF_FEBRUARY_NORM 59 //31+28
/**
* @brief number of day in normal year up to the end of july
*
*/
#define END_OF_JULY_NORM 212 //31+28+...
/**
* @brief delta is referenced to Unix time
* @note UNIX time 0 = starts at 01:00:00, 01/01/1970
* but calculation is easier from Monday 1st January 1968
*
*/
#define CALC_REF_YEAR 68
/**
* @brief delta is referenced to Unix time
* @note UNIX time 0 = starts at 01:00:00, 01/01/1970
* but calculation is easier from Monday 1st January 1968
*
*/
#define CALC_REF_YEAR_TO_UNIX_REF_YEAR_COMPENSATION_IN_SECONDS ( ( TM_DAYS_IN_LEAP_YEAR + TM_DAYS_IN_YEAR ) * TM_SECONDS_IN_1DAY )
/**
* @brief month correction table of a normal year. To calculate the day number within a year
* @note error compensation is between 0 and 2 days. 2 bits per month
*
*/
#define DAYS_IN_MONTH_CORRECTION_NORM ( (uint32_t )0x99AAA0 )
/**
* @brief month correction table of a leap year. To calculate the day number within a year
* @note error compensation is between 0 and 2 days. 2 bits per month
*
*/
#define DAYS_IN_MONTH_CORRECTION_LEAP ( (uint32_t )0x445550 )
/**
* @brief find X/365.25
*
*/
/* 365.25 = (366 + 365 + 365 + 365)/4 */
#define DIV_365_25( X ) ( ( ( X ) * 91867 + 22750 ) >> 25 )
/**
* @brief find the nearest quotient of X/86400 (8640 number of seconds in one week)
*
*/
#define DIV_APPROX_86400( X ) ( ( ( X ) >> 18 ) + ( ( X ) >> 17 ) )
/**
* @brief find the nearest quotient of X/1000
*
*/
#define DIV_APPROX_1000( X ) ( ( ( X ) >> 10 ) +( ( X ) >> 16 ) + ( ( X ) >> 17 ) )
/**
* @brief find the nearest quotient of X/60
*
*/
#define DIV_APPROX_60( X ) ( ( ( X ) * 17476 ) >> 20 )
/**
* @brief find the nearest quotient of X/61
*
*/
#define DIV_APPROX_61( X ) ( ( ( X ) * 68759 ) >> 22 )
/**
* @brief Calculates mod(x,7)
*
*/
#define MODULO_7( X ) ( ( X ) -( ( ( ( ( X ) + 1 ) * 299593 ) >> 21 ) * 7 ) )
/**
* @brief Calculates ceiling( X / N )
*
*/
#define DIVC( X, N ) ( ( ( X ) + ( N ) -1 ) / ( N ) )
/**
* @brief Calculates ceiling( X / 4 )
*
*/
#define DIVC_BY_4( X ) ( ( ( X ) + 3 ) >>2 )
/**
* @brief Calculates ceiling( X / 2 )
*
*/
#define DIVC_BY_2( X ) ( ( ( X ) + 1 ) >> 1 )
/**
* @}
*/
/* Private constants -----------------------------------------------------------*/
/**
* @defgroup SYSTIME_private_variable SYSTIME private constants
* @{
*/
const char *WeekDayString[]={ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
/**
* @}
*/
/* Private function prototypes -----------------------------------------------*/
/**
* @defgroup SYSTIME_private_function_prototypes SYSTIME private function prototypes
* @{
*/
static uint32_t CalendarGetMonth( uint32_t days, uint32_t year );
static void CalendarDiv86400( uint32_t in, uint32_t* out, uint32_t* remainder );
static uint32_t CalendarDiv61( uint32_t in );
static void CalendarDiv60( uint32_t in, uint32_t* out, uint32_t* remainder );
/**
* @}
*/
/* Functions Definition ------------------------------------------------------*/
/**
* @addtogroup SYSTIME_exported_function
* @{
*/
SysTime_t SysTimeAdd( SysTime_t a, SysTime_t b )
{
SysTime_t c = { .Seconds = 0, .SubSeconds = 0 };
c.Seconds = a.Seconds + b.Seconds;
c.SubSeconds = a.SubSeconds + b.SubSeconds;
if( c.SubSeconds >= 1000 )
{
c.Seconds++;
c.SubSeconds -= 1000;
}
return c;
}
SysTime_t SysTimeSub( SysTime_t a, SysTime_t b )
{
SysTime_t c = { .Seconds = 0, .SubSeconds = 0 };
c.Seconds = a.Seconds - b.Seconds;
c.SubSeconds = a.SubSeconds - b.SubSeconds;
if( c.SubSeconds < 0 )
{
c.Seconds--;
c.SubSeconds += 1000;
}
return c;
}
void SysTimeSet( SysTime_t sysTime )
{
SysTime_t DeltaTime;
SysTime_t calendarTime = { .Seconds = 0, .SubSeconds = 0 };
calendarTime.Seconds = UTIL_SYSTIMDriver.GetCalendarTime( ( uint16_t* )&calendarTime.SubSeconds );
// sysTime is UNIX epoch
DeltaTime = SysTimeSub( sysTime, calendarTime );
UTIL_SYSTIMDriver.BKUPWrite_Seconds( DeltaTime.Seconds );
UTIL_SYSTIMDriver.BKUPWrite_SubSeconds( ( uint32_t ) DeltaTime.SubSeconds );
}
SysTime_t SysTimeGet( void )
{
SysTime_t calendarTime = { .Seconds = 0, .SubSeconds = 0 };
SysTime_t sysTime = { .Seconds = 0, .SubSeconds = 0 };
SysTime_t DeltaTime;
calendarTime.Seconds = UTIL_SYSTIMDriver.GetCalendarTime( ( uint16_t* )&calendarTime.SubSeconds );
DeltaTime.SubSeconds = (int16_t)UTIL_SYSTIMDriver.BKUPRead_SubSeconds();
DeltaTime.Seconds = UTIL_SYSTIMDriver.BKUPRead_Seconds();
sysTime = SysTimeAdd( DeltaTime, calendarTime );
return sysTime;
}
SysTime_t SysTimeGetMcuTime( void )
{
SysTime_t calendarTime = { .Seconds = 0, .SubSeconds = 0 };
calendarTime.Seconds = UTIL_SYSTIMDriver.GetCalendarTime( ( uint16_t* )&calendarTime.SubSeconds );
return calendarTime;
}
uint32_t SysTimeToMs( SysTime_t sysTime )
{
SysTime_t DeltaTime;
DeltaTime.SubSeconds = (int16_t)UTIL_SYSTIMDriver.BKUPRead_SubSeconds();
DeltaTime.Seconds = UTIL_SYSTIMDriver.BKUPRead_Seconds();
SysTime_t calendarTime = SysTimeSub( sysTime, DeltaTime );
return calendarTime.Seconds * 1000 + calendarTime.SubSeconds;
}
SysTime_t SysTimeFromMs( uint32_t timeMs )
{
uint32_t seconds = timeMs / 1000;
SysTime_t sysTime = { .Seconds = seconds, .SubSeconds = timeMs - seconds * 1000 };
SysTime_t DeltaTime = { 0 };
DeltaTime.SubSeconds = (int16_t)UTIL_SYSTIMDriver.BKUPRead_SubSeconds();
DeltaTime.Seconds = UTIL_SYSTIMDriver.BKUPRead_Seconds();
return SysTimeAdd( sysTime, DeltaTime );
}
uint32_t SysTimeMkTime( const struct tm* localtime )
{
uint32_t nbdays;
uint32_t nbsecs;
uint32_t year = localtime->tm_year - CALC_REF_YEAR;
uint32_t correctionMonth[4] =
{
DAYS_IN_MONTH_CORRECTION_LEAP,
DAYS_IN_MONTH_CORRECTION_NORM,
DAYS_IN_MONTH_CORRECTION_NORM,
DAYS_IN_MONTH_CORRECTION_NORM
};
nbdays = DIVC( ( TM_DAYS_IN_YEAR * 3 + TM_DAYS_IN_LEAP_YEAR ) * year, 4 );
nbdays += ( DIVC_BY_2( ( localtime->tm_mon ) * ( 30 + 31 ) ) -
( ( ( correctionMonth[year % 4] >> ( ( localtime->tm_mon ) * 2 ) ) & 0x03 ) ) );
nbdays += ( localtime->tm_mday - 1 );
// Convert from days to seconds
nbsecs = nbdays * TM_SECONDS_IN_1DAY;
nbsecs += ( ( uint32_t )localtime->tm_sec +
( ( uint32_t )localtime->tm_min * TM_SECONDS_IN_1MINUTE ) +
( ( uint32_t )localtime->tm_hour * TM_SECONDS_IN_1HOUR ) );
return nbsecs - CALC_REF_YEAR_TO_UNIX_REF_YEAR_COMPENSATION_IN_SECONDS;
}
void SysTimeLocalTime( const uint32_t timestamp, struct tm *localtime )
{
uint32_t correctionMonth[4] =
{
DAYS_IN_MONTH_CORRECTION_LEAP,
DAYS_IN_MONTH_CORRECTION_NORM,
DAYS_IN_MONTH_CORRECTION_NORM,
DAYS_IN_MONTH_CORRECTION_NORM
};
uint32_t weekDays = 1; // Monday 1st January 1968
uint32_t seconds;
uint32_t minutes;
uint32_t days;
uint32_t divOut;
uint32_t divReminder;
CalendarDiv86400( timestamp + CALC_REF_YEAR_TO_UNIX_REF_YEAR_COMPENSATION_IN_SECONDS, &days, &seconds );
// Calculates seconds
CalendarDiv60( seconds, &minutes, &divReminder );
localtime->tm_sec = ( uint8_t )divReminder;
// Calculates minutes and hours
CalendarDiv60( minutes, &divOut, &divReminder);
localtime->tm_min = ( uint8_t )divReminder;
localtime->tm_hour = ( uint8_t )divOut;
// Calculates year
localtime->tm_year = DIV_365_25( days );
days-= DIVC_BY_4( ( TM_DAYS_IN_YEAR * 3 + TM_DAYS_IN_LEAP_YEAR ) * localtime->tm_year );
localtime->tm_yday = days;
// Calculates month
localtime->tm_mon = CalendarGetMonth( days, localtime->tm_year );
// calculates weekdays
weekDays += DIVC_BY_4( ( localtime->tm_year * 5 ) );
weekDays += days;
localtime->tm_wday = MODULO_7( weekDays );
days -= ( DIVC_BY_2( ( localtime->tm_mon ) * ( 30 + 31 ) ) -
( ( ( correctionMonth[localtime->tm_year % 4] >> ( ( localtime->tm_mon ) * 2 ) ) & 0x03 ) ) );
// Convert 0 to 1 indexed.
localtime->tm_mday = days + 1;
localtime->tm_year += CALC_REF_YEAR;
localtime->tm_isdst = -1;
}
/**
* @}
*/
/**************************** Private functions *******************************/
/**
* @addtogroup SYSTIME_private_function
*
* @{
*/
static uint32_t CalendarGetMonth( uint32_t days, uint32_t year )
{
uint32_t month;
if( ( year % 4 ) == 0 )
{ /*leap year*/
if( days < END_OF_FEBRUARY_LEAP )
{ // January or February
// month = days * 2 / ( 30 + 31 );
month = CalendarDiv61( days * 2 );
}
else if( days < END_OF_JULY_LEAP )
{
month = CalendarDiv61( ( days - END_OF_FEBRUARY_LEAP ) * 2 ) + 2;
}
else
{
month = CalendarDiv61( ( days - END_OF_JULY_LEAP ) * 2 ) + 7;
}
}
else
{
if( days < END_OF_FEBRUARY_NORM )
{ // January or February
month = CalendarDiv61( days * 2 );
}
else if( days < END_OF_JULY_NORM )
{
month = CalendarDiv61( ( days - END_OF_FEBRUARY_NORM ) * 2 ) + 2;
}
else
{
month = CalendarDiv61( ( days - END_OF_JULY_NORM ) * 2 ) + 7;
}
}
return month;
}
static void CalendarDiv86400( uint32_t in, uint32_t* out, uint32_t* remainder )
{
#if 0
*remainder = in % SECONDS_IN_1DAY;
*out = in / SECONDS_IN_1DAY;
#else
uint32_t outTemp = 0;
uint32_t divResult = DIV_APPROX_86400( in );
while( divResult >=1 )
{
outTemp += divResult;
in -= divResult * 86400;
divResult= DIV_APPROX_86400( in );
}
if( in >= 86400 )
{
outTemp += 1;
in -= 86400;
}
*remainder = in;
*out = outTemp;
#endif
}
static uint32_t CalendarDiv61( uint32_t in )
{
#if 0
return( in / 61 );
#else
uint32_t outTemp = 0;
uint32_t divResult = DIV_APPROX_61( in );
while( divResult >=1 )
{
outTemp += divResult;
in -= divResult * 61;
divResult = DIV_APPROX_61( in );
}
if( in >= 61 )
{
outTemp += 1;
in -= 61;
}
return outTemp;
#endif
}
static void CalendarDiv60( uint32_t in, uint32_t* out, uint32_t* remainder )
{
#if 0
*remainder = in % 60;
*out = in / 60;
#else
uint32_t outTemp = 0;
uint32_t divResult = DIV_APPROX_60( in );
while( divResult >=1 )
{
outTemp += divResult;
in -= divResult * 60;
divResult = DIV_APPROX_60( in );
}
if( in >= 60 )
{
outTemp += 1;
in -= 60;
}
*remainder = in;
*out = outTemp;
#endif
}
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@@ -0,0 +1,282 @@
/*!
* \file timer.c
*
* \brief Timer objects and scheduling management implementation
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013-2017 Semtech
*
* \endcode
*
* \author Miguel Luis ( Semtech )
*
* \author Gregory Cristian ( Semtech )
*/
/******************************************************************************
* @file stm32_timer.c
* @author MCD Application Team
* @brief Time server utility
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32_timer.h"
/** @addtogroup TIMER_SERVER
* @{
*/
/* Private macro -----------------------------------------------------------*/
/**
* @defgroup TIMER_SERVER_private_macro TIMER_SERVER private macros
* @{
*/
/**
* @brief macro definition to initialize a critical section.
*
*/
#ifndef UTIL_TIMER_INIT_CRITICAL_SECTION
#define UTIL_TIMER_INIT_CRITICAL_SECTION( )
#endif
/**
* @brief macro definition to enter a critical section.
*
*/
#ifndef UTIL_TIMER_ENTER_CRITICAL_SECTION
#define UTIL_TIMER_ENTER_CRITICAL_SECTION( ) UTILS_ENTER_CRITICAL_SECTION( )
#endif
/**
* @brief macro definition to exit a critical section.
*
*/
#ifndef UTIL_TIMER_EXIT_CRITICAL_SECTION
#define UTIL_TIMER_EXIT_CRITICAL_SECTION( ) UTILS_EXIT_CRITICAL_SECTION( )
#endif
/**
* @}
*/
/* Private variables -----------------------------------------------------------*/
/**
* @defgroup TIMER_SERVER_private_varaible TIMER_SERVER private variable
* @{
*/
/**
* @brief Timers list head pointer
*
*/
static UTIL_TIMER_Object_t *TimerListHead = NULL;
/**
* @}
*/
/**
* @defgroup TIMER_SERVER_private_function TIMER_SERVER private function
* @{
*/
bool TimerExists( UTIL_TIMER_Object_t *TimerObject );
/**
* @}
*/
/* Functions Definition ------------------------------------------------------*/
/**
* @addtogroup TIMER_SERVER_exported_function
* @{
*/
UTIL_TIMER_Status_t UTIL_TIMER_Init(void)
{
UTIL_TIMER_INIT_CRITICAL_SECTION();
TimerListHead = NULL;
return UTIL_TimerDriver.InitTimer();
}
UTIL_TIMER_Status_t UTIL_TIMER_DeInit(void)
{
return UTIL_TimerDriver.DeInitTimer();
}
UTIL_TIMER_Status_t UTIL_TIMER_Create( UTIL_TIMER_Object_t *TimerObject, uint32_t PeriodValue, UTIL_TIMER_Mode_t Mode, void ( *Callback )( void *), void *Argument)
{
if((TimerObject != NULL) && (Callback != NULL))
{
osTimerDef(TimerObject, (void*)(const void *)Callback);
TimerObject->Handle = osTimerCreate(osTimer(TimerObject), Mode, Argument);
return UTIL_TIMER_OK;
}
else
{
return UTIL_TIMER_INVALID_PARAM;
}
}
UTIL_TIMER_Status_t UTIL_TIMER_Start( UTIL_TIMER_Object_t *TimerObject)
{
UTIL_TIMER_Status_t ret = UTIL_TIMER_OK;
if(( TimerObject != NULL ) && ( TimerExists( TimerObject ) == true ) )
{
osTimerStart( TimerObject->Handle, TimerObject->ReloadValue);
}
else
{
ret = UTIL_TIMER_INVALID_PARAM;
}
return ret;
}
UTIL_TIMER_Status_t UTIL_TIMER_StartWithPeriod( UTIL_TIMER_Object_t *TimerObject, uint32_t PeriodValue)
{
UTIL_TIMER_Status_t ret = UTIL_TIMER_OK;
if(NULL == TimerObject)
{
ret = UTIL_TIMER_INVALID_PARAM;
}
else
{
TimerObject->ReloadValue = UTIL_TimerDriver.ms2Tick(PeriodValue);
if(TimerExists(TimerObject))
{
(void)UTIL_TIMER_Stop(TimerObject);
}
ret = UTIL_TIMER_Start(TimerObject);
}
return ret;
}
UTIL_TIMER_Status_t UTIL_TIMER_Stop( UTIL_TIMER_Object_t *TimerObject )
{
UTIL_TIMER_Status_t ret = UTIL_TIMER_OK;
if(NULL == TimerObject)
{
ret = UTIL_TIMER_INVALID_PARAM;
}
else
{
osTimerStop( TimerObject->Handle );
}
return ret;
}
UTIL_TIMER_Status_t UTIL_TIMER_SetPeriod(UTIL_TIMER_Object_t *TimerObject, uint32_t NewPeriodValue)
{
UTIL_TIMER_Status_t ret = UTIL_TIMER_OK;
if(NULL == TimerObject)
{
ret = UTIL_TIMER_INVALID_PARAM;
}
else
{
TimerObject->ReloadValue = NewPeriodValue;
if(TimerExists(TimerObject))
{
(void)UTIL_TIMER_Stop(TimerObject);
ret = UTIL_TIMER_Start(TimerObject);
}
}
return ret;
}
UTIL_TIMER_Status_t UTIL_TIMER_SetReloadMode(UTIL_TIMER_Object_t *TimerObject, UTIL_TIMER_Mode_t ReloadMode)
{
UTIL_TIMER_Status_t ret = UTIL_TIMER_OK;
if(NULL == TimerObject)
{
ret = UTIL_TIMER_INVALID_PARAM;
}
else
{
TimerObject->Mode = ReloadMode;
}
return ret;
}
uint32_t UTIL_TIMER_IsRunning( UTIL_TIMER_Object_t *TimerObject )
{
if( TimerObject != NULL )
{
return TimerObject->Handle != NULL;
}
else
{
return 0;
}
}
UTIL_TIMER_Time_t UTIL_TIMER_GetCurrentTime(void)
{
uint32_t now = UTIL_TimerDriver.GetTimerValue( );
return UTIL_TimerDriver.Tick2ms(now);
}
UTIL_TIMER_Time_t UTIL_TIMER_GetElapsedTime(UTIL_TIMER_Time_t past )
{
uint32_t nowInTicks = UTIL_TimerDriver.GetTimerValue( );
uint32_t pastInTicks = UTIL_TimerDriver.ms2Tick( past );
/* intentional wrap around. Works Ok if tick duation below 1ms */
return UTIL_TimerDriver.Tick2ms( nowInTicks- pastInTicks );
}
/**
* @}
*/
/**************************** Private functions *******************************/
/**
* @addtogroup TIMER_SERVER_private_function
*
* @{
*/
/**
* @brief Check if the Object to be added is not already in the list
*
* @param TimerObject Structure containing the timer object parameters
* @retval 1 (the object is already in the list) or 0
*/
bool TimerExists( UTIL_TIMER_Object_t *TimerObject )
{
return TimerObject->Handle != NULL;
}
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/