1358616Scy/*
2358616Scy * ntp_calgps.h - calendar for GPS/GNSS based clocks
3358616Scy *
4358616Scy * Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project.
5358616Scy * The contents of 'html/copyright.html' apply.
6358616Scy *
7358616Scy * --------------------------------------------------------------------
8358616Scy *
9358616Scy * This module implements stuff often used with GPS/GNSS receivers
10358616Scy */
11358616Scy#ifndef NTP_CALGPS_H
12358616Scy#define NTP_CALGPS_H
13358616Scy
14358616Scy#include <time.h>
15358616Scy
16358616Scy#include "ntp_types.h"
17358616Scy#include "ntp_fp.h"
18358616Scy#include "ntp_calendar.h"
19358616Scy
20358616Scy/* GPS week calendar (extended weeks)
21358616Scy * We use weeks based on 1899-31-12, which was the last Sunday before
22358616Scy * the begin of the NTP epoch. (Which is equivalent to saying 1900-01-01
23358616Scy * was a Monday...)
24358616Scy *
25358616Scy * We simply pre-calculate the offsets and cycle shifts for the real GPS
26358616Scy * calendar, which starts at 1980-01-06, to simplyfy some expressions.
27358616Scy *
28358616Scy * This has a fringe benefit that should not be overlooked: Since week zero
29358616Scy * is around 1900, and we should never have to deal with dates before
30358616Scy * 1970 or 1980, a week number of zero can be easily used to indicate
31358616Scy * an invalid week time stamp.
32358616Scy */
33358616Scy#define GPSNTP_WSHIFT	4175	/* weeks 1899-31-12 --> 1980-01-06 */
34358616Scy#define GPSNTP_WCYCLE	  79	/* above, modulo 1024 */
35358616Scy#define GPSNTP_DSHIFT	   1	/* day number of 1900-01-01 in week */
36358616Scy
37358616Scystruct gpsdatum {
38358616Scy	uint32_t weeks;		/* weeks since GPS epoch	*/
39358616Scy	int32_t  wsecs;		/* seconds since week start	*/
40358616Scy	uint32_t frac;		/* fractional seconds		*/
41358616Scy};
42358616Scytypedef struct gpsdatum TGpsDatum;
43358616Scytypedef struct gpsdatum const TcGpsDatum;
44358616Scy
45358616Scy/* NTP date/time in split representation */
46358616Scystruct ntpdatum {
47358616Scy	uint32_t days;		/* since NTP epoch		*/
48358616Scy	int32_t  secs;		/* since midnight, denorm is ok */
49358616Scy	uint32_t frac;		/* fractional seconds		*/
50358616Scy};
51358616Scytypedef struct ntpdatum TNtpDatum;
52358616Scytypedef struct ntpdatum const TcNtpDatum;
53358616Scy
54358616Scy/*
55358616Scy * GPS week/sec calendar functions
56358616Scy *
57358616Scy * see the implementation for details, especially the
58358616Scy * 'gpscal_from_weektime{1,2}()'
59358616Scy */
60358616Scy
61358616Scyextern TGpsDatum
62358616Scygpscal_fix_gps_era(TcGpsDatum *);
63358616Scy
64358616Scyextern void
65358616Scygpscal_add_offset(TGpsDatum *datum, l_fp offset);
66358616Scy
67358616Scyextern TGpsDatum
68358616Scygpscal_from_calendar_ex(TcCivilDate*, l_fp fofs, int/*BOOL*/ warp);
69358616Scy
70358616Scystatic inline TGpsDatum
71358616Scygpscal_from_calendar(TcCivilDate *pCiv, l_fp fofs) {
72358616Scy    return gpscal_from_calendar_ex(pCiv, fofs, TRUE);
73358616Scy}
74358616Scy
75358616Scyextern TGpsDatum 	/* see source for semantic of the 'fofs' value! */
76358616Scygpscal_from_gpsweek(uint16_t w, int32_t s, l_fp fofs);
77358616Scy
78358616Scyextern TGpsDatum
79358616Scygpscal_from_weektime1(int32_t wsecs, l_fp fofs, l_fp pivot);
80358616Scy
81358616Scyextern TGpsDatum
82358616Scygpscal_from_weektime2(int32_t wsecs, l_fp fofs,	TcGpsDatum *pivot);
83358616Scy
84358616Scyextern void
85358616Scygpscal_to_calendar(TCivilDate*, TcGpsDatum*);
86358616Scy
87358616Scyextern TGpsDatum
88358616Scygpscal_from_gpsntp(TcNtpDatum*);
89358616Scy
90358616Scyextern l_fp
91358616Scyntpfp_from_gpsdatum(TcGpsDatum *);
92358616Scy
93358616Scy/*
94358616Scy * NTP day/sec calendar functions
95358616Scy *
96358616Scy * see the implementation for details, especially the
97358616Scy * 'gpscal_from_daytime{1,2}()'
98358616Scy */
99358616Scyextern TNtpDatum
100358616Scygpsntp_fix_gps_era(TcNtpDatum *);
101358616Scy
102358616Scyextern void
103358616Scygpsntp_add_offset(TNtpDatum *datum, l_fp offset);
104358616Scy
105358616Scyextern TNtpDatum
106358616Scygpsntp_from_calendar_ex(TcCivilDate*, l_fp fofs, int/*BOOL*/ warp);
107358616Scy
108358616Scystatic inline TNtpDatum
109358616Scygpsntp_from_calendar(TcCivilDate * pCiv, l_fp fofs) {
110358616Scy	return gpsntp_from_calendar_ex(pCiv, fofs, TRUE);
111358616Scy}
112358616Scy
113358616Scyextern TNtpDatum
114358616Scygpsntp_from_daytime1_ex(TcCivilDate *dt, l_fp fofs, l_fp pivot, int/*BOOL*/ warp);
115358616Scy
116358616Scystatic inline TNtpDatum
117358616Scygpsntp_from_daytime1(TcCivilDate *dt, l_fp fofs, l_fp pivot) {
118358616Scy	return gpsntp_from_daytime1_ex(dt, fofs, pivot, TRUE);
119358616Scy}
120358616Scy
121358616Scyextern TNtpDatum
122358616Scygpsntp_from_daytime2_ex(TcCivilDate *dt, l_fp fofs, TcNtpDatum *pivot, int/*BOOL*/ warp);
123358616Scy
124358616Scystatic inline TNtpDatum
125358616Scygpsntp_from_daytime2(TcCivilDate *dt, l_fp fofs, TcNtpDatum *pivot) {
126358616Scy	return gpsntp_from_daytime2_ex(dt, fofs, pivot, TRUE);
127358616Scy}
128358616Scy
129358616Scyextern TNtpDatum
130358616Scygpsntp_from_gpscal_ex(TcGpsDatum*, int/*BOOL*/ warp);
131358616Scy
132358616Scystatic inline TNtpDatum
133358616Scygpsntp_from_gpscal(TcGpsDatum *wd) {
134358616Scy	return gpsntp_from_gpscal_ex(wd, FALSE);
135358616Scy}
136358616Scy
137358616Scyextern void
138358616Scygpsntp_to_calendar(TCivilDate*, TcNtpDatum*);
139358616Scy
140358616Scyextern l_fp
141358616Scyntpfp_from_ntpdatum(TcNtpDatum*);
142358616Scy
143358616Scy/*
144358616Scy * Some helpers
145358616Scy */
146358616Scy
147358616Scy/* apply fudge to time stamp: *SUBTRACT* the given offset from an l_fp*/
148358616Scyextern l_fp
149358616Scyntpfp_with_fudge(l_fp lfp, double ofs);
150358616Scy
151358616Scy#endif /*!defined(NTP_CALGPS_H)*/
152