/* * 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 #include #include #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 */