ff_time.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. /*
  2. * FreeRTOS+FAT V2.3.3
  3. * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
  4. *
  5. * Permission is hereby granted, free of charge, to any person obtaining a copy of
  6. * this software and associated documentation files (the "Software"), to deal in
  7. * the Software without restriction, including without limitation the rights to
  8. * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  9. * the Software, and to permit persons to whom the Software is furnished to do so,
  10. * subject to the following conditions:
  11. *
  12. * The above copyright notice and this permission notice shall be included in all
  13. * copies or substantial portions of the Software.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  17. * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  18. * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  19. * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  20. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  21. *
  22. * https://www.FreeRTOS.org
  23. * https://github.com/FreeRTOS
  24. *
  25. */
  26. #include <stdio.h>
  27. #include <time.h>
  28. #include <string.h>
  29. #include "FreeRTOS.h"
  30. #include "task.h"
  31. #include "ff_time.h"
  32. /**
  33. * @file ff_time.c
  34. * @ingroup TIME
  35. *
  36. * @defgroup TIME Real-Time Clock Interface
  37. * @brief Allows FreeRTOS+FAT to time-stamp files.
  38. *
  39. * Provides a means for receiving the time on any platform.
  40. **/
  41. #if ( ffconfigTIME_SUPPORT != 0 ) /* This if-block spans the rest of the source file. */
  42. /**
  43. * @public
  44. * @brief Populates an FF_SystemTime_t object with the current time from the system.
  45. *
  46. * The developer must modify this function so that it is suitable for their platform.
  47. * The function must return with 0, and if the time is not available all elements of the
  48. * FF_SystemTime_t object must be zero'd, as in the examples provided.
  49. *
  50. * @param pxTime Pointer to an FF_TIME object.
  51. *
  52. * @return Always returns 0.
  53. **/
  54. int32_t FF_GetSystemTime( FF_SystemTime_t * pxTime )
  55. {
  56. FF_TimeStruct_t xTimeStruct;
  57. /* Fetch the current time. */
  58. time_t secs = FreeRTOS_time( NULL );
  59. /* Fill the fields in 'xTimeStruct'. */
  60. FreeRTOS_gmtime_r( &secs, &xTimeStruct );
  61. pxTime->Hour = xTimeStruct.tm_hour;
  62. pxTime->Minute = xTimeStruct.tm_min;
  63. pxTime->Second = xTimeStruct.tm_sec;
  64. pxTime->Day = xTimeStruct.tm_mday;
  65. pxTime->Month = xTimeStruct.tm_mon + 1;
  66. pxTime->Year = xTimeStruct.tm_year + 1900;
  67. return 0;
  68. } /* FF_GetSystemTime() */
  69. /*-----------------------------------------------------------*/
  70. /*
  71. * FreeRTOS+FAT
  72. * Time conversion functions:
  73. *
  74. * FF_TimeStruct_t *FreeRTOS_gmtime_r( const time_t *pxTime, FF_TimeStruct_t *pxTimeBuf )
  75. * time_t FreeRTOS_mktime(FF_TimeStruct_t *pxTimeBuf)
  76. */
  77. #define GMTIME_FIRST_YEAR ( 1970 )
  78. #define TM_STRUCT_FIRST_YEAR ( 1900 )
  79. #define SECONDS_PER_MINUTE ( 60 )
  80. #define MINUTES_PER_HOUR ( 60 )
  81. #define HOURS_PER_DAY ( 24 )
  82. #define SECONDS_PER_HOUR ( MINUTES_PER_HOUR * SECONDS_PER_MINUTE )
  83. #define SECONDS_PER_DAY ( HOURS_PER_DAY * SECONDS_PER_HOUR )
  84. /* The first weekday in 'FF_TimeStruct_t' is Sunday. */
  85. #define WEEK_DAY_SUNDAY 0
  86. #define WEEK_DAY_MONNDAY 1
  87. #define WEEK_DAY_TUESDAY 2
  88. #define WEEK_DAY_WEDNESDAY 3
  89. #define WEEK_DAY_THURSDAY 4
  90. #define WEEK_DAY_FRIDAY 5
  91. #define WEEK_DAY_SATURDAY 6
  92. /* Make a bitmask with a '1' for each 31-day month. */
  93. #define _MM( month ) ( 1u << ( month - 1 ) )
  94. #define MASK_LONG_MONTHS ( _MM( 1 ) | _MM( 3 ) | _MM( 5 ) | _MM( 7 ) | _MM( 8 ) | _MM( 10 ) | _MM( 12 ) )
  95. #define DAYS_UNTIL_1970 ( ( 1970 * 365 ) + ( 1970 / 4 ) - ( 1970 / 100 ) + ( 1970 / 400 ) )
  96. #define DAYS_BEFORE_MARCH ( 59 )
  97. static portINLINE int iIsLeapyear( int iYear )
  98. {
  99. int iReturn;
  100. if( ( iYear % 4 ) != 0 )
  101. {
  102. /* Not a multiple of 4 years. */
  103. iReturn = pdFALSE;
  104. }
  105. else if( ( iYear % 400 ) == 0 )
  106. {
  107. /* Every 4 centuries there is a leap year */
  108. iReturn = pdTRUE;
  109. }
  110. else if( ( iYear % 100 ) == 0 )
  111. {
  112. /* Other centuries are not a leap year */
  113. iReturn = pdFALSE;
  114. }
  115. else
  116. {
  117. /* Otherwise every fourth year. */
  118. iReturn = pdTRUE;
  119. }
  120. return iReturn;
  121. }
  122. static portINLINE unsigned long ulDaysPerYear( int iYear )
  123. {
  124. int iDays;
  125. if( iIsLeapyear( iYear ) )
  126. {
  127. iDays = 366;
  128. }
  129. else
  130. {
  131. iDays = 365;
  132. }
  133. return iDays;
  134. }
  135. static int iDaysPerMonth( int iYear,
  136. int iMonth )
  137. {
  138. int iDays;
  139. /* Month is zero-based, 1 is February. */
  140. if( iMonth != 1 )
  141. {
  142. /* 30 or 31 days? */
  143. if( ( MASK_LONG_MONTHS & ( 1u << iMonth ) ) != 0 )
  144. {
  145. iDays = 31;
  146. }
  147. else
  148. {
  149. iDays = 30;
  150. }
  151. }
  152. else if( iIsLeapyear( iYear ) == pdFALSE )
  153. {
  154. /* February, non leap year. */
  155. iDays = 28;
  156. }
  157. else
  158. {
  159. /* February, leap year. */
  160. iDays = 29;
  161. }
  162. return iDays;
  163. }
  164. FF_TimeStruct_t * FreeRTOS_gmtime_r( const time_t * pxTime,
  165. FF_TimeStruct_t * pxTimeBuf )
  166. {
  167. time_t xTime = *pxTime;
  168. unsigned long ulDaySeconds, ulDayNumber;
  169. int iYear = GMTIME_FIRST_YEAR;
  170. int iMonth;
  171. /* Clear all fields, some might not get set here. */
  172. memset( ( void * ) pxTimeBuf, '\0', sizeof( *pxTimeBuf ) );
  173. /* Seconds since last midnight. */
  174. ulDaySeconds = ( unsigned long ) ( xTime % SECONDS_PER_DAY );
  175. /* Days since 1 Jan 1970. */
  176. ulDayNumber = ( unsigned long ) ( xTime / SECONDS_PER_DAY );
  177. /* Today's HH:MM:SS */
  178. pxTimeBuf->tm_hour = ulDaySeconds / SECONDS_PER_HOUR;
  179. pxTimeBuf->tm_min = ( ulDaySeconds % SECONDS_PER_HOUR ) / 60;
  180. pxTimeBuf->tm_sec = ulDaySeconds % 60;
  181. /* Today's week day, knowing that 1-1-1970 was a THursday. */
  182. pxTimeBuf->tm_wday = ( ulDayNumber + WEEK_DAY_THURSDAY ) % 7;
  183. for( ; ; )
  184. {
  185. /* Keep subtracting 365 (or 366) days while possible. */
  186. unsigned long ulDays = ulDaysPerYear( iYear );
  187. if( ulDayNumber < ulDays )
  188. {
  189. break;
  190. }
  191. ulDayNumber -= ulDays;
  192. iYear++;
  193. }
  194. /* Subtract 1900. */
  195. pxTimeBuf->tm_year = iYear - TM_STRUCT_FIRST_YEAR;
  196. /* The day within this year. */
  197. pxTimeBuf->tm_yday = ulDayNumber;
  198. /* Month are counted as 0..11 */
  199. iMonth = 0;
  200. for( ; ; )
  201. {
  202. unsigned long ulDays = iDaysPerMonth( iYear, iMonth );
  203. /* Keep subtracting 30 (or 28, 29, or 31) days while possible. */
  204. if( ulDayNumber < ulDays )
  205. {
  206. break;
  207. }
  208. ulDayNumber -= ulDays;
  209. iMonth++;
  210. }
  211. pxTimeBuf->tm_mon = iMonth;
  212. /* Month days are counted as 1..31 */
  213. pxTimeBuf->tm_mday = ulDayNumber + 1;
  214. return pxTimeBuf;
  215. }
  216. time_t FreeRTOS_mktime( const FF_TimeStruct_t * pxTimeBuf )
  217. {
  218. /* Get year AD. */
  219. int iYear = 1900 + pxTimeBuf->tm_year; /* 20xx */
  220. /* Get month zero-based. */
  221. int iMonth = pxTimeBuf->tm_mon; /* 0..11 */
  222. uint32_t ulDays;
  223. uint32_t ulResult;
  224. ulDays = pxTimeBuf->tm_mday - 1; /* 1..31 */
  225. /* Make March the first month. */
  226. iMonth -= 2;
  227. if( iMonth < 0 )
  228. {
  229. /* January or February: leap day has yet to come for this year. */
  230. iYear--;
  231. iMonth += 12;
  232. }
  233. /* Add the number of days past until this month. */
  234. ulDays += ( ( 306 * iMonth ) + 5 ) / 10;
  235. /* Add days past before this year: */
  236. ulDays +=
  237. +( iYear * 365 ) /* Every normal year. */
  238. + ( iYear / 4 ) /* Plus a day for every leap year. */
  239. - ( iYear / 100 ) /* Minus the centuries. */
  240. + ( iYear / 400 ) /* Except every fourth century. */
  241. - ( DAYS_UNTIL_1970 ) /* Minus the days before 1-1-1970 */
  242. + ( DAYS_BEFORE_MARCH ); /* Because 2 months were subtracted. */
  243. ulResult =
  244. ( ulDays * SECONDS_PER_DAY ) +
  245. ( pxTimeBuf->tm_hour * SECONDS_PER_HOUR ) +
  246. ( pxTimeBuf->tm_min * SECONDS_PER_MINUTE ) +
  247. pxTimeBuf->tm_sec;
  248. return ulResult;
  249. }
  250. #endif /* ffconfigTIME_SUPPORT */