fix all board compile for v3.0
fix all board compile for v3.0
This commit is contained in:
@@ -0,0 +1,180 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @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 component is licensed by ST under BSD 3-Clause license,
|
||||
* the "License"; You may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at:
|
||||
* opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "stm32_lpm.h"
|
||||
#include "utilities_conf.h"
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
/* Private macros ------------------------------------------------------------*/
|
||||
#define UTIL_LPM_NO_BIT_SET (0)
|
||||
|
||||
#ifndef UTIL_LPM_INIT_CRITICAL_SECTION
|
||||
#define UTIL_LPM_INIT_CRITICAL_SECTION( )
|
||||
#endif
|
||||
|
||||
#ifndef UTIL_LPM_ENTER_CRITICAL_SECTION
|
||||
#define UTIL_LPM_ENTER_CRITICAL_SECTION( ) UTILS_ENTER_CRITICAL_SECTION( )
|
||||
#endif
|
||||
|
||||
#ifndef UTIL_LPM_EXIT_CRITICAL_SECTION
|
||||
#define UTIL_LPM_EXIT_CRITICAL_SECTION( ) UTILS_EXIT_CRITICAL_SECTION( )
|
||||
#endif
|
||||
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
/* Private defines -----------------------------------------------------------*/
|
||||
/* Private macros ------------------------------------------------------------*/
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
static UTIL_LPM_bm_t StopModeDisable = UTIL_LPM_NO_BIT_SET;
|
||||
static UTIL_LPM_bm_t OffModeDisable = UTIL_LPM_NO_BIT_SET;
|
||||
|
||||
/* Global variables ----------------------------------------------------------*/
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
/* Functions Definition ------------------------------------------------------*/
|
||||
|
||||
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( );
|
||||
|
||||
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( );
|
||||
}
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
@@ -0,0 +1,126 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @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 component is licensed by ST under BSD 3-Clause license,
|
||||
* the "License"; You may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at:
|
||||
* opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __STM32_LPM_H
|
||||
#define __STM32_LPM_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "stdint.h"
|
||||
|
||||
typedef uint32_t UTIL_LPM_bm_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
UTIL_LPM_ENABLE=0,
|
||||
UTIL_LPM_DISABLE,
|
||||
} UTIL_LPM_State_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
UTIL_LPM_SLEEPMODE,
|
||||
UTIL_LPM_STOPMODE,
|
||||
UTIL_LPM_OFFMODE,
|
||||
} UTIL_LPM_Mode_t;
|
||||
|
||||
/*!
|
||||
* \brief LPM driver definition
|
||||
*/
|
||||
struct UTIL_LPM_Driver_s
|
||||
{
|
||||
void (* EnterSleepMode) ( void );
|
||||
void (* ExitSleepMode) ( void );
|
||||
void (* EnterStopMode) ( void );
|
||||
void (* ExitStopMode) ( void );
|
||||
void (* EnterOffMode) ( void );
|
||||
void (* ExitOffMode) ( void );
|
||||
};
|
||||
|
||||
/*!
|
||||
*
|
||||
* \Remark : This structure is defined and initialized in the specific platform
|
||||
* power implementation
|
||||
*/
|
||||
extern const struct UTIL_LPM_Driver_s UTIL_PowerDriver;
|
||||
|
||||
/* Exported constants --------------------------------------------------------*/
|
||||
/* External variables --------------------------------------------------------*/
|
||||
/* Exported macros -----------------------------------------------------------*/
|
||||
/* Exported functions ------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* @brief This API Initializes the LPM resources.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void UTIL_LPM_Init( void );
|
||||
|
||||
/**
|
||||
* @brief This API Un-Initializes the LPM resources.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
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.
|
||||
* @param None
|
||||
* @retval 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
|
||||
* @retval None
|
||||
*/
|
||||
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
|
||||
* @retval None
|
||||
*/
|
||||
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
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void UTIL_LPM_EnterLowPower( void );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*__STM32_LPM_H */
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file stm32_mem.c
|
||||
* @author MCD Application Team
|
||||
* @brief standard memory operation
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© Copyright (c) 2019 STMicroelectronics.
|
||||
* All rights reserved.</center></h2>
|
||||
*
|
||||
* This software component is licensed by ST under BSD 3-Clause license,
|
||||
* the "License"; You may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at:
|
||||
* opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "stdint.h"
|
||||
#include "stm32_mem.h"
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
/* Private defines -----------------------------------------------------------*/
|
||||
/* Private macros ------------------------------------------------------------*/
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
/* Global variables ----------------------------------------------------------*/
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
/* Functions Definition ------------------------------------------------------*/
|
||||
|
||||
void UTIL_MEM_cpy_8( void *dst, const void *src, uint16_t size )
|
||||
{
|
||||
uint8_t* dst8= (uint8_t *) dst;
|
||||
uint8_t* src8= (uint8_t *) src;
|
||||
|
||||
while( size-- )
|
||||
{
|
||||
*dst8++ = *src8++;
|
||||
}
|
||||
}
|
||||
|
||||
void UTIL_MEM_cpyr_8( void *dst, const void *src, uint16_t size )
|
||||
{
|
||||
uint8_t* dst8= (uint8_t *) dst;
|
||||
uint8_t* src8= (uint8_t *) src;
|
||||
|
||||
dst8 = dst8 + ( size - 1 );
|
||||
while( size-- )
|
||||
{
|
||||
*dst8-- = *src8++;
|
||||
}
|
||||
}
|
||||
|
||||
void UTIL_MEM_set_8( void *dst, uint8_t value, uint16_t size )
|
||||
{
|
||||
uint8_t* dst8= (uint8_t *) dst;
|
||||
while( size-- )
|
||||
{
|
||||
*dst8++ = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file stm32_mem.h
|
||||
* @author MCD Application Team
|
||||
* @brief standard memory operation
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© Copyright (c) 2019 STMicroelectronics.
|
||||
* All rights reserved.</center></h2>
|
||||
*
|
||||
* This software component is licensed by ST under BSD 3-Clause license,
|
||||
* the "License"; You may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at:
|
||||
* opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* 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 copies one value into buffer
|
||||
* @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__
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
|
||||
|
@@ -0,0 +1,351 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file stm32_systime.c
|
||||
* @author MCD Application Team
|
||||
* @brief System time functions implementation
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© Copyright (c) 2019 STMicroelectronics.
|
||||
* All rights reserved.</center></h2>
|
||||
*
|
||||
* This software component is licensed by ST under BSD 3-Clause license,
|
||||
* the "License"; You may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at:
|
||||
* opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include <stdio.h>
|
||||
#include "stm32_systime.h"
|
||||
#include "rtc_if.h"
|
||||
|
||||
#define END_OF_FEBRUARY_LEAP 60 //31+29
|
||||
#define END_OF_JULY_LEAP 213 //31+29+...
|
||||
|
||||
#define END_OF_FEBRUARY_NORM 59 //31+28
|
||||
#define END_OF_JULY_NORM 212 //31+28+...
|
||||
|
||||
#define UNIX_YEAR 68 //1968 is leap year
|
||||
|
||||
//UNIX time 0 = start at 01:00:00, 01/01/1970
|
||||
#define UNIX_HOUR_OFFSET ( ( TM_DAYS_IN_LEAP_YEAR + TM_DAYS_IN_YEAR ) * TM_SECONDS_IN_1DAY )
|
||||
|
||||
/*!
|
||||
* \brief Correction factors
|
||||
*/
|
||||
#define DAYS_IN_MONTH_CORRECTION_NORM ( (uint32_t )0x99AAA0 )
|
||||
#define DAYS_IN_MONTH_CORRECTION_LEAP ( (uint32_t )0x445550 )
|
||||
|
||||
|
||||
/* 365.25 = (366 + 365 + 365 + 365)/4 */
|
||||
#define DIV_365_25( X ) ( ( ( X ) * 91867 + 22750 ) >> 25 )
|
||||
|
||||
#define DIV_APPROX_86400( X ) ( ( ( X ) >> 18 ) + ( ( X ) >> 17 ) )
|
||||
|
||||
#define DIV_APPROX_1000( X ) ( ( ( X ) >> 10 ) +( ( X ) >> 16 ) + ( ( X ) >> 17 ) )
|
||||
|
||||
#define DIV_APPROX_60( X ) ( ( ( X ) * 17476 ) >> 20 )
|
||||
|
||||
#define DIV_APPROX_61( X ) ( ( ( X ) * 68759 ) >> 22 )
|
||||
|
||||
#define MODULO_7( X ) ( ( X ) -( ( ( ( ( X ) + 1 ) * 299593 ) >> 21 ) * 7 ) )
|
||||
|
||||
/*!
|
||||
* \brief Calculates ceiling( X / N )
|
||||
*/
|
||||
#define DIVC( X, N ) ( ( ( X ) + ( N ) -1 ) / ( N ) )
|
||||
|
||||
#define DIVC_BY_4( X ) ( ( ( X ) + 3 ) >>2 )
|
||||
|
||||
#define DIVC_BY_2( X ) ( ( ( X ) + 1 ) >> 1 )
|
||||
|
||||
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 );
|
||||
|
||||
const char *WeekDayString[]={ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
|
||||
|
||||
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 = HW_RTC_GetCalendarTime( ( uint16_t* )&calendarTime.SubSeconds );
|
||||
|
||||
// sysTime is epoch
|
||||
DeltaTime = SysTimeSub( sysTime, calendarTime );
|
||||
|
||||
HW_RTC_BKUPWrite( DeltaTime.Seconds, ( 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 = HW_RTC_GetCalendarTime( ( uint16_t* )&calendarTime.SubSeconds );
|
||||
|
||||
HW_RTC_BKUPRead( &DeltaTime.Seconds, ( uint32_t* )&DeltaTime.SubSeconds );
|
||||
|
||||
sysTime = SysTimeAdd( DeltaTime, calendarTime );
|
||||
|
||||
return sysTime;
|
||||
}
|
||||
|
||||
|
||||
SysTime_t SysTimeGetMcuTime( void )
|
||||
{
|
||||
SysTime_t calendarTime = { .Seconds = 0, .SubSeconds = 0 };
|
||||
|
||||
calendarTime.Seconds = HW_RTC_GetCalendarTime( ( uint16_t* )&calendarTime.SubSeconds );
|
||||
|
||||
return calendarTime;
|
||||
}
|
||||
|
||||
uint32_t SysTimeToMs( SysTime_t sysTime )
|
||||
{
|
||||
SysTime_t DeltaTime;
|
||||
HW_RTC_BKUPRead( &DeltaTime.Seconds, ( uint32_t* )&DeltaTime.SubSeconds );
|
||||
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 };
|
||||
HW_RTC_BKUPRead( &DeltaTime.Seconds, ( uint32_t* )&DeltaTime.SubSeconds );
|
||||
|
||||
return SysTimeAdd( sysTime, DeltaTime );
|
||||
}
|
||||
|
||||
uint32_t SysTimeMkTime( const struct tm* localtime )
|
||||
{
|
||||
uint32_t nbdays;
|
||||
uint32_t nbsecs;
|
||||
uint32_t year = localtime->tm_year - UNIX_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 - UNIX_HOUR_OFFSET;
|
||||
}
|
||||
|
||||
|
||||
|
||||
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 + UNIX_HOUR_OFFSET, &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 += UNIX_YEAR;
|
||||
|
||||
localtime->tm_isdst = -1;
|
||||
}
|
||||
|
||||
static uint32_t CalendarGetMonth( uint32_t days, uint32_t year )
|
||||
{
|
||||
uint32_t month;
|
||||
if( ( year % 4 ) == 0 )
|
||||
{ /*leap year*/
|
||||
if( days < END_OF_FEBRUARY_LEAP )
|
||||
{ // January or February
|
||||
// month = days * 2 / ( 30 + 31 );
|
||||
month = CalendarDiv61( days * 2 );
|
||||
}
|
||||
else if( days < END_OF_JULY_LEAP )
|
||||
{
|
||||
month = CalendarDiv61( ( days - END_OF_FEBRUARY_LEAP ) * 2 ) + 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
month = CalendarDiv61( ( days - END_OF_JULY_LEAP ) * 2 ) + 7;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( days < END_OF_FEBRUARY_NORM )
|
||||
{ // January or February
|
||||
month = CalendarDiv61( days * 2 );
|
||||
}
|
||||
else if( days < END_OF_JULY_NORM )
|
||||
{
|
||||
month = CalendarDiv61( ( days - END_OF_FEBRUARY_NORM ) * 2 ) + 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
month = CalendarDiv61( ( days - END_OF_JULY_NORM ) * 2 ) + 7;
|
||||
}
|
||||
}
|
||||
return month;
|
||||
}
|
||||
|
||||
static void CalendarDiv86400( uint32_t in, uint32_t* out, uint32_t* remainder )
|
||||
{
|
||||
#if 0
|
||||
*remainder = in % SECONDS_IN_1DAY;
|
||||
*out = in / SECONDS_IN_1DAY;
|
||||
#else
|
||||
uint32_t outTemp = 0;
|
||||
uint32_t divResult = DIV_APPROX_86400( in );
|
||||
|
||||
while( divResult >=1 )
|
||||
{
|
||||
outTemp += divResult;
|
||||
in -= divResult * 86400;
|
||||
divResult= DIV_APPROX_86400( in );
|
||||
}
|
||||
if( in >= 86400 )
|
||||
{
|
||||
outTemp += 1;
|
||||
in -= 86400;
|
||||
}
|
||||
|
||||
*remainder = in;
|
||||
*out = outTemp;
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint32_t CalendarDiv61( uint32_t in )
|
||||
{
|
||||
#if 0
|
||||
return( in / 61 );
|
||||
#else
|
||||
uint32_t outTemp = 0;
|
||||
uint32_t divResult = DIV_APPROX_61( in );
|
||||
while( divResult >=1 )
|
||||
{
|
||||
outTemp += divResult;
|
||||
in -= divResult * 61;
|
||||
divResult = DIV_APPROX_61( in );
|
||||
}
|
||||
if( in >= 61 )
|
||||
{
|
||||
outTemp += 1;
|
||||
in -= 61;
|
||||
}
|
||||
return outTemp;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void CalendarDiv60( uint32_t in, uint32_t* out, uint32_t* remainder )
|
||||
{
|
||||
#if 0
|
||||
*remainder = in % 60;
|
||||
*out = in / 60;
|
||||
#else
|
||||
uint32_t outTemp = 0;
|
||||
uint32_t divResult = DIV_APPROX_60( in );
|
||||
|
||||
while( divResult >=1 )
|
||||
{
|
||||
outTemp += divResult;
|
||||
in -= divResult * 60;
|
||||
divResult = DIV_APPROX_60( in );
|
||||
}
|
||||
if( in >= 60 )
|
||||
{
|
||||
outTemp += 1;
|
||||
in -= 60;
|
||||
}
|
||||
*remainder = in;
|
||||
*out = outTemp;
|
||||
#endif
|
||||
}
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
|
@@ -0,0 +1,175 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file stm32_systime.h
|
||||
* @author MCD Application Team
|
||||
* @brief System time functions implementation
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© Copyright (c) 2019 STMicroelectronics.
|
||||
* All rights reserved.</center></h2>
|
||||
*
|
||||
* This software component is licensed by ST under BSD 3-Clause license,
|
||||
* the "License"; You may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at:
|
||||
* opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __STM32_SYS_TIME_H__
|
||||
#define __STM32_SYS_TIME_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include <stdint.h>
|
||||
#include "time.h"
|
||||
|
||||
|
||||
/* 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 and GPS epoch
|
||||
*/
|
||||
#define UNIX_GPS_EPOCH_OFFSET 315964800
|
||||
/* External variables --------------------------------------------------------*/
|
||||
|
||||
/*!
|
||||
* @brief Structure holding the system time in seconds and milliseconds.
|
||||
*/
|
||||
typedef struct SysTime_s
|
||||
{
|
||||
uint32_t Seconds;
|
||||
int16_t SubSeconds;
|
||||
}SysTime_t;
|
||||
|
||||
/* Exported macros -----------------------------------------------------------*/
|
||||
/* Exported functions ------------------------------------------------------- */
|
||||
/*!
|
||||
* @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__
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
|
@@ -0,0 +1,976 @@
|
||||
/******************************************************************************
|
||||
* @file stm32_tiny_sscanf.c
|
||||
* @author MCD Application Team
|
||||
* @brief Tiny implementation of sscanf
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© Copyright (c) 2019 STMicroelectronics.
|
||||
* All rights reserved.</center></h2>
|
||||
*
|
||||
* This software component is licensed by ST under BSD 3-Clause license,
|
||||
* the "License"; You may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at:
|
||||
* opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* 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 define ------------------------------------------------------------*/
|
||||
#define TINY_SSCANF
|
||||
#define TINY_NO_OX
|
||||
#define TINY_SPACE_NOT_SPECIALCASE
|
||||
|
||||
/* Private macro -------------------------------------------------------------*/
|
||||
/* 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 mimicks 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 considerd
|
||||
* 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);
|
||||
}
|
||||
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
@@ -0,0 +1,67 @@
|
||||
/*******************************************************************************
|
||||
* @file stm32_tiny_sscanf.h
|
||||
* @author MCD Application Team
|
||||
* @brief Header for driver tiny_sscanf.c module
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© Copyright (c) 2019 STMicroelectronics.
|
||||
* All rights reserved.</center></h2>
|
||||
*
|
||||
* This software component is licensed by ST under BSD 3-Clause license,
|
||||
* the "License"; You may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at:
|
||||
* opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* 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__ */
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
@@ -0,0 +1,669 @@
|
||||
/******************************************************************************
|
||||
* @file stm32_tiny_vsnprintf.c
|
||||
* @author MCD Application Team
|
||||
* @brief Tiny implementation of vsnprintf like function
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© Copyright (c) 2019 STMicroelectronics.
|
||||
* All rights reserved.</center></h2>
|
||||
*
|
||||
* This software component is licensed by ST under BSD 3-Clause license,
|
||||
* the "License"; You may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at:
|
||||
* opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
@@ -0,0 +1,62 @@
|
||||
/******************************************************************************
|
||||
* @file tiny_vsnprintf.h
|
||||
* @author MCD Application Team
|
||||
* @brief Header for tiny_vsnprintf.c module
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© Copyright (c) 2019 STMicroelectronics.
|
||||
* All rights reserved.</center></h2>
|
||||
*
|
||||
* This software component is licensed by ST under BSD 3-Clause license,
|
||||
* the "License"; You may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at:
|
||||
* opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* 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__*/
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
Reference in New Issue
Block a user