This commit is contained in:
2025-03-19 11:06:57 +08:00
commit 49f5db3a10
1343 changed files with 599230 additions and 0 deletions

View File

@ -0,0 +1,6 @@
This software component is provided to you as part of a software package and
applicable license terms are in the Package_license file. If you received this
software component outside of a package or without applicable license terms,
the terms of the BSD-3-Clause license shall apply.
You may obtain a copy of the BSD-3-Clause at:
https://opensource.org/licenses/BSD-3-Clause

View File

@ -0,0 +1,258 @@
/**
******************************************************************************
* @file stm32_lpm.c
* @author MCD Application Team
* @brief Low Power Manager
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32_lpm.h"
#include "utilities_conf.h"
/** @addtogroup TINY_LPM
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private macros ------------------------------------------------------------*/
/** @defgroup TINY_LPM_Private_macros TINY LPM private macros
* @{
*/
/**
* @brief macro used to initialized the critical section
*/
#ifndef UTIL_LPM_INIT_CRITICAL_SECTION
#define UTIL_LPM_INIT_CRITICAL_SECTION( )
#endif
/**
* @brief macro used to enter the critical section
*/
#ifndef UTIL_LPM_ENTER_CRITICAL_SECTION
#define UTIL_LPM_ENTER_CRITICAL_SECTION( ) UTILS_ENTER_CRITICAL_SECTION( )
#endif
/**
* @brief macro used to exit the critical section
*/
#ifndef UTIL_LPM_EXIT_CRITICAL_SECTION
#define UTIL_LPM_EXIT_CRITICAL_SECTION( ) UTILS_EXIT_CRITICAL_SECTION( )
#endif
/**
* @brief macro used to enter the critical section when Entering Low Power
* @note this macro is only called inside the function UTIL_LPM_EnterLowPower
* and in a basic configuration shall be identcal to the macro
* UTIL_LPM_EXIT_CRITICAL_SECTION. In general, the request to enter the
* low power mode is already done under a critical section and
* nesting it is useless (in specific implementations not even possible).
* So the users could define their own macro)
*/
#ifndef UTIL_LPM_ENTER_CRITICAL_SECTION_ELP
#define UTIL_LPM_ENTER_CRITICAL_SECTION_ELP( ) UTIL_LPM_ENTER_CRITICAL_SECTION( )
#endif
/**
* @brief macro used to exit the critical section when exting Low Power
* @note the behavior of the macro shall be symmetrical with the macro
* UTIL_LPM_ENTER_CRITICAL_SECTION_ELP
*/
#ifndef UTIL_LPM_EXIT_CRITICAL_SECTION_ELP
#define UTIL_LPM_EXIT_CRITICAL_SECTION_ELP( ) UTIL_LPM_EXIT_CRITICAL_SECTION( )
#endif
/**
* @}
*/
/* Private function prototypes -----------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private defines -----------------------------------------------------------*/
/** @defgroup TINY_LPM_Private_define TINY LPM private defines
* @{
*/
/**
* @brief value used to reset the LPM mode
*/
#define UTIL_LPM_NO_BIT_SET (0UL)
/**
* @}
*/
/* Private macros ------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/** @defgroup TINY_LPM_Private_variables TINY LPM private variables
* @{
*/
/**
* @brief value used to represent the LPM state of stop mode
*/
static UTIL_LPM_bm_t StopModeDisable = UTIL_LPM_NO_BIT_SET;
/**
* @brief value used to represent the LPM state of off mode
*/
static UTIL_LPM_bm_t OffModeDisable = UTIL_LPM_NO_BIT_SET;
/**
* @}
*/
/* Global variables ----------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Functions Definition ------------------------------------------------------*/
/** @addtogroup TINY_LPM_Exported_function
* @{
*/
void UTIL_LPM_Init( void )
{
StopModeDisable = UTIL_LPM_NO_BIT_SET;
OffModeDisable = UTIL_LPM_NO_BIT_SET;
UTIL_LPM_INIT_CRITICAL_SECTION( );
}
void UTIL_LPM_DeInit( void )
{
}
void UTIL_LPM_SetStopMode( UTIL_LPM_bm_t lpm_id_bm, UTIL_LPM_State_t state )
{
UTIL_LPM_ENTER_CRITICAL_SECTION( );
switch( state )
{
case UTIL_LPM_DISABLE:
{
StopModeDisable |= lpm_id_bm;
break;
}
case UTIL_LPM_ENABLE:
{
StopModeDisable &= ( ~lpm_id_bm );
break;
}
default :
{
break;
}
}
UTIL_LPM_EXIT_CRITICAL_SECTION( );
}
void UTIL_LPM_SetOffMode( UTIL_LPM_bm_t lpm_id_bm, UTIL_LPM_State_t state )
{
UTIL_LPM_ENTER_CRITICAL_SECTION( );
switch(state)
{
case UTIL_LPM_DISABLE:
{
OffModeDisable |= lpm_id_bm;
break;
}
case UTIL_LPM_ENABLE:
{
OffModeDisable &= ( ~lpm_id_bm );
break;
}
default :
{
break;
}
}
UTIL_LPM_EXIT_CRITICAL_SECTION( );
}
UTIL_LPM_Mode_t UTIL_LPM_GetMode( void )
{
UTIL_LPM_Mode_t mode_selected;
UTIL_LPM_ENTER_CRITICAL_SECTION( );
if( StopModeDisable != UTIL_LPM_NO_BIT_SET )
{
/**
* At least one user disallows Stop Mode
*/
mode_selected = UTIL_LPM_SLEEPMODE;
}
else
{
if( OffModeDisable != UTIL_LPM_NO_BIT_SET )
{
/**
* At least one user disallows Off Mode
*/
mode_selected = UTIL_LPM_STOPMODE;
}
else
{
mode_selected = UTIL_LPM_OFFMODE;
}
}
UTIL_LPM_EXIT_CRITICAL_SECTION( );
return mode_selected;
}
void UTIL_LPM_EnterLowPower( void )
{
UTIL_LPM_ENTER_CRITICAL_SECTION_ELP( );
if( StopModeDisable != UTIL_LPM_NO_BIT_SET )
{
/**
* At least one user disallows Stop Mode
* SLEEP mode is required
*/
UTIL_PowerDriver.EnterSleepMode( );
UTIL_PowerDriver.ExitSleepMode( );
}
else
{
if( OffModeDisable != UTIL_LPM_NO_BIT_SET )
{
/**
* At least one user disallows Off Mode
* STOP mode is required
*/
UTIL_PowerDriver.EnterStopMode( );
UTIL_PowerDriver.ExitStopMode( );
}
else
{
/**
* OFF mode is required
*/
UTIL_PowerDriver.EnterOffMode( );
UTIL_PowerDriver.ExitOffMode( );
}
}
UTIL_LPM_EXIT_CRITICAL_SECTION_ELP( );
}
/**
* @}
*/
/**
* @}
*/

View File

@ -0,0 +1,167 @@
/**
******************************************************************************
* @file stm32_lpm.h
* @author MCD Application Team
* @brief Header for stm32_lpm.c module
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef STM32_TINY_LPM_H
#define STM32_TINY_LPM_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stdint.h"
/** @defgroup TINY_LPM TINY LPM
* @{
*/
/* Exported typedef ---------------------------------------------------------*/
/** @defgroup TINY_LPM_Exported_typedef TINY LPM exported typedef
* @{
*/
/**
* @brief type definition to represent the bit mask of an LPM mode
*/
typedef uint32_t UTIL_LPM_bm_t;
/**
* @brief type definition to represent value of an LPM mode
*/
typedef enum
{
UTIL_LPM_ENABLE=0,
UTIL_LPM_DISABLE,
} UTIL_LPM_State_t;
/**
* @brief type definition to represent the different type of LPM mode
*/
typedef enum
{
UTIL_LPM_SLEEPMODE,
UTIL_LPM_STOPMODE,
UTIL_LPM_OFFMODE,
} UTIL_LPM_Mode_t;
/**
* @}
*/
/** @defgroup TINY_LPM_Exported_struct TINY LPM exported struct
* @{
*/
/**
* @brief LPM driver definition
*/
struct UTIL_LPM_Driver_s
{
void (*EnterSleepMode) ( void ); /*!<function to enter the sleep mode */
void (*ExitSleepMode) ( void ); /*!<function to exit the sleep mode */
void (*EnterStopMode) ( void ); /*!<function to enter the stop mode */
void (*ExitStopMode) ( void ); /*!<function to exit the stop mode */
void (*EnterOffMode) ( void ); /*!<function to enter the off mode */
void (*ExitOffMode) ( void ); /*!<function to exit the off mode */
};
/**
* @}
*/
/* External variables --------------------------------------------------------*/
/** @defgroup TINY_LPM_Exported_struct TINY LPM exported struct
* @{
*/
/**
* @brief LPM driver
*
* @note This structure is defined and initialized in the specific platform
* power implementation
*/
extern const struct UTIL_LPM_Driver_s UTIL_PowerDriver;
/**
* @}
*/
/* Exported macros -----------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
/** @defgroup TINY_LPM_Exported_function TINY LPM exported functions
* @{
*/
/**
* @brief This API Initializes the LPM resources.
*/
void UTIL_LPM_Init( void );
/**
* @brief This API Un-Initializes the LPM resources.
*/
void UTIL_LPM_DeInit( void );
/**
* @brief This API returns the Low Power Mode selected that will be applied when the system will enter low power mode
* if there is no update between the time the mode is read with this API and the time the system enters
* low power mode.
* @retval the LPM mode based on @ref UTIL_LPM_Mode_t
*/
UTIL_LPM_Mode_t UTIL_LPM_GetMode( void );
/**
* @brief This API notifies the low power manager if the specified user allows the Stop mode or not.
* The default mode selection for all users is Stop Mode enabled
* @param lpm_id_bm: identifier of the user ( 1 bit per user )
* @param state: Specify whether StopMode is allowed or not by this user
*/
void UTIL_LPM_SetStopMode( UTIL_LPM_bm_t lpm_id_bm, UTIL_LPM_State_t state );
/**
* @brief This API notifies the low power manager if the specified user allows the Off mode or not.
* The default mode selection for all users is Off mode enabled
* @param lpm_id_bm: identifier of the user ( 1 bit per user )
* @param state: Specify whether OffMode is allowed or not by this user
*/
void UTIL_LPM_SetOffMode( UTIL_LPM_bm_t lpm_id_bm, UTIL_LPM_State_t state );
/**
* @brief This API is called by the low power manager in a critical section (PRIMASK bit set) to allow the
* application to implement dedicated code before entering Low Power Mode
*/
void UTIL_LPM_EnterLowPower( void );
/**
*@}
*/
/**
*@}
*/
#ifdef __cplusplus
}
#endif
#endif /* STM32_TINY_LPM_H */

View File

@ -0,0 +1,131 @@
/*******************************************************************************
* @file stm32_lpm_if.c
* @author MCD Application Team
* @brief Low layer function to enter/exit low power modes (stop, sleep)
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32_lpm_if.h"
#include "stm32_lpm.h"
/** @addtogroup TINY_LPM_IF
* @{
*/
/* USER CODE BEGIN include */
/* USER CODE END include */
/* Exported variables --------------------------------------------------------*/
/** @defgroup TINY_LPM_IF_Exported_varaibles TINY LPM IF exported variables
* @{
*/
/**
* @brief variable to provide all the functions corresponding to the different low power modes.
*/
const struct UTIL_LPM_Driver_s UTIL_PowerDriver =
{
PWR_EnterSleepMode,
PWR_ExitSleepMode,
PWR_EnterStopMode,
PWR_ExitStopMode,
PWR_EnterOffMode,
PWR_ExitOffMode,
};
/**
* @}
*/
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN Private_Function_Prototypes */
/* USER CODE END Private_Function_Prototypes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN Private_Typedef */
/* USER CODE END Private_Typedef */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN Private_Define */
/* USER CODE END Private_Define */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN Private_Macro */
/* USER CODE END Private_Macro */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Private_Variables */
/* USER CODE END Private_Variables */
/** @addtogroup TINY_LPM_IF_Exported_functions
* @{
*/
void PWR_EnterOffMode( void )
{
/* USER CODE BEGIN PWR_EnterOffMode */
/* USER CODE END PWR_EnterOffMode */
}
void PWR_ExitOffMode( void )
{
/* USER CODE BEGIN PWR_ExitOffMode */
/* USER CODE END PWR_ExitOffMode */
}
void PWR_EnterStopMode( void )
{
/* USER CODE BEGIN PWR_EnterStopMode */
/* USER CODE END PWR_EnterStopMode */
}
void PWR_ExitStopMode( void )
{
/* USER CODE BEGIN PWR_ExitStopMode */
/* USER CODE END PWR_ExitStopMode */
}
void PWR_EnterSleepMode( void )
{
/* USER CODE BEGIN PWR_EnterSleepMode */
/* USER CODE END PWR_EnterSleepMode */
}
void PWR_ExitSleepMode( void )
{
/* USER CODE BEGIN PWR_ExitSleepMode */
/* USER CODE END PWR_ExitSleepMode */
}
/* USER CODE BEGIN Private_Functions */
/* USER CODE END Private_Functions */
/**
* @}
*/
/**
* @}
*/

View File

@ -0,0 +1,79 @@
/**
******************************************************************************
* @file stm32_lpm_if.h
* @brief Header for stm32_lpm_f.c module (device specific LP management)
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef STM32_TINY_LPM_IF_H
#define STM32_TINY_LPM_IF_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
/** @defgroup TINY_LPM_IF TINY LPM IF
* @{
*/
/* Exported Functions ------------------------------------------------------------------*/
/** @defgroup TINY_LPM_IF_Exported_functions TINY LPM IF Exported functions
* @{
*/
/**
* @brief Enters Low Power Off Mode
*/
void PWR_EnterOffMode( void );
/**
* @brief Exits Low Power Off Mode
*/
void PWR_ExitOffMode( void );
/**
* @brief Enters Low Power Stop Mode
*/
void PWR_EnterStopMode( void );
/**
* @brief Exits Low Power Stop Mode
*/
void PWR_ExitStopMode( void );
/**
* @brief Enters Low Power Sleep Mode
*/
void PWR_EnterSleepMode( void );
/**
* @brief Exits Low Power Sleep Mode
*/
void PWR_ExitSleepMode( void );
/**
* @}
*/
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* STM32_TINY_LPM_IF_H */

View File

@ -0,0 +1,6 @@
This software component is provided to you as part of a software package and
applicable license terms are in the Package_license file. If you received this
software component outside of a package or without applicable license terms,
the terms of the BSD-3-Clause license shall apply.
You may obtain a copy of the BSD-3-Clause at:
https://opensource.org/licenses/BSD-3-Clause

