refclock_tsyncpci.c revision 1.2.2.3 1 1.2.2.3 snj /* $NetBSD: refclock_tsyncpci.c,v 1.2.2.3 2016/05/08 21:55:49 snj Exp $ */
2 1.2.2.2 snj
3 1.2.2.2 snj /*******************************************************************************
4 1.2.2.2 snj *
5 1.2.2.2 snj * Module : refclock_tsyncpci.c
6 1.2.2.2 snj * Date : 09/08/08
7 1.2.2.2 snj * Purpose : Implements a reference clock driver for the NTP daemon. This
8 1.2.2.2 snj * reference clock driver provides a means to communicate with
9 1.2.2.2 snj * the Spectracom TSYNC PCI timing devices and use them as a time
10 1.2.2.2 snj * source.
11 1.2.2.2 snj *
12 1.2.2.2 snj * (C) Copyright 2008 Spectracom Corporation
13 1.2.2.2 snj *
14 1.2.2.2 snj * This software is provided by Spectracom Corporation 'as is' and
15 1.2.2.2 snj * any express or implied warranties, including, but not limited to, the
16 1.2.2.2 snj * implied warranties of merchantability and fitness for a particular purpose
17 1.2.2.2 snj * are disclaimed. In no event shall Spectracom Corporation be liable
18 1.2.2.2 snj * for any direct, indirect, incidental, special, exemplary, or consequential
19 1.2.2.2 snj * damages (including, but not limited to, procurement of substitute goods
20 1.2.2.2 snj * or services; loss of use, data, or profits; or business interruption)
21 1.2.2.2 snj * however caused and on any theory of liability, whether in contract, strict
22 1.2.2.2 snj * liability, or tort (including negligence or otherwise) arising in any way
23 1.2.2.2 snj * out of the use of this software, even if advised of the possibility of
24 1.2.2.2 snj * such damage.
25 1.2.2.2 snj *
26 1.2.2.2 snj * This software is released for distribution according to the NTP copyright
27 1.2.2.2 snj * and license contained in html/copyright.html of NTP source.
28 1.2.2.2 snj *
29 1.2.2.2 snj *******************************************************************************/
30 1.2.2.2 snj #ifdef HAVE_CONFIG_H
31 1.2.2.2 snj #include <config.h>
32 1.2.2.2 snj #endif
33 1.2.2.2 snj
34 1.2.2.2 snj #if defined(REFCLOCK) && defined(CLOCK_TSYNCPCI)
35 1.2.2.2 snj
36 1.2.2.2 snj #include <asm/ioctl.h>
37 1.2.2.2 snj #ifdef HAVE_SYS_IOCTL_H
38 1.2.2.2 snj # include <sys/ioctl.h>
39 1.2.2.2 snj #endif
40 1.2.2.2 snj
41 1.2.2.2 snj #include <stdio.h>
42 1.2.2.2 snj #include <ctype.h>
43 1.2.2.2 snj #include <netinet/in.h>
44 1.2.2.2 snj
45 1.2.2.2 snj
46 1.2.2.2 snj #include "ntpd.h"
47 1.2.2.2 snj #include "ntp_io.h"
48 1.2.2.2 snj #include "ntp_refclock.h"
49 1.2.2.2 snj #include "ntp_unixtime.h"
50 1.2.2.2 snj #include "ntp_stdlib.h"
51 1.2.2.2 snj #include "ntp_calendar.h"
52 1.2.2.2 snj
53 1.2.2.2 snj
54 1.2.2.2 snj /*******************************************************************************
55 1.2.2.2 snj **
56 1.2.2.2 snj ** This driver supports the Spectracom TSYNC PCI GPS receiver. It requires
57 1.2.2.2 snj ** that the tsyncpci.o device driver be installed and loaded.
58 1.2.2.2 snj **
59 1.2.2.2 snj *******************************************************************************/
60 1.2.2.2 snj
61 1.2.2.2 snj #define TSYNC_PCI_REVISION "1.11"
62 1.2.2.2 snj
63 1.2.2.2 snj /*
64 1.2.2.2 snj ** TPRO interface definitions
65 1.2.2.2 snj */
66 1.2.2.2 snj #define DEVICE "/dev/tsyncpci" /* device name */
67 1.2.2.2 snj #define PRECISION (-20) /* precision assumed (1 us) */
68 1.2.2.2 snj #define DESCRIPTION "Spectracom TSYNC-PCI" /* WRU */
69 1.2.2.2 snj
70 1.2.2.2 snj #define SECONDS_1900_TO_1970 (2208988800U)
71 1.2.2.2 snj
72 1.2.2.2 snj #define TSYNC_REF_IID (0x2500) // SS CAI, REF IID
73 1.2.2.2 snj #define TSYNC_REF_DEST_ID (0x0001) // KTS Firmware
74 1.2.2.2 snj #define TSYNC_REF_IN_PYLD_OFF (0)
75 1.2.2.2 snj #define TSYNC_REF_IN_LEN (0)
76 1.2.2.2 snj #define TSYNC_REF_OUT_PYLD_OFF (0)
77 1.2.2.2 snj #define TSYNC_REF_OUT_LEN (8)
78 1.2.2.2 snj #define TSYNC_REF_MAX_OUT_LEN (16)
79 1.2.2.2 snj #define TSYNC_REF_PYLD_LEN (TSYNC_REF_IN_LEN + \
80 1.2.2.2 snj TSYNC_REF_MAX_OUT_LEN)
81 1.2.2.2 snj #define TSYNC_REF_LEN (4)
82 1.2.2.2 snj #define TSYNC_REF_LOCAL ("LOCL")
83 1.2.2.2 snj
84 1.2.2.2 snj #define TSYNC_TMSCL_IID (0x2301) // CS CAI, TIMESCALE IID
85 1.2.2.2 snj #define TSYNC_TMSCL_DEST_ID (0x0001) // KTS Firmware
86 1.2.2.2 snj #define TSYNC_TMSCL_IN_PYLD_OFF (0)
87 1.2.2.2 snj #define TSYNC_TMSCL_IN_LEN (0)
88 1.2.2.2 snj #define TSYNC_TMSCL_OUT_PYLD_OFF (0)
89 1.2.2.2 snj #define TSYNC_TMSCL_OUT_LEN (4)
90 1.2.2.2 snj #define TSYNC_TMSCL_MAX_OUT_LEN (12)
91 1.2.2.2 snj #define TSYNC_TMSCL_PYLD_LEN (TSYNC_TMSCL_IN_LEN + \
92 1.2.2.2 snj TSYNC_TMSCL_MAX_OUT_LEN)
93 1.2.2.2 snj
94 1.2.2.2 snj #define TSYNC_LEAP_IID (0x2307) // CS CAI, LEAP SEC IID
95 1.2.2.2 snj #define TSYNC_LEAP_DEST_ID (0x0001) // KTS Firmware
96 1.2.2.2 snj #define TSYNC_LEAP_IN_PYLD_OFF (0)
97 1.2.2.2 snj #define TSYNC_LEAP_IN_LEN (0)
98 1.2.2.2 snj #define TSYNC_LEAP_OUT_PYLD_OFF (0)
99 1.2.2.2 snj #define TSYNC_LEAP_OUT_LEN (28)
100 1.2.2.2 snj #define TSYNC_LEAP_MAX_OUT_LEN (36)
101 1.2.2.2 snj #define TSYNC_LEAP_PYLD_LEN (TSYNC_LEAP_IN_LEN + \
102 1.2.2.2 snj TSYNC_LEAP_MAX_OUT_LEN)
103 1.2.2.2 snj
104 1.2.2.2 snj // These define the base date/time of the system clock. The system time will
105 1.2.2.2 snj // be tracked as the number of seconds from this date/time.
106 1.2.2.2 snj #define TSYNC_TIME_BASE_YEAR (1970) // earliest acceptable year
107 1.2.2.2 snj
108 1.2.2.2 snj #define TSYNC_LCL_STRATUM (0)
109 1.2.2.2 snj
110 1.2.2.2 snj /*
111 1.2.2.2 snj ** TSYNC Time Scales type
112 1.2.2.2 snj */
113 1.2.2.2 snj typedef enum
114 1.2.2.2 snj {
115 1.2.2.2 snj TIME_SCALE_UTC = 0, // Universal Coordinated Time
116 1.2.2.2 snj TIME_SCALE_TAI = 1, // International Atomic Time
117 1.2.2.2 snj TIME_SCALE_GPS = 2, // Global Positioning System
118 1.2.2.2 snj TIME_SCALE_LOCAL = 3, // UTC w/local rules for time zone and DST
119 1.2.2.2 snj NUM_TIME_SCALES = 4, // Number of time scales
120 1.2.2.2 snj
121 1.2.2.2 snj TIME_SCALE_MAX = 15 // Maximum number of timescales
122 1.2.2.2 snj
123 1.2.2.2 snj } TIME_SCALE;
124 1.2.2.2 snj
125 1.2.2.2 snj /*
126 1.2.2.2 snj ** TSYNC Board Object
127 1.2.2.2 snj */
128 1.2.2.2 snj typedef struct BoardObj {
129 1.2.2.2 snj
130 1.2.2.2 snj int file_descriptor;
131 1.2.2.2 snj unsigned short devid;
132 1.2.2.2 snj unsigned short options;
133 1.2.2.2 snj unsigned char firmware[5];
134 1.2.2.2 snj unsigned char FPGA[5];
135 1.2.2.2 snj unsigned char driver[7];
136 1.2.2.2 snj
137 1.2.2.2 snj } BoardObj;
138 1.2.2.2 snj
139 1.2.2.2 snj /*
140 1.2.2.2 snj ** TSYNC Time Object
141 1.2.2.2 snj */
142 1.2.2.2 snj typedef struct TimeObj {
143 1.2.2.2 snj
144 1.2.2.2 snj unsigned char syncOption; /* -M option */
145 1.2.2.2 snj unsigned int secsDouble; /* seconds floating pt */
146 1.2.2.2 snj unsigned char seconds; /* seconds whole num */
147 1.2.2.2 snj unsigned char minutes;
148 1.2.2.2 snj unsigned char hours;
149 1.2.2.2 snj unsigned short days;
150 1.2.2.2 snj unsigned short year;
151 1.2.2.2 snj unsigned short flags; /* bit 2 SYNC, bit 1 TCODE; all others 0 */
152 1.2.2.2 snj
153 1.2.2.2 snj } TimeObj;
154 1.2.2.2 snj
155 1.2.2.2 snj /*
156 1.2.2.2 snj ** NTP Time Object
157 1.2.2.2 snj */
158 1.2.2.2 snj typedef struct NtpTimeObj {
159 1.2.2.2 snj
160 1.2.2.2 snj TimeObj timeObj;
161 1.2.2.2 snj struct timeval tv;
162 1.2.2.2 snj unsigned int refId;
163 1.2.2.2 snj
164 1.2.2.2 snj } NtpTimeObj;
165 1.2.2.2 snj /*
166 1.2.2.2 snj ** TSYNC Supervisor Reference Object
167 1.2.2.2 snj */
168 1.2.2.2 snj typedef struct ReferenceObj {
169 1.2.2.2 snj
170 1.2.2.2 snj char time[TSYNC_REF_LEN];
171 1.2.2.2 snj char pps[TSYNC_REF_LEN];
172 1.2.2.2 snj
173 1.2.2.2 snj } ReferenceObj;
174 1.2.2.2 snj
175 1.2.2.2 snj /*
176 1.2.2.2 snj ** TSYNC Seconds Time Object
177 1.2.2.2 snj */
178 1.2.2.2 snj typedef struct SecTimeObj
179 1.2.2.2 snj {
180 1.2.2.2 snj unsigned int seconds;
181 1.2.2.2 snj unsigned int ns;
182 1.2.2.2 snj }
183 1.2.2.2 snj SecTimeObj;
184 1.2.2.2 snj
185 1.2.2.2 snj /*
186 1.2.2.2 snj ** TSYNC DOY Time Object
187 1.2.2.2 snj */
188 1.2.2.2 snj typedef struct DoyTimeObj
189 1.2.2.2 snj {
190 1.2.2.2 snj unsigned int year;
191 1.2.2.2 snj unsigned int doy;
192 1.2.2.2 snj unsigned int hour;
193 1.2.2.2 snj unsigned int minute;
194 1.2.2.2 snj unsigned int second;
195 1.2.2.2 snj unsigned int ns;
196 1.2.2.2 snj }
197 1.2.2.2 snj DoyTimeObj;
198 1.2.2.2 snj
199 1.2.2.2 snj /*
200 1.2.2.2 snj ** TSYNC Leap Second Object
201 1.2.2.2 snj */
202 1.2.2.2 snj typedef struct LeapSecondObj
203 1.2.2.2 snj {
204 1.2.2.2 snj int offset;
205 1.2.2.2 snj DoyTimeObj utcDate;
206 1.2.2.2 snj }
207 1.2.2.2 snj LeapSecondObj;
208 1.2.2.2 snj
209 1.2.2.2 snj /*
210 1.2.2.2 snj * structures for ioctl interactions with driver
211 1.2.2.2 snj */
212 1.2.2.2 snj #define DI_PAYLOADS_STARTER_LENGTH 4
213 1.2.2.2 snj typedef struct ioctl_trans_di {
214 1.2.2.2 snj
215 1.2.2.2 snj // input parameters
216 1.2.2.2 snj uint16_t dest;
217 1.2.2.2 snj uint16_t iid;
218 1.2.2.2 snj
219 1.2.2.2 snj uint32_t inPayloadOffset;
220 1.2.2.2 snj uint32_t inLength;
221 1.2.2.2 snj uint32_t outPayloadOffset;
222 1.2.2.2 snj uint32_t maxOutLength;
223 1.2.2.2 snj
224 1.2.2.2 snj // output parameters
225 1.2.2.2 snj uint32_t actualOutLength;
226 1.2.2.2 snj int32_t status;
227 1.2.2.2 snj
228 1.2.2.2 snj // Input and output
229 1.2.2.2 snj
230 1.2.2.2 snj // The payloads field MUST be last in ioctl_trans_di.
231 1.2.2.2 snj uint8_t payloads[DI_PAYLOADS_STARTER_LENGTH];
232 1.2.2.2 snj
233 1.2.2.2 snj }ioctl_trans_di;
234 1.2.2.2 snj
235 1.2.2.2 snj /*
236 1.2.2.2 snj * structure for looking up a reference ID from a reference name
237 1.2.2.2 snj */
238 1.2.2.2 snj typedef struct
239 1.2.2.2 snj {
240 1.2.2.2 snj const char* pRef; // KTS Reference Name
241 1.2.2.2 snj const char* pRefId; // NTP Reference ID
242 1.2.2.2 snj
243 1.2.2.2 snj } RefIdLookup;
244 1.2.2.2 snj
245 1.2.2.2 snj /*
246 1.2.2.2 snj * unit control structure
247 1.2.2.2 snj */
248 1.2.2.2 snj typedef struct {
249 1.2.2.2 snj uint32_t refPrefer; // Reference prefer flag
250 1.2.2.2 snj uint32_t refId; // Host peer reference ID
251 1.2.2.2 snj uint8_t refStratum; // Host peer reference stratum
252 1.2.2.2 snj
253 1.2.2.2 snj } TsyncUnit;
254 1.2.2.2 snj
255 1.2.2.2 snj /*
256 1.2.2.2 snj ** Function prototypes
257 1.2.2.2 snj */
258 1.2.2.2 snj static void tsync_poll (int unit, struct peer *);
259 1.2.2.2 snj static void tsync_shutdown (int, struct peer *);
260 1.2.2.2 snj static int tsync_start (int, struct peer *);
261 1.2.2.2 snj
262 1.2.2.2 snj /*
263 1.2.2.2 snj ** Helper functions
264 1.2.2.2 snj */
265 1.2.2.2 snj static void ApplyTimeOffset (DoyTimeObj* pDt, int off);
266 1.2.2.2 snj static void SecTimeFromDoyTime (SecTimeObj* pSt, DoyTimeObj* pDt);
267 1.2.2.2 snj static void DoyTimeFromSecTime (DoyTimeObj* pDt, SecTimeObj* pSt);
268 1.2.2.2 snj
269 1.2.2.2 snj /*
270 1.2.2.2 snj ** Transfer vector
271 1.2.2.2 snj */
272 1.2.2.2 snj struct refclock refclock_tsyncpci = {
273 1.2.2.2 snj tsync_start, /* start up driver */
274 1.2.2.2 snj tsync_shutdown, /* shut down driver */
275 1.2.2.2 snj tsync_poll, /* transmit poll message */
276 1.2.2.2 snj noentry, /* not used (old tsync_control) */
277 1.2.2.2 snj noentry, /* initialize driver (not used) */
278 1.2.2.2 snj noentry, /* not used (old tsync_buginfo) */
279 1.2.2.2 snj NOFLAGS /* not used */
280 1.2.2.2 snj };
281 1.2.2.2 snj
282 1.2.2.2 snj /*
283 1.2.2.2 snj * Reference ID lookup table
284 1.2.2.2 snj */
285 1.2.2.2 snj static RefIdLookup RefIdLookupTbl[] =
286 1.2.2.2 snj {
287 1.2.2.2 snj {"gps", "GPS"},
288 1.2.2.2 snj {"ir", "IRIG"},
289 1.2.2.2 snj {"hvq", "HVQ"},
290 1.2.2.2 snj {"frq", "FREQ"},
291 1.2.2.2 snj {"mdm", "ACTS"},
292 1.2.2.2 snj {"epp", "PPS"},
293 1.2.2.2 snj {"ptp", "PTP"},
294 1.2.2.2 snj {"asc", "ATC"},
295 1.2.2.2 snj {"hst0", "USER"},
296 1.2.2.2 snj {"hst", TSYNC_REF_LOCAL},
297 1.2.2.2 snj {"self", TSYNC_REF_LOCAL},
298 1.2.2.2 snj {NULL, NULL}
299 1.2.2.2 snj };
300 1.2.2.2 snj
301 1.2.2.2 snj /*******************************************************************************
302 1.2.2.2 snj ** IOCTL DEFINITIONS
303 1.2.2.2 snj *******************************************************************************/
304 1.2.2.2 snj #define IOCTL_TPRO_ID 't'
305 1.2.2.2 snj #define IOCTL_TPRO_OPEN _IOWR(IOCTL_TPRO_ID, 0, BoardObj)
306 1.2.2.2 snj #define IOCTL_TPRO_GET_NTP_TIME _IOWR(IOCTL_TPRO_ID, 25, NtpTimeObj)
307 1.2.2.2 snj #define IOCTL_TSYNC_GET _IOWR(IOCTL_TPRO_ID, 26, ioctl_trans_di)
308 1.2.2.2 snj
309 1.2.2.2 snj /******************************************************************************
310 1.2.2.2 snj *
311 1.2.2.2 snj * Function: tsync_start()
312 1.2.2.2 snj * Description: Used to intialize the Spectracom TSYNC reference driver.
313 1.2.2.2 snj *
314 1.2.2.2 snj * Parameters:
315 1.2.2.2 snj * IN: unit - not used.
316 1.2.2.2 snj * *peer - pointer to this reference clock's peer structure
317 1.2.2.2 snj * Returns: 0 - unsuccessful
318 1.2.2.2 snj * 1 - successful
319 1.2.2.2 snj *
320 1.2.2.2 snj *******************************************************************************/
321 1.2.2.2 snj static int tsync_start(int unit, struct peer *peer)
322 1.2.2.2 snj {
323 1.2.2.2 snj struct refclockproc *pp;
324 1.2.2.2 snj TsyncUnit *up;
325 1.2.2.2 snj
326 1.2.2.2 snj
327 1.2.2.2 snj /*
328 1.2.2.2 snj ** initialize reference clock and peer parameters
329 1.2.2.2 snj */
330 1.2.2.2 snj pp = peer->procptr;
331 1.2.2.2 snj pp->clockdesc = DESCRIPTION;
332 1.2.2.2 snj pp->io.clock_recv = noentry;
333 1.2.2.2 snj pp->io.srcclock = peer;
334 1.2.2.2 snj pp->io.datalen = 0;
335 1.2.2.2 snj peer->precision = PRECISION;
336 1.2.2.2 snj
337 1.2.2.2 snj // Allocate and initialize unit structure
338 1.2.2.2 snj if (!(up = (TsyncUnit*)emalloc(sizeof(TsyncUnit))))
339 1.2.2.2 snj {
340 1.2.2.2 snj return (0);
341 1.2.2.2 snj }
342 1.2.2.2 snj
343 1.2.2.2 snj // Store reference preference
344 1.2.2.2 snj up->refPrefer = peer->flags & FLAG_PREFER;
345 1.2.2.2 snj
346 1.2.2.2 snj // Initialize reference stratum level and ID
347 1.2.2.2 snj up->refStratum = STRATUM_UNSPEC;
348 1.2.2.2 snj strncpy((char *)&up->refId, TSYNC_REF_LOCAL, TSYNC_REF_LEN);
349 1.2.2.2 snj
350 1.2.2.2 snj // Attach unit structure
351 1.2.2.2 snj pp->unitptr = (caddr_t)up;
352 1.2.2.2 snj
353 1.2.2.2 snj /* Declare our refId as local in the beginning because we do not know
354 1.2.2.2 snj * what our actual refid is yet.
355 1.2.2.2 snj */
356 1.2.2.2 snj strncpy((char *)&pp->refid, TSYNC_REF_LOCAL, TSYNC_REF_LEN);
357 1.2.2.2 snj
358 1.2.2.2 snj return (1);
359 1.2.2.2 snj
360 1.2.2.2 snj } /* End - tsync_start() */
361 1.2.2.2 snj
362 1.2.2.2 snj /*******************************************************************************
363 1.2.2.2 snj **
364 1.2.2.2 snj ** Function: tsync_shutdown()
365 1.2.2.2 snj ** Description: Handles anything related to shutting down the reference clock
366 1.2.2.2 snj ** driver. Nothing at this point in time.
367 1.2.2.2 snj **
368 1.2.2.2 snj ** Parameters:
369 1.2.2.2 snj ** IN: unit - not used.
370 1.2.2.2 snj ** *peer - pointer to this reference clock's peer structure
371 1.2.2.2 snj ** Returns: none.
372 1.2.2.2 snj **
373 1.2.2.2 snj *******************************************************************************/
374 1.2.2.2 snj static void tsync_shutdown(int unit, struct peer *peer)
375 1.2.2.2 snj {
376 1.2.2.2 snj
377 1.2.2.2 snj } /* End - tsync_shutdown() */
378 1.2.2.2 snj
379 1.2.2.2 snj /******************************************************************************
380 1.2.2.2 snj *
381 1.2.2.2 snj * Function: tsync_poll()
382 1.2.2.2 snj * Description: Retrieve time from the TSYNC device.
383 1.2.2.2 snj *
384 1.2.2.2 snj * Parameters:
385 1.2.2.2 snj * IN: unit - not used.
386 1.2.2.2 snj * *peer - pointer to this reference clock's peer structure
387 1.2.2.2 snj * Returns: none.
388 1.2.2.2 snj *
389 1.2.2.2 snj *******************************************************************************/
390 1.2.2.2 snj static void tsync_poll(int unit, struct peer *peer)
391 1.2.2.2 snj {
392 1.2.2.2 snj char device[32];
393 1.2.2.2 snj struct refclockproc *pp;
394 1.2.2.2 snj struct calendar jt;
395 1.2.2.2 snj TsyncUnit *up;
396 1.2.2.2 snj unsigned char synch;
397 1.2.2.2 snj double seconds;
398 1.2.2.2 snj int err;
399 1.2.2.2 snj int err1;
400 1.2.2.2 snj int err2;
401 1.2.2.2 snj int err3;
402 1.2.2.2 snj int i;
403 1.2.2.2 snj int j;
404 1.2.2.2 snj unsigned int itAllocationLength;
405 1.2.2.2 snj unsigned int itAllocationLength1;
406 1.2.2.2 snj unsigned int itAllocationLength2;
407 1.2.2.2 snj NtpTimeObj TimeContext;
408 1.2.2.2 snj BoardObj hBoard;
409 1.2.2.2 snj char timeRef[TSYNC_REF_LEN + 1];
410 1.2.2.2 snj char ppsRef [TSYNC_REF_LEN + 1];
411 1.2.2.2 snj TIME_SCALE tmscl = TIME_SCALE_UTC;
412 1.2.2.2 snj LeapSecondObj leapSec;
413 1.2.2.2 snj ioctl_trans_di *it;
414 1.2.2.2 snj ioctl_trans_di *it1;
415 1.2.2.2 snj ioctl_trans_di *it2;
416 1.2.2.2 snj l_fp offset;
417 1.2.2.2 snj l_fp ltemp;
418 1.2.2.2 snj ReferenceObj * pRefObj;
419 1.2.2.2 snj
420 1.2.2.2 snj
421 1.2.2.2 snj /* Construct the device name */
422 1.2.2.2 snj sprintf(device, "%s%d", DEVICE, (int)peer->refclkunit);
423 1.2.2.2 snj
424 1.2.2.2 snj printf("Polling device number %d...\n", (int)peer->refclkunit);
425 1.2.2.2 snj
426 1.2.2.2 snj /* Open the TSYNC device */
427 1.2.2.2 snj hBoard.file_descriptor = open(device, O_RDONLY | O_NDELAY, 0777);
428 1.2.2.2 snj
429 1.2.2.2 snj /* If error opening TSYNC device... */
430 1.2.2.2 snj if (hBoard.file_descriptor < 0)
431 1.2.2.2 snj {
432 1.2.2.2 snj msyslog(LOG_ERR, "Couldn't open device");
433 1.2.2.2 snj return;
434 1.2.2.2 snj }
435 1.2.2.2 snj
436 1.2.2.2 snj /* If error while initializing the board... */
437 1.2.2.2 snj if (ioctl(hBoard.file_descriptor, IOCTL_TPRO_OPEN, &hBoard) < 0)
438 1.2.2.2 snj {
439 1.2.2.2 snj msyslog(LOG_ERR, "Couldn't initialize device");
440 1.2.2.2 snj close(hBoard.file_descriptor);
441 1.2.2.2 snj return;
442 1.2.2.2 snj }
443 1.2.2.2 snj
444 1.2.2.2 snj /* Allocate memory for ioctl message */
445 1.2.2.2 snj itAllocationLength =
446 1.2.2.2 snj (sizeof(ioctl_trans_di) - DI_PAYLOADS_STARTER_LENGTH) +
447 1.2.2.2 snj TSYNC_REF_IN_LEN + TSYNC_REF_MAX_OUT_LEN;
448 1.2.2.2 snj
449 1.2.2.2 snj it = (ioctl_trans_di*)alloca(itAllocationLength);
450 1.2.2.2 snj if (it == NULL) {
451 1.2.2.2 snj msyslog(LOG_ERR, "Couldn't allocate transaction memory - Reference");
452 1.2.2.2 snj return;
453 1.2.2.2 snj }
454 1.2.2.2 snj
455 1.2.2.2 snj /* Build SS_GetRef ioctl message */
456 1.2.2.2 snj it->dest = TSYNC_REF_DEST_ID;
457 1.2.2.2 snj it->iid = TSYNC_REF_IID;
458 1.2.2.2 snj it->inPayloadOffset = TSYNC_REF_IN_PYLD_OFF;
459 1.2.2.2 snj it->inLength = TSYNC_REF_IN_LEN;
460 1.2.2.2 snj it->outPayloadOffset = TSYNC_REF_OUT_PYLD_OFF;
461 1.2.2.2 snj it->maxOutLength = TSYNC_REF_MAX_OUT_LEN;
462 1.2.2.2 snj it->actualOutLength = 0;
463 1.2.2.2 snj it->status = 0;
464 1.2.2.2 snj memset(it->payloads, 0, TSYNC_REF_MAX_OUT_LEN);
465 1.2.2.2 snj
466 1.2.2.2 snj /* Read the reference from the TSYNC-PCI device */
467 1.2.2.2 snj err = ioctl(hBoard.file_descriptor,
468 1.2.2.2 snj IOCTL_TSYNC_GET,
469 1.2.2.2 snj (char *)it);
470 1.2.2.2 snj
471 1.2.2.2 snj /* Allocate memory for ioctl message */
472 1.2.2.2 snj itAllocationLength1 =
473 1.2.2.2 snj (sizeof(ioctl_trans_di) - DI_PAYLOADS_STARTER_LENGTH) +
474 1.2.2.2 snj TSYNC_TMSCL_IN_LEN + TSYNC_TMSCL_MAX_OUT_LEN;
475 1.2.2.2 snj
476 1.2.2.2 snj it1 = (ioctl_trans_di*)alloca(itAllocationLength1);
477 1.2.2.2 snj if (it1 == NULL) {
478 1.2.2.2 snj msyslog(LOG_ERR, "Couldn't allocate transaction memory - Time Scale");
479 1.2.2.2 snj return;
480 1.2.2.2 snj }
481 1.2.2.2 snj
482 1.2.2.2 snj /* Build CS_GetTimeScale ioctl message */
483 1.2.2.2 snj it1->dest = TSYNC_TMSCL_DEST_ID;
484 1.2.2.2 snj it1->iid = TSYNC_TMSCL_IID;
485 1.2.2.2 snj it1->inPayloadOffset = TSYNC_TMSCL_IN_PYLD_OFF;
486 1.2.2.2 snj it1->inLength = TSYNC_TMSCL_IN_LEN;
487 1.2.2.2 snj it1->outPayloadOffset = TSYNC_TMSCL_OUT_PYLD_OFF;
488 1.2.2.2 snj it1->maxOutLength = TSYNC_TMSCL_MAX_OUT_LEN;
489 1.2.2.2 snj it1->actualOutLength = 0;
490 1.2.2.2 snj it1->status = 0;
491 1.2.2.2 snj memset(it1->payloads, 0, TSYNC_TMSCL_MAX_OUT_LEN);
492 1.2.2.2 snj
493 1.2.2.2 snj /* Read the Time Scale info from the TSYNC-PCI device */
494 1.2.2.2 snj err1 = ioctl(hBoard.file_descriptor,
495 1.2.2.2 snj IOCTL_TSYNC_GET,
496 1.2.2.2 snj (char *)it1);
497 1.2.2.2 snj
498 1.2.2.2 snj /* Allocate memory for ioctl message */
499 1.2.2.2 snj itAllocationLength2 =
500 1.2.2.2 snj (sizeof(ioctl_trans_di) - DI_PAYLOADS_STARTER_LENGTH) +
501 1.2.2.2 snj TSYNC_LEAP_IN_LEN + TSYNC_LEAP_MAX_OUT_LEN;
502 1.2.2.2 snj
503 1.2.2.2 snj it2 = (ioctl_trans_di*)alloca(itAllocationLength2);
504 1.2.2.2 snj if (it2 == NULL) {
505 1.2.2.2 snj msyslog(LOG_ERR, "Couldn't allocate transaction memory - Leap Second");
506 1.2.2.2 snj return;
507 1.2.2.2 snj }
508 1.2.2.2 snj
509 1.2.2.2 snj /* Build CS_GetLeapSec ioctl message */
510 1.2.2.2 snj it2->dest = TSYNC_LEAP_DEST_ID;
511 1.2.2.2 snj it2->iid = TSYNC_LEAP_IID;
512 1.2.2.2 snj it2->inPayloadOffset = TSYNC_LEAP_IN_PYLD_OFF;
513 1.2.2.2 snj it2->inLength = TSYNC_LEAP_IN_LEN;
514 1.2.2.2 snj it2->outPayloadOffset = TSYNC_LEAP_OUT_PYLD_OFF;
515 1.2.2.2 snj it2->maxOutLength = TSYNC_LEAP_MAX_OUT_LEN;
516 1.2.2.2 snj it2->actualOutLength = 0;
517 1.2.2.2 snj it2->status = 0;
518 1.2.2.2 snj memset(it2->payloads, 0, TSYNC_LEAP_MAX_OUT_LEN);
519 1.2.2.2 snj
520 1.2.2.2 snj /* Read the leap seconds info from the TSYNC-PCI device */
521 1.2.2.2 snj err2 = ioctl(hBoard.file_descriptor,
522 1.2.2.2 snj IOCTL_TSYNC_GET,
523 1.2.2.2 snj (char *)it2);
524 1.2.2.2 snj
525 1.2.2.2 snj pp = peer->procptr;
526 1.2.2.2 snj up = (TsyncUnit*)pp->unitptr;
527 1.2.2.2 snj
528 1.2.2.2 snj /* Read the time from the TSYNC-PCI device */
529 1.2.2.2 snj err3 = ioctl(hBoard.file_descriptor,
530 1.2.2.2 snj IOCTL_TPRO_GET_NTP_TIME,
531 1.2.2.2 snj (char *)&TimeContext);
532 1.2.2.2 snj
533 1.2.2.2 snj /* Close the TSYNC device */
534 1.2.2.2 snj close(hBoard.file_descriptor);
535 1.2.2.2 snj
536 1.2.2.2 snj // Check for errors
537 1.2.2.2 snj if ((err < 0) ||(err1 < 0) || (err2 < 0) || (err3 < 0) ||
538 1.2.2.2 snj (it->status != 0) || (it1->status != 0) || (it2->status != 0) ||
539 1.2.2.2 snj (it->actualOutLength != TSYNC_REF_OUT_LEN) ||
540 1.2.2.2 snj (it1->actualOutLength != TSYNC_TMSCL_OUT_LEN) ||
541 1.2.2.2 snj (it2->actualOutLength != TSYNC_LEAP_OUT_LEN)) {
542 1.2.2.2 snj refclock_report(peer, CEVNT_FAULT);
543 1.2.2.2 snj return;
544 1.2.2.2 snj }
545 1.2.2.2 snj
546 1.2.2.2 snj // Extract reference identifiers from ioctl payload
547 1.2.2.2 snj memset(timeRef, '\0', sizeof(timeRef));
548 1.2.2.2 snj memset(ppsRef, '\0', sizeof(ppsRef));
549 1.2.2.2 snj pRefObj = (void *)it->payloads;
550 1.2.2.2 snj memcpy(timeRef, pRefObj->time, TSYNC_REF_LEN);
551 1.2.2.2 snj memcpy(ppsRef, pRefObj->pps, TSYNC_REF_LEN);
552 1.2.2.2 snj
553 1.2.2.2 snj // Extract the Clock Service Time Scale and convert to correct byte order
554 1.2.2.3 snj memcpy(&tmscl, it1->payloads, sizeof(tmscl));
555 1.2.2.2 snj tmscl = ntohl(tmscl);
556 1.2.2.2 snj
557 1.2.2.2 snj // Extract leap second info from ioctl payload and perform byte swapping
558 1.2.2.2 snj for (i = 0; i < (sizeof(leapSec) / 4); i++)
559 1.2.2.2 snj {
560 1.2.2.2 snj for (j = 0; j < 4; j++)
561 1.2.2.2 snj {
562 1.2.2.2 snj ((unsigned char*)&leapSec)[(i * 4) + j] =
563 1.2.2.2 snj ((unsigned char*)(it2->payloads))[(i * 4) + (3 - j)];
564 1.2.2.2 snj }
565 1.2.2.2 snj }
566 1.2.2.2 snj
567 1.2.2.2 snj // Determine time reference ID from reference name
568 1.2.2.2 snj for (i = 0; RefIdLookupTbl[i].pRef != NULL; i++)
569 1.2.2.2 snj {
570 1.2.2.2 snj // Search RefID table
571 1.2.2.2 snj if (strstr(timeRef, RefIdLookupTbl[i].pRef) != NULL)
572 1.2.2.2 snj {
573 1.2.2.2 snj // Found the matching string
574 1.2.2.2 snj break;
575 1.2.2.2 snj }
576 1.2.2.2 snj }
577 1.2.2.2 snj
578 1.2.2.2 snj // Determine pps reference ID from reference name
579 1.2.2.2 snj for (j = 0; RefIdLookupTbl[j].pRef != NULL; j++)
580 1.2.2.2 snj {
581 1.2.2.2 snj // Search RefID table
582 1.2.2.2 snj if (strstr(ppsRef, RefIdLookupTbl[j].pRef) != NULL)
583 1.2.2.2 snj {
584 1.2.2.2 snj // Found the matching string
585 1.2.2.2 snj break;
586 1.2.2.2 snj }
587 1.2.2.2 snj }
588 1.2.2.2 snj
589 1.2.2.2 snj // Determine synchronization state from flags
590 1.2.2.2 snj synch = (TimeContext.timeObj.flags == 0x4) ? 1 : 0;
591 1.2.2.2 snj
592 1.2.2.2 snj // Pull seconds information from time object
593 1.2.2.2 snj seconds = (double) (TimeContext.timeObj.secsDouble);
594 1.2.2.2 snj seconds /= (double) 1000000.0;
595 1.2.2.2 snj
596 1.2.2.2 snj /*
597 1.2.2.2 snj ** Convert the number of microseconds to double and then place in the
598 1.2.2.2 snj ** peer's last received long floating point format.
599 1.2.2.2 snj */
600 1.2.2.2 snj DTOLFP(((double)TimeContext.tv.tv_usec / 1000000.0), &pp->lastrec);
601 1.2.2.2 snj
602 1.2.2.2 snj /*
603 1.2.2.2 snj ** The specTimeStamp is the number of seconds since 1/1/1970, while the
604 1.2.2.2 snj ** peer's lastrec time should be compatible with NTP which is seconds since
605 1.2.2.2 snj ** 1/1/1900. So Add the number of seconds between 1900 and 1970 to the
606 1.2.2.2 snj ** specTimeStamp and place in the peer's lastrec long floating point struct.
607 1.2.2.2 snj */
608 1.2.2.2 snj pp->lastrec.Ul_i.Xl_ui += (unsigned int)TimeContext.tv.tv_sec +
609 1.2.2.2 snj SECONDS_1900_TO_1970;
610 1.2.2.2 snj
611 1.2.2.2 snj pp->polls++;
612 1.2.2.2 snj
613 1.2.2.2 snj /*
614 1.2.2.2 snj ** set the reference clock object
615 1.2.2.2 snj */
616 1.2.2.2 snj sprintf(pp->a_lastcode, "%03d %02d:%02d:%02.6f",
617 1.2.2.2 snj TimeContext.timeObj.days, TimeContext.timeObj.hours,
618 1.2.2.2 snj TimeContext.timeObj.minutes, seconds);
619 1.2.2.2 snj
620 1.2.2.2 snj pp->lencode = strlen (pp->a_lastcode);
621 1.2.2.2 snj pp->day = TimeContext.timeObj.days;
622 1.2.2.2 snj pp->hour = TimeContext.timeObj.hours;
623 1.2.2.2 snj pp->minute = TimeContext.timeObj.minutes;
624 1.2.2.2 snj pp->second = (int) seconds;
625 1.2.2.2 snj seconds = (seconds - (double) (pp->second / 1.0)) * 1000000000;
626 1.2.2.2 snj pp->nsec = (long) seconds;
627 1.2.2.2 snj
628 1.2.2.2 snj /*
629 1.2.2.2 snj ** calculate year start
630 1.2.2.2 snj */
631 1.2.2.2 snj jt.year = TimeContext.timeObj.year;
632 1.2.2.2 snj jt.yearday = 1;
633 1.2.2.2 snj jt.monthday = 1;
634 1.2.2.2 snj jt.month = 1;
635 1.2.2.2 snj jt.hour = 0;
636 1.2.2.2 snj jt.minute = 0;
637 1.2.2.2 snj jt.second = 0;
638 1.2.2.2 snj pp->yearstart = caltontp(&jt);
639 1.2.2.2 snj
640 1.2.2.2 snj // Calculate and report reference clock offset
641 1.2.2.2 snj offset.l_ui = (long)(((pp->day - 1) * 24) + pp->hour + GMT);
642 1.2.2.2 snj offset.l_ui = (offset.l_ui * 60) + (long)pp->minute;
643 1.2.2.2 snj offset.l_ui = (offset.l_ui * 60) + (long)pp->second;
644 1.2.2.2 snj offset.l_ui = offset.l_ui + (long)pp->yearstart;
645 1.2.2.2 snj offset.l_uf = 0;
646 1.2.2.2 snj DTOLFP(pp->nsec / 1e9, <emp);
647 1.2.2.2 snj L_ADD(&offset, <emp);
648 1.2.2.2 snj refclock_process_offset(pp, offset, pp->lastrec,
649 1.2.2.2 snj pp->fudgetime1);
650 1.2.2.2 snj
651 1.2.2.2 snj // KTS in sync
652 1.2.2.2 snj if (synch) {
653 1.2.2.2 snj // Subtract leap second info by one second to determine effective day
654 1.2.2.2 snj ApplyTimeOffset(&(leapSec.utcDate), -1);
655 1.2.2.2 snj
656 1.2.2.2 snj // If there is a leap second today and the KTS is using a time scale
657 1.2.2.2 snj // which handles leap seconds then
658 1.2.2.2 snj if ((tmscl != TIME_SCALE_GPS) && (tmscl != TIME_SCALE_TAI) &&
659 1.2.2.2 snj (leapSec.utcDate.year == (unsigned int)TimeContext.timeObj.year) &&
660 1.2.2.2 snj (leapSec.utcDate.doy == (unsigned int)TimeContext.timeObj.days))
661 1.2.2.2 snj {
662 1.2.2.2 snj // If adding a second
663 1.2.2.2 snj if (leapSec.offset == 1)
664 1.2.2.2 snj {
665 1.2.2.2 snj pp->leap = LEAP_ADDSECOND;
666 1.2.2.2 snj }
667 1.2.2.2 snj // Else if removing a second
668 1.2.2.2 snj else if (leapSec.offset == -1)
669 1.2.2.2 snj {
670 1.2.2.2 snj pp->leap = LEAP_DELSECOND;
671 1.2.2.2 snj }
672 1.2.2.2 snj // Else report no leap second pending (no handling of offsets
673 1.2.2.2 snj // other than +1 or -1)
674 1.2.2.2 snj else
675 1.2.2.2 snj {
676 1.2.2.2 snj pp->leap = LEAP_NOWARNING;
677 1.2.2.2 snj }
678 1.2.2.2 snj }
679 1.2.2.2 snj // Else report no leap second pending
680 1.2.2.2 snj else
681 1.2.2.2 snj {
682 1.2.2.2 snj pp->leap = LEAP_NOWARNING;
683 1.2.2.2 snj }
684 1.2.2.2 snj
685 1.2.2.2 snj peer->leap = pp->leap;
686 1.2.2.2 snj refclock_report(peer, CEVNT_NOMINAL);
687 1.2.2.2 snj
688 1.2.2.2 snj // If reference name reported, then not in holdover
689 1.2.2.2 snj if ((RefIdLookupTbl[i].pRef != NULL) &&
690 1.2.2.2 snj (RefIdLookupTbl[j].pRef != NULL))
691 1.2.2.2 snj {
692 1.2.2.2 snj // Determine if KTS being synchronized by host (identified as
693 1.2.2.2 snj // "LOCL")
694 1.2.2.2 snj if ((strcmp(RefIdLookupTbl[i].pRefId, TSYNC_REF_LOCAL) == 0) ||
695 1.2.2.2 snj (strcmp(RefIdLookupTbl[j].pRefId, TSYNC_REF_LOCAL) == 0))
696 1.2.2.2 snj {
697 1.2.2.2 snj // Clear prefer flag
698 1.2.2.2 snj peer->flags &= ~FLAG_PREFER;
699 1.2.2.2 snj
700 1.2.2.2 snj // Set reference clock stratum level as unusable
701 1.2.2.2 snj pp->stratum = STRATUM_UNSPEC;
702 1.2.2.2 snj peer->stratum = pp->stratum;
703 1.2.2.2 snj
704 1.2.2.2 snj // If a valid peer is available
705 1.2.2.2 snj if ((sys_peer != NULL) && (sys_peer != peer))
706 1.2.2.2 snj {
707 1.2.2.2 snj // Store reference peer stratum level and ID
708 1.2.2.2 snj up->refStratum = sys_peer->stratum;
709 1.2.2.2 snj up->refId = addr2refid(&sys_peer->srcadr);
710 1.2.2.2 snj }
711 1.2.2.2 snj }
712 1.2.2.2 snj else
713 1.2.2.2 snj {
714 1.2.2.2 snj // Restore prefer flag
715 1.2.2.2 snj peer->flags |= up->refPrefer;
716 1.2.2.2 snj
717 1.2.2.2 snj // Store reference stratum as local clock
718 1.2.2.2 snj up->refStratum = TSYNC_LCL_STRATUM;
719 1.2.2.2 snj strncpy((char *)&up->refId, RefIdLookupTbl[j].pRefId,
720 1.2.2.2 snj TSYNC_REF_LEN);
721 1.2.2.2 snj
722 1.2.2.2 snj // Set reference clock stratum level as local clock
723 1.2.2.2 snj pp->stratum = TSYNC_LCL_STRATUM;
724 1.2.2.2 snj peer->stratum = pp->stratum;
725 1.2.2.2 snj }
726 1.2.2.2 snj
727 1.2.2.2 snj // Update reference name
728 1.2.2.2 snj strncpy((char *)&pp->refid, RefIdLookupTbl[j].pRefId,
729 1.2.2.2 snj TSYNC_REF_LEN);
730 1.2.2.2 snj peer->refid = pp->refid;
731 1.2.2.2 snj }
732 1.2.2.2 snj // Else in holdover
733 1.2.2.2 snj else
734 1.2.2.2 snj {
735 1.2.2.2 snj // Restore prefer flag
736 1.2.2.2 snj peer->flags |= up->refPrefer;
737 1.2.2.2 snj
738 1.2.2.2 snj // Update reference ID to saved ID
739 1.2.2.2 snj pp->refid = up->refId;
740 1.2.2.2 snj peer->refid = pp->refid;
741 1.2.2.2 snj
742 1.2.2.2 snj // Update stratum level to saved stratum level
743 1.2.2.2 snj pp->stratum = up->refStratum;
744 1.2.2.2 snj peer->stratum = pp->stratum;
745 1.2.2.2 snj }
746 1.2.2.2 snj }
747 1.2.2.2 snj // Else KTS not in sync
748 1.2.2.2 snj else {
749 1.2.2.2 snj // Place local identifier in peer RefID
750 1.2.2.2 snj strncpy((char *)&pp->refid, TSYNC_REF_LOCAL, TSYNC_REF_LEN);
751 1.2.2.2 snj peer->refid = pp->refid;
752 1.2.2.2 snj
753 1.2.2.2 snj // Report not in sync
754 1.2.2.2 snj pp->leap = LEAP_NOTINSYNC;
755 1.2.2.2 snj peer->leap = pp->leap;
756 1.2.2.2 snj }
757 1.2.2.2 snj
758 1.2.2.2 snj if (pp->coderecv == pp->codeproc) {
759 1.2.2.2 snj refclock_report(peer, CEVNT_TIMEOUT);
760 1.2.2.2 snj return;
761 1.2.2.2 snj }
762 1.2.2.2 snj
763 1.2.2.2 snj record_clock_stats(&peer->srcadr, pp->a_lastcode);
764 1.2.2.2 snj refclock_receive(peer);
765 1.2.2.2 snj
766 1.2.2.2 snj /* Increment the number of times the reference has been polled */
767 1.2.2.2 snj pp->polls++;
768 1.2.2.2 snj
769 1.2.2.2 snj } /* End - tsync_poll() */
770 1.2.2.2 snj
771 1.2.2.2 snj
772 1.2.2.2 snj ////////////////////////////////////////////////////////////////////////////////
773 1.2.2.2 snj // Function: ApplyTimeOffset
774 1.2.2.2 snj // Description: The ApplyTimeOffset function adds an offset (in seconds) to a
775 1.2.2.2 snj // specified date and time. The specified date and time is passed
776 1.2.2.2 snj // back after being modified.
777 1.2.2.2 snj //
778 1.2.2.2 snj // Assumptions: 1. Every fourth year is a leap year. Therefore, this function
779 1.2.2.2 snj // is only accurate through Feb 28, 2100.
780 1.2.2.2 snj ////////////////////////////////////////////////////////////////////////////////
781 1.2.2.2 snj void ApplyTimeOffset(DoyTimeObj* pDt, int off)
782 1.2.2.2 snj {
783 1.2.2.2 snj SecTimeObj st; // Time, in seconds
784 1.2.2.2 snj
785 1.2.2.2 snj
786 1.2.2.2 snj // Convert date and time to seconds
787 1.2.2.2 snj SecTimeFromDoyTime(&st, pDt);
788 1.2.2.2 snj
789 1.2.2.2 snj // Apply offset
790 1.2.2.2 snj st.seconds = (int)((signed long long)st.seconds + (signed long long)off);
791 1.2.2.2 snj
792 1.2.2.2 snj // Convert seconds to date and time
793 1.2.2.2 snj DoyTimeFromSecTime(pDt, &st);
794 1.2.2.2 snj
795 1.2.2.2 snj } // End ApplyTimeOffset
796 1.2.2.2 snj
797 1.2.2.2 snj
798 1.2.2.2 snj ////////////////////////////////////////////////////////////////////////////////
799 1.2.2.2 snj // Function: SecTimeFromDoyTime
800 1.2.2.2 snj // Description: The SecTimeFromDoyTime function converts a specified date
801 1.2.2.2 snj // and time into a count of seconds since the base time. This
802 1.2.2.2 snj // function operates across the range Base Time to Max Time for
803 1.2.2.2 snj // the system.
804 1.2.2.2 snj //
805 1.2.2.2 snj // Assumptions: 1. A leap year is any year evenly divisible by 4. Therefore,
806 1.2.2.2 snj // this function is only accurate through Feb 28, 2100.
807 1.2.2.2 snj // 2. Conversion does not account for leap seconds.
808 1.2.2.2 snj ////////////////////////////////////////////////////////////////////////////////
809 1.2.2.2 snj void SecTimeFromDoyTime(SecTimeObj* pSt, DoyTimeObj* pDt)
810 1.2.2.2 snj {
811 1.2.2.2 snj unsigned int yrs; // Years
812 1.2.2.2 snj unsigned int lyrs; // Leap years
813 1.2.2.2 snj
814 1.2.2.2 snj
815 1.2.2.2 snj // Start with accumulated time of 0
816 1.2.2.2 snj pSt->seconds = 0;
817 1.2.2.2 snj
818 1.2.2.2 snj // Calculate the number of years and leap years
819 1.2.2.2 snj yrs = pDt->year - TSYNC_TIME_BASE_YEAR;
820 1.2.2.2 snj lyrs = (yrs + 1) / 4;
821 1.2.2.2 snj
822 1.2.2.2 snj // Convert leap years and years
823 1.2.2.2 snj pSt->seconds += lyrs * SECSPERLEAPYEAR;
824 1.2.2.2 snj pSt->seconds += (yrs - lyrs) * SECSPERYEAR;
825 1.2.2.2 snj
826 1.2.2.2 snj // Convert days, hours, minutes and seconds
827 1.2.2.2 snj pSt->seconds += (pDt->doy - 1) * SECSPERDAY;
828 1.2.2.2 snj pSt->seconds += pDt->hour * SECSPERHR;
829 1.2.2.2 snj pSt->seconds += pDt->minute * SECSPERMIN;
830 1.2.2.2 snj pSt->seconds += pDt->second;
831 1.2.2.2 snj
832 1.2.2.2 snj // Copy the subseconds count
833 1.2.2.2 snj pSt->ns = pDt->ns;
834 1.2.2.2 snj
835 1.2.2.2 snj } // End SecTimeFromDoyTime
836 1.2.2.2 snj
837 1.2.2.2 snj
838 1.2.2.2 snj ////////////////////////////////////////////////////////////////////////////////
839 1.2.2.2 snj // Function: DoyTimeFromSecTime
840 1.2.2.2 snj // Description: The DoyTimeFromSecTime function converts a specified count
841 1.2.2.2 snj // of seconds since the start of our base time into a SecTimeObj
842 1.2.2.2 snj // structure.
843 1.2.2.2 snj //
844 1.2.2.2 snj // Assumptions: 1. A leap year is any year evenly divisible by 4. Therefore,
845 1.2.2.2 snj // this function is only accurate through Feb 28, 2100.
846 1.2.2.2 snj // 2. Conversion does not account for leap seconds.
847 1.2.2.2 snj ////////////////////////////////////////////////////////////////////////////////
848 1.2.2.2 snj void DoyTimeFromSecTime(DoyTimeObj* pDt, SecTimeObj* pSt)
849 1.2.2.2 snj {
850 1.2.2.2 snj signed long long secs; // Seconds accumulator variable
851 1.2.2.2 snj unsigned int yrs; // Years accumulator variable
852 1.2.2.2 snj unsigned int doys; // Days accumulator variable
853 1.2.2.2 snj unsigned int hrs; // Hours accumulator variable
854 1.2.2.2 snj unsigned int mins; // Minutes accumulator variable
855 1.2.2.2 snj
856 1.2.2.2 snj
857 1.2.2.2 snj // Convert the seconds count into a signed 64-bit number for calculations
858 1.2.2.2 snj secs = (signed long long)(pSt->seconds);
859 1.2.2.2 snj
860 1.2.2.2 snj // Calculate the number of 4 year chunks
861 1.2.2.2 snj yrs = (unsigned int)((secs /
862 1.2.2.2 snj ((SECSPERYEAR * 3) + SECSPERLEAPYEAR)) * 4);
863 1.2.2.2 snj secs %= ((SECSPERYEAR * 3) + SECSPERLEAPYEAR);
864 1.2.2.2 snj
865 1.2.2.2 snj // If there is at least a normal year worth of time left
866 1.2.2.2 snj if (secs >= SECSPERYEAR)
867 1.2.2.2 snj {
868 1.2.2.2 snj // Increment the number of years and subtract a normal year of time
869 1.2.2.2 snj yrs++;
870 1.2.2.2 snj secs -= SECSPERYEAR;
871 1.2.2.2 snj }
872 1.2.2.2 snj
873 1.2.2.2 snj // If there is still at least a normal year worth of time left
874 1.2.2.2 snj if (secs >= SECSPERYEAR)
875 1.2.2.2 snj {
876 1.2.2.2 snj // Increment the number of years and subtract a normal year of time
877 1.2.2.2 snj yrs++;
878 1.2.2.2 snj secs -= SECSPERYEAR;
879 1.2.2.2 snj }
880 1.2.2.2 snj
881 1.2.2.2 snj // If there is still at least a leap year worth of time left
882 1.2.2.2 snj if (secs >= SECSPERLEAPYEAR)
883 1.2.2.2 snj {
884 1.2.2.2 snj // Increment the number of years and subtract a leap year of time
885 1.2.2.2 snj yrs++;
886 1.2.2.2 snj secs -= SECSPERLEAPYEAR;
887 1.2.2.2 snj }
888 1.2.2.2 snj
889 1.2.2.2 snj // Calculate the day of year as the number of days left, then add 1
890 1.2.2.2 snj // because months start on the 1st.
891 1.2.2.2 snj doys = (unsigned int)((secs / SECSPERDAY) + 1);
892 1.2.2.2 snj secs %= SECSPERDAY;
893 1.2.2.2 snj
894 1.2.2.2 snj // Calculate the hour
895 1.2.2.2 snj hrs = (unsigned int)(secs / SECSPERHR);
896 1.2.2.2 snj secs %= SECSPERHR;
897 1.2.2.2 snj
898 1.2.2.2 snj // Calculate the minute
899 1.2.2.2 snj mins = (unsigned int)(secs / SECSPERMIN);
900 1.2.2.2 snj secs %= SECSPERMIN;
901 1.2.2.2 snj
902 1.2.2.2 snj // Fill in the doytime structure
903 1.2.2.2 snj pDt->year = yrs + TSYNC_TIME_BASE_YEAR;
904 1.2.2.2 snj pDt->doy = doys;
905 1.2.2.2 snj pDt->hour = hrs;
906 1.2.2.2 snj pDt->minute = mins;
907 1.2.2.2 snj pDt->second = (unsigned int)secs;
908 1.2.2.2 snj pDt->ns = pSt->ns;
909 1.2.2.2 snj
910 1.2.2.2 snj } // End DoyTimeFromSecTime
911 1.2.2.2 snj
912 1.2.2.2 snj #else
913 1.2.2.2 snj int refclock_tsyncpci_bs;
914 1.2.2.2 snj #endif /* REFCLOCK */
915