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