Coverage Report

Created: 2023-05-19 06:16

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