303 lines
8.9 KiB
C
303 lines
8.9 KiB
C
/*
|
|
* FreeRTOS+FAT V2.3.3
|
|
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
* this software and associated documentation files (the "Software"), to deal in
|
|
* the Software without restriction, including without limitation the rights to
|
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
|
* subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*
|
|
* https://www.FreeRTOS.org
|
|
* https://github.com/FreeRTOS
|
|
*
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <time.h>
|
|
#include <string.h>
|
|
|
|
#include "FreeRTOS.h"
|
|
#include "task.h"
|
|
|
|
#include "ff_time.h"
|
|
|
|
/**
|
|
* @file ff_time.c
|
|
* @ingroup TIME
|
|
*
|
|
* @defgroup TIME Real-Time Clock Interface
|
|
* @brief Allows FreeRTOS+FAT to time-stamp files.
|
|
*
|
|
* Provides a means for receiving the time on any platform.
|
|
**/
|
|
|
|
#if ( ffconfigTIME_SUPPORT != 0 ) /* This if-block spans the rest of the source file. */
|
|
|
|
/**
|
|
* @public
|
|
* @brief Populates an FF_SystemTime_t object with the current time from the system.
|
|
*
|
|
* The developer must modify this function so that it is suitable for their platform.
|
|
* The function must return with 0, and if the time is not available all elements of the
|
|
* FF_SystemTime_t object must be zero'd, as in the examples provided.
|
|
*
|
|
* @param pxTime Pointer to an FF_TIME object.
|
|
*
|
|
* @return Always returns 0.
|
|
**/
|
|
|
|
int32_t FF_GetSystemTime( FF_SystemTime_t * pxTime )
|
|
{
|
|
FF_TimeStruct_t xTimeStruct;
|
|
|
|
/* Fetch the current time. */
|
|
time_t secs = FreeRTOS_time( NULL );
|
|
|
|
/* Fill the fields in 'xTimeStruct'. */
|
|
FreeRTOS_gmtime_r( &secs, &xTimeStruct );
|
|
|
|
pxTime->Hour = xTimeStruct.tm_hour;
|
|
pxTime->Minute = xTimeStruct.tm_min;
|
|
pxTime->Second = xTimeStruct.tm_sec;
|
|
pxTime->Day = xTimeStruct.tm_mday;
|
|
pxTime->Month = xTimeStruct.tm_mon + 1;
|
|
pxTime->Year = xTimeStruct.tm_year + 1900;
|
|
|
|
return 0;
|
|
} /* FF_GetSystemTime() */
|
|
/*-----------------------------------------------------------*/
|
|
|
|
/*
|
|
* FreeRTOS+FAT
|
|
* Time conversion functions:
|
|
*
|
|
* FF_TimeStruct_t *FreeRTOS_gmtime_r( const time_t *pxTime, FF_TimeStruct_t *pxTimeBuf )
|
|
* time_t FreeRTOS_mktime(FF_TimeStruct_t *pxTimeBuf)
|
|
*/
|
|
|
|
#define GMTIME_FIRST_YEAR ( 1970 )
|
|
#define TM_STRUCT_FIRST_YEAR ( 1900 )
|
|
#define SECONDS_PER_MINUTE ( 60 )
|
|
#define MINUTES_PER_HOUR ( 60 )
|
|
#define HOURS_PER_DAY ( 24 )
|
|
#define SECONDS_PER_HOUR ( MINUTES_PER_HOUR * SECONDS_PER_MINUTE )
|
|
#define SECONDS_PER_DAY ( HOURS_PER_DAY * SECONDS_PER_HOUR )
|
|
|
|
/* The first weekday in 'FF_TimeStruct_t' is Sunday. */
|
|
#define WEEK_DAY_SUNDAY 0
|
|
#define WEEK_DAY_MONNDAY 1
|
|
#define WEEK_DAY_TUESDAY 2
|
|
#define WEEK_DAY_WEDNESDAY 3
|
|
#define WEEK_DAY_THURSDAY 4
|
|
#define WEEK_DAY_FRIDAY 5
|
|
#define WEEK_DAY_SATURDAY 6
|
|
|
|
/* Make a bitmask with a '1' for each 31-day month. */
|
|
#define _MM( month ) ( 1u << ( month - 1 ) )
|
|
#define MASK_LONG_MONTHS ( _MM( 1 ) | _MM( 3 ) | _MM( 5 ) | _MM( 7 ) | _MM( 8 ) | _MM( 10 ) | _MM( 12 ) )
|
|
|
|
#define DAYS_UNTIL_1970 ( ( 1970 * 365 ) + ( 1970 / 4 ) - ( 1970 / 100 ) + ( 1970 / 400 ) )
|
|
#define DAYS_BEFORE_MARCH ( 59 )
|
|
|
|
static portINLINE int iIsLeapyear( int iYear )
|
|
{
|
|
int iReturn;
|
|
|
|
if( ( iYear % 4 ) != 0 )
|
|
{
|
|
/* Not a multiple of 4 years. */
|
|
iReturn = pdFALSE;
|
|
}
|
|
else if( ( iYear % 400 ) == 0 )
|
|
{
|
|
/* Every 4 centuries there is a leap year */
|
|
iReturn = pdTRUE;
|
|
}
|
|
else if( ( iYear % 100 ) == 0 )
|
|
{
|
|
/* Other centuries are not a leap year */
|
|
iReturn = pdFALSE;
|
|
}
|
|
else
|
|
{
|
|
/* Otherwise every fourth year. */
|
|
iReturn = pdTRUE;
|
|
}
|
|
|
|
return iReturn;
|
|
}
|
|
|
|
static portINLINE unsigned long ulDaysPerYear( int iYear )
|
|
{
|
|
int iDays;
|
|
|
|
if( iIsLeapyear( iYear ) )
|
|
{
|
|
iDays = 366;
|
|
}
|
|
else
|
|
{
|
|
iDays = 365;
|
|
}
|
|
|
|
return iDays;
|
|
}
|
|
|
|
static int iDaysPerMonth( int iYear,
|
|
int iMonth )
|
|
{
|
|
int iDays;
|
|
|
|
/* Month is zero-based, 1 is February. */
|
|
if( iMonth != 1 )
|
|
{
|
|
/* 30 or 31 days? */
|
|
if( ( MASK_LONG_MONTHS & ( 1u << iMonth ) ) != 0 )
|
|
{
|
|
iDays = 31;
|
|
}
|
|
else
|
|
{
|
|
iDays = 30;
|
|
}
|
|
}
|
|
else if( iIsLeapyear( iYear ) == pdFALSE )
|
|
{
|
|
/* February, non leap year. */
|
|
iDays = 28;
|
|
}
|
|
else
|
|
{
|
|
/* February, leap year. */
|
|
iDays = 29;
|
|
}
|
|
|
|
return iDays;
|
|
}
|
|
|
|
FF_TimeStruct_t * FreeRTOS_gmtime_r( const time_t * pxTime,
|
|
FF_TimeStruct_t * pxTimeBuf )
|
|
{
|
|
time_t xTime = *pxTime;
|
|
unsigned long ulDaySeconds, ulDayNumber;
|
|
int iYear = GMTIME_FIRST_YEAR;
|
|
int iMonth;
|
|
|
|
/* Clear all fields, some might not get set here. */
|
|
memset( ( void * ) pxTimeBuf, '\0', sizeof( *pxTimeBuf ) );
|
|
|
|
/* Seconds since last midnight. */
|
|
ulDaySeconds = ( unsigned long ) ( xTime % SECONDS_PER_DAY );
|
|
|
|
/* Days since 1 Jan 1970. */
|
|
ulDayNumber = ( unsigned long ) ( xTime / SECONDS_PER_DAY );
|
|
|
|
/* Today's HH:MM:SS */
|
|
pxTimeBuf->tm_hour = ulDaySeconds / SECONDS_PER_HOUR;
|
|
pxTimeBuf->tm_min = ( ulDaySeconds % SECONDS_PER_HOUR ) / 60;
|
|
pxTimeBuf->tm_sec = ulDaySeconds % 60;
|
|
|
|
/* Today's week day, knowing that 1-1-1970 was a THursday. */
|
|
pxTimeBuf->tm_wday = ( ulDayNumber + WEEK_DAY_THURSDAY ) % 7;
|
|
|
|
for( ; ; )
|
|
{
|
|
/* Keep subtracting 365 (or 366) days while possible. */
|
|
unsigned long ulDays = ulDaysPerYear( iYear );
|
|
|
|
if( ulDayNumber < ulDays )
|
|
{
|
|
break;
|
|
}
|
|
|
|
ulDayNumber -= ulDays;
|
|
iYear++;
|
|
}
|
|
|
|
/* Subtract 1900. */
|
|
pxTimeBuf->tm_year = iYear - TM_STRUCT_FIRST_YEAR;
|
|
|
|
/* The day within this year. */
|
|
pxTimeBuf->tm_yday = ulDayNumber;
|
|
|
|
/* Month are counted as 0..11 */
|
|
iMonth = 0;
|
|
|
|
for( ; ; )
|
|
{
|
|
unsigned long ulDays = iDaysPerMonth( iYear, iMonth );
|
|
|
|
/* Keep subtracting 30 (or 28, 29, or 31) days while possible. */
|
|
if( ulDayNumber < ulDays )
|
|
{
|
|
break;
|
|
}
|
|
|
|
ulDayNumber -= ulDays;
|
|
iMonth++;
|
|
}
|
|
|
|
pxTimeBuf->tm_mon = iMonth;
|
|
|
|
/* Month days are counted as 1..31 */
|
|
pxTimeBuf->tm_mday = ulDayNumber + 1;
|
|
|
|
return pxTimeBuf;
|
|
}
|
|
|
|
time_t FreeRTOS_mktime( const FF_TimeStruct_t * pxTimeBuf )
|
|
{
|
|
/* Get year AD. */
|
|
int iYear = 1900 + pxTimeBuf->tm_year; /* 20xx */
|
|
/* Get month zero-based. */
|
|
int iMonth = pxTimeBuf->tm_mon; /* 0..11 */
|
|
uint32_t ulDays;
|
|
uint32_t ulResult;
|
|
|
|
ulDays = pxTimeBuf->tm_mday - 1; /* 1..31 */
|
|
|
|
/* Make March the first month. */
|
|
iMonth -= 2;
|
|
|
|
if( iMonth < 0 )
|
|
{
|
|
/* January or February: leap day has yet to come for this year. */
|
|
iYear--;
|
|
iMonth += 12;
|
|
}
|
|
|
|
/* Add the number of days past until this month. */
|
|
ulDays += ( ( 306 * iMonth ) + 5 ) / 10;
|
|
|
|
/* Add days past before this year: */
|
|
ulDays +=
|
|
+( iYear * 365 ) /* Every normal year. */
|
|
+ ( iYear / 4 ) /* Plus a day for every leap year. */
|
|
- ( iYear / 100 ) /* Minus the centuries. */
|
|
+ ( iYear / 400 ) /* Except every fourth century. */
|
|
- ( DAYS_UNTIL_1970 ) /* Minus the days before 1-1-1970 */
|
|
+ ( DAYS_BEFORE_MARCH ); /* Because 2 months were subtracted. */
|
|
|
|
ulResult =
|
|
( ulDays * SECONDS_PER_DAY ) +
|
|
( pxTimeBuf->tm_hour * SECONDS_PER_HOUR ) +
|
|
( pxTimeBuf->tm_min * SECONDS_PER_MINUTE ) +
|
|
pxTimeBuf->tm_sec;
|
|
|
|
return ulResult;
|
|
}
|
|
|
|
#endif /* ffconfigTIME_SUPPORT */
|