1*2d4e511cSCy Schubert /*
2*2d4e511cSCy Schubert * ntp_calgps.h - calendar for GPS/GNSS based clocks
3*2d4e511cSCy Schubert *
4*2d4e511cSCy Schubert * Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project.
5*2d4e511cSCy Schubert * The contents of 'html/copyright.html' apply.
6*2d4e511cSCy Schubert *
7*2d4e511cSCy Schubert * --------------------------------------------------------------------
8*2d4e511cSCy Schubert *
9*2d4e511cSCy Schubert * This module implements stuff often used with GPS/GNSS receivers
10*2d4e511cSCy Schubert */
11*2d4e511cSCy Schubert #ifndef NTP_CALGPS_H
12*2d4e511cSCy Schubert #define NTP_CALGPS_H
13*2d4e511cSCy Schubert
14*2d4e511cSCy Schubert #include <time.h>
15*2d4e511cSCy Schubert
16*2d4e511cSCy Schubert #include "ntp_types.h"
17*2d4e511cSCy Schubert #include "ntp_fp.h"
18*2d4e511cSCy Schubert #include "ntp_calendar.h"
19*2d4e511cSCy Schubert
20*2d4e511cSCy Schubert /* GPS week calendar (extended weeks)
21*2d4e511cSCy Schubert * We use weeks based on 1899-31-12, which was the last Sunday before
22*2d4e511cSCy Schubert * the begin of the NTP epoch. (Which is equivalent to saying 1900-01-01
23*2d4e511cSCy Schubert * was a Monday...)
24*2d4e511cSCy Schubert *
25*2d4e511cSCy Schubert * We simply pre-calculate the offsets and cycle shifts for the real GPS
26*2d4e511cSCy Schubert * calendar, which starts at 1980-01-06, to simplyfy some expressions.
27*2d4e511cSCy Schubert *
28*2d4e511cSCy Schubert * This has a fringe benefit that should not be overlooked: Since week zero
29*2d4e511cSCy Schubert * is around 1900, and we should never have to deal with dates before
30*2d4e511cSCy Schubert * 1970 or 1980, a week number of zero can be easily used to indicate
31*2d4e511cSCy Schubert * an invalid week time stamp.
32*2d4e511cSCy Schubert */
33*2d4e511cSCy Schubert #define GPSNTP_WSHIFT 4175 /* weeks 1899-31-12 --> 1980-01-06 */
34*2d4e511cSCy Schubert #define GPSNTP_WCYCLE 79 /* above, modulo 1024 */
35*2d4e511cSCy Schubert #define GPSNTP_DSHIFT 1 /* day number of 1900-01-01 in week */
36*2d4e511cSCy Schubert
37*2d4e511cSCy Schubert struct gpsdatum {
38*2d4e511cSCy Schubert uint32_t weeks; /* weeks since GPS epoch */
39*2d4e511cSCy Schubert int32_t wsecs; /* seconds since week start */
40*2d4e511cSCy Schubert uint32_t frac; /* fractional seconds */
41*2d4e511cSCy Schubert };
42*2d4e511cSCy Schubert typedef struct gpsdatum TGpsDatum;
43*2d4e511cSCy Schubert typedef struct gpsdatum const TcGpsDatum;
44*2d4e511cSCy Schubert
45*2d4e511cSCy Schubert /* NTP date/time in split representation */
46*2d4e511cSCy Schubert struct ntpdatum {
47*2d4e511cSCy Schubert uint32_t days; /* since NTP epoch */
48*2d4e511cSCy Schubert int32_t secs; /* since midnight, denorm is ok */
49*2d4e511cSCy Schubert uint32_t frac; /* fractional seconds */
50*2d4e511cSCy Schubert };
51*2d4e511cSCy Schubert typedef struct ntpdatum TNtpDatum;
52*2d4e511cSCy Schubert typedef struct ntpdatum const TcNtpDatum;
53*2d4e511cSCy Schubert
54*2d4e511cSCy Schubert /*
55*2d4e511cSCy Schubert * GPS week/sec calendar functions
56*2d4e511cSCy Schubert *
57*2d4e511cSCy Schubert * see the implementation for details, especially the
58*2d4e511cSCy Schubert * 'gpscal_from_weektime{1,2}()'
59*2d4e511cSCy Schubert */
60*2d4e511cSCy Schubert
61*2d4e511cSCy Schubert extern TGpsDatum
62*2d4e511cSCy Schubert gpscal_fix_gps_era(TcGpsDatum *);
63*2d4e511cSCy Schubert
64*2d4e511cSCy Schubert extern void
65*2d4e511cSCy Schubert gpscal_add_offset(TGpsDatum *datum, l_fp offset);
66*2d4e511cSCy Schubert
67*2d4e511cSCy Schubert extern TGpsDatum
68*2d4e511cSCy Schubert gpscal_from_calendar_ex(TcCivilDate*, l_fp fofs, int/*BOOL*/ warp);
69*2d4e511cSCy Schubert
70*2d4e511cSCy Schubert static inline TGpsDatum
gpscal_from_calendar(TcCivilDate * pCiv,l_fp fofs)71*2d4e511cSCy Schubert gpscal_from_calendar(TcCivilDate *pCiv, l_fp fofs) {
72*2d4e511cSCy Schubert return gpscal_from_calendar_ex(pCiv, fofs, TRUE);
73*2d4e511cSCy Schubert }
74*2d4e511cSCy Schubert
75*2d4e511cSCy Schubert extern TGpsDatum /* see source for semantic of the 'fofs' value! */
76*2d4e511cSCy Schubert gpscal_from_gpsweek(uint16_t w, int32_t s, l_fp fofs);
77*2d4e511cSCy Schubert
78*2d4e511cSCy Schubert extern TGpsDatum
79*2d4e511cSCy Schubert gpscal_from_weektime1(int32_t wsecs, l_fp fofs, l_fp pivot);
80*2d4e511cSCy Schubert
81*2d4e511cSCy Schubert extern TGpsDatum
82*2d4e511cSCy Schubert gpscal_from_weektime2(int32_t wsecs, l_fp fofs, TcGpsDatum *pivot);
83*2d4e511cSCy Schubert
84*2d4e511cSCy Schubert extern void
85*2d4e511cSCy Schubert gpscal_to_calendar(TCivilDate*, TcGpsDatum*);
86*2d4e511cSCy Schubert
87*2d4e511cSCy Schubert extern TGpsDatum
88*2d4e511cSCy Schubert gpscal_from_gpsntp(TcNtpDatum*);
89*2d4e511cSCy Schubert
90*2d4e511cSCy Schubert extern l_fp
91*2d4e511cSCy Schubert ntpfp_from_gpsdatum(TcGpsDatum *);
92*2d4e511cSCy Schubert
93*2d4e511cSCy Schubert /*
94*2d4e511cSCy Schubert * NTP day/sec calendar functions
95*2d4e511cSCy Schubert *
96*2d4e511cSCy Schubert * see the implementation for details, especially the
97*2d4e511cSCy Schubert * 'gpscal_from_daytime{1,2}()'
98*2d4e511cSCy Schubert */
99*2d4e511cSCy Schubert extern TNtpDatum
100*2d4e511cSCy Schubert gpsntp_fix_gps_era(TcNtpDatum *);
101*2d4e511cSCy Schubert
102*2d4e511cSCy Schubert extern void
103*2d4e511cSCy Schubert gpsntp_add_offset(TNtpDatum *datum, l_fp offset);
104*2d4e511cSCy Schubert
105*2d4e511cSCy Schubert extern TNtpDatum
106*2d4e511cSCy Schubert gpsntp_from_calendar_ex(TcCivilDate*, l_fp fofs, int/*BOOL*/ warp);
107*2d4e511cSCy Schubert
108*2d4e511cSCy Schubert static inline TNtpDatum
gpsntp_from_calendar(TcCivilDate * pCiv,l_fp fofs)109*2d4e511cSCy Schubert gpsntp_from_calendar(TcCivilDate * pCiv, l_fp fofs) {
110*2d4e511cSCy Schubert return gpsntp_from_calendar_ex(pCiv, fofs, TRUE);
111*2d4e511cSCy Schubert }
112*2d4e511cSCy Schubert
113*2d4e511cSCy Schubert extern TNtpDatum
114*2d4e511cSCy Schubert gpsntp_from_daytime1_ex(TcCivilDate *dt, l_fp fofs, l_fp pivot, int/*BOOL*/ warp);
115*2d4e511cSCy Schubert
116*2d4e511cSCy Schubert static inline TNtpDatum
gpsntp_from_daytime1(TcCivilDate * dt,l_fp fofs,l_fp pivot)117*2d4e511cSCy Schubert gpsntp_from_daytime1(TcCivilDate *dt, l_fp fofs, l_fp pivot) {
118*2d4e511cSCy Schubert return gpsntp_from_daytime1_ex(dt, fofs, pivot, TRUE);
119*2d4e511cSCy Schubert }
120*2d4e511cSCy Schubert
121*2d4e511cSCy Schubert extern TNtpDatum
122*2d4e511cSCy Schubert gpsntp_from_daytime2_ex(TcCivilDate *dt, l_fp fofs, TcNtpDatum *pivot, int/*BOOL*/ warp);
123*2d4e511cSCy Schubert
124*2d4e511cSCy Schubert static inline TNtpDatum
gpsntp_from_daytime2(TcCivilDate * dt,l_fp fofs,TcNtpDatum * pivot)125*2d4e511cSCy Schubert gpsntp_from_daytime2(TcCivilDate *dt, l_fp fofs, TcNtpDatum *pivot) {
126*2d4e511cSCy Schubert return gpsntp_from_daytime2_ex(dt, fofs, pivot, TRUE);
127*2d4e511cSCy Schubert }
128*2d4e511cSCy Schubert
129*2d4e511cSCy Schubert extern TNtpDatum
130*2d4e511cSCy Schubert gpsntp_from_gpscal_ex(TcGpsDatum*, int/*BOOL*/ warp);
131*2d4e511cSCy Schubert
132*2d4e511cSCy Schubert static inline TNtpDatum
gpsntp_from_gpscal(TcGpsDatum * wd)133*2d4e511cSCy Schubert gpsntp_from_gpscal(TcGpsDatum *wd) {
134*2d4e511cSCy Schubert return gpsntp_from_gpscal_ex(wd, FALSE);
135*2d4e511cSCy Schubert }
136*2d4e511cSCy Schubert
137*2d4e511cSCy Schubert extern void
138*2d4e511cSCy Schubert gpsntp_to_calendar(TCivilDate*, TcNtpDatum*);
139*2d4e511cSCy Schubert
140*2d4e511cSCy Schubert extern l_fp
141*2d4e511cSCy Schubert ntpfp_from_ntpdatum(TcNtpDatum*);
142*2d4e511cSCy Schubert
143*2d4e511cSCy Schubert /*
144*2d4e511cSCy Schubert * Some helpers
145*2d4e511cSCy Schubert */
146*2d4e511cSCy Schubert
147*2d4e511cSCy Schubert /* apply fudge to time stamp: *SUBTRACT* the given offset from an l_fp*/
148*2d4e511cSCy Schubert extern l_fp
149*2d4e511cSCy Schubert ntpfp_with_fudge(l_fp lfp, double ofs);
150*2d4e511cSCy Schubert
151*2d4e511cSCy Schubert #endif /*!defined(NTP_CALGPS_H)*/
152