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