Home | History | Annotate | Line # | Download | only in ntpd
refclock_tsyncpci.c revision 1.1.1.2
      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  christos     memcpy(&tmscl, ((TIME_SCALE*)(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