View File

@ -0,0 +1,61 @@
/**
******************************************************************************
* @file stm32_mem.c
* @author MCD Application Team
* @brief standard memory operation
******************************************************************************
* @attention
*
* Copyright (c) 2019 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "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;
}
}

View File

@ -0,0 +1,70 @@
/**
******************************************************************************
* @file stm32_mem.h
* @author MCD Application Team
* @brief standard memory operation
******************************************************************************
* @attention
*
* Copyright (c) 2019 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM32_MEM_H__
#define __STM32_MEM_H__
#ifdef __cplusplus
extern "C"
{
#endif
/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include "utilities_conf.h"
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* ---- Memory mapping macros ----------------------------------------------- */
#define UTIL_MEM_PLACE_IN_SECTION( __x__ ) UTIL_PLACE_IN_SECTION( __x__ )
#define UTIL_MEM_ALIGN ALIGN
/* Exported functions ------------------------------------------------------- */
/**
* @brief This API copies one buffer to another
* @param dst: output buffer to be filled
* @param src: input buffer
* @param size: size of 8b data
* @retval None
*/
void UTIL_MEM_cpy_8( void *dst, const void *src, uint16_t size );
/**
* @brief This API copies one buffer to another in reverse
* @param dst: output buffer to be filled
* @param src: input buffer
* @param size: size of 8b data
* @retval None
*/
void UTIL_MEM_cpyr_8( void *dst, const void *src, uint16_t size );
/**
* @brief This API fills a buffer with value
* @param dst: output buffer to be filled
* @param value: value
* @param size: size of 8b data
* @retval None
*/
void UTIL_MEM_set_8( void *dst, uint8_t value, uint16_t size );
#ifdef __cplusplus
}
#endif
#endif /* __STM32_MEM_H__ */

View File

@ -0,0 +1,496 @@
/*!
* \file stm32_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
*
* Copyright (c) 2019 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include <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
}
/**
* @}
*/
/**
* @}
*/

View File

@ -0,0 +1,252 @@
/*!
* \file stm32_systime.h
*
* \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.h
* @author MCD Application Team
* @brief System time functions implementation
******************************************************************************
* @attention
*
* Copyright (c) 2019 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM32_SYS_TIME_H__
#define __STM32_SYS_TIME_H__
#ifdef __cplusplus
extern "C"
{
#endif
/** @defgroup SYSTIME timer server
* @{
*/
/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include "time.h"
/* Exported constants --------------------------------------------------------*/
/** @defgroup SYSTIME_exported_constants SYSTIME exported constants
* @{
*/
/*!
* @brief Days, Hours, Minutes and seconds of systime.h
*/
#define TM_DAYS_IN_LEAP_YEAR ( ( uint32_t ) 366U )
#define TM_DAYS_IN_YEAR ( ( uint32_t ) 365U )
#define TM_SECONDS_IN_1DAY ( ( uint32_t )86400U )
#define TM_SECONDS_IN_1HOUR ( ( uint32_t ) 3600U )
#define TM_SECONDS_IN_1MINUTE ( ( uint32_t ) 60U )
#define TM_MINUTES_IN_1HOUR ( ( uint32_t ) 60U )
#define TM_HOURS_IN_1DAY ( ( uint32_t ) 24U )
/*!
* @brief Months of systime.h
*/
#define TM_MONTH_JANUARY ( ( uint8_t ) 0U )
#define TM_MONTH_FEBRUARY ( ( uint8_t ) 1U )
#define TM_MONTH_MARCH ( ( uint8_t ) 2U )
#define TM_MONTH_APRIL ( ( uint8_t ) 3U )
#define TM_MONTH_MAY ( ( uint8_t ) 4U )
#define TM_MONTH_JUNE ( ( uint8_t ) 5U )
#define TM_MONTH_JULY ( ( uint8_t ) 6U )
#define TM_MONTH_AUGUST ( ( uint8_t ) 7U )
#define TM_MONTH_SEPTEMBER ( ( uint8_t ) 8U )
#define TM_MONTH_OCTOBER ( ( uint8_t ) 9U )
#define TM_MONTH_NOVEMBER ( ( uint8_t )10U )
#define TM_MONTH_DECEMBER ( ( uint8_t )11U )
/*!
* @brief Week days of systime.h
*/
#define TM_WEEKDAY_SUNDAY ( ( uint8_t )0U )
#define TM_WEEKDAY_MONDAY ( ( uint8_t )1U )
#define TM_WEEKDAY_TUESDAY ( ( uint8_t )2U )
#define TM_WEEKDAY_WEDNESDAY ( ( uint8_t )3U )
#define TM_WEEKDAY_THURSDAY ( ( uint8_t )4U )
#define TM_WEEKDAY_FRIDAY ( ( uint8_t )5U )
#define TM_WEEKDAY_SATURDAY ( ( uint8_t )6U )
/*!
* @brief Number of seconds elapsed between Unix epoch and GPS epoch
*/
#define UNIX_GPS_EPOCH_OFFSET 315964800
/**
* @}
*/
/* External Typedef --------------------------------------------------------*/
/** @defgroup SYSTIME_exported_TypeDef SYSTIME exported Typedef
* @{
*/
/**
* @brief Structure holding the system time in seconds and milliseconds.
*/
typedef struct SysTime_s
{
uint32_t Seconds;
int16_t SubSeconds;
}SysTime_t;
/**
* @brief SysTime driver definition
*/
typedef struct
{
void (*BKUPWrite_Seconds) ( uint32_t Seconds); /*!< Set the timer differencebetween real time and rtc time */
uint32_t (*BKUPRead_Seconds) ( void ); /*!< Get the timer differencebetween real time and rtc time */
void (*BKUPWrite_SubSeconds) ( uint32_t SubSeconds); /*!< Set the timer differencebetween real time and rtc time */
uint32_t (*BKUPRead_SubSeconds) ( void ); /*!< Get the timer differencebetween real time and rtc time */
uint32_t (*GetCalendarTime)( uint16_t* SubSeconds ); /*!< Set the rtc time */
} UTIL_SYSTIM_Driver_s;
/**
* @}
*/
/* Exported macros -----------------------------------------------------------*/
/* Exported variables ------------------------------------------------------------*/
/** @defgroup SYSTIME_exported_Variable SYSTIME exported Variable
* @{
*/
/**
* @brief low layer interface to handle systim
*
* @remark This structure is defined and initialized in the specific platform
* timer implementation e.g rtc
*/
extern const UTIL_SYSTIM_Driver_s UTIL_SYSTIMDriver;
/**
* @}
*/
/* Exported functions ------------------------------------------------------- */
/** @defgroup SYSTIME_exported_function SYSTIME exported function
* @{
*/
/*!
* @brief Adds 2 SysTime_t values
*
* @param a Value
* @param b Value to added
*
* @retval result Addition result (SysTime_t value)
*/
SysTime_t SysTimeAdd( SysTime_t a, SysTime_t b );
/*!
* @brief Subtracts 2 SysTime_t values
*
* @param a Value
* @param b Value to be subtracted
*
* @retval result Subtraction result (SysTime_t value)
*/
SysTime_t SysTimeSub( SysTime_t a, SysTime_t b );
/*!
* @brief Sets new system time
*
* @param sysTime New seconds/sub-seconds since UNIX epoch origin
*/
void SysTimeSet( SysTime_t sysTime );
/*!
* @brief Gets current system time
*
* @retval sysTime Current seconds/sub-seconds since UNIX epoch origin
*/
SysTime_t SysTimeGet( void );
/*!
* @brief Gets current MCU system time
*
* @retval sysTime Current seconds/sub-seconds since Mcu started
*/
SysTime_t SysTimeGetMcuTime( void );
/*!
* Converts the given SysTime to the equivalent RTC value in milliseconds
*
* @param [IN] sysTime System time to be converted
*
* @retval timeMs The RTC converted time value in ms
*/
uint32_t SysTimeToMs( SysTime_t sysTime );
/*!
* Converts the given RTC value in milliseconds to the equivalent SysTime
*
* \param [IN] timeMs The RTC time value in ms to be converted
*
* \retval sysTime Converted system time
*/
SysTime_t SysTimeFromMs( uint32_t timeMs );
/*!
* @brief Convert a calendar time into time since UNIX epoch as a uint32_t.
*
* @param [IN] localtime Pointer to the object containing the calendar time
* @retval timestamp The calendar time as seconds since UNIX epoch.
*/
uint32_t SysTimeMkTime( const struct tm* localtime );
/*!
* @brief Converts a given time in seconds since UNIX epoch into calendar time.
*
* @param [IN] timestamp The time since UNIX epoch to convert into calendar time.
* @param [OUT] localtime Pointer to the calendar time object which will contain
the result of the conversion.
*/
void SysTimeLocalTime( const uint32_t timestamp, struct tm *localtime );
/**
* @}
*/
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __STM32_SYS_TIME_H__ */

View File

@ -0,0 +1,62 @@
/**
******************************************************************************
* @file stm32_systime_if_template.c
* @author MCD Application Team
* @brief This file provides the ll driver for the time server
******************************************************************************
* @attention
*
* Copyright (c) 2019 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include <math.h>
#include "stm32_systime_if.h"
/* Private typedef -----------------------------------------------------------*/
/* Private defines -----------------------------------------------------------*/
/* Private macros ------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Exported variables --------------------------------------------------------*/
/*System Time driver*/
const UTIL_SYSTIM_Driver_s UTIL_SYSTIMDriver =
{
PPP_BkUp_Write_Seconds,
PPP_BkUp_Read_Seconds,
PPP_BkUp_Write_SubSeconds,
PPP_BkUp_Read_SubSeconds,
PPP_GetTime,
};
uint32_t RTC_IF_GetTime(uint16_t *mSeconds)
{
return 0;
}
void RTC_IF_BkUp_Write_Seconds(uint32_t Seconds)
{
}
void RTC_IF_BkUp_Write_SubSeconds(uint32_t SubSeconds)
{
}
uint32_t RTC_IF_BkUp_Read_Seconds(void)
{
return 0;
}
uint32_t RTC_IF_BkUp_Read_SubSeconds(void)
{
return 0;
}

View File

@ -0,0 +1,79 @@
/**
******************************************************************************
* @file stm32_systime_if_template.h
* @author MCD Application Team
* @brief This file provides the ll driver for the time server
******************************************************************************
* @attention
*
* Copyright (c) 2019 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM32_SYSTIME_IF_H__
#define __STM32_SYSTIME_IF_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32_systime.h"
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* External variables --------------------------------------------------------*/
/* Exported macros -----------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
/*!
* @brief Get rtc time
* @param [OUT] subSeconds in ticks
* @retval returns time seconds
*/
uint32_t PPP_GetTime(uint16_t *subSeconds);
/*!
* @brief write seconds in backUp register
* @Note Used to store seconds difference between RTC time and Unix time
* @param [IN] time in seconds
* @retval None
*/
void PPP_BkUp_Write_Seconds(uint32_t Seconds);
/*!
* @brief reads seconds from backUp register
* @Note Used to store seconds difference between RTC time and Unix time
* @param [IN] None
* @retval Time in seconds
*/
uint32_t PPP_BkUp_Read_Seconds(void);
/*!
* @brief writes SubSeconds in backUp register
* @Note Used to store SubSeconds difference between RTC time and Unix time
* @param [IN] time in SubSeconds
* @retval None
*/
void PPP_BkUp_Write_SubSeconds(uint32_t SubSeconds);
/*!
* @brief reads SubSeconds from backUp register
* @Note Used to store SubSeconds difference between RTC time and Unix time
* @param [IN] None
* @retval Time in SubSeconds
*/
uint32_t PPP_BkUp_Read_SubSeconds(void);
#ifdef __cplusplus
}
#endif
#endif /* __STM32_TIMER_IF_H__ */

View File

