blob: a5e5856a913582e7cc78bba567b70b76a20a50ee [file] [log] [blame]
/*
* FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab!
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* Authors include James Walmsley, Hein Tibosch and Richard Barry
*
* 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
*
*/
#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 */