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