Origin
This commit is contained in:
@@ -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>© 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,×tamp_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, ×tamp_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, ×tamp_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****/
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file stm32_mem.c
|
||||
* @author MCD Application Team
|
||||
* @brief standard memory operation
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© 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****/
|
||||
@@ -0,0 +1,512 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file stm32_seq.c
|
||||
* @author MCD Application Team
|
||||
* @brief Simple sequencer implementation
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© 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****/
|
||||
@@ -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>© 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****/
|
||||
|
||||
@@ -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>© 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****/
|
||||
Reference in New Issue
Block a user