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

View File

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

View File

@ -0,0 +1,61 @@
/**
******************************************************************************
* @file stm32_mem.c
* @author MCD Application Team
* @brief standard memory operation
******************************************************************************
* @attention
*
* Copyright (c) 2019 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stdint.h"
#include "stm32_mem.h"
/* Private typedef -----------------------------------------------------------*/
/* Private defines -----------------------------------------------------------*/
/* Private macros ------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Global variables ----------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Functions Definition ------------------------------------------------------*/
void UTIL_MEM_cpy_8( void *dst, const void *src, uint16_t size )
{
uint8_t* dst8= (uint8_t *) dst;
uint8_t* src8= (uint8_t *) src;
while( size-- )
{
*dst8++ = *src8++;
}
}
void UTIL_MEM_cpyr_8( void *dst, const void *src, uint16_t size )
{
uint8_t* dst8= (uint8_t *) dst;
uint8_t* src8= (uint8_t *) src;
dst8 = dst8 + ( size - 1 );
while( size-- )
{
*dst8-- = *src8++;
}
}
void UTIL_MEM_set_8( void *dst, uint8_t value, uint16_t size )
{
uint8_t* dst8= (uint8_t *) dst;
while( size-- )
{
*dst8++ = value;
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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