first
This commit is contained in:
6
Utilities/lpm/tiny_lpm/LICENSE.txt
Normal file
6
Utilities/lpm/tiny_lpm/LICENSE.txt
Normal 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
|
||||
258
Utilities/lpm/tiny_lpm/stm32_lpm.c
Normal file
258
Utilities/lpm/tiny_lpm/stm32_lpm.c
Normal file
@ -0,0 +1,258 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file stm32_lpm.c
|
||||
* @author MCD Application Team
|
||||
* @brief Low Power Manager
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© 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( );
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
167
Utilities/lpm/tiny_lpm/stm32_lpm.h
Normal file
167
Utilities/lpm/tiny_lpm/stm32_lpm.h
Normal file
@ -0,0 +1,167 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file stm32_lpm.h
|
||||
* @author MCD Application Team
|
||||
* @brief Header for stm32_lpm.c module
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© 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 */
|
||||
|
||||
131
Utilities/lpm/tiny_lpm/stm32_lpm_if_template.c
Normal file
131
Utilities/lpm/tiny_lpm/stm32_lpm_if_template.c
Normal 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>© 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 */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
79
Utilities/lpm/tiny_lpm/stm32_lpm_if_template.h
Normal file
79
Utilities/lpm/tiny_lpm/stm32_lpm_if_template.h
Normal 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>© 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 */
|
||||
|
||||
6
Utilities/misc/LICENSE.txt
Normal file
6
Utilities/misc/LICENSE.txt
Normal 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
|
||||
61
Utilities/misc/stm32_mem.c
Normal file
61
Utilities/misc/stm32_mem.c
Normal 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;
|
||||
}
|
||||
}
|
||||
70
Utilities/misc/stm32_mem.h
Normal file
70
Utilities/misc/stm32_mem.h
Normal 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__ */
|
||||
496
Utilities/misc/stm32_systime.c
Normal file
496
Utilities/misc/stm32_systime.c
Normal 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
|
||||
}
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
252
Utilities/misc/stm32_systime.h
Normal file
252
Utilities/misc/stm32_systime.h
Normal 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__ */
|
||||
62
Utilities/misc/stm32_systime_if_template.c
Normal file
62
Utilities/misc/stm32_systime_if_template.c
Normal 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;
|
||||
}
|
||||
79
Utilities/misc/stm32_systime_if_template.h
Normal file
79
Utilities/misc/stm32_systime_if_template.h
Normal 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__ */
|
||||
992
Utilities/misc/stm32_tiny_sscanf.c
Normal file
992
Utilities/misc/stm32_tiny_sscanf.c
Normal 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);
|
||||
}
|
||||
65
Utilities/misc/stm32_tiny_sscanf.h
Normal file
65
Utilities/misc/stm32_tiny_sscanf.h
Normal 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__ */
|
||||
695
Utilities/misc/stm32_tiny_vsnprintf.c
Normal file
695
Utilities/misc/stm32_tiny_vsnprintf.c
Normal 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;
|
||||
}
|
||||
60
Utilities/misc/stm32_tiny_vsnprintf.h
Normal file
60
Utilities/misc/stm32_tiny_vsnprintf.h
Normal 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__ */
|
||||
6
Utilities/sequencer/LICENSE.txt
Normal file
6
Utilities/sequencer/LICENSE.txt
Normal 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
|
||||
550
Utilities/sequencer/stm32_seq.c
Normal file
550
Utilities/sequencer/stm32_seq.c
Normal file
@ -0,0 +1,550 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file stm32_seq.c
|
||||
* @author MCD Application Team
|
||||
* @brief Simple sequencer implementation
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© Copyright (c) 2019 STMicroelectronics.
|
||||
* All rights reserved.</center></h2>
|
||||
*
|
||||
* This software 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
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
360
Utilities/sequencer/stm32_seq.h
Normal file
360
Utilities/sequencer/stm32_seq.h
Normal file
@ -0,0 +1,360 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file stm32_seq.h
|
||||
* @author MCD Application Team
|
||||
* @brief sequencer interface
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© 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 */
|
||||
|
||||
6
Utilities/timer/LICENSE.txt
Normal file
6
Utilities/timer/LICENSE.txt
Normal 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
|
||||
542
Utilities/timer/stm32_timer.c
Normal file
542
Utilities/timer/stm32_timer.c
Normal 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>© 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 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
292
Utilities/timer/stm32_timer.h
Normal file
292
Utilities/timer/stm32_timer.h
Normal 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>© 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__*/
|
||||
|
||||
166
Utilities/timer/stm32_timer_if_template.c
Normal file
166
Utilities/timer/stm32_timer_if_template.c
Normal 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>© 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 );
|
||||
}
|
||||
|
||||
120
Utilities/timer/stm32_timer_if_template.h
Normal file
120
Utilities/timer/stm32_timer_if_template.h
Normal 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>© 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__ */
|
||||
|
||||
6
Utilities/trace/adv_trace/LICENSE.txt
Normal file
6
Utilities/trace/adv_trace/LICENSE.txt
Normal 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
|
||||
828
Utilities/trace/adv_trace/stm32_adv_trace.c
Normal file
828
Utilities/trace/adv_trace/stm32_adv_trace.c
Normal 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>© 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,×tamp_size);
|
||||
}
|
||||
|
||||
va_start( vaArgs, strFormat);
|
||||
buff_size =(uint16_t)UTIL_ADV_TRACE_VSNPRINTF((char *)sztmp,UTIL_ADV_TRACE_TMP_BUF_SIZE, strFormat, vaArgs);
|
||||
|
||||
TRACE_Lock();
|
||||
|
||||
/* if allocation is ok, write data into the buffer */
|
||||
if (TRACE_AllocateBufer((buff_size+timestamp_size),&writepos) != -1)
|
||||
{
|
||||
#if defined(UTIL_ADV_TRACE_OVERRUN)
|
||||
UTIL_ADV_TRACE_ENTER_CRITICAL_SECTION();
|
||||
if(ADV_TRACE_Ctx.OverRunStatus == TRACE_OVERRUN_EXECUTED)
|
||||
{
|
||||
/* clear the over run */
|
||||
ADV_TRACE_Ctx.OverRunStatus = TRACE_OVERRUN_NONE;
|
||||
}
|
||||
UTIL_ADV_TRACE_EXIT_CRITICAL_SECTION();
|
||||
#endif
|
||||
|
||||
/* copy the timestamp */
|
||||
for (idx = 0u; idx < timestamp_size; idx++)
|
||||
{
|
||||
ADV_TRACE_Buffer[writepos] = buf[idx];
|
||||
writepos = writepos + 1u;
|
||||
}
|
||||
|
||||
/* copy the data */
|
||||
(void)UTIL_ADV_TRACE_VSNPRINTF((char *)(&ADV_TRACE_Buffer[writepos]), UTIL_ADV_TRACE_TMP_BUF_SIZE, strFormat, vaArgs);
|
||||
va_end(vaArgs);
|
||||
|
||||
TRACE_UnLock();
|
||||
|
||||
return TRACE_Send();
|
||||
}
|
||||
|
||||
va_end(vaArgs);
|
||||
TRACE_UnLock();
|
||||
#if defined(UTIL_ADV_TRACE_OVERRUN)
|
||||
UTIL_ADV_TRACE_ENTER_CRITICAL_SECTION();
|
||||
if((ADV_TRACE_Ctx.OverRunStatus == TRACE_OVERRUN_NONE ) && (NULL != ADV_TRACE_Ctx.overrun_func))
|
||||
{
|
||||
UTIL_ADV_TRACE_DEBUG("UTIL_ADV_TRACE_Send:TRACE_OVERRUN_INDICATION");
|
||||
ADV_TRACE_Ctx.OverRunStatus = TRACE_OVERRUN_INDICATION;
|
||||
}
|
||||
UTIL_ADV_TRACE_EXIT_CRITICAL_SECTION();
|
||||
#endif
|
||||
|
||||
return UTIL_ADV_TRACE_MEM_FULL;
|
||||
|
||||
#else
|
||||
if((ADV_TRACE_Ctx.timestamp_func != NULL) && (TimeStampState != 0u))
|
||||
{
|
||||
ADV_TRACE_Ctx.timestamp_func(buf,&buff_size);
|
||||
}
|
||||
|
||||
va_start(vaArgs, strFormat);
|
||||
buff_size += (uint16_t) UTIL_ADV_TRACE_VSNPRINTF((char* )(buf + buff_size), UTIL_ADV_TRACE_TMP_BUF_SIZE, strFormat, vaArgs);
|
||||
va_end(vaArgs);
|
||||
|
||||
return UTIL_ADV_TRACE_Send(buf, buff_size);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
UTIL_ADV_TRACE_Status_t UTIL_ADV_TRACE_FSend(const char *strFormat, ...)
|
||||
{
|
||||
uint8_t buf[UTIL_ADV_TRACE_TMP_BUF_SIZE];
|
||||
va_list vaArgs;
|
||||
|
||||
va_start(vaArgs, strFormat);
|
||||
uint16_t bufSize = (uint16_t) UTIL_ADV_TRACE_VSNPRINTF((char* )buf, UTIL_ADV_TRACE_TMP_BUF_SIZE, strFormat, vaArgs);
|
||||
va_end(vaArgs);
|
||||
|
||||
return UTIL_ADV_TRACE_Send(buf, bufSize);
|
||||
}
|
||||
|
||||
#if defined(UTIL_ADV_TRACE_CONDITIONNAL)
|
||||
UTIL_ADV_TRACE_Status_t UTIL_ADV_TRACE_COND_ZCSend_Allocation(uint32_t VerboseLevel, uint32_t Region, uint32_t TimeStampState, uint16_t length, uint8_t **pData, uint16_t *FifoSize, uint16_t *WritePos)
|
||||
{
|
||||
UTIL_ADV_TRACE_Status_t ret = UTIL_ADV_TRACE_OK;
|
||||
uint16_t writepos;
|
||||
uint8_t timestamp_ptr[UTIL_ADV_TRACE_TMP_MAX_TIMESTMAP_SIZE];
|
||||
uint16_t timestamp_size = 0u;
|
||||
|
||||
/* check verbose level */
|
||||
if(!(ADV_TRACE_Ctx.CurrentVerboseLevel >= VerboseLevel))
|
||||
{
|
||||
return UTIL_ADV_TRACE_GIVEUP;
|
||||
}
|
||||
|
||||
if((Region & ADV_TRACE_Ctx.RegionMask) != Region)
|
||||
{
|
||||
return UTIL_ADV_TRACE_REGIONMASKED;
|
||||
}
|
||||
|
||||
if((ADV_TRACE_Ctx.timestamp_func != NULL) && (TimeStampState != 0u))
|
||||
{
|
||||
ADV_TRACE_Ctx.timestamp_func(timestamp_ptr, ×tamp_size);
|
||||
}
|
||||
|
||||
TRACE_Lock();
|
||||
|
||||
/* if allocation is ok, write data into the buffer */
|
||||
if (TRACE_AllocateBufer(length+timestamp_size, &writepos) != -1)
|
||||
{
|
||||
/* fill time stamp information */
|
||||
for (uint16_t index = 0u; index < timestamp_size; index++)
|
||||
{
|
||||
ADV_TRACE_Buffer[writepos] = timestamp_ptr[index];
|
||||
writepos = (uint16_t) ((writepos + 1u) % UTIL_ADV_TRACE_FIFO_SIZE);
|
||||
}
|
||||
|
||||
/*user fill */
|
||||
*pData = ADV_TRACE_Buffer;
|
||||
*FifoSize = (uint16_t) UTIL_ADV_TRACE_FIFO_SIZE;
|
||||
*WritePos = writepos;
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE_UnLock();
|
||||
ret = UTIL_ADV_TRACE_MEM_FULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
UTIL_ADV_TRACE_Status_t UTIL_ADV_TRACE_COND_ZCSend_Finalize(void)
|
||||
{
|
||||
return UTIL_ADV_TRACE_ZCSend_Finalize();
|
||||
}
|
||||
#endif
|
||||
|
||||
UTIL_ADV_TRACE_Status_t UTIL_ADV_TRACE_ZCSend_Allocation(uint16_t Length, uint8_t **pData, uint16_t *FifoSize, uint16_t *WritePos)
|
||||
{
|
||||
UTIL_ADV_TRACE_Status_t ret = UTIL_ADV_TRACE_OK;
|
||||
uint16_t writepos;
|
||||
|
||||
TRACE_Lock();
|
||||
|
||||
/* if allocation is ok, write data into the buffer */
|
||||
if (TRACE_AllocateBufer(Length,&writepos) != -1)
|
||||
{
|
||||
/*user fill */
|
||||
*pData = ADV_TRACE_Buffer;
|
||||
*FifoSize = UTIL_ADV_TRACE_FIFO_SIZE;
|
||||
*WritePos = (uint16_t)writepos;
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE_UnLock();
|
||||
ret = UTIL_ADV_TRACE_MEM_FULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
UTIL_ADV_TRACE_Status_t UTIL_ADV_TRACE_ZCSend_Finalize(void)
|
||||
{
|
||||
TRACE_UnLock();
|
||||
return TRACE_Send();
|
||||
}
|
||||
|
||||
#if defined(UTIL_ADV_TRACE_CONDITIONNAL)
|
||||
UTIL_ADV_TRACE_Status_t UTIL_ADV_TRACE_COND_Send(uint32_t VerboseLevel, uint32_t Region, uint32_t TimeStampState, const uint8_t *pData, uint16_t Length)
|
||||
{
|
||||
UTIL_ADV_TRACE_Status_t ret;
|
||||
uint16_t writepos;
|
||||
uint32_t idx;
|
||||
uint8_t timestamp_ptr[UTIL_ADV_TRACE_TMP_MAX_TIMESTMAP_SIZE];
|
||||
uint16_t timestamp_size = 0u;
|
||||
|
||||
/* check verbose level */
|
||||
if(!(ADV_TRACE_Ctx.CurrentVerboseLevel >= VerboseLevel))
|
||||
{
|
||||
return UTIL_ADV_TRACE_GIVEUP;
|
||||
}
|
||||
|
||||
if((Region & ADV_TRACE_Ctx.RegionMask) != Region)
|
||||
{
|
||||
return UTIL_ADV_TRACE_REGIONMASKED;
|
||||
}
|
||||
|
||||
if((ADV_TRACE_Ctx.timestamp_func != NULL) && (TimeStampState != 0u))
|
||||
{
|
||||
ADV_TRACE_Ctx.timestamp_func(timestamp_ptr, ×tamp_size);
|
||||
}
|
||||
|
||||
TRACE_Lock();
|
||||
|
||||
/* if allocation is ok, write data into the buffer */
|
||||
if (TRACE_AllocateBufer(Length + timestamp_size, &writepos) != -1)
|
||||
{
|
||||
/* fill time stamp information */
|
||||
for (idx = 0; idx < timestamp_size; idx++)
|
||||
{
|
||||
ADV_TRACE_Buffer[writepos] = timestamp_ptr[idx];
|
||||
writepos = (uint16_t) ((writepos + 1u) % UTIL_ADV_TRACE_FIFO_SIZE);
|
||||
}
|
||||
|
||||
for (idx = 0u; idx < Length; idx++)
|
||||
{
|
||||
ADV_TRACE_Buffer[writepos] = pData[idx];
|
||||
writepos = (uint16_t) ((writepos + 1u) % UTIL_ADV_TRACE_FIFO_SIZE);
|
||||
}
|
||||
|
||||
TRACE_UnLock();
|
||||
ret = TRACE_Send();
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE_UnLock();
|
||||
ret = UTIL_ADV_TRACE_MEM_FULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
UTIL_ADV_TRACE_Status_t UTIL_ADV_TRACE_Send(const uint8_t *pData, uint16_t Length)
|
||||
{
|
||||
UTIL_ADV_TRACE_Status_t ret;
|
||||
uint16_t writepos;
|
||||
uint32_t idx;
|
||||
|
||||
TRACE_Lock();
|
||||
|
||||
/* if allocation is ok, write data into the buffer */
|
||||
if (TRACE_AllocateBufer(Length,&writepos) != -1)
|
||||
{
|
||||
/* initialize the Ptr for Read/Write */
|
||||
for (idx = 0u; idx < Length; idx++)
|
||||
{
|
||||
ADV_TRACE_Buffer[writepos] = pData[idx];
|
||||
writepos = (uint16_t) ((writepos + 1u) % UTIL_ADV_TRACE_FIFO_SIZE);
|
||||
}
|
||||
TRACE_UnLock();
|
||||
|
||||
ret = TRACE_Send();
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE_UnLock();
|
||||
ret = UTIL_ADV_TRACE_MEM_FULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if defined(UTIL_ADV_TRACE_OVERRUN)
|
||||
void UTIL_ADV_TRACE_RegisterOverRunFunction(cb_overrun *cb)
|
||||
{
|
||||
ADV_TRACE_Ctx.overrun_func = *cb;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(UTIL_ADV_TRACE_CONDITIONNAL)
|
||||
void UTIL_ADV_TRACE_RegisterTimeStampFunction(cb_timestamp *cb)
|
||||
{
|
||||
ADV_TRACE_Ctx.timestamp_func = *cb;
|
||||
}
|
||||
|
||||
void UTIL_ADV_TRACE_SetVerboseLevel(uint8_t Level)
|
||||
{
|
||||
ADV_TRACE_Ctx.CurrentVerboseLevel = Level;
|
||||
}
|
||||
|
||||
uint8_t UTIL_ADV_TRACE_GetVerboseLevel(void)
|
||||
{
|
||||
return ADV_TRACE_Ctx.CurrentVerboseLevel;
|
||||
}
|
||||
|
||||
void UTIL_ADV_TRACE_SetRegion(uint32_t Region)
|
||||
{
|
||||
ADV_TRACE_Ctx.RegionMask |= Region;
|
||||
}
|
||||
|
||||
uint32_t UTIL_ADV_TRACE_GetRegion(void)
|
||||
{
|
||||
return ADV_TRACE_Ctx.RegionMask;
|
||||
}
|
||||
|
||||
void UTIL_ADV_TRACE_ResetRegion(uint32_t Region)
|
||||
{
|
||||
ADV_TRACE_Ctx.RegionMask &= ~Region;
|
||||
}
|
||||
#endif
|
||||
|
||||
__WEAK void UTIL_ADV_TRACE_PreSendHook(void)
|
||||
{
|
||||
}
|
||||
|
||||
__WEAK void UTIL_ADV_TRACE_PostSendHook(void)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup ADV_TRACE_private_function
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief send the data of the trace to low layer
|
||||
* @retval Status based on @ref UTIL_ADV_TRACE_Status_t
|
||||
*/
|
||||
static UTIL_ADV_TRACE_Status_t TRACE_Send(void)
|
||||
{
|
||||
UTIL_ADV_TRACE_Status_t ret = UTIL_ADV_TRACE_OK;
|
||||
uint8_t *ptr = NULL;
|
||||
|
||||
UTIL_ADV_TRACE_ENTER_CRITICAL_SECTION();
|
||||
|
||||
if(TRACE_IsLocked() == 0u)
|
||||
{
|
||||
TRACE_Lock();
|
||||
|
||||
if(ADV_TRACE_Ctx.TraceRdPtr != ADV_TRACE_Ctx.TraceWrPtr)
|
||||
{
|
||||
#ifdef UTIL_ADV_TRACE_UNCHUNK_MODE
|
||||
if(TRACE_UNCHUNK_DETECTED == ADV_TRACE_Ctx.unchunk_status)
|
||||
{
|
||||
ADV_TRACE_Ctx.TraceSentSize = (uint16_t) (ADV_TRACE_Ctx.unchunk_enabled - ADV_TRACE_Ctx.TraceRdPtr);
|
||||
ADV_TRACE_Ctx.unchunk_status = TRACE_UNCHUNK_TRANSFER;
|
||||
ADV_TRACE_Ctx.unchunk_enabled = 0;
|
||||
|
||||
UTIL_ADV_TRACE_DEBUG("\nTRACE_TxCpltCallback::unchunk start(%d,%d)\n", ADV_TRACE_Ctx.unchunk_enabled, ADV_TRACE_Ctx.TraceRdPtr);
|
||||
|
||||
if(0u == ADV_TRACE_Ctx.TraceSentSize)
|
||||
{
|
||||
ADV_TRACE_Ctx.unchunk_status = TRACE_UNCHUNK_NONE;
|
||||
ADV_TRACE_Ctx.TraceRdPtr = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(TRACE_UNCHUNK_NONE == ADV_TRACE_Ctx.unchunk_status)
|
||||
{
|
||||
#endif
|
||||
if(ADV_TRACE_Ctx.TraceWrPtr > ADV_TRACE_Ctx.TraceRdPtr)
|
||||
{
|
||||
ADV_TRACE_Ctx.TraceSentSize = ADV_TRACE_Ctx.TraceWrPtr - ADV_TRACE_Ctx.TraceRdPtr;
|
||||
}
|
||||
else /* TraceRdPtr > TraceWrPtr */
|
||||
{
|
||||
ADV_TRACE_Ctx.TraceSentSize = UTIL_ADV_TRACE_FIFO_SIZE - ADV_TRACE_Ctx.TraceRdPtr;
|
||||
|
||||
}
|
||||
#ifdef UTIL_ADV_TRACE_UNCHUNK_MODE
|
||||
}
|
||||
#endif
|
||||
ptr = &ADV_TRACE_Buffer[ADV_TRACE_Ctx.TraceRdPtr];
|
||||
|
||||
UTIL_ADV_TRACE_EXIT_CRITICAL_SECTION();
|
||||
UTIL_ADV_TRACE_PreSendHook();
|
||||
|
||||
UTIL_ADV_TRACE_DEBUG("\n--TRACE_Send(%d-%d)--\n", ADV_TRACE_Ctx.TraceRdPtr, ADV_TRACE_Ctx.TraceSentSize);
|
||||
ret = UTIL_TraceDriver.Send(ptr, ADV_TRACE_Ctx.TraceSentSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE_UnLock();
|
||||
UTIL_ADV_TRACE_EXIT_CRITICAL_SECTION();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UTIL_ADV_TRACE_EXIT_CRITICAL_SECTION();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tx callback called by the low layer level to inform a transfer complete
|
||||
* @param Ptr pointer not used only for HAL compatibility
|
||||
* @retval none
|
||||
*/
|
||||
static void TRACE_TxCpltCallback(void *Ptr)
|
||||
{
|
||||
uint8_t *ptr = NULL;
|
||||
UTIL_ADV_TRACE_ENTER_CRITICAL_SECTION();
|
||||
|
||||
#if defined(UTIL_ADV_TRACE_OVERRUN)
|
||||
if(ADV_TRACE_Ctx.OverRunStatus == TRACE_OVERRUN_TRANSFERT)
|
||||
{
|
||||
ADV_TRACE_Ctx.OverRunStatus = TRACE_OVERRUN_EXECUTED;
|
||||
UTIL_ADV_TRACE_DEBUG("\n--TRACE_Send overrun complete--\n");
|
||||
ADV_TRACE_Ctx.TraceSentSize = 0u;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(UTIL_ADV_TRACE_UNCHUNK_MODE)
|
||||
if(TRACE_UNCHUNK_TRANSFER == ADV_TRACE_Ctx.unchunk_status)
|
||||
{
|
||||
ADV_TRACE_Ctx.unchunk_status = TRACE_UNCHUNK_NONE;
|
||||
ADV_TRACE_Ctx.TraceRdPtr = 0;
|
||||
UTIL_ADV_TRACE_DEBUG("\nTRACE_TxCpltCallback::unchunk complete\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
ADV_TRACE_Ctx.TraceRdPtr = (ADV_TRACE_Ctx.TraceRdPtr + ADV_TRACE_Ctx.TraceSentSize) % UTIL_ADV_TRACE_FIFO_SIZE;
|
||||
}
|
||||
#else
|
||||
ADV_TRACE_Ctx.TraceRdPtr = (ADV_TRACE_Ctx.TraceRdPtr + ADV_TRACE_Ctx.TraceSentSize) % UTIL_ADV_TRACE_FIFO_SIZE;
|
||||
#endif
|
||||
|
||||
#if defined(UTIL_ADV_TRACE_OVERRUN)
|
||||
if(ADV_TRACE_Ctx.OverRunStatus == TRACE_OVERRUN_INDICATION)
|
||||
{
|
||||
uint8_t *ptr = NULL;
|
||||
ADV_TRACE_Ctx.OverRunStatus = TRACE_OVERRUN_TRANSFERT;
|
||||
UTIL_ADV_TRACE_EXIT_CRITICAL_SECTION();
|
||||
ADV_TRACE_Ctx.overrun_func(&ptr, &ADV_TRACE_Ctx.TraceSentSize);
|
||||
UTIL_ADV_TRACE_DEBUG("\n--Driver_Send overrun(%d)--\n", ADV_TRACE_Ctx.TraceSentSize);
|
||||
UTIL_TraceDriver.Send(ptr, ADV_TRACE_Ctx.TraceSentSize);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if((ADV_TRACE_Ctx.TraceRdPtr != ADV_TRACE_Ctx.TraceWrPtr) && (1u == ADV_TRACE_Ctx.TraceLock))
|
||||
{
|
||||
#ifdef UTIL_ADV_TRACE_UNCHUNK_MODE
|
||||
if(TRACE_UNCHUNK_DETECTED == ADV_TRACE_Ctx.unchunk_status)
|
||||
{
|
||||
ADV_TRACE_Ctx.TraceSentSize = ADV_TRACE_Ctx.unchunk_enabled - ADV_TRACE_Ctx.TraceRdPtr;
|
||||
ADV_TRACE_Ctx.unchunk_status = TRACE_UNCHUNK_TRANSFER;
|
||||
ADV_TRACE_Ctx.unchunk_enabled = 0;
|
||||
|
||||
UTIL_ADV_TRACE_DEBUG("\nTRACE_TxCpltCallback::unchunk start(%d,%d)\n", ADV_TRACE_Ctx.unchunk_enabled, ADV_TRACE_Ctx.TraceRdPtr);
|
||||
|
||||
if(0u == ADV_TRACE_Ctx.TraceSentSize)
|
||||
{
|
||||
/* this case occurs when an ongoing write aligned the Rd position with chunk position */
|
||||
/* in that case the unchunk is forgot */
|
||||
ADV_TRACE_Ctx.unchunk_status = TRACE_UNCHUNK_NONE;
|
||||
ADV_TRACE_Ctx.TraceRdPtr = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(TRACE_UNCHUNK_NONE == ADV_TRACE_Ctx.unchunk_status)
|
||||
{
|
||||
#endif
|
||||
if(ADV_TRACE_Ctx.TraceWrPtr > ADV_TRACE_Ctx.TraceRdPtr)
|
||||
{
|
||||
ADV_TRACE_Ctx.TraceSentSize = ADV_TRACE_Ctx.TraceWrPtr - ADV_TRACE_Ctx.TraceRdPtr;
|
||||
}
|
||||
else /* TraceRdPtr > TraceWrPtr */
|
||||
{
|
||||
ADV_TRACE_Ctx.TraceSentSize = UTIL_ADV_TRACE_FIFO_SIZE - ADV_TRACE_Ctx.TraceRdPtr;
|
||||
}
|
||||
#ifdef UTIL_ADV_TRACE_UNCHUNK_MODE
|
||||
}
|
||||
#endif
|
||||
ptr = &ADV_TRACE_Buffer[ADV_TRACE_Ctx.TraceRdPtr];
|
||||
UTIL_ADV_TRACE_EXIT_CRITICAL_SECTION();
|
||||
UTIL_ADV_TRACE_DEBUG("\n--TRACE_Send(%d-%d)--\n", ADV_TRACE_Ctx.TraceRdPtr, ADV_TRACE_Ctx.TraceSentSize);
|
||||
UTIL_TraceDriver.Send(ptr, ADV_TRACE_Ctx.TraceSentSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
UTIL_ADV_TRACE_EXIT_CRITICAL_SECTION();
|
||||
UTIL_ADV_TRACE_PostSendHook();
|
||||
TRACE_UnLock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief allocate space inside the buffer to push data
|
||||
* @param Size to allocate within fifo
|
||||
* @param Pos position within the fifo
|
||||
* @retval write position inside the buffer is -1 no space available.
|
||||
*/
|
||||
static int16_t TRACE_AllocateBufer(uint16_t Size, uint16_t *Pos)
|
||||
{
|
||||
uint16_t freesize;
|
||||
int16_t ret = -1;
|
||||
|
||||
UTIL_ADV_TRACE_ENTER_CRITICAL_SECTION();
|
||||
|
||||
if(ADV_TRACE_Ctx.TraceWrPtr == ADV_TRACE_Ctx.TraceRdPtr)
|
||||
{
|
||||
#ifdef UTIL_ADV_TRACE_UNCHUNK_MODE
|
||||
freesize = (uint16_t)(UTIL_ADV_TRACE_FIFO_SIZE - ADV_TRACE_Ctx.TraceWrPtr);
|
||||
if((Size >= freesize) && (ADV_TRACE_Ctx.TraceRdPtr > Size))
|
||||
{
|
||||
ADV_TRACE_Ctx.unchunk_status = TRACE_UNCHUNK_DETECTED;
|
||||
ADV_TRACE_Ctx.unchunk_enabled = ADV_TRACE_Ctx.TraceWrPtr;
|
||||
freesize = ADV_TRACE_Ctx.TraceRdPtr;
|
||||
ADV_TRACE_Ctx.TraceWrPtr = 0;
|
||||
}
|
||||
#else
|
||||
/* need to add buffer full management*/
|
||||
freesize = (int16_t)UTIL_ADV_TRACE_FIFO_SIZE;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef UTIL_ADV_TRACE_UNCHUNK_MODE
|
||||
if (ADV_TRACE_Ctx.TraceWrPtr > ADV_TRACE_Ctx.TraceRdPtr)
|
||||
{
|
||||
freesize = (uint16_t)(UTIL_ADV_TRACE_FIFO_SIZE - ADV_TRACE_Ctx.TraceWrPtr);
|
||||
if((Size >= freesize) && (ADV_TRACE_Ctx.TraceRdPtr > Size))
|
||||
{
|
||||
ADV_TRACE_Ctx.unchunk_status = TRACE_UNCHUNK_DETECTED;
|
||||
ADV_TRACE_Ctx.unchunk_enabled = ADV_TRACE_Ctx.TraceWrPtr;
|
||||
freesize = ADV_TRACE_Ctx.TraceRdPtr;
|
||||
ADV_TRACE_Ctx.TraceWrPtr = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
freesize = (uint16_t)(ADV_TRACE_Ctx.TraceRdPtr - ADV_TRACE_Ctx.TraceWrPtr);
|
||||
}
|
||||
#else
|
||||
if (ADV_TRACE_Ctx.TraceWrPtr > ADV_TRACE_Ctx.TraceRdPtr)
|
||||
{
|
||||
freesize = UTIL_ADV_TRACE_FIFO_SIZE - ADV_TRACE_Ctx.TraceWrPtr + ADV_TRACE_Ctx.TraceRdPtr;
|
||||
}
|
||||
else
|
||||
{
|
||||
freesize = ADV_TRACE_Ctx.TraceRdPtr - ADV_TRACE_Ctx.TraceWrPtr;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if(freesize > Size)
|
||||
{
|
||||
*Pos = ADV_TRACE_Ctx.TraceWrPtr;
|
||||
ADV_TRACE_Ctx.TraceWrPtr = (ADV_TRACE_Ctx.TraceWrPtr + Size) % UTIL_ADV_TRACE_FIFO_SIZE;
|
||||
ret = 0;
|
||||
#if defined(UTIL_ADV_TRACE_OVERRUN)
|
||||
if(ADV_TRACE_Ctx.OverRunStatus == TRACE_OVERRUN_EXECUTED)
|
||||
{
|
||||
/* clear the over run */
|
||||
ADV_TRACE_Ctx.OverRunStatus = TRACE_OVERRUN_NONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef UTIL_ADV_TRACE_UNCHUNK_MODE
|
||||
UTIL_ADV_TRACE_DEBUG("\n--TRACE_AllocateBufer(%d-%d-%d::%d-%d)--\n", freesize - Size, Size, ADV_TRACE_Ctx.unchunk_enabled, ADV_TRACE_Ctx.TraceRdPtr, ADV_TRACE_Ctx.TraceWrPtr);
|
||||
#else
|
||||
UTIL_ADV_TRACE_DEBUG("\n--TRACE_AllocateBufer(%d-%d::%d-%d)--\n",freesize - Size, Size, ADV_TRACE_Ctx.TraceRdPtr, ADV_TRACE_Ctx.TraceWrPtr);
|
||||
#endif
|
||||
}
|
||||
#if defined(UTIL_ADV_TRACE_OVERRUN)
|
||||
else
|
||||
{
|
||||
if((ADV_TRACE_Ctx.OverRunStatus == TRACE_OVERRUN_NONE) && (NULL != ADV_TRACE_Ctx.overrun_func))
|
||||
{
|
||||
UTIL_ADV_TRACE_DEBUG(":TRACE_OVERRUN_INDICATION");
|
||||
ADV_TRACE_Ctx.OverRunStatus = TRACE_OVERRUN_INDICATION;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
UTIL_ADV_TRACE_EXIT_CRITICAL_SECTION();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Lock the trace buffer.
|
||||
* @retval None.
|
||||
*/
|
||||
static void TRACE_Lock(void)
|
||||
{
|
||||
UTIL_ADV_TRACE_ENTER_CRITICAL_SECTION();
|
||||
ADV_TRACE_Ctx.TraceLock++;
|
||||
UTIL_ADV_TRACE_EXIT_CRITICAL_SECTION();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief UnLock the trace buffer.
|
||||
* @retval None.
|
||||
*/
|
||||
static void TRACE_UnLock(void)
|
||||
{
|
||||
UTIL_ADV_TRACE_ENTER_CRITICAL_SECTION();
|
||||
ADV_TRACE_Ctx.TraceLock--;
|
||||
UTIL_ADV_TRACE_EXIT_CRITICAL_SECTION();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief UnLock the trace buffer.
|
||||
* @retval None.
|
||||
*/
|
||||
static uint32_t TRACE_IsLocked(void)
|
||||
{
|
||||
return (ADV_TRACE_Ctx.TraceLock == 0u? 0u: 1u);
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
273
Utilities/trace/adv_trace/stm32_adv_trace.h
Normal file
273
Utilities/trace/adv_trace/stm32_adv_trace.h
Normal file
@ -0,0 +1,273 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file stm32_adv_trace.h
|
||||
* @author MCD Application Team
|
||||
* @brief Header for stm32_adv_trace.c
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© 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 */
|
||||
90
Utilities/trace/adv_trace/stm32_adv_trace_if_template.c
Normal file
90
Utilities/trace/adv_trace/stm32_adv_trace_if_template.c
Normal 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>© 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 */
|
||||
|
||||
74
Utilities/trace/adv_trace/stm32_adv_trace_if_template.h
Normal file
74
Utilities/trace/adv_trace/stm32_adv_trace_if_template.h
Normal file
@ -0,0 +1,74 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file : stm32_adv_trace_if_template.h
|
||||
* @brief : Header file for stm32_adv_trace interface file
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© 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__*/
|
||||
Reference in New Issue
Block a user