5 * th9x - http://code.google.com/p/th9x
6 * er9x - http://code.google.com/p/er9x
7 * gruvin9x - http://code.google.com/p/gruvin9x
9 * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
24 extern void rtcdriver_settime(struct gtm
* t
);
26 #define LEAP_SECONDS_POSSIBLE 0
28 /* Shift A right by B bits portably, by dividing A by 2**B and
29 truncating towards minus infinity. A and B should be free of side
30 effects, and B should be in the range 0 <= B <= INT_BITS - 2, where
31 INT_BITS is the number of useful bits in an int. GNU code can
32 assume that INT_BITS is at least 32.
34 ISO C99 says that A >> B is implementation-defined if A < 0. Some
35 implementations (e.g., UNICOS 9.0 on a Cray Y-MP EL) don't shift
36 right in the usual way when A < 0, so SHR falls back on division if
37 ordinary A >> B doesn't seem to be the usual signed shift. */
38 #define SHR(a, b) (-1 >> 1 == -1 ? (a) >> (b) : (a) / (1 << (b)) - ((a) % (1 << (b)) < 0))
40 /* The extra casts in the following macros work around compiler bugs,
41 e.g., in Cray C 5.0.3.0. */
43 /* True if the arithmetic type T is an integer type. bool counts as
45 #define TYPE_IS_INTEGER(t) ((t) 1.5 == 1)
47 /* True if negative values of the signed integer type T use two's
48 complement, ones' complement, or signed magnitude representation,
49 respectively. Much GNU code assumes two's complement, but some
50 people like to be portable to all possible C hosts. */
51 #define TYPE_TWOS_COMPLEMENT(t) ((t) ~ (t) 0 == (t) -1)
52 #define TYPE_ONES_COMPLEMENT(t) ((t) ~ (t) 0 == 0)
53 #define TYPE_SIGNED_MAGNITUDE(t) ((t) ~ (t) 0 < (t) -1)
55 /* True if the arithmetic type T is signed. */
56 #define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
58 /* The maximum and minimum values for the integer type T. These
59 macros have undefined behavior if T is signed and has padding bits.
60 If this is a problem for you, please let us know how to fix it for
62 #define TYPE_MINIMUM(t) \
63 ((t) (! TYPE_SIGNED (t) \
65 : TYPE_SIGNED_MAGNITUDE (t) \
67 : ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1)))
68 #define TYPE_MAXIMUM(t) \
69 ((t) (! TYPE_SIGNED (t) \
71 : ~ (~ (t) 0 << (sizeof (t) * CHAR_BIT - 1))))
74 # define TIME_T_MIN TYPE_MINIMUM (gtime_t)
77 # define TIME_T_MAX TYPE_MAXIMUM (gtime_t)
79 #define TIME_T_MIDPOINT (SHR (TIME_T_MIN + TIME_T_MAX, 1) + 1)
83 static_assert(TYPE_IS_INTEGER(gtime_t
), "gtime_t is not integer");
84 static_assert(TYPE_TWOS_COMPLEMENT(int), "twos complement arithmetic");
85 /* The code also assumes that signed integer overflow silently wraps
86 around, but this assumption can't be stated without causing a
87 diagnostic on some hosts. */
89 #define EPOCH_YEAR 1970
90 static_assert(TM_YEAR_BASE
% 100 == 0, "base year is not a multiple of 100");
92 /* Return 1 if YEAR + TM_YEAR_BASE is a leap year. */
93 static inline int leapyear(long int year
)
95 /* Don't add YEAR to TM_YEAR_BASE, as that might overflow.
96 Also, work even if YEAR is negative. */
97 return ((year
& 3) == 0
99 || ((year
/ 100) & 3) == (-(TM_YEAR_BASE
/ 100) & 3)));
102 const unsigned short int __mon_yday
[2][13] = {
104 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
106 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
109 /* Compute the `struct tm' representation of *T,
110 offset OFFSET seconds east of UTC,
111 and store year, yday, mon, mday, wday, hour, min, sec into *TP.
112 Return nonzero if successful. */
113 int __offtime(const gtime_t
* t
, long int offset
, struct gtm
* tp
)
115 long int days
, rem
, y
;
116 const unsigned short int * ip
;
118 days
= *t
/ SECS_PER_DAY
;
119 rem
= *t
% SECS_PER_DAY
;
125 while (rem
>= (long int)SECS_PER_DAY
) {
129 tp
->tm_hour
= rem
/ SECS_PER_HOUR
;
130 rem
%= SECS_PER_HOUR
;
131 tp
->tm_min
= rem
/ 60;
132 tp
->tm_sec
= rem
% 60;
133 /* January 1, 1970 was a Thursday. */
134 tp
->tm_wday
= (4 + days
) % 7;
139 #define DIV(a, b) ((a) / (b) - ((a) % (b) < 0))
140 #define LEAPS_THRU_END_OF(y) (DIV(y, 4) - DIV(y, 100) + DIV(y, 400))
142 while (days
< 0 || days
>= (leapyear(y
) ? 366 : 365)) {
143 /* Guess a corrected year, assuming 365 days per year. */
144 long int yg
= y
+ days
/ 365 - (days
% 365 < 0);
146 /* Adjust DAYS and Y to match the guessed year. */
147 days
-= ((yg
- y
) * 365 + LEAPS_THRU_END_OF(yg
- 1) - LEAPS_THRU_END_OF(y
- 1));
150 tp
->tm_year
= y
- TM_YEAR_BASE
;
151 if (tp
->tm_year
!= y
- TM_YEAR_BASE
) {
152 /* The year cannot be represented due to overflow. */
153 // __set_errno (EOVERFLOW);
157 ip
= __mon_yday
[leapyear(y
)];
158 for (y
= 11; days
< (long int)ip
[y
]; --y
)
162 tp
->tm_mday
= days
+ 1;
166 /* time_r function implementations */
167 // G: No time zones in our implementation so just do the converion from gtime_t to struct tm
168 struct gtm
* __localtime_r(const gtime_t
* t
, struct gtm
* tp
)
175 /* Return an integer value measuring (YEAR1-YDAY1 HOUR1:MIN1:SEC1) -
176 (YEAR0-YDAY0 HOUR0:MIN0:SEC0) in seconds, assuming that the clocks
177 were not adjusted between the time stamps.
179 The YEAR values uses the same numbering as TP->tm_year. Values
180 need not be in the usual range. However, YEAR1 must not be less
181 than 2 * INT_MIN or greater than 2 * INT_MAX.
183 The result may overflow. It is the caller's responsibility to
186 static inline gtime_t
ydhms_diff(long int year1
, long int yday1
, int hour1
, int min1
, int sec1
,
187 int year0
, int yday0
, int hour0
, int min0
, int sec0
)
189 static_assert(-1 / 2 == 0, "no C99 integer division");
190 static_assert(INT_MAX
<= LONG_MAX
/ 2 || TIME_T_MAX
<= INT_MAX
, "long int year and yday are not wide enough");
192 /* Compute intervening leap days correctly even if year is negative.
193 Take care to avoid integer overflow here. */
194 int a4
= SHR(year1
, 2) + SHR(TM_YEAR_BASE
, 2) - !(year1
& 3);
195 int b4
= SHR(year0
, 2) + SHR(TM_YEAR_BASE
, 2) - !(year0
& 3);
196 int a100
= a4
/ 25 - (a4
% 25 < 0);
197 int b100
= b4
/ 25 - (b4
% 25 < 0);
198 int a400
= SHR(a100
, 2);
199 int b400
= SHR(b100
, 2);
200 int intervening_leap_days
= (a4
- b4
) - (a100
- b100
) + (a400
- b400
);
202 /* Compute the desired time in gtime_t precision. Overflow might
204 gtime_t tyear1
= year1
;
205 gtime_t years
= tyear1
- year0
;
206 gtime_t days
= 365 * years
+ yday1
- yday0
+ intervening_leap_days
;
207 gtime_t hours
= 24 * days
+ hour1
- hour0
;
208 gtime_t minutes
= 60 * hours
+ min1
- min0
;
209 gtime_t seconds
= 60 * minutes
+ sec1
- sec0
;
213 /* Return a gtime_t value corresponding to (YEAR-YDAY HOUR:MIN:SEC),
214 assuming that *T corresponds to *TP and that no clock adjustments
215 occurred between *TP and the desired time.
216 If TP is null, return a value not equal to *T; this avoids false matches.
217 If overflow occurs, yield the minimal or maximal value, except do not
218 yield a value equal to *T. */
219 static gtime_t
guess_time_tm(long int year
, long int yday
, int hour
, int min
, int sec
,
220 gtime_t
* t
, struct gtm
* tp
)
223 gtime_t d
= ydhms_diff(year
, yday
, hour
, min
, sec
,
224 tp
->tm_year
, tp
->tm_yday
,
225 tp
->tm_hour
, tp
->tm_min
, tp
->tm_sec
);
227 if ((t1
< *t
) == (TYPE_SIGNED(gtime_t
) ? d
< 0 : TIME_T_MAX
/ 2 < d
))
231 /* Overflow occurred one way or another. Return the nearest result
232 that is actually in range, except don't report a zero difference
233 if the actual difference is nonzero, as that would cause a false
234 match; and don't oscillate between two values, as that would
235 confuse the spring-forward gap detector. */
236 return (*t
< TIME_T_MIDPOINT
237 ? (*t
<= TIME_T_MIN
+ 1 ? *t
+ 1 : TIME_T_MIN
)
238 : (TIME_T_MAX
- 1 <= *t
? *t
- 1 : TIME_T_MAX
));
241 /* Use CONVERT to convert *T to a broken down time in *TP.
242 If *T is out of range for conversion, adjust it so that
243 it is the nearest in-range value and then convert that. */
244 static struct gtm
* ranged_convert(struct gtm
*(*convert
)(const gtime_t
*, struct gtm
*), gtime_t
* t
, struct gtm
* tp
)
246 struct gtm
* r
= convert(t
, tp
);
252 /* BAD is a known unconvertible gtime_t, and OK is a known good one.
253 Use binary search to narrow the range between BAD and OK until
255 while (bad
!= ok
+ (bad
< 0 ? -1 : 1)) {
256 gtime_t mid
= *t
= (bad
< 0 ? bad
+ ((ok
- bad
) >> 1) : ok
+ ((bad
- ok
) >> 1));
263 /* The last conversion attempt failed;
264 revert to the most recent successful attempt. */
273 /* Convert *TP to a gtime_t value, inverting
274 the monotonic and mostly-unit-linear conversion function CONVERT.
275 Use *OFFSET to keep track of a guess at the offset of the result,
276 compared to what the result would be for UTC without leap seconds.
277 If *OFFSET's guess is correct, only one CONVERT call is needed.
278 This function is external because it is used also by timegm.c. */
279 gtime_t
__mktime_internal(struct gtm
* tp
,
280 struct gtm
*(*convert
)(const gtime_t
*, struct gtm
*),
283 gtime_t t
, gt
, t0
, t1
, t2
;
286 /* The maximum number of probes (calls to CONVERT) should be enough
287 to handle any combinations of time zone rule changes, solar time,
288 leap seconds, and oscillations around a spring-forward gap.
289 POSIX.1 prohibits leap seconds, but some hosts have them anyway. */
290 int remaining_probes
= 6;
292 /* Time requested. Copy it in case CONVERT modifies *TP; this can
293 occur if TP is localtime's returned value and CONVERT is localtime. */
294 int sec
= tp
->tm_sec
;
295 int min
= tp
->tm_min
;
296 int hour
= tp
->tm_hour
;
297 int mday
= tp
->tm_mday
;
298 int mon
= tp
->tm_mon
;
299 int year_requested
= tp
->tm_year
;
301 /* Ensure that mon is in range, and set year accordingly. */
302 int mon_remainder
= mon
% 12;
303 int negative_mon_remainder
= mon_remainder
< 0;
304 int mon_years
= mon
/ 12 - negative_mon_remainder
;
305 long int lyear_requested
= year_requested
;
306 long int year
= lyear_requested
+ mon_years
;
308 /* The other values need not be in range:
309 the remaining code handles minor overflows correctly,
310 assuming int and gtime_t arithmetic wraps around.
311 Major overflows are caught at the end. */
313 /* Calculate day of year from year, month, and day of month.
314 The result need not be in range. */
315 int mon_yday
= ((__mon_yday
[leapyear(year
)][mon_remainder
+ 12 * negative_mon_remainder
]) - 1);
316 long int lmday
= mday
;
317 long int yday
= mon_yday
+ lmday
;
319 gtime_t guessed_offset
= *offset
;
321 int sec_requested
= sec
;
324 if (LEAP_SECONDS_POSSIBLE)
326 // Handle out-of-range seconds specially,
327 // since ydhms_tm_diff assumes every minute has 60 seconds.
335 /* Invert CONVERT by probing. First assume the same offset as last
338 t0
= ydhms_diff(year
, yday
, hour
, min
, sec
, EPOCH_YEAR
- TM_YEAR_BASE
, 0, 0, 0, -guessed_offset
);
340 if (TIME_T_MAX
/ INT_MAX
/ 366 / 24 / 60 / 60 < 3) {
341 /* gtime_t isn't large enough to rule out overflows, so check
342 for major overflows. A gross check suffices, since if t0
343 has overflowed, it is off by a multiple of TIME_T_MAX -
344 TIME_T_MIN + 1. So ignore any component of the difference
345 that is bounded by a small value. */
347 /* Approximate log base 2 of the number of time units per
348 biennium. A biennium is 2 years; use this unit instead of
349 years to avoid integer overflow. For example, 2 average
350 Gregorian years are 2 * 365.2425 * 24 * 60 * 60 seconds,
351 which is 63113904 seconds, and rint (log2 (63113904)) is
353 int ALOG2_SECONDS_PER_BIENNIUM
= 26;
354 int ALOG2_MINUTES_PER_BIENNIUM
= 20;
355 int ALOG2_HOURS_PER_BIENNIUM
= 14;
356 int ALOG2_DAYS_PER_BIENNIUM
= 10;
357 int LOG2_YEARS_PER_BIENNIUM
= 1;
359 int approx_requested_biennia
=
360 (SHR(year_requested
, LOG2_YEARS_PER_BIENNIUM
)
361 - SHR(EPOCH_YEAR
- TM_YEAR_BASE
, LOG2_YEARS_PER_BIENNIUM
)
362 + SHR(mday
, ALOG2_DAYS_PER_BIENNIUM
)
363 + SHR(hour
, ALOG2_HOURS_PER_BIENNIUM
)
364 + SHR(min
, ALOG2_MINUTES_PER_BIENNIUM
)
365 + (LEAP_SECONDS_POSSIBLE
367 : SHR(sec
, ALOG2_SECONDS_PER_BIENNIUM
)));
369 int approx_biennia
= SHR(t0
, ALOG2_SECONDS_PER_BIENNIUM
);
370 int diff
= approx_biennia
- approx_requested_biennia
;
371 int abs_diff
= diff
< 0 ? -diff
: diff
;
373 /* IRIX 4.0.5 cc miscalculates TIME_T_MIN / 3: it erroneously
374 gives a positive value of 715827882. Setting a variable
375 first then doing math on it seems to work.
376 (ghazi@caip.rutgers.edu) */
377 gtime_t time_t_max
= TIME_T_MAX
;
378 gtime_t time_t_min
= TIME_T_MIN
;
379 gtime_t overflow_threshold
= (time_t_max
/ 3 - time_t_min
/ 3) >> ALOG2_SECONDS_PER_BIENNIUM
;
381 if (overflow_threshold
< abs_diff
) {
382 /* Overflow occurred. Try repairing it; this might work if
383 the time zone offset is enough to undo the overflow. */
384 gtime_t repaired_t0
= -1 - t0
;
385 approx_biennia
= SHR(repaired_t0
, ALOG2_SECONDS_PER_BIENNIUM
);
386 diff
= approx_biennia
- approx_requested_biennia
;
387 abs_diff
= diff
< 0 ? -diff
: diff
;
388 if (overflow_threshold
< abs_diff
)
390 guessed_offset
+= repaired_t0
- t0
;
395 /* Repeatedly use the error to improve the guess. */
396 for (t
= t1
= t2
= t0
;
397 (gt
= guess_time_tm(year
, yday
, hour
, min
, sec
, &t
, ranged_convert(convert
, &t
, &tm
)), t
!= gt
);
398 t1
= t2
, t2
= t
, t
= gt
) {
399 if (t
== t1
&& t
!= t2
)
401 else if (--remaining_probes
== 0)
406 *offset
= guessed_offset
+ t
- t0
;
408 if (LEAP_SECONDS_POSSIBLE
&& sec_requested
!= tm
.tm_sec
) {
409 /* Adjust time to reflect the tm_sec requested, not the normalized value.
410 Also, repair any damage from a false match due to a leap second. */
411 int sec_adjustment
= (sec
== 0 && tm
.tm_sec
== 60) - sec
;
412 t1
= t
+ sec_requested
;
413 t2
= t1
+ sec_adjustment
;
414 if (((t1
< t
) != (sec_requested
< 0))
415 | ((t2
< t1
) != (sec_adjustment
< 0))
416 | !convert(&t2
, &tm
))
425 /* Convert *TP to a gtime_t value. */
426 gtime_t
gmktime(struct gtm
* tp
)
428 // no time zone stuff. Just do the math ;)
429 static gtime_t localtime_offset
;
430 return __mktime_internal(tp
, __localtime_r
, &localtime_offset
);
433 /* Fill a (struct tm) TP* from a given gtime_t time stamp */
434 gtime_t
filltm(const gtime_t
* t
, struct gtm
* tp
)
436 return __offtime(t
, 0, tp
);
440 uint8_t g_ms100
= 0; // global to allow time set function to reset to zero
442 void gettime(struct gtm
* tm
)
444 filltm(&g_rtcTime
, tm
); // create a struct tm date/time structure from global unix time stamp
447 void rtcGetTime(struct gtm
* t
);
449 #define RTC_ADJUST_PERIOD 60 // how often RTC is checked for accuracy [seconds]
450 #define RTC_ADJUST_TRESHOLD 20 // how much clock must differ before adjustment is made [seconds]
452 Changes RTC date/time to the given UTC date/time if:
453 * RTC_ADJUST_PERIOD seconds have elapsed from the last time this function adjusted the RTC clock
454 * AND if actual RTC clock differs from the given clock by more than RTC_ADJUST_TRESHOLD seconds
455 * Function does nothing for a minute around midnight, where date change could produce erroneous result
457 uint8_t rtcAdjust(uint16_t year
, uint8_t mon
, uint8_t day
, uint8_t hour
, uint8_t min
, uint8_t sec
)
459 static tmr10ms_t lastRtcAdjust
= 0;
460 if ((get_tmr10ms() - lastRtcAdjust
) > (RTC_ADJUST_PERIOD
* 100)) {
461 lastRtcAdjust
= get_tmr10ms();
463 if (year
== 0 || (hour
== 0 && min
== 0) || (hour
== 23 && min
== 59)) return 0;
465 // convert given UTC time to local time (to seconds) and compare it with RTC
467 t
.tm_year
= year
- TM_YEAR_BASE
;
473 gtime_t newTime
= gmktime(&t
) + g_eeGeneral
.timezone
* 3600;
474 gtime_t diff
= (g_rtcTime
> newTime
) ? (g_rtcTime
- newTime
) : (newTime
- g_rtcTime
);
476 #if defined(DEBUG) && defined (PCBTARANIS)
479 gtime_t rtcTime
= gmktime(&utm
);
480 TRACE("rtc: %d, grtc: %d, gps: %d, diff: %d, ", rtcTime
, g_rtcTime
, newTime
, diff
);
483 if (diff
> RTC_ADJUST_TRESHOLD
) {
484 // convert newTime to struct gtm and set RTC clock
485 filltm(&newTime
, &t
);
486 g_rtcTime
= gmktime(&t
); // update local timestamp and get wday calculated
488 TRACE("RTC clock adjusted to %04d-%02d-%02d %02d:%02d:%02d", year
, mon
, day
, hour
, min
, sec
);
489 // TODO perhaps some kind of audio notification ???