@ -0,0 +1,992 @@
/**
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
/**
******************************************************************************
* @file stm32_tiny_sscanf.c
* @author MCD Application Team
* @brief Tiny implementation of sscanf
******************************************************************************
* @attention
*
* Copyright (c) 2019 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/*
* This code is derived from
* https://github.com/rapid7/metasploit-payloads/, in c/meterpreter/source/bionic/libc/stdio/sscanf.c
* It has been derived in order to optimize code size. In this context
* all the formats are not supported. Current supported formats are
* %hx, %hhx, %ul, %d,...
* when TINY_SSCANF is defined
*
* When TINY_NO_OX is defined, this is not possible to sscanf("%x") of "0xab",
* only "ab" is possible
*
* When TINY_SPACE_NOT_SPECIALCASE is defined, "space" is not a special character.
* That means that we expect a single space, and not any of ispace() character
* (space, tabs,...)
*/
/* Includes ------------------------------------------------------------------*/
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdlib.h>
#include <inttypes.h>
#include "stm32_tiny_sscanf.h"
/* Private typedef -----------------------------------------------------------*/
/* Private defines -----------------------------------------------------------*/
#define TINY_SSCANF
#define TINY_NO_OX
#define TINY_SPACE_NOT_SPECIALCASE
/* Private macros ------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Functions Definition ------------------------------------------------------*/
#ifdef FLOATING_POINT
#include "floatio.h"
#endif
#define BUF 513 /* Maximum length of numeric string. */
/*
* Flags used during conversion.
*/
#define LONG 0x00001 /* l: long or double */
#define SHORT 0x00004 /* h: short */
#define SHORTSHORT 0x00008 /* hh: 8 bit integer */
#define UNSIGNED 0x00800 /* %[oupxX] conversions */
#ifdef TINY_SSCANF
#else
#define LONGDBL 0x00002 /* L: long double; unimplemented */
#define LLONG 0x00010 /* ll: long long (+ deprecated q: quad) */
#define POINTER 0x00020 /* p: void * (as hex) */
#define SIZEINT 0x00040 /* z: (signed) size_t */
#define MAXINT 0x00080 /* j: intmax_t */
#define PTRINT 0x00100 /* t: ptrdiff_t */
#define NOSKIP 0x00200 /* [ or c: do not skip blanks */
#define SUPPRESS 0x00400 /* *: suppress assignment */
#endif
/*
* The following are used in numeric conversions only:
* SIGNOK, HAVESIGN, NDIGITS, DPTOK, and EXPOK are for floating point;
* SIGNOK, HAVESIGN, NDIGITS, PFXOK, and NZDIGITS are for integral.
*/
#define SIGNOK 0x01000 /* +/- is (still) legal */
#define HAVESIGN 0x02000 /* sign detected */
#define NDIGITS 0x04000 /* no digits detected */
#define DPTOK 0x08000 /* (float) decimal point is still legal */
#define EXPOK 0x10000 /* (float) exponent (e+3, etc) still legal */
#ifdef TINY_NO_OX
#else
#define PFXOK 0x08000 /* 0x prefix is (still) legal */
#define NZDIGITS 0x10000 /* no zero digits detected */
#endif
/*
* Conversion types.
*/
#define CT_INT 3 /* integer, i.e., strtoimax or strtoumax */
#define CT_FLOAT 4 /* floating, i.e., strtod */
#ifdef TINY_SSCANF
#else
#define CT_CHAR 0 /* %c conversion */
#define CT_CCL 1 /* %[...] conversion */
#define CT_STRING 2 /* %s conversion */
#endif
#define u_char unsigned char
#define u_long unsigned long
#ifdef TINY_SSCANF
#else
static u_char *__sccl(char *, u_char *);
#endif
#define VFSCANF tiny_vfscanf
#if !defined(VFSCANF)
#define VFSCANF vfscanf
#endif
#define __srefill(_x) 1
#define ungetc(_c, _fp) do { (_c), fp_p--; fp_r++; } while (0)
/*
* vfscanf
*/
static inline int
VFSCANF(const char *str, const char *fmt0, va_list ap)
{
u_char *fmt = (u_char *)fmt0;
int c; /* character from format, or conversion */
size_t width; /* field width, or 0 */
char *p; /* points into all kinds of strings */
int flags; /* flags as defined above */
int nassigned; /* number of fields assigned */
int nread; /* number of characters consumed from fp */
int base; /* base argument to strtoimax/strtouimax */
char buf[BUF]; /* buffer for numeric conversions */
const char *fp_p;
int fp_r;
uintmax_t value;
int sign_minus;
#ifdef TINY_SSCANF
#else
int n; /* handy integer */
char *p0; /* saves original value of p when necessary */
char ccltab[256]; /* character class table for %[...] */
#endif
/* `basefix' is used to avoid `if' tests in the integer scanner */
#ifdef TINY_SSCANF
/* basefix[] can be removed as we do not support %i */
#else
static short basefix[17] =
{ 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
#endif
fp_p = str;
fp_r = strlen(str);
nassigned = 0;
nread = 0;
base = 0; /* XXX just to keep gcc happy */
for (;;) {
c = *fmt++;
if (c == 0)
return (nassigned);
#ifdef TINY_SPACE_NOT_SPECIALCASE
#else
if (isspace(c)) {
while ((fp_r > 0 || __srefill(fp) == 0) &&
isspace(*fp_p))
nread++, fp_r--, fp_p++;
continue;
}
#endif
if (c != '%')
goto literal;
width = 0;
flags = 0;
/*
* switch on the format. continue if done;
* break once format type is derived.
*/
again: c = *fmt++;
switch (c) {
case '%':
literal:
if (fp_r <= 0 && __srefill(fp))
goto input_failure;
if (*fp_p != c)
goto match_failure;
fp_r--, fp_p++;
nread++;
continue;
#ifdef TINY_SSCANF
#else
case '*':
flags |= SUPPRESS;
goto again;
case 'j':
flags |= MAXINT;
goto again;
case 'L':
flags |= LONGDBL;
goto again;
#endif
case 'h':
if (*fmt == 'h') {
fmt++;
flags |= SHORTSHORT;
} else {
flags |= SHORT;
}
goto again;
case 'l':
#ifdef TINY_SSCANF
/* %ll not supported */
flags |= LONG;
goto again;
#else
if (*fmt == 'l') {
fmt++;
flags |= LLONG;
} else {
flags |= LONG;
}
goto again;
#endif
#ifdef TINY_SSCANF
#else
case 'q':
flags |= LLONG; /* deprecated */
goto again;
case 't':
flags |= PTRINT;
goto again;
case 'z':
flags |= SIZEINT;
goto again;
#endif
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
width = width * 10 + c - '0';
goto again;
/*
* Conversions.
* Those marked `compat' are for 4.[123]BSD compatibility.
*
* (According to ANSI, E and X formats are supposed
* to the same as e and x. Sorry about that.)
*/
case 'D': /* compat */
flags |= LONG;
/* FALLTHROUGH */
case 'd':
c = CT_INT;
base = 10;
break;
#ifdef TINY_SSCANF
/*
* We do not support %i to remove potential base=8 in the following
* Hence basefix can be removed
*/
#else
case 'i':
c = CT_INT;
base = 0;
break;
#endif
#ifdef TINY_SSCANF
#else
case 'O': /* compat */
flags |= LONG;
/* FALLTHROUGH */
case 'o':
c = CT_INT;
flags |= UNSIGNED;
base = 8;
break;
#endif
case 'u':
c = CT_INT;
flags |= UNSIGNED;
base = 10;
break;
case 'X':
case 'x':
#ifdef TINY_NO_OX
#else
flags |= PFXOK; /* enable 0x prefixing */
#endif
c = CT_INT;
flags |= UNSIGNED;
base = 16;
break;
#ifdef FLOATING_POINT
case 'E':
case 'G':
case 'e':
case 'f':
case 'g':
c = CT_FLOAT;
break;
#endif
#ifdef TINY_SSCANF
#else
case 's':
c = CT_STRING;
break;
case '[':
fmt = __sccl(ccltab, fmt);
flags |= NOSKIP;
c = CT_CCL;
break;
case 'c':
flags |= NOSKIP;
c = CT_CHAR;
break;
case 'p': /* pointer format is like hex */
flags |= POINTER | PFXOK;
c = CT_INT;
flags |= UNSIGNED;
base = 16;
break;
case 'n':
if (flags & SUPPRESS)
continue;
if (flags & SHORTSHORT)
*va_arg(ap, char *) = nread;
else if (flags & SHORT)
*va_arg(ap, short *) = nread;
else if (flags & LONG)
*va_arg(ap, long *) = nread;
else if (flags & SIZEINT)
*va_arg(ap, size_t *) = nread;
else if (flags & PTRINT)
*va_arg(ap, ptrdiff_t *) = nread;
else if (flags & LLONG)
*va_arg(ap, long long *) = nread;
else if (flags & MAXINT)
*va_arg(ap, intmax_t *) = nread;
else
*va_arg(ap, int *) = nread;
continue;
#endif
/*
* Disgusting backwards compatibility hacks. XXX
*/
case '\0': /* compat */
return (EOF);
default: /* compat */
#ifdef TINY_SSCANF
#else
if (isupper(c))
flags |= LONG;
c = CT_INT;
base = 10;
#endif
break;
}
/*
* We have a conversion that requires input.
*/
if (fp_r <= 0 && __srefill(fp))
goto input_failure;
/*
* Consume leading white space, except for formats
* that suppress this.
*/
#ifdef TINY_SSCANF
#else
if ((flags & NOSKIP) == 0) {
while (isspace(*fp_p)) {
nread++;
if (--fp_r > 0)
fp_p++;
else if (__srefill(fp))
goto input_failure;
}
/*
* Note that there is at least one character in
* the buffer, so conversions that do not set NOSKIP
* ca no longer result in an input failure.
*/
}
#endif
/*
* Do the conversion.
*/
switch (c) {
#ifdef TINY_SSCANF
#else
case CT_CHAR:
/* scan arbitrary characters (sets NOSKIP) */
if (width == 0)
width = 1;
if (flags & SUPPRESS) {
size_t sum = 0;
for (;;) {
if ((n = fp_r) < (int)width) {
sum += n;
width -= n;
fp_p += n;
if (__srefill(fp)) {
if (sum == 0)
goto input_failure;
break;
}
} else {
sum += width;
fp_r -= width;
fp_p += width;
break;
}
}
nread += sum;
} else {
size_t r = fread((void *)va_arg(ap, char *), 1,
width, fp);
if (r == 0)
goto input_failure;
nread += r;
nassigned++;
}
break;
#endif
#ifdef TINY_SSCANF
#else
case CT_CCL:
/* scan a (nonempty) character class (sets NOSKIP) */
if (width == 0)
width = (size_t)~0; /* `infinity' */
/* take only those things in the class */
if (flags & SUPPRESS) {
n = 0;
while (ccltab[*fp_p]) {
n++, fp_r--, fp_p++;
if (--width == 0)
break;
if (fp_r <= 0 && __srefill(fp)) {
if (n == 0)
goto input_failure;
break;
}
}
if (n == 0)
goto match_failure;
} else {
p0 = p = va_arg(ap, char *);
while (ccltab[*fp_p]) {
fp_r--;
*p++ = *fp_p++;
if (--width == 0)
break;
if (fp_r <= 0 && __srefill(fp)) {
if (p == p0)
goto input_failure;
break;
}
}
n = p - p0;
if (n == 0)
goto match_failure;
*p = '\0';
nassigned++;
}
nread += n;
break;
#endif
#ifdef TINY_SSCANF
#else
case CT_STRING:
/* like CCL, but zero-length string OK, & no NOSKIP */
if (width == 0)
width = (size_t)~0;
if (flags & SUPPRESS) {
n = 0;
while (!isspace(*fp_p)) {
n++, fp_r--, fp_p++;
if (--width == 0)
break;
if (fp_r <= 0 && __srefill(fp))
break;
}
nread += n;
} else {
p0 = p = va_arg(ap, char *);
while (!isspace(*fp_p)) {
fp_r--;
*p++ = *fp_p++;
if (--width == 0)
break;
if (fp_r <= 0 && __srefill(fp))
break;
}
*p = '\0';
nread += p - p0;
nassigned++;
}
continue;
#endif
case CT_INT:
/* scan an integer as if by strtoimax/strtoumax */
#ifdef hardway
if (width == 0 || width > sizeof(buf) - 1)
width = sizeof(buf) - 1;
#else
/* size_t is unsigned, hence this optimisation */
if (--width > sizeof(buf) - 2)
width = sizeof(buf) - 2;
width++;
#endif
#ifdef TINY_NO_OX
flags |= SIGNOK | NDIGITS;
#else
flags |= SIGNOK | NDIGITS | NZDIGITS;
#endif
sign_minus = 0;
value = 0;
for (p = buf; width; width--) {
c = *fp_p;
/*
* Switch on the character; `goto ok'
* if we accept it as a part of number.
*/
switch (c) {
/*
* The digit 0 is always legal, but is
* special. For %i conversions, if no
* digits (zero or nonzero) have been
* scanned (only signs), we will have
* base==0. In that case, we should set
* it to 8 and enable 0x prefixing.
* Also, if we have not scanned zero digits
* before this, do not turn off prefixing
* (someone else will turn it off if we
* have scanned any nonzero digits).
*/
case '0':
#ifdef TINY_NO_OX
/* FALLTHROUGH */
#else
#ifdef TINY_SSCANF
#else
if (base == 0) {
base = 8;
flags |= PFXOK;
}
#endif
if (!(flags & NDIGITS)) {
value = value * base;
}
if (flags & NZDIGITS)
flags &= ~(SIGNOK|NZDIGITS|NDIGITS);
else
flags &= ~(SIGNOK|PFXOK|NDIGITS);
goto ok;
#endif
#ifdef TINY_SSCANF
/* we only support base 10 and 16 */
case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
case '8': case '9':
#ifdef TINY_NO_OX
flags &= ~(SIGNOK | NDIGITS);
#else
flags &= ~(SIGNOK | PFXOK | NDIGITS);
#endif
value = value * base + c - '0';
goto ok;
#else
/* 1 through 7 always legal */
case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
base = basefix[base];
flags &= ~(SIGNOK | PFXOK | NDIGITS);
value = value * base + c - '0';
goto ok;
/* digits 8 and 9 ok iff decimal or hex */
case '8': case '9':
base = basefix[base];
if (base <= 8)
break; /* not legal here */
flags &= ~(SIGNOK | PFXOK | NDIGITS);
value = value * base + c - '0';
goto ok;
#endif
/* letters ok iff hex */
case 'A': case 'B': case 'C':
case 'D': case 'E': case 'F':
/* no need to fix base here */
if (base <= 10)
break; /* not legal here */
#ifdef TINY_NO_OX
flags &= ~(SIGNOK | NDIGITS);
#else
flags &= ~(SIGNOK | PFXOK | NDIGITS);
#endif
value = value * base + c - 'A' + 10;
goto ok;
case 'a': case 'b': case 'c':
case 'd': case 'e': case 'f':
/* no need to fix base here */
if (base <= 10)
break; /* not legal here */
#ifdef TINY_NO_OX
flags &= ~(SIGNOK | NDIGITS);
#else
flags &= ~(SIGNOK | PFXOK | NDIGITS);
#endif
value = value * base + c - 'a' + 10;
goto ok;
/* sign ok only as first character */
case '-':
if (!(flags & HAVESIGN)) {
sign_minus = 1;
}
/* FALLTHROUGH */
case '+':
if (flags & SIGNOK) {
flags &= ~SIGNOK;
flags |= HAVESIGN;
goto ok;
}
break;
/*
* x ok iff flag still set and 2nd char (or
* 3rd char if we have a sign).
*/
#ifdef TINY_NO_OX
#else
case 'x': case 'X':
if ((flags & PFXOK) && p ==
buf + 1 + !!(flags & HAVESIGN)) {
base = 16; /* if %i */
flags &= ~PFXOK;
goto ok;
}
break;
#endif
}
/*
* If we got here, c is not a legal character
* for a number. Stop accumulating digits.
*/
break;
ok:
/*
* c is legal: store it and look at the next.
*/
*p++ = c;
if (--fp_r > 0)
fp_p++;
else if (__srefill(fp))
break; /* EOF */
}
/*
* If we had only a sign, it is no good; push
* back the sign. If the number ends in `x',
* it was [sign] '0' 'x', so push back the x
* and treat it as [sign] '0'.
*/
if (flags & NDIGITS) {
if (p > buf)
{
--c;
--p;
ungetc(c++, fp);
/* There is a dummy post-increment to
avoid an unused value warning */
}
goto match_failure;
}
#ifdef TINY_NO_OX
#else
c = ((u_char *)p)[-1];
if (c == 'x' || c == 'X') {
--p;
ungetc(c, fp);
}
#endif
#ifdef TINY_SSCANF
{
#else
if ((flags & SUPPRESS) == 0) {
#endif
*p = '\0';
if (sign_minus)
value = -value;
#ifdef TINY_SSCANF
#else
if (flags & POINTER)
*va_arg(ap, void **) =
(void *)(uintptr_t)value;
else if (flags & MAXINT)
*va_arg(ap, intmax_t *) = value;
else if (flags & LLONG)
*va_arg(ap, long long *) = value;
else if (flags & SIZEINT)
*va_arg(ap, size_t *) = value;
else if (flags & PTRINT)
*va_arg(ap, ptrdiff_t *) = value;
else
#endif
if (flags & LONG)
*va_arg(ap, long *) = value;
else if (flags & SHORT)
*va_arg(ap, short *) = value;
else if (flags & SHORTSHORT)
*va_arg(ap, char *) = value;
else
*va_arg(ap, int *) = value;
nassigned++;
}
nread += p - buf;
break;
#ifdef FLOATING_POINT
case CT_FLOAT:
/* scan a floating point number as if by strtod */
#ifdef hardway
if (width == 0 || width > sizeof(buf) - 1)
width = sizeof(buf) - 1;
#else
/* size_t is unsigned, hence this optimisation */
if (--width > sizeof(buf) - 2)
width = sizeof(buf) - 2;
width++;
#endif
flags |= SIGNOK | NDIGITS | DPTOK | EXPOK;
for (p = buf; width; width--) {
c = *fp->_p;
/*
* This code mimics the integer conversion
* code, but is much simpler.
*/
switch (c) {
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
case '8': case '9':
flags &= ~(SIGNOK | NDIGITS);
goto fok;
case '+': case '-':
if (flags & SIGNOK) {
flags &= ~SIGNOK;
goto fok;
}
break;
case '.':
if (flags & DPTOK) {
flags &= ~(SIGNOK | DPTOK);
goto fok;
}
break;
case 'e': case 'E':
/* no exponent without some digits */
if ((flags&(NDIGITS|EXPOK)) == EXPOK) {
flags =
(flags & ~(EXPOK|DPTOK)) |
SIGNOK | NDIGITS;
goto fok;
}
break;
}
break;
fok:
*p++ = c;
if (--fp->_r > 0)
fp->_p++;
else if (__srefill(fp))
break; /* EOF */
}
/*
* If no digits, might be missing exponent digits
* (just give back the exponent) or might be missing
* regular digits, but had sign and/or decimal point.
*/
if (flags & NDIGITS) {
if (flags & EXPOK) {
/* no digits at all */
while (p > buf)
ungetc(*(u_char *)--p, fp);
goto match_failure;
}
/* just a bad exponent (e and maybe sign) */
c = *(u_char *)--p;
if (c != 'e' && c != 'E') {
(void) ungetc(c, fp);/* sign */
c = *(u_char *)--p;
}
(void) ungetc(c, fp);
}
if ((flags & SUPPRESS) == 0) {
double res;
*p = '\0';
res = strtod(buf, (char **) NULL);
if (flags & LONGDBL)
*va_arg(ap, long double *) = res;
else if (flags & LONG)
*va_arg(ap, double *) = res;
else
*va_arg(ap, float *) = res;
nassigned++;
}
nread += p - buf;
break;
#endif /* FLOATING_POINT */
}
}
input_failure:
return (nassigned ? nassigned : -1);
match_failure:
return (nassigned);
}
#ifdef TINY_SSCANF
#else
/*
* Fill in the given table from the scanset at the given format
* (just after `['). Return a pointer to the character past the
* closing `]'. The table has a 1 wherever characters should be
* considered part of the scanset.
*/
static u_char *
__sccl(char *tab, u_char *fmt)
{
int c, n, v;
/* first `clear' the whole table */
c = *fmt++; /* first char hat => negated scanset */
if (c == '^') {
v = 1; /* default => accept */
c = *fmt++; /* get new first char */
} else
v = 0; /* default => reject */
/* should probably use memset here */
for (n = 0; n < 256; n++)
tab[n] = v;
if (c == 0)
return (fmt - 1);/* format ended before closing ] */
/*
* Now set the entries corresponding to the actual scanset
* to the opposite of the above.
*
* The first character may be ']' (or '-') without being special;
* the last character may be '-'.
*/
v = 1 - v;
for (;;) {
tab[c] = v; /* take character c */
doswitch:
n = *fmt++; /* and examine the next */
switch (n) {
case 0: /* format ended too soon */
return (fmt - 1);
case '-':
/*
* A scanset of the form
* [01+-]
* is defined as `the digit 0, the digit 1,
* the character +, the character -', but
* the effect of a scanset such as
* [a-zA-Z0-9]
* is implementation defined. The V7 Unix
* scanf treats `a-z' as `the letters a through
* z', but treats `a-a' as `the letter a, the
* character -, and the letter a'.
*
* For compatibility, the `-' is not considered
* to define a range if the character following
* it is either a close bracket (required by ANSI)
* or is not numerically greater than the character
* we just stored in the table (c).
*/
n = *fmt;
if (n == ']' || n < c) {
c = '-';
break; /* resume the for(;;) */
}
fmt++;
do { /* fill in the range */
tab[++c] = v;
} while (c < n);
#if 1 /* XXX another disgusting compatibility hack */
/*
* Alas, the V7 Unix scanf also treats formats
* such as [a-c-e] as `the letters a through e'.
* This too is permitted by the standard....
*/
goto doswitch;
#else
c = *fmt++;
if (c == 0)
return (fmt - 1);
if (c == ']')
return (fmt);
#endif
break;
case ']': /* end of scanset */
return (fmt);
default: /* just another character */
c = n;
break;
}
}
/* NOTREACHED */
}
#endif
int
tiny_sscanf(const char *str, const char *fmt, ...)
{
int ret;
va_list ap;
va_start(ap, fmt);
ret = tiny_vfscanf(str, fmt, ap);
va_end(ap);
return (ret);
}

View File

@ -0,0 +1,65 @@
/**
******************************************************************************
* @file stm32_tiny_sscanf.h
* @author MCD Application Team
* @brief Header for driver tiny_sscanf.c module
******************************************************************************
* @attention
*
* Copyright (c) 2019 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM32_TINY_SSCANF_H__
#define __STM32_TINY_SSCANF_H__
#ifdef __cplusplus
extern "C"
{
#endif
/* Includes ------------------------------------------------------------------*/
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* External variables --------------------------------------------------------*/
/* Exported macros -----------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
/**
* @brief Read formatted data from string
*
* Reads data from s and stores them according to parameter format into the
* locations given by the additional arguments, as if scanf was used, but
* reading from s instead of the standard input (stdin).
*
* The additional arguments should point to already allocated objects of the
* type specified by their corresponding format specifier within the format string.
*
* @param C string that the function processes as its source to retrieve the data.
* @param C string that contains a format string that follows the same specifications
* as format in scanf (see scanf for details).
* @param Depending on the format string, the function may expect a sequence of
* additional arguments, each containing a pointer to allocated storage
* where the interpretation of the extracted characters is stored with
* the appropriate type.
* There should be at least as many of these arguments as the number of
* values stored by the format specifiers. Additional arguments are
* ignored by the function.
* @retval The number of items in the argument list successfully filled. This
* count can match the expected number of items or be less (even zero)
* in the case of a matching failure
* @note Current supported formats are %hx, %hhx, %ul, %d,...
*/
int tiny_sscanf(const char *str, const char *fmt, ...);
#ifdef __cplusplus
}
#endif
#endif /* __STM32_TINY_SSCANF_H__ */

View File

@ -0,0 +1,695 @@
/**
Copyright (C) 2002 Michael Ringgaard. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the project nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
*/
/**
******************************************************************************
* @file stm32_tiny_vsnprintf.c
* @author MCD Application Team
* @brief Tiny implementation of vsnprintf like function
******************************************************************************
* @attention
*
* Copyright (c) 2019 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/*
* Following implementation is adapted from original one
* https://github.com/jpbonn/coremark_lm32/blob/master/ee_printf.c
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32_tiny_vsnprintf.h"
/* Private typedef -----------------------------------------------------------*/
/* Private defines -----------------------------------------------------------*/
#define TINY_PRINTF
#define ZEROPAD (1<<0) /* Pad with zero */
#define SIGN (1<<1) /* Unsigned/signed long */
#define UPPERCASE (1<<6) /* 'ABCDEF' */
#ifdef TINY_PRINTF
#else
#define PLUS (1<<2) /* Show plus */
#define HEX_PREP (1<<5) /* 0x */
#define SPACE (1<<3) /* Spacer */
#define LEFT (1<<4) /* Left justified */
#endif
#define is_digit(c) ((c) >= '0' && (c) <= '9')
/* Private macros ------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Global variables ----------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
static char *lower_digits = "0123456789abcdefghijklmnopqrstuvwxyz";
static char *upper_digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
/* Functions Definition ------------------------------------------------------*/
#ifdef TINY_PRINTF
#else
static size_t strnlen(const char *s, size_t count);
static size_t strnlen(const char *s, size_t count)
{
const char *sc;
for (sc = s; *sc != '\0' && count--; ++sc);
return sc - s;
}
#endif
static int ee_skip_atoi(const char **s)
{
int i = 0;
while (is_digit(**s)) i = i*10 + *((*s)++) - '0';
return i;
}
#define ASSIGN_STR(_c) do { *str++ = (_c); max_size--; if (max_size == 0) return str; } while (0)
static char *ee_number(char *str, int max_size, long num, int base, int size, int precision, int type)
{
char c;
char sign, tmp[66];
char *dig = lower_digits;
int i;
if (type & UPPERCASE) dig = upper_digits;
#ifdef TINY_PRINTF
#else
if (type & LEFT) type &= ~ZEROPAD;
#endif
if (base < 2 || base > 36) return 0;
c = (type & ZEROPAD) ? '0' : ' ';
sign = 0;
if (type & SIGN)
{
if (num < 0)
{
sign = '-';
num = -num;
size--;
}
#ifdef TINY_PRINTF
#else
else if (type & PLUS)
{
sign = '+';
size--;
}
else if (type & SPACE)
{
sign = ' ';
size--;
}
#endif
}
#ifdef TINY_PRINTF
#else
if (type & HEX_PREP)
{
if (base == 16)
size -= 2;
else if (base == 8)
size--;
}
#endif
i = 0;
if (num == 0)
tmp[i++] = '0';
else
{
while (num != 0)
{
tmp[i++] = dig[((unsigned long) num) % (unsigned) base];
num = ((unsigned long) num) / (unsigned) base;
}
}
if (i > precision) precision = i;
size -= precision;
if (!(type & (ZEROPAD /* TINY option | LEFT */))) while (size-- > 0) ASSIGN_STR(' ');
if (sign) ASSIGN_STR(sign);
#ifdef TINY_PRINTF
#else
if (type & HEX_PREP)
{
if (base == 8)
ASSIGN_STR('0');
else if (base == 16)
{
ASSIGN_STR('0');
ASSIGN_STR(lower_digits[33]);
}
}
#endif
#ifdef TINY_PRINTF
while (size-- > 0) ASSIGN_STR(c);
#else
if (!(type & LEFT)) while (size-- > 0) ASSIGN_STR(c);
#endif
while (i < precision--) ASSIGN_STR('0');
while (i-- > 0) ASSIGN_STR(tmp[i]);
while (size-- > 0) ASSIGN_STR(' ');
return str;
}
#ifdef TINY_PRINTF
#else
static char *eaddr(char *str, unsigned char *addr, int size, int precision, int type)
{
char tmp[24];
char *dig = lower_digits;
int i, len;
if (type & UPPERCASE) dig = upper_digits;
len = 0;
for (i = 0; i < 6; i++)
{
if (i != 0) tmp[len++] = ':';
tmp[len++] = dig[addr[i] >> 4];
tmp[len++] = dig[addr[i] & 0x0F];
}
if (!(type & LEFT)) while (len < size--) *str++ = ' ';
for (i = 0; i < len; ++i) *str++ = tmp[i];
while (len < size--) *str++ = ' ';
return str;
}
static char *iaddr(char *str, unsigned char *addr, int size, int precision, int type)
{
char tmp[24];
int i, n, len;
len = 0;
for (i = 0; i < 4; i++)
{
if (i != 0) tmp[len++] = '.';
n = addr[i];
if (n == 0)
tmp[len++] = lower_digits[0];
else
{
if (n >= 100)
{
tmp[len++] = lower_digits[n / 100];
n = n % 100;
tmp[len++] = lower_digits[n / 10];
n = n % 10;
}
else if (n >= 10)
{
tmp[len++] = lower_digits[n / 10];
n = n % 10;
}
tmp[len++] = lower_digits[n];
}
}
if (!(type & LEFT)) while (len < size--) *str++ = ' ';
for (i = 0; i < len; ++i) *str++ = tmp[i];
while (len < size--) *str++ = ' ';
return str;
}
#endif
#ifdef HAS_FLOAT
char *ecvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf);
char *fcvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf);
static void ee_bufcpy(char *d, char *s, int count);
void ee_bufcpy(char *pd, char *ps, int count) {
char *pe=ps+count;
while (ps!=pe)
*pd++=*ps++;
}
static void parse_float(double value, char *buffer, char fmt, int precision)
{
int decpt, sign, exp, pos;
char *fdigits = NULL;
char cvtbuf[80];
int capexp = 0;
int magnitude;
if (fmt == 'G' || fmt == 'E')
{
capexp = 1;
fmt += 'a' - 'A';
}
if (fmt == 'g')
{
fdigits = ecvtbuf(value, precision, &decpt, &sign, cvtbuf);
magnitude = decpt - 1;
if (magnitude < -4 || magnitude > precision - 1)
{
fmt = 'e';
precision -= 1;
}
else
{
fmt = 'f';
precision -= decpt;
}
}
if (fmt == 'e')
{
fdigits = ecvtbuf(value, precision + 1, &decpt, &sign, cvtbuf);
if (sign) *buffer++ = '-';
*buffer++ = *fdigits;
if (precision > 0) *buffer++ = '.';
ee_bufcpy(buffer, fdigits + 1, precision);
buffer += precision;
*buffer++ = capexp ? 'E' : 'e';
if (decpt == 0)
{
if (value == 0.0)
exp = 0;
else
exp = -1;
}
else
exp = decpt - 1;
if (exp < 0)
{
*buffer++ = '-';
exp = -exp;
}
else
*buffer++ = '+';
buffer[2] = (exp % 10) + '0';
exp = exp / 10;
buffer[1] = (exp % 10) + '0';
exp = exp / 10;
buffer[0] = (exp % 10) + '0';
buffer += 3;
}
else if (fmt == 'f')
{
fdigits = fcvtbuf(value, precision, &decpt, &sign, cvtbuf);
if (sign) *buffer++ = '-';
if (*fdigits)
{
if (decpt <= 0)
{
*buffer++ = '0';
*buffer++ = '.';
for (pos = 0; pos < -decpt; pos++) *buffer++ = '0';
while (*fdigits) *buffer++ = *fdigits++;
}
else
{
pos = 0;
while (*fdigits)
{
if (pos++ == decpt) *buffer++ = '.';
*buffer++ = *fdigits++;
}
}
}
else
{
*buffer++ = '0';
if (precision > 0)
{
*buffer++ = '.';
for (pos = 0; pos < precision; pos++) *buffer++ = '0';
}
}
}
*buffer = '\0';
}
static void decimal_point(char *buffer)
{
while (*buffer)
{
if (*buffer == '.') return;
if (*buffer == 'e' || *buffer == 'E') break;
buffer++;
}
if (*buffer)
{
int n = strnlen(buffer,256);
while (n > 0)
{
buffer[n + 1] = buffer[n];
n--;
}
*buffer = '.';
}
else
{
*buffer++ = '.';
*buffer = '\0';
}
}
static void cropzeros(char *buffer)
{
char *stop;
while (*buffer && *buffer != '.') buffer++;
if (*buffer++)
{
while (*buffer && *buffer != 'e' && *buffer != 'E') buffer++;
stop = buffer--;
while (*buffer == '0') buffer--;
if (*buffer == '.') buffer--;
while (buffer!=stop)
*++buffer=0;
}
}
static char *flt(char *str, double num, int size, int precision, char fmt, int flags)
{
char tmp[80];
char c, sign;
int n, i;
// Left align means no zero padding
#ifdef TINY_PRINTF
#else
if (flags & LEFT) flags &= ~ZEROPAD;
#endif
// Determine padding and sign char
c = (flags & ZEROPAD) ? '0' : ' ';
sign = 0;
if (flags & SIGN)
{
if (num < 0.0)
{
sign = '-';
num = -num;
size--;
}
#ifdef TINY_PRINTF
#else
else if (flags & PLUS)
{
sign = '+';
size--;
}
else if (flags & SPACE)
{
sign = ' ';
size--;
}
#endif
}
// Compute the precision value
if (precision < 0)
precision = 6; // Default precision: 6
// Convert floating point number to text
parse_float(num, tmp, fmt, precision);
#ifdef TINY_PRINTF
#else
if ((flags & HEX_PREP) && precision == 0) decimal_point(tmp);
#endif
if (fmt == 'g' && !(flags & HEX_PREP)) cropzeros(tmp);
n = strnlen(tmp,256);
// Output number with alignment and padding
size -= n;
if (!(flags & (ZEROPAD | LEFT))) while (size-- > 0) *str++ = ' ';
if (sign) *str++ = sign;
if (!(flags & LEFT)) while (size-- > 0) *str++ = c;
for (i = 0; i < n; i++) *str++ = tmp[i];
while (size-- > 0) *str++ = ' ';
return str;
}
#endif
#define CHECK_STR_SIZE(_buf, _str, _size) \
if ((((_str) - (_buf)) >= ((_size)-1))) { break; }
int tiny_vsnprintf_like(char *buf, const int size, const char *fmt, va_list args)
{
unsigned long num;
int base;
char *str;
int len;
int i;
char *s;
int flags; // Flags to number()
int field_width; // Width of output field
int precision; // Min. # of digits for integers; max number of chars for from string
int qualifier; // 'h', 'l', or 'L' for integer fields
if (size <= 0)
{
return 0;
}
for (str = buf; *fmt || ((str - buf) >= size-1); fmt++)
{
CHECK_STR_SIZE(buf, str, size);
if (*fmt != '%')
{
*str++ = *fmt;
continue;
}
// Process flags
flags = 0;
#ifdef TINY_PRINTF
/* Support %0, but not %-, %+, %space and %# */
fmt++;
if (*fmt == '0')
{
flags |= ZEROPAD;
}
#else
repeat:
fmt++; // This also skips first '%'
switch (*fmt)
{
case '-': flags |= LEFT; goto repeat;
case '+': flags |= PLUS; goto repeat;
case ' ': flags |= SPACE; goto repeat;
case '#': flags |= HEX_PREP; goto repeat;
case '0': flags |= ZEROPAD; goto repeat;
}
#endif
// Get field width
field_width = -1;
if (is_digit(*fmt))
field_width = ee_skip_atoi(&fmt);
#ifdef TINY_PRINTF
/* Does not support %* */
#else
else if (*fmt == '*')
{
fmt++;
field_width = va_arg(args, int);
if (field_width < 0)
{
field_width = -field_width;
flags |= LEFT;
}
}
#endif
// Get the precision
precision = -1;
#ifdef TINY_PRINTF
/* Does not support %. */
#else
if (*fmt == '.')
{
++fmt;
if (is_digit(*fmt))
precision = ee_skip_atoi(&fmt);
else if (*fmt == '*')
{
++fmt;
precision = va_arg(args, int);
}
if (precision < 0) precision = 0;
}
#endif
// Get the conversion qualifier
qualifier = -1;
#ifdef TINY_PRINTF
/* Does not support %l and %L */
#else
if (*fmt == 'l' || *fmt == 'L')
{
qualifier = *fmt;
fmt++;
}
#endif
// Default base
base = 10;
switch (*fmt)
{
case 'c':
#ifdef TINY_PRINTF
#else
if (!(flags & LEFT))
#endif
while (--field_width > 0) *str++ = ' ';
*str++ = (unsigned char) va_arg(args, int);
#ifdef TINY_PRINTF
#else
while (--field_width > 0) *str++ = ' ';
#endif
continue;
case 's':
s = va_arg(args, char *);
if (!s) s = "<NULL>";
#ifdef TINY_PRINTF
len = strlen(s);
#else
len = strnlen(s, precision);
if (!(flags & LEFT))
#endif
while (len < field_width--) *str++ = ' ';
for (i = 0; i < len; ++i) *str++ = *s++;
#ifdef TINY_PRINTF
#else
while (len < field_width--) *str++ = ' ';
#endif
continue;
#ifdef TINY_PRINTF
/* Does not support %p, %A, %a, %o */
#else
case 'p':
if (field_width == -1)
{
field_width = 2 * sizeof(void *);
flags |= ZEROPAD;
}
str = ee_number(str, (size - (str - buf)), (unsigned long) va_arg(args, void *), 16, field_width, precision, flags);
continue;
case 'A':
flags |= UPPERCASE;
case 'a':
if (qualifier == 'l')
str = eaddr(str, va_arg(args, unsigned char *), field_width, precision, flags);
else
str = iaddr(str, va_arg(args, unsigned char *), field_width, precision, flags);
continue;
// Integer number formats - set up the flags and "break"
case 'o':
base = 8;
break;
#endif
case 'X':
flags |= UPPERCASE;
case 'x':
base = 16;
break;
case 'd':
case 'i':
flags |= SIGN;
case 'u':
break;
#ifdef HAS_FLOAT
case 'f':
str = flt(str, va_arg(args, double), field_width, precision, *fmt, flags | SIGN);
continue;
#endif
default:
if (*fmt != '%') *str++ = '%';
CHECK_STR_SIZE(buf, str, size);
if (*fmt)
*str++ = *fmt;
else
--fmt;
CHECK_STR_SIZE(buf, str, size);
continue;
}
if (qualifier == 'l')
num = va_arg(args, unsigned long);
else if (flags & SIGN)
num = va_arg(args, int);
else
num = va_arg(args, unsigned int);
str = ee_number(str, ((size - 1) - (str - buf)), num, base, field_width, precision, flags);
}
*str = '\0';
return str - buf;
}

