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