View File

@ -0,0 +1,60 @@
/**
******************************************************************************
* @file stm32_tiny_vsnprintf.h
* @author MCD Application Team
* @brief Header for tiny_vsnprintf.c module
******************************************************************************
* @attention
*
* Copyright (c) 2019 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM32_TINY_VSNPRINTF_H__
#define __STM32_TINY_VSNPRINTF_H__
#ifdef __cplusplus
extern "C"
{
#endif
/* Includes ------------------------------------------------------------------*/
#include <stdarg.h>
#include <string.h>
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* External variables --------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
/**
* @brief Tiny implementation of vsnprintf() like function
*
* It has been adapted so that:
* - Tiny implementation, when defining TINY_PRINTF, is available. In such as case,
* not all the format are available. Instead, only %02X, %x, %d, %u, %s and %c are available.
* %f,, %+, %#, %- and others are excluded
* - Provide a snprintf like implementation. The size of the buffer is provided,
* and the length of the filled buffer is returned (not including the final '\0' char).
* The string may be truncated
* @param Pointer to a buffer where the resulting C-string is stored. The buffer should have a size of
* at least n characters.
* @param Maximum number of bytes to be used in the buffer. The generated string has a length of at
* most n-1, leaving space for the additional terminating null character.
* @param C string that contains a format string that follows the same specifications as format
* in printf (see printf for details).
* @param A value identifying a variable arguments list initialized with va_start.
* @retval The number of written char (note that this is different from vsnprintf()
*/
int tiny_vsnprintf_like(char *buf, const int size, const char *fmt, va_list args);
#ifdef __cplusplus
}
#endif
#endif /* __STM32_TINY_VSNPRINTF_H__ */

View File

@ -0,0 +1,6 @@
This software component is provided to you as part of a software package and
applicable license terms are in the Package_license file. If you received this
software component outside of a package or without applicable license terms,
the terms of the BSD-3-Clause license shall apply.
You may obtain a copy of the BSD-3-Clause at:
https://opensource.org/licenses/BSD-3-Clause

View File

@ -0,0 +1,550 @@
/**
******************************************************************************
* @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 is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "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 volatile UTIL_SEQ_bm_t TaskSet;
/**
* @brief task mask.
*/
static volatile 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 volatile UTIL_SEQ_bm_t EvtSet = UTIL_SEQ_NO_BIT_SET;
/**
* @brief evt expected mask.
*/
static volatile 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 volatile 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((uint8_t *)TaskCb, 0, sizeof(TaskCb));
for(uint32_t index = 0; index < UTIL_SEQ_CONF_PRIO_NBR; index++)
{
TaskPrio[index].priority = 0;
TaskPrio[index].round_robin = 0;
}
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;
UTIL_SEQ_bm_t local_taskset;
UTIL_SEQ_bm_t local_evtset;
UTIL_SEQ_bm_t local_taskmask;
UTIL_SEQ_bm_t local_evtwaited;
/*
* 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
*/
local_taskset = TaskSet;
local_evtset = EvtSet;
local_taskmask = TaskMask;
local_evtwaited = EvtWaited;
while(((local_taskset & local_taskmask & SuperMask) != 0U) && ((local_evtset & local_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 & local_taskmask & SuperMask)== 0U)
{
counter++;
}
current_task_set = TaskPrio[counter].priority & local_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 reinitialize 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]( );
local_taskset = TaskSet;
local_evtset = EvtSet;
local_taskmask = TaskMask;
local_evtwaited = EvtWaited;
}
/* 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( );
local_taskset = TaskSet;
local_evtset = EvtSet;
local_taskmask = TaskMask;
if ((local_taskset & local_taskmask & SuperMask) == 0U)
{
if ((local_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 ))
{
(void)Flags;
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_bm_t local_taskset;
UTIL_SEQ_ENTER_CRITICAL_SECTION();
local_taskset = TaskSet;
_status = ((local_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) ? 0u:1u;
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 = 0u;
}
else
{
wait_task_idx = (uint32_t)1u << 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 & EvtId_bm) == 0U)
{
UTIL_SEQ_EvtIdle(wait_task_idx, EvtId_bm);
}
/*
* 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;
UTIL_SEQ_ENTER_CRITICAL_SECTION( );
EvtSet &= (~EvtId_bm);
UTIL_SEQ_EXIT_CRITICAL_SECTION( );
EvtWaited = event_waited_id_backup;
return;
}
UTIL_SEQ_bm_t UTIL_SEQ_IsEvtPend( void )
{
UTIL_SEQ_bm_t local_evtwaited = EvtWaited;
return (EvtSet & local_evtwaited);
}
__WEAK void UTIL_SEQ_EvtIdle( UTIL_SEQ_bm_t TaskId_bm, UTIL_SEQ_bm_t EvtWaited_bm )
{
(void)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)
const uint8_t SEQ_clz_table_4bit[16U] = { 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;
uint32_t lvalue = Value;
if ((lvalue & 0xFFFF0000U) == 0U) { n = 16U; lvalue <<= 16U; }
if ((lvalue & 0xFF000000U) == 0U) { n += 8U; lvalue <<= 8U; }
if ((lvalue & 0xF0000000U) == 0U) { n += 4U; lvalue <<= 4U; }
n += SEQ_clz_table_4bit[lvalue >> (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
/**
* @}
*/
/**
* @}
*/

View File

@ -0,0 +1,360 @@
/**
******************************************************************************
* @file stm32_seq.h
* @author MCD Application Team
* @brief sequencer interface
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef STM32_SEQ_H
#define STM32_SEQ_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stdint.h"
/** @defgroup SEQUENCER sequencer utilities
* @{
*/
/* Exported types ------------------------------------------------------------*/
/** @defgroup SEQUENCER_Exported_type SEQUENCER exported types
* @{
*/
/**
* @brief bit mapping of the task.
* this value is used to represent a list of task (each corresponds to a task).
*/
typedef uint32_t UTIL_SEQ_bm_t;
/**
* @}
*/
/* Exported constants --------------------------------------------------------*/
/** @defgroup SEQUENCER_Exported_const SEQUENCER exported constants
* @{
*/
/**
* @brief This provides a default value for unused parameter
*
*/
#define UTIL_SEQ_RFU 0
/**
* @brief Default value used to start the scheduling.
*
* This informs the sequencer that all tasks registered shall be considered
*
* @note
* This should be used in the application\n
* while(1)\n
* {\n
* UTIL_SEQ_Run( UTIL_SEQ_DEFAULT );\n
* }\n
*
*/
#define UTIL_SEQ_DEFAULT (~0U)
/**
* @}
*/
/* External variables --------------------------------------------------------*/
/* Exported macros -----------------------------------------------------------*/
/** @defgroup SEQUENCER_Exported_macro SEQUENCER exported macros
* @{
*/
/**
* @brief This macro can be used to define a task with one parameter
*
* @note this is an example of using this macro
*
* task prototype definition
* void FUNCTION_NAME(void *Instance)
* {
* uint8_t _instance = *(uint8_t*) Instance;
* }
*
* task declaration in the application for two instances
* const uint8_t instance1 = 1;
* const uint8_t instance2 = 2;
* UTIL_SEQ_TaskParamDef(FUNCTION_NAME, instance1)
* UTIL_SEQ_TaskParamDef(FUNCTION_NAME, instance2)
*
* task initialization
* UTIL_SEQ_RegTask(1 << 1, 0, UTIL_SEQ_TaskFunction(FUNCTION_NAME,instance2));
* UTIL_SEQ_RegTask(1 << 10, 0, UTIL_SEQ_TaskFunction(FUNCTION_NAME,instance3));
*
* Then no change on the management of the task within the application, the instance being managed within the overloaded function
*
*/
#define UTIL_SEQ_TaskParamDef(_FUNC_,_PARAM_VAL_) \
static void SEQ_FUNC_##_FUNC_##_PARAM_VAL_(void); \
static void SEQ_FUNC_##_FUNC_##_PARAM_VAL_(void) \
{ \
static void *SEQ_PARAM_##_FUNC_ = (void*)&_PARAM_VAL_;\
_FUNC_(SEQ_PARAM_##_FUNC_); \
}
/**
* @brief This macro is used to retrieve the function name of the task
*/
#define UTIL_SEQ_TaskFunction(_FUNC_,_PARAM_VAL_) SEQ_FUNC_##_FUNC_##_PARAM_VAL_
/**
* @}
*/
/* Exported functions ------------------------------------------------------- */
/** @defgroup SEQUENCER_Exported_function SEQUENCER exported functions
* @{
*/
/**
* @brief This function initializes the sequencer resources.
*
* @note It shall not be called from an ISR.
*
*/
void UTIL_SEQ_Init( void );
/**
* @brief This function un-initializes the sequencer resources.
*
* @note It shall not be called from an ISR
*
*/
void UTIL_SEQ_DeInit( void );
/**
* @brief This function is called by the sequencer in critical section (PRIMASK bit) when
* - there are no more tasks to be executed
* AND
* - there are no pending event or the pending event is still not set
* @note The application should enter low power mode in this function
* When this function is not implemented by the application, the sequencer keeps running a while loop (RUN MODE).
* It shall be called only by the sequencer.
*
*/
void UTIL_SEQ_Idle( void );
/**
* @brief This function is called by the sequencer outside critical section just before calling UTIL_SEQ_Idle( )
* UTIL_SEQ_PreIdle() is considered as the last task executed before calling UTIL_SEQ_Idle( )
* In case a task or an event is set from an interrupt handler just after UTIL_SEQ_PreIdle() is called,
* UTIL_SEQ_Idle() will not be called.
*
* @note It shall be called only by the sequencer.
*
*/
void UTIL_SEQ_PreIdle( void );
/**
* @brief This function is called by the sequencer outside critical section either
* - after calling UTIL_SEQ_Idle( )
* OR
* - after calling UTIL_SEQ_PreIdle( ) without call to UTIL_SEQ_Idle() due to an incoming task set or event
* requested after UTIL_SEQ_PreIdle() has been called.
*
* @note UTIL_SEQ_PostIdle() is always called if UTIL_SEQ_PreIdle() has been called and never called otherwise.
* It shall be called only by the sequencer.
*
*/
void UTIL_SEQ_PostIdle( void );
/**
* @brief This function requests the sequencer to execute all pending tasks using round robin mechanism.
* When no task are pending, it calls UTIL_SEQ_Idle();
* This function should be called in a while loop in the application
*
* @param Mask_bm list of task (bit mapping) that is be kept in the sequencer list.
*
* @note It shall not be called from an ISR.
* @note The construction of the task must take into account the fact that there is no counting / protection
* on the activation of the task. Thus, when the task is running, it must perform all the operations
* in progress programmed before its call or manage a reprogramming of the task.
*
*/
void UTIL_SEQ_Run( UTIL_SEQ_bm_t Mask_bm );
/**
* @brief This function registers a task in the sequencer.
*
* @param TaskId_bm The Id of the task
* @param Flags Flags are reserved param for future use
* @param Task Reference of the function to be executed
*
* @note It may be called from an ISR.
*
*/
void UTIL_SEQ_RegTask( UTIL_SEQ_bm_t TaskId_bm, uint32_t Flags, void (*Task)( void ) );
/**
* @brief This function requests a task to be executed
*
* @param TaskId_bm The Id of the task
* It shall be (1<<task_id) where task_id is the number assigned when the task has been registered
* @param Task_Prio The priority of the task
* It shall a number from 0 (high priority) to 31 (low priority)
* The priority is checked each time the sequencer needs to select a new task to execute
* It does not permit to preempt a running task with lower priority
*
* @note It may be called from an ISR
*
*/
void UTIL_SEQ_SetTask( UTIL_SEQ_bm_t TaskId_bm , uint32_t Task_Prio );
/**
* @brief This function checks if a task could be scheduled.
*
* @param TaskId_bm The Id of the task
* It shall be (1<<task_id) where task_id is the number assigned when the task has been registered
* @retval 0 if not 1 if true
*
* @note It may be called from an ISR.
*
*/
uint32_t UTIL_SEQ_IsSchedulableTask( UTIL_SEQ_bm_t TaskId_bm);
/**
* @brief This function prevents a task to be called by the sequencer even when set with UTIL_SEQ_SetTask()
* By default, all tasks are executed by the sequencer when set with UTIL_SEQ_SetTask()
* When a task is paused, it is moved out from the sequencer list
*
* @param TaskId_bm The Id of the task
* It shall be (1<<task_id) where task_id is the number assigned when the task has been registered
*
* @note It may be called from an ISR.
*
*/
void UTIL_SEQ_PauseTask( UTIL_SEQ_bm_t TaskId_bm );
/**
* @brief This function allows to know if the task has been put in pause.
* By default, all tasks are executed by the sequencer when set with UTIL_SEQ_SetTask()
* The exit of the pause shall be done by the function UTIL_SEQ_ResumeTask.
*
* @param TaskId_bm The Id of the task
* It shall be (1<<task_id) where task_id is the number assigned when the task has been registered
*
* @note It may be called from an ISR.
*
*/
uint32_t UTIL_SEQ_IsPauseTask( UTIL_SEQ_bm_t TaskId_bm );
/**
* @brief This function allows again a task to be called by the sequencer if set with UTIL_SEQ_SetTask()
* This is used in relation with UTIL_SEQ_PauseTask()
*
* @param TaskId_bm The Id of the task
* It shall be (1<<task_id) where task_id is the number assigned when the task has been registered
*
* @note It may be called from an ISR.
*
*/
void UTIL_SEQ_ResumeTask( UTIL_SEQ_bm_t TaskId_bm );
/**
* @brief This function sets an event that is waited with UTIL_SEQ_WaitEvt()
*
* @param EvtId_bm event id bit mask
*
* @note An event shall be a 32 bit mapping where only 1 bit is set
* It may be called from an ISR.
*
*/
void UTIL_SEQ_SetEvt( UTIL_SEQ_bm_t EvtId_bm );
/**
* @brief This function may be used to clear the event before calling UTIL_SEQ_WaitEvt()
* This API may be useful when the UTIL_SEQ_SetEvt() is called several time to notify the same event.
* Due to Software Architecture where the timings are hard to control, this may be an unwanted case.
*
* @param EvtId_bm event id bm
* It shall be a bit mapping where only 1 bit is set
*
* @note It may be called from an ISR.
*
*/
void UTIL_SEQ_ClrEvt( UTIL_SEQ_bm_t EvtId_bm );
/**
* @brief This function waits for a specific event to be set. The sequencer loops UTIL_SEQ_EvtIdle() until the event is set
* When called recursively, it acts as a First in / Last out mechanism. The sequencer waits for the
* last event requested to be set even though one of the already requested event has been set.
*
* @param EvtId_bm event id bit mask
* It shall be a bit mapping where only 1 bit is set
*
* @note It shall not be called from an ISR.
* @note The construction of the task must take into account the fact that there is no counting / protection on the
* event. Thus, when the task is running, it must perform all the operations in progress programmed before its call
* or manage a reprogramming of the task.
*/
void UTIL_SEQ_WaitEvt( UTIL_SEQ_bm_t EvtId_bm );
/**
* @brief This function returns whether the waited event is pending or not
* It is useful only when the UTIL_SEQ_EvtIdle() is overloaded by the application. In that case, when the low
* power mode needs to be executed, the application shall first check whether the waited event is pending
* or not. Both the event checking and the low power mode processing should be done in critical section
*
* @retval 0 when the waited event is not there or the evt_id when the waited event is pending
*
* @note It may be called from an ISR.
*
*/
UTIL_SEQ_bm_t UTIL_SEQ_IsEvtPend( void );
/**
* @brief This function loops until the waited event is set
* @param TaskId_bm The task id that is currently running. When task_id_bm = 0, it means UTIL_SEQ_WaitEvt( )
* has been called outside a registered task (ie at startup before UTIL_SEQ_Run( ) has been called
* @param EvtWaited_bm The event id that is waited.
*
* @note When not implemented by the application, it calls UTIL_SEQ_Run(~TaskId_bm) which means the waited
* task is suspended until the waited event and the other tasks are running or the application enter
* low power mode.
* Else the user can redefine his own function for example call sequencer UTIL_SEQ_Run(0) to suspend all
* the task and let the sequencer enter the low power mode.
* It shall be called only by the sequencer.
*
*/
void UTIL_SEQ_EvtIdle( UTIL_SEQ_bm_t TaskId_bm, UTIL_SEQ_bm_t EvtWaited_bm );
/**
* @}
*/
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /*__STM32_SEQ_H */

View File

@ -0,0 +1,6 @@
This software component is provided to you as part of a software package and
applicable license terms are in the Package_license file. If you received this
software component outside of a package or without applicable license terms,
the terms of the BSD-3-Clause license shall apply.
You may obtain a copy of the BSD-3-Clause at:
https://opensource.org/licenses/BSD-3-Clause

View File

@ -0,0 +1,542 @@
/*!
* \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 is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "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
* @{
*/
void TimerInsertNewHeadTimer( UTIL_TIMER_Object_t *TimerObject );
void TimerInsertTimer( UTIL_TIMER_Object_t *TimerObject );
void TimerSetTimeout( UTIL_TIMER_Object_t *TimerObject );
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))
{
TimerObject->Timestamp = 0U;
TimerObject->ReloadValue = UTIL_TimerDriver.ms2Tick(PeriodValue);
TimerObject->IsPending = 0U;
TimerObject->IsRunning = 0U;
TimerObject->IsReloadStopped = 0U;
TimerObject->Callback = Callback;
TimerObject->argument = Argument;
TimerObject->Mode = Mode;
TimerObject->Next = NULL;
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;
uint32_t elapsedTime;
uint32_t minValue;
uint32_t ticks;
if(( TimerObject != NULL ) && ( TimerExists( TimerObject ) == false ) && (TimerObject->IsRunning == 0U))
{
UTIL_TIMER_ENTER_CRITICAL_SECTION();
ticks = TimerObject->ReloadValue;
minValue = UTIL_TimerDriver.GetMinimumTimeout( );
if( ticks < minValue )
{
ticks = minValue;
}
TimerObject->Timestamp = ticks;
TimerObject->IsPending = 0U;
TimerObject->IsRunning = 1U;
TimerObject->IsReloadStopped = 0U;
if( TimerListHead == NULL )
{
UTIL_TimerDriver.SetTimerContext();
TimerInsertNewHeadTimer( TimerObject ); /* insert a timeout at now+obj->Timestamp */
}
else
{
elapsedTime = UTIL_TimerDriver.GetTimerElapsedTime( );
TimerObject->Timestamp += elapsedTime;
if( TimerObject->Timestamp < TimerListHead->Timestamp )
{
TimerInsertNewHeadTimer( TimerObject);
}
else
{
TimerInsertTimer( TimerObject);
}
}
UTIL_TIMER_EXIT_CRITICAL_SECTION();
}
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)
{
UTIL_TIMER_ENTER_CRITICAL_SECTION();
UTIL_TIMER_Object_t* prev = TimerListHead;
UTIL_TIMER_Object_t* cur = TimerListHead;
TimerObject->IsReloadStopped = 1U;
/* List is empty or the Obj to stop does not exist */
if(NULL != TimerListHead)
{
TimerObject->IsRunning = 0U;
if( TimerListHead == TimerObject ) /* Stop the Head */
{
TimerListHead->IsPending = 0;
if( TimerListHead->Next != NULL )
{
TimerListHead = TimerListHead->Next;
TimerSetTimeout( TimerListHead );
}
else
{
UTIL_TimerDriver.StopTimerEvt( );
TimerListHead = NULL;
}
}
else /* Stop an object within the list */
{
while( cur != NULL )
{
if( cur == TimerObject )
{
if( cur->Next != NULL )
{
cur = cur->Next;
prev->Next = cur;
}
else
{
cur = NULL;
prev->Next = cur;
}
break;
}
else
{
prev = cur;
cur = cur->Next;
}
}
}
ret = UTIL_TIMER_OK;
}
UTIL_TIMER_EXIT_CRITICAL_SECTION();
}
else
{
ret = UTIL_TIMER_INVALID_PARAM;
}
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 = UTIL_TimerDriver.ms2Tick(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;
}
UTIL_TIMER_Status_t UTIL_TIMER_GetRemainingTime(UTIL_TIMER_Object_t *TimerObject, uint32_t *ElapsedTime)
{
UTIL_TIMER_Status_t ret = UTIL_TIMER_OK;
if(TimerExists(TimerObject))
{
uint32_t time = UTIL_TimerDriver.GetTimerElapsedTime();
if (TimerObject->Timestamp < time )
{
*ElapsedTime = 0;
}
else
{
*ElapsedTime = TimerObject->Timestamp - time;
}
}
else
{
ret = UTIL_TIMER_INVALID_PARAM;
}
return ret;
}
uint32_t UTIL_TIMER_IsRunning( UTIL_TIMER_Object_t *TimerObject )
{
if( TimerObject != NULL )
{
return TimerObject->IsRunning;
}
else
{
return 0;
}
}
uint32_t UTIL_TIMER_GetFirstRemainingTime(void)
{
uint32_t NextTimer = 0xFFFFFFFFU;
if(TimerListHead != NULL)
{
(void)UTIL_TIMER_GetRemainingTime(TimerListHead, &NextTimer);
}
return NextTimer;
}
void UTIL_TIMER_IRQ_Handler( void )
{
UTIL_TIMER_Object_t* cur;
uint32_t old, now, DeltaContext;
UTIL_TIMER_ENTER_CRITICAL_SECTION();
old = UTIL_TimerDriver.GetTimerContext( );
now = UTIL_TimerDriver.SetTimerContext( );
DeltaContext = now - old; /*intentional wrap around */
/* update timeStamp based upon new Time Reference*/
/* because delta context should never exceed 2^32*/
if ( TimerListHead != NULL )
{
cur = TimerListHead;
do {
if (cur->Timestamp > DeltaContext)
{
cur->Timestamp -= DeltaContext;
}
else
{
cur->Timestamp = 0;
}
cur = cur->Next;
} while(cur != NULL);
}
/* Execute expired timer and update the list */
while ((TimerListHead != NULL) && ((TimerListHead->Timestamp == 0U) || (TimerListHead->Timestamp < UTIL_TimerDriver.GetTimerElapsedTime( ))))
{
cur = TimerListHead;
TimerListHead = TimerListHead->Next;
cur->IsPending = 0;
cur->IsRunning = 0;
cur->Callback(cur->argument);
if(( cur->Mode == UTIL_TIMER_PERIODIC) && (cur->IsReloadStopped == 0U))
{
(void)UTIL_TIMER_Start(cur);
}
}
/* start the next TimerListHead if it exists and it is not pending*/
if(( TimerListHead != NULL ) && (TimerListHead->IsPending == 0U))
{
TimerSetTimeout( TimerListHead );
}
UTIL_TIMER_EXIT_CRITICAL_SECTION();
}
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 )
{
UTIL_TIMER_Object_t* cur = TimerListHead;
while( cur != NULL )
{
if( cur == TimerObject )
{
return true;
}
cur = cur->Next;
}
return false;
}
/**
* @brief Sets a timeout with the duration "timestamp"
*
* @param TimerObject Structure containing the timer object parameters
*/
void TimerSetTimeout( UTIL_TIMER_Object_t *TimerObject )
{
uint32_t minTicks= UTIL_TimerDriver.GetMinimumTimeout( );
TimerObject->IsPending = 1;
/* In case deadline too soon */
if(TimerObject->Timestamp < (UTIL_TimerDriver.GetTimerElapsedTime( ) + minTicks) )
{
TimerObject->Timestamp = UTIL_TimerDriver.GetTimerElapsedTime( ) + minTicks;
}
UTIL_TimerDriver.StartTimerEvt( TimerObject->Timestamp );
}
/**
* @brief Adds a timer to the list.
*
* @remark The list is automatically sorted. The list head always contains the
* next timer to expire.
*
* @param TimerObject Structure containing the timer object parameters
*/
void TimerInsertTimer( UTIL_TIMER_Object_t *TimerObject)
{
UTIL_TIMER_Object_t* cur = TimerListHead;
UTIL_TIMER_Object_t* next = TimerListHead->Next;
while (cur->Next != NULL )
{
if( TimerObject->Timestamp > next->Timestamp )
{
cur = next;
next = next->Next;
}
else
{
cur->Next = TimerObject;
TimerObject->Next = next;
return;
}
}
cur->Next = TimerObject;
TimerObject->Next = NULL;
}
/**
* @brief Adds or replace the head timer of the list.
*
* @param TimerObject Structure containing the timer object parameters
*
* @remark The list is automatically sorted. The list head always contains the
* next timer to expire.
*/
void TimerInsertNewHeadTimer( UTIL_TIMER_Object_t *TimerObject )
{
UTIL_TIMER_Object_t* cur = TimerListHead;
if( cur != NULL )
{
cur->IsPending = 0;
}
TimerObject->Next = cur;
TimerListHead = TimerObject;
TimerSetTimeout( TimerListHead );
}
/**
* @}
*/
/**
* @}
*/

View File

@ -0,0 +1,292 @@
/*!
* \file timer.h
*
* \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.h
* @author MCD Application Team
* @brief This is the header of the timer server driver
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef UTIL_TIME_SERVER_H__
#define UTIL_TIME_SERVER_H__
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup TIMER_SERVER timer server
* @{
*/
/* Includes ------------------------------------------------------------------*/
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include <cmsis_compiler.h>
#include "utilities_conf.h"
/* Exported types ------------------------------------------------------------*/
/** @defgroup TIMER_SERVER_exported_TypeDef TIMER_SERVER exported Typedef
* @{
*/
/**
* @brief Timer mode
*/
typedef enum {
UTIL_TIMER_ONESHOT = 0, /*!<One-shot timer. */
UTIL_TIMER_PERIODIC = 1 /*!<Periodic timer. */
} UTIL_TIMER_Mode_t;
/**
* @brief Timer status
*/
typedef enum {
UTIL_TIMER_OK = 0, /*!<Operation terminated successfully.*/
UTIL_TIMER_INVALID_PARAM = 1, /*!<Invalid Parameter. */
UTIL_TIMER_HW_ERROR = 2, /*!<Hardware Error. */
UTIL_TIMER_UNKNOWN_ERROR = 3 /*!<Unknown Error. */
} UTIL_TIMER_Status_t;
/**
* @brief Timer object description
*/
typedef struct TimerEvent_s
{
uint32_t Timestamp; /*!<Expiring timer value in ticks from TimerContext */
uint32_t ReloadValue; /*!<Reload Value when Timer is restarted */
uint8_t IsPending; /*!<Is the timer waiting for an event */
uint8_t IsRunning; /*!<Is the timer running */
uint8_t IsReloadStopped; /*!<Is the reload stopped */
UTIL_TIMER_Mode_t Mode; /*!<Timer type : one-shot/continuous */
void ( *Callback )( void *); /*!<callback function */
void *argument; /*!<callback argument */
struct TimerEvent_s *Next; /*!<Pointer to the next Timer object. */
} UTIL_TIMER_Object_t;
/**
* @brief Timer driver definition
*/
typedef struct
{
UTIL_TIMER_Status_t (* InitTimer )( void ); /*!< Initialisation of the low layer timer */
UTIL_TIMER_Status_t (* DeInitTimer )( void ); /*!< Un-Initialisation of the low layer timer */
UTIL_TIMER_Status_t (* StartTimerEvt )( uint32_t timeout ); /*!< Start the low layer timer */
UTIL_TIMER_Status_t (* StopTimerEvt )( void); /*!< Stop the low layer timer */
uint32_t (* SetTimerContext)( void ); /*!< Set the timer context */
uint32_t (* GetTimerContext)( void ); /*!< Get the timer context */
uint32_t (* GetTimerElapsedTime)( void ); /*!< Get elapsed time */
uint32_t (* GetTimerValue)( void ); /*!< Get timer value */
uint32_t (* GetMinimumTimeout)( void ); /*!< Get Minimum timeout */
uint32_t (* ms2Tick)( uint32_t timeMicroSec ); /*!< convert ms to tick */
uint32_t (* Tick2ms)( uint32_t tick ); /*!< convert tick into ms */
} UTIL_TIMER_Driver_s;
/**
* @brief Timer value on 32 bits
*/
typedef uint32_t UTIL_TIMER_Time_t;
/**
* @}
*/
/* Exported variables ------------------------------------------------------------*/
/** @defgroup TIMER_SERVER_exported_Variable TIMER_SERVER exported Variable
* @{
*/
/**
* @brief low layer interface to handle timing execution
*
* @remark This structure is defined and initialized in the specific platform
* timer implementation
*/
extern const UTIL_TIMER_Driver_s UTIL_TimerDriver;
/**
* @}
*/
/* Exported constants --------------------------------------------------------*/
/* External variables --------------------------------------------------------*/
/* Exported macros -----------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
/** @defgroup TIMER_SERVER_exported_function TIMER_SERVER exported function
* @{
*/
/**
* @brief Initialize the timer server
*
* @retval Status based on @ref UTIL_TIMER_Status_t
*/
UTIL_TIMER_Status_t UTIL_TIMER_Init(void);
/**
* @brief Un-Initialize the timer server
*
* @retval Status based on @ref UTIL_TIMER_Status_t
*/
UTIL_TIMER_Status_t UTIL_TIMER_DeInit(void);
/**
* @brief Create the timer object
*
* @remark TimerSetValue function must be called before starting the timer.
* this function initializes timestamp and reload value at 0.
*
* @param TimerObject Structure containing the timer object parameters
* @param PeriodValue Period value of the timer in ms
* @param Mode @ref UTIL_TIMER_Mode_t
* @param Callback Function callback called at the end of the timeout
* @param Argument argument for the callback function
* @retval Status based on @ref UTIL_TIMER_Status_t
*/
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);
/**
* @brief Start and adds the timer object to the list of timer events
*
* @param TimerObject Structure containing the timer object parameters
* @retval Status based on @ref UTIL_TIMER_Status_t
*/
UTIL_TIMER_Status_t UTIL_TIMER_Start( UTIL_TIMER_Object_t *TimerObject );
/**
* @brief Start and adds the timer object to the list of timer events
*
* @param TimerObject Structure containing the timer object parameters
* @param PeriodValue period value of the timer
* @retval Status based on @ref UTIL_TIMER_Status_t
*/
UTIL_TIMER_Status_t UTIL_TIMER_StartWithPeriod( UTIL_TIMER_Object_t *TimerObject, uint32_t PeriodValue);
/**
* @brief Stop and removes the timer object from the list of timer events
*
* @param TimerObject Structure containing the timer object parameters
* @retval Status based on @ref UTIL_TIMER_Status_t
*/
UTIL_TIMER_Status_t UTIL_TIMER_Stop( UTIL_TIMER_Object_t *TimerObject );
/**
* @brief update the period and start the timer
*
* @param TimerObject Structure containing the timer object parameters
* @param NewPeriodValue new period value of the timer
* @retval Status based on @ref UTIL_TIMER_Status_t
*/
UTIL_TIMER_Status_t UTIL_TIMER_SetPeriod(UTIL_TIMER_Object_t *TimerObject, uint32_t NewPeriodValue);
/**
* @brief update the period and start the timer
*
* @param TimerObject Structure containing the timer object parameters
* @param ReloadMode new reload mode @ref UTIL_TIMER_Mode_t
* @retval Status based on @ref UTIL_TIMER_Status_t
*/
UTIL_TIMER_Status_t UTIL_TIMER_SetReloadMode(UTIL_TIMER_Object_t *TimerObject, UTIL_TIMER_Mode_t ReloadMode);
/**
* @brief get the remaining time before timer expiration
* *
* @param TimerObject Structure containing the timer object parameters
* @param Time time before expiration in ms
* @retval Status based on @ref UTIL_TIMER_Status_t
*/
UTIL_TIMER_Status_t UTIL_TIMER_GetRemainingTime(UTIL_TIMER_Object_t *TimerObject, uint32_t *Time);
/**
* @brief return timer state
*
* @param TimerObject Structure containing the timer object parameters
* @retval boolean value is returned 0 = false and 1 = true
*/
uint32_t UTIL_TIMER_IsRunning( UTIL_TIMER_Object_t *TimerObject );
/**
* @brief return the remaining time of the first timer in the chain list
*
* @retval return the time in ms, the value 0xFFFFFFFF means no timer running
*/
uint32_t UTIL_TIMER_GetFirstRemainingTime(void);
/**
* @brief return the current time
*
* @retval time value
*/
UTIL_TIMER_Time_t UTIL_TIMER_GetCurrentTime(void);
/**
* @brief return the elapsed time
*
* @param past a value returned by the function UTIL_TIMER_GetCurrentTime
* @retval elasped time value
*/
UTIL_TIMER_Time_t UTIL_TIMER_GetElapsedTime(UTIL_TIMER_Time_t past );
/**
* @brief Timer IRQ event handler
*
* @note Head Timer Object is automatically removed from the List
*
* @note e.g. it is not needed to stop it
*/
void UTIL_TIMER_IRQ_Handler( void );
/**
* @}
*/
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* UTIL_TIME_SERVER_H__*/

View File

@ -0,0 +1,166 @@
/*******************************************************************************
* File Name : stm32_timer_if.c
* Description : This file provides the ll driver for the time server
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include <math.h>
#include "stm32_timer_if.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Exported variables ---------------------------------------------------------*/
const UTIL_TIMER_Driver_s UTIL_TimerDriver =
{
PPP_Init,
PPP_DeInit,
PPP_StartTimer,
PPP_StopTimer,
PPP_SetTimerContext,
PPP_GetTimerContext,
PPP_GetTimerElapsedTime,
PPP_GetTimerValue,
PPP_GetMinimumTimeout,
PPP_ms2Tick,
PPP_Tick2ms,
};
/*!
* @brief Initializes the PPP timer
* @note The timer is based on the PPP
* @param none
* @retval none
*/
UTIL_TIMER_Status_t PPP_Init( void )
{
return UTIL_TIMER_OK;
}
/*!
* @brief Initializes the PPP timer
* @note The timer is based on the PPP
* @param none
* @retval none
*/
UTIL_TIMER_Status_t PPP_DeInit( void )
{
return UTIL_TIMER_OK;
}
/*!
* @brief Set the timer
* @note The timer is set at now (read in this function) + timeout
* @param timeout Duration of the Timer ticks
*/
UTIL_TIMER_Status_t PPP_StartTimer( uint32_t timeout )
{
return UTIL_TIMER_OK;
}
/*!
* @brief Stop the timer
* @param none
* @retval none
*/
UTIL_TIMER_Status_t PPP_StopTimer( void )
{
return UTIL_TIMER_OK;
}
/*!
* @brief returns the wake up time in ticks
* @param none
* @retval wake up time in ticks
*/
uint32_t PPP_GetMinimumTimeout( void )
{
return ( 0 );
}
/*!
* @brief converts time in ms to time in ticks
* @param [IN] time in milliseconds
* @retval returns time in timer ticks
*/
uint32_t PPP_ms2Tick( uint32_t timeMicroSec )
{
return ( 0 );
}
/*!
* @brief converts time in ticks to time in ms
* @param [IN] time in timer ticks
* @retval returns time in milliseconds
*/
uint32_t PPP_Tick2ms( uint32_t tick )
{
return ( 0 );
}
/*!
* @brief Get the PPP timer elapsed time since the last timer was set
* @param none
* @retval PPP Elapsed time in ticks
*/
uint32_t PPP_GetTimerElapsedTime( void )
{
return ( 0 );
}
/*!
* @brief Get the PPP timer value
* @param none
* @retval PPP Timer value in ticks
*/
uint32_t PPP_GetTimerValue( void )
{
return ( 0 );
}
/*!
* @brief PPP IRQ Handler on the PPP timer
* @param none
* @retval none
*/
void PPP_IrqHandler ( void )
{
}
/*!
* @brief set Time Reference set also the sDate and sTime
* @param none
* @retval Timer Value
*/
uint32_t PPP_SetTimerContext( void )
{
return ( 0 );
}
/*!
* @brief Get the PPP timer Reference
* @param none
* @retval Timer Value in Ticks
*/
uint32_t PPP_GetTimerContext( void )
{
return ( 0 );
}

View File

@ -0,0 +1,120 @@
/**
******************************************************************************
* File Name : stm32_timer_if.h
* Description : This file provides the ll driver for the time server
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef STM32_TIMER_IF_H__
#define STM32_TIMER_IF_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32_timer.h"
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* External variables --------------------------------------------------------*/
/* Exported macros -----------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
/*!
* @brief Initialize the PPP timer
* @note The timer is based on the PPP
*/
UTIL_TIMER_Status_t PPP_Init( void );
/*!
* @brief Un-initialize the PPP timer
* @note The timer is based on the PPP
*/
UTIL_TIMER_Status_t PPP_DeInit( void );
/*!
* @brief Start the timer
* @note The timer is set at Reference + timeout
* @param timeout Duration of the Timer in ticks
*/
UTIL_TIMER_Status_t PPP_StartTimer( uint32_t timeout );
/*!
* @brief Stop the timer
* @param none
* @retval none
*/
UTIL_TIMER_Status_t PPP_StopTimer( void );
/*!
* @brief Return the minimum timeout the PPP is able to handle
* @param none
* @retval minimum value for a timeout
*/
uint32_t PPP_GetMinimumTimeout( void );
/*!
* @brief Get the PPP timer elapsed time since the last Reference was set
* @retval PPP Elapsed time in ticks
*/
uint32_t PPP_GetTimerElapsedTime( void );
/*!
* @brief Get the PPP timer value
* @retval none
*/
uint32_t PPP_GetTimerValue( void );
/*!
* @brief Set the PPP timer Reference
* @retval Timer Reference Value in Ticks
*/
uint32_t PPP_SetTimerContext( void );
/*!
* @brief Get the PPP timer Reference
* @retval Timer Value in Ticks
*/
uint32_t PPP_GetTimerContext( void );
/*!
* @brief PPP IRQ Handler on the PPP timer
* @param none
* @retval none
*/
void PPP_IrqHandler ( void );
/*!
* @brief converts time in ms to time in ticks
* @param [IN] time in milliseconds
* @retval returns time in ticks
*/
uint32_t PPP_ms2Tick( uint32_t timeMicroSec );
/*!
* @brief converts time in ticks to time in ms
* @param [IN] time in ticks
* @retval returns time in milliseconds
*/
uint32_t PPP_Tick2ms( uint32_t tick );
#ifdef __cplusplus
}
#endif
#endif /* STM32_TIMER_IF_H__ */

View File

@ -0,0 +1,6 @@
This software component is provided to you as part of a software package and
applicable license terms are in the Package_license file. If you received this
software component outside of a package or without applicable license terms,
the terms of the BSD-3-Clause license shall apply.
You may obtain a copy of the BSD-3-Clause at:
https://opensource.org/licenses/BSD-3-Clause

View File

@ -0,0 +1,828 @@
/**
******************************************************************************
* @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 is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "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);
}
/**
* @}
*/
/**
* @}
*/

View File

@ -0,0 +1,273 @@
/**
******************************************************************************
* @file stm32_adv_trace.h
* @author MCD Application Team
* @brief Header for stm32_adv_trace.c
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __ADV_TRACE_H
#define __ADV_TRACE_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stdint.h"
#include "utilities_conf.h"
/** @defgroup ADV_TRACE advanced tracer
* @{
*/
/* Exported types ------------------------------------------------------------*/
/** @defgroup ADV_TRACE_exported_TypeDef ADV_TRACE exported Typedef
* @{
*/
/**
* @brief prototype of the time stamp function.
*/
typedef void cb_timestamp(uint8_t *pData, uint16_t *Size);
/**
* @brief prototype of the overrun function.
*/
typedef void cb_overrun(uint8_t **pData, uint16_t *size);
/**
* @brief List the Advanced trace function status.
* list of the returned status value, any negative value is corresponding to an error.
*/
typedef enum{
UTIL_ADV_TRACE_OK = 0, /*!< Operation terminated successfully.*/
UTIL_ADV_TRACE_INVALID_PARAM = -1, /*!< Invalid Parameter. */
UTIL_ADV_TRACE_HW_ERROR = -2, /*!< Hardware Error. */
UTIL_ADV_TRACE_MEM_FULL = -3, /*!< Memory fifo full. */
UTIL_ADV_TRACE_UNKNOWN_ERROR = -4, /*!< Unknown Error. */
#if defined(UTIL_ADV_TRACE_CONDITIONNAL)
UTIL_ADV_TRACE_GIVEUP = -5, /*!< trace give up */
UTIL_ADV_TRACE_REGIONMASKED = -6 /*!< trace region masked */
#endif
} UTIL_ADV_TRACE_Status_t;
/**
* @brief Advanced trace driver definition
*/
typedef struct {
UTIL_ADV_TRACE_Status_t (* Init)(void (*cb)(void *ptr)); /*!< Media initialization. */
UTIL_ADV_TRACE_Status_t (* DeInit)(void); /*!< Media Un-initialization. */
UTIL_ADV_TRACE_Status_t (* StartRx)(void (*cb)(uint8_t *pdata, uint16_t size, uint8_t error)); /*!< Media to start RX process. */
UTIL_ADV_TRACE_Status_t (* Send)(uint8_t *pdata, uint16_t size); /*!< Media to send data. */
}UTIL_ADV_TRACE_Driver_s;
/**
* @}
*/
/* External variables --------------------------------------------------------*/
/** @defgroup ADV_TRACE_exported_variables ADV_TRACE exported variables
*
* @{
*/
/**
* @brief This structure is the linked with the IF layer implementation.
*/
extern const UTIL_ADV_TRACE_Driver_s UTIL_TraceDriver;
/**
* @}
*/
/* Exported constants --------------------------------------------------------*/
/* Exported macros -----------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
/** @defgroup ADV_TRACE_exported_function ADV_TRACE exported function
* @{
*/
/**
* @brief TraceInit Initializes Logging feature
* @retval Status based on @ref UTIL_ADV_TRACE_Status_t
*/
UTIL_ADV_TRACE_Status_t UTIL_ADV_TRACE_Init(void);
/**
* @brief TraceDeInit module DeInitializes.
* @retval Status based on @ref UTIL_ADV_TRACE_Status_t
*/
UTIL_ADV_TRACE_Status_t UTIL_ADV_TRACE_DeInit(void);
/**
* @brief this function check if the buffer is empty.
* @retval 1 if the buffer is empty else 0
*/
uint8_t UTIL_ADV_TRACE_IsBufferEmpty(void);
/**
* @brief start the RX process.
* @param UserCallback ptr function used to get the RX data
* @retval Status based on @ref UTIL_ADV_TRACE_Status_t
*/
UTIL_ADV_TRACE_Status_t UTIL_ADV_TRACE_StartRxProcess(void (*UserCallback)(uint8_t *PData, uint16_t Size, uint8_t Error));
/**
* @brief TraceSend decode the strFormat and post it to the circular queue for printing
* @param strFormat Trace message and format
* @retval Status based on @ref UTIL_ADV_TRACE_Status_t
*/
UTIL_ADV_TRACE_Status_t UTIL_ADV_TRACE_FSend(const char *strFormat, ...);
/**
* @brief post data to the circular queue
* @param *pdata pointer to Data
* @param length length of data buffer to be sent
* @retval Status based on @ref UTIL_ADV_TRACE_Status_t
*/
UTIL_ADV_TRACE_Status_t UTIL_ADV_TRACE_Send(const uint8_t *pdata, uint16_t length);
/**
* @brief ZCSend_Allocation allocate the memory and return information to write the data
* @param Length trase size
* @param pData pointer on the fifo
* @param FifoSize size of the fifo
* @param WritePos write position of the fifo
* @retval Status based on @ref UTIL_ADV_TRACE_Status_t
*/
UTIL_ADV_TRACE_Status_t UTIL_ADV_TRACE_ZCSend_Allocation(uint16_t Length, uint8_t **pData, uint16_t *FifoSize, uint16_t *WritePos);
/**
* @brief ZCSend finalize the data transfer
* @retval Status based on @ref UTIL_ADV_TRACE_Status_t
*/
UTIL_ADV_TRACE_Status_t UTIL_ADV_TRACE_ZCSend_Finalize(void);
/**
* @brief Trace send started hook
* @retval None
*/
/**
* @brief Trace send pre hook function
*/
void UTIL_ADV_TRACE_PreSendHook(void);
/**
* @brief Trace send post hook function
*/
void UTIL_ADV_TRACE_PostSendHook(void);
#if defined(UTIL_ADV_TRACE_OVERRUN)
/**
* @brief Register a function used to add overrun info inside the trace
* @param cb pointer of function to return overrun information
*/
void UTIL_ADV_TRACE_RegisterOverRunFunction(cb_overrun *cb);
#endif
#if defined(UTIL_ADV_TRACE_CONDITIONNAL)
/**
* @brief conditional FSend decode the strFormat and post it to the circular queue for printing
* @param VerboseLevel verbose level of the trace
* @param Region region of the trace
* @param TimeStampState 0 no time stamp insertion, 1 time stamp inserted inside the trace data
* @param strFormat formatted string
* @retval Status based on @ref UTIL_ADV_TRACE_Status_t
*/
UTIL_ADV_TRACE_Status_t UTIL_ADV_TRACE_COND_FSend(uint32_t VerboseLevel, uint32_t Region,uint32_t TimeStampState, const char *strFormat, ...);
/**
* @brief conditional ZCSend Write user formatted data directly in the FIFO (Z-Cpy)
* @param VerboseLevel verbose level of the trace
* @param Region region of the trace
* @param TimeStampState 0 no time stamp insertion, 1 time stamp inserted inside the trace data
* @param length data length
* @param pData pointer on the fifo
* @param FifoSize size of the fifo
* @param WritePos write position of the fifo
* @retval Status based on @ref UTIL_ADV_TRACE_Status_t
*/
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);
/**
* @brief conditional ZCSend finalize the data transfer
* @retval Status based on @ref UTIL_ADV_TRACE_Status_t
*/
UTIL_ADV_TRACE_Status_t UTIL_ADV_TRACE_COND_ZCSend_Finalize(void);
/**
* @brief confitionnal Send post data to the circular queue
* @param VerboseLevel verbose level of the trace
* @param Region region of the trace
* @param TimeStampState 0 no time stamp insertion, 1 time stamp inserted inside the trace data
* @param *pdata pointer to Data
* @param length length of data buffer ro be sent
* @retval Status based on @ref UTIL_ADV_TRACE_Status_t
*/
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);
/**
* @brief Register a function used to add timestamp inside the trace
* @param cb pointer of function to return timestamp information
*/
void UTIL_ADV_TRACE_RegisterTimeStampFunction(cb_timestamp *cb);
/**
* @brief Set the verbose level
* @param Level (0 to 255)
* @retval None
*/
void UTIL_ADV_TRACE_SetVerboseLevel(uint8_t Level);
/**
* @brief Get the verbose level
* @retval verbose level
*/
uint8_t UTIL_ADV_TRACE_GetVerboseLevel(void);
/**
* @brief add to the mask a bit field region.
* @param Region bit field of region to enable
* @retval None
*/
void UTIL_ADV_TRACE_SetRegion(uint32_t Region);
/**
* @brief add to the mask a bit field region.
* @retval None
*/
uint32_t UTIL_ADV_TRACE_GetRegion(void);
/**
* @brief remove from the mask a bit field region.
* @param Region Region bit field of region to disable
* @retval None
*/
void UTIL_ADV_TRACE_ResetRegion(uint32_t Region);
#endif
/**
* @}
*/
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /*__ADV_TRACE_H */

View File

@ -0,0 +1,90 @@
/**
******************************************************************************
* @file : stm32_adv_trace_if_template.c
* @brief : Source file for interfacing the stm32_adv_trace to hardware
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#include "stm32_adv_trace.h"
#include "stm32_adv_trace_if.h"
/* USER CODE BEGIN include */
/* USER CODE END include */
/* Exported variables --------------------------------------------------------*/
/**
* @brief trace tracer definition.
*
* list all the driver interface used by the trace application.
*/
const UTIL_ADV_TRACE_Driver_s UTIL_TraceDriver =
{
UART_Init,
UART_DeInit,
UART_StartRx,
UART_TransmitDMA
};
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN Private_Function_Prototypes */
/* USER CODE END Private_Function_Prototypes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN Private_Typedef */
/* USER CODE END Private_Typedef */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN Private_Define */
/* USER CODE END Private_Define */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN Private_Macro */
/* USER CODE END Private_Macro */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Private_Variables */
/* USER CODE END Private_Variables */
UTIL_ADV_TRACE_Status_t UART_Init( void (*cb)(void *))
{
/* USER CODE BEGIN UART_Init */
return UTIL_ADV_TRACE_OK;
/* USER CODE END UART_Init */
}
UTIL_ADV_TRACE_Status_t UART_DeInit( void )
{
/* USER CODE BEGIN UART_DeInit */
return UTIL_ADV_TRACE_OK;
/* USER CODE END UART_DeInit */
}
UTIL_ADV_TRACE_Status_t UART_StartRx(void (*cb)(uint8_t *pdata, uint16_t size, uint8_t error))
{
/* USER CODE BEGIN UART_DeInit */
return UTIL_ADV_TRACE_OK;
/* USER CODE END UART_DeInit */
}
UTIL_ADV_TRACE_Status_t UART_TransmitDMA ( uint8_t *pdata, uint16_t size )
{
/* USER CODE BEGIN UART_DeInit */
return UTIL_ADV_TRACE_OK;
/* USER CODE END UART_DeInit */
}
/* USER CODE BEGIN Private_Functions */
/* USER CODE END Private_Functions */

View File

@ -0,0 +1,74 @@
/**
******************************************************************************
* @file : stm32_adv_trace_if_template.h
* @brief : Header file for stm32_adv_trace interface file
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#include "stm32_adv_trace.h"
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM32_ADV_TRACE_IF_H__
#define __STM32_ADV_TRACE_IF_H__
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup ADV_TRACE_IF low layer level of the advanced tracer
* @{
*/
/* Includes ------------------------------------------------------------------*/
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* External variables --------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
/**
* @brief Init the UART and associated DMA.
* @param cb tx function callback.
* @return @ref UTIL_ADV_TRACE_Status_t
*/
UTIL_ADV_TRACE_Status_t UART_Init(void (*cb)(void *));
/**
* @brief DeInit the UART and associated DMA.
* @return @ref UTIL_ADV_TRACE_Status_t
*/
UTIL_ADV_TRACE_Status_t UART_DeInit(void);
/**
* @brief send buffer to UART using DMA
* @param pdata data to be sent
* @param size of buffer p_data to be sent
* @return @ref UTIL_ADV_TRACE_Status_t
*/
UTIL_ADV_TRACE_Status_t UART_TransmitDMA(uint8_t *pdata, uint16_t size);
/**
* @brief start Rx process
* @param cb callback to receive the data
* @return @ref UTIL_ADV_TRACE_Status_t
*/
UTIL_ADV_TRACE_Status_t UART_StartRx(void (*cb)(uint8_t *pdata, uint16_t size, uint8_t error));
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#endif /* __STM32_ADV_TRACE_IF_H__*/