xref: /freebsd/contrib/ntp/ntpd/refclock_tsyncpci.c (revision f5f40dd63bc7acbb5312b26ac1ea1103c12352a6)
12b15cb3dSCy Schubert /*******************************************************************************
22b15cb3dSCy Schubert *
32b15cb3dSCy Schubert *  Module  : refclock_tsyncpci.c
42b15cb3dSCy Schubert *  Date    : 09/08/08
52b15cb3dSCy Schubert *  Purpose : Implements a reference clock driver for the NTP daemon.  This
62b15cb3dSCy Schubert *            reference clock driver provides a means to communicate with
72b15cb3dSCy Schubert *            the Spectracom TSYNC PCI timing devices and use them as a time
82b15cb3dSCy Schubert *            source.
92b15cb3dSCy Schubert *
102b15cb3dSCy Schubert *  (C) Copyright 2008 Spectracom Corporation
112b15cb3dSCy Schubert *
122b15cb3dSCy Schubert *  This software is provided by Spectracom Corporation 'as is' and
132b15cb3dSCy Schubert *  any express or implied warranties, including, but not limited to, the
142b15cb3dSCy Schubert *  implied warranties of merchantability and fitness for a particular purpose
152b15cb3dSCy Schubert *  are disclaimed.  In no event shall Spectracom Corporation be liable
162b15cb3dSCy Schubert *  for any direct, indirect, incidental, special, exemplary, or consequential
172b15cb3dSCy Schubert *  damages (including, but not limited to, procurement of substitute goods
182b15cb3dSCy Schubert *  or services; loss of use, data, or profits; or business interruption)
192b15cb3dSCy Schubert *  however caused and on any theory of liability, whether in contract, strict
202b15cb3dSCy Schubert *  liability, or tort (including negligence or otherwise) arising in any way
212b15cb3dSCy Schubert *  out of the use of this software, even if advised of the possibility of
222b15cb3dSCy Schubert *  such damage.
232b15cb3dSCy Schubert *
242b15cb3dSCy Schubert *  This software is released for distribution according to the NTP copyright
252b15cb3dSCy Schubert *  and license contained in html/copyright.html of NTP source.
262b15cb3dSCy Schubert *
272b15cb3dSCy Schubert *******************************************************************************/
282b15cb3dSCy Schubert #ifdef HAVE_CONFIG_H
292b15cb3dSCy Schubert #include <config.h>
302b15cb3dSCy Schubert #endif
312b15cb3dSCy Schubert 
322b15cb3dSCy Schubert #if defined(REFCLOCK) && defined(CLOCK_TSYNCPCI)
332b15cb3dSCy Schubert 
342b15cb3dSCy Schubert #include <asm/ioctl.h>
352b15cb3dSCy Schubert #ifdef HAVE_SYS_IOCTL_H
362b15cb3dSCy Schubert # include <sys/ioctl.h>
372b15cb3dSCy Schubert #endif
382b15cb3dSCy Schubert 
392b15cb3dSCy Schubert #include <stdio.h>
402b15cb3dSCy Schubert #include <ctype.h>
412b15cb3dSCy Schubert #include <netinet/in.h>
422b15cb3dSCy Schubert 
432b15cb3dSCy Schubert 
442b15cb3dSCy Schubert #include "ntpd.h"
452b15cb3dSCy Schubert #include "ntp_io.h"
462b15cb3dSCy Schubert #include "ntp_refclock.h"
472b15cb3dSCy Schubert #include "ntp_unixtime.h"
482b15cb3dSCy Schubert #include "ntp_stdlib.h"
492b15cb3dSCy Schubert #include "ntp_calendar.h"
502b15cb3dSCy Schubert 
512b15cb3dSCy Schubert 
522b15cb3dSCy Schubert /*******************************************************************************
532b15cb3dSCy Schubert **
542b15cb3dSCy Schubert ** This driver supports the Spectracom TSYNC PCI GPS receiver.  It requires
552b15cb3dSCy Schubert ** that the tsyncpci.o device driver be installed and loaded.
562b15cb3dSCy Schubert **
572b15cb3dSCy Schubert *******************************************************************************/
582b15cb3dSCy Schubert 
592b15cb3dSCy Schubert #define TSYNC_PCI_REVISION "1.11"
602b15cb3dSCy Schubert 
612b15cb3dSCy Schubert /*
622b15cb3dSCy Schubert ** TPRO interface definitions
632b15cb3dSCy Schubert */
642b15cb3dSCy Schubert #define DEVICE      "/dev/tsyncpci"             /* device name */
652b15cb3dSCy Schubert #define PRECISION   (-20)                       /* precision assumed (1 us) */
662b15cb3dSCy Schubert #define DESCRIPTION "Spectracom TSYNC-PCI"      /* WRU */
672b15cb3dSCy Schubert 
682b15cb3dSCy Schubert #define SECONDS_1900_TO_1970 (2208988800U)
692b15cb3dSCy Schubert 
702b15cb3dSCy Schubert #define TSYNC_REF_IID               (0x2500)    // SS CAI, REF IID
712b15cb3dSCy Schubert #define TSYNC_REF_DEST_ID           (0x0001)    // KTS Firmware
722b15cb3dSCy Schubert #define TSYNC_REF_IN_PYLD_OFF       (0)
732b15cb3dSCy Schubert #define TSYNC_REF_IN_LEN            (0)
742b15cb3dSCy Schubert #define TSYNC_REF_OUT_PYLD_OFF      (0)
752b15cb3dSCy Schubert #define TSYNC_REF_OUT_LEN           (8)
762b15cb3dSCy Schubert #define TSYNC_REF_MAX_OUT_LEN       (16)
772b15cb3dSCy Schubert #define TSYNC_REF_PYLD_LEN          (TSYNC_REF_IN_LEN +                     \
782b15cb3dSCy Schubert                                      TSYNC_REF_MAX_OUT_LEN)
792b15cb3dSCy Schubert #define TSYNC_REF_LEN               (4)
802b15cb3dSCy Schubert #define TSYNC_REF_LOCAL             ("LOCL")
812b15cb3dSCy Schubert 
822b15cb3dSCy Schubert #define TSYNC_TMSCL_IID              (0x2301)    // CS CAI, TIMESCALE IID
832b15cb3dSCy Schubert #define TSYNC_TMSCL_DEST_ID          (0x0001)    // KTS Firmware
842b15cb3dSCy Schubert #define TSYNC_TMSCL_IN_PYLD_OFF      (0)
852b15cb3dSCy Schubert #define TSYNC_TMSCL_IN_LEN           (0)
862b15cb3dSCy Schubert #define TSYNC_TMSCL_OUT_PYLD_OFF     (0)
872b15cb3dSCy Schubert #define TSYNC_TMSCL_OUT_LEN          (4)
882b15cb3dSCy Schubert #define TSYNC_TMSCL_MAX_OUT_LEN      (12)
892b15cb3dSCy Schubert #define TSYNC_TMSCL_PYLD_LEN         (TSYNC_TMSCL_IN_LEN +                    \
902b15cb3dSCy Schubert                                      TSYNC_TMSCL_MAX_OUT_LEN)
912b15cb3dSCy Schubert 
922b15cb3dSCy Schubert #define TSYNC_LEAP_IID              (0x2307)    // CS CAI, LEAP SEC IID
932b15cb3dSCy Schubert #define TSYNC_LEAP_DEST_ID          (0x0001)    // KTS Firmware
942b15cb3dSCy Schubert #define TSYNC_LEAP_IN_PYLD_OFF      (0)
952b15cb3dSCy Schubert #define TSYNC_LEAP_IN_LEN           (0)
962b15cb3dSCy Schubert #define TSYNC_LEAP_OUT_PYLD_OFF     (0)
972b15cb3dSCy Schubert #define TSYNC_LEAP_OUT_LEN          (28)
982b15cb3dSCy Schubert #define TSYNC_LEAP_MAX_OUT_LEN      (36)
992b15cb3dSCy Schubert #define TSYNC_LEAP_PYLD_LEN         (TSYNC_LEAP_IN_LEN +                    \
1002b15cb3dSCy Schubert                                      TSYNC_LEAP_MAX_OUT_LEN)
1012b15cb3dSCy Schubert 
1022b15cb3dSCy Schubert // These define the base date/time of the system clock.  The system time will
1032b15cb3dSCy Schubert // be tracked as the number of seconds from this date/time.
1042b15cb3dSCy Schubert #define TSYNC_TIME_BASE_YEAR        (1970) // earliest acceptable year
1052b15cb3dSCy Schubert 
1062b15cb3dSCy Schubert #define TSYNC_LCL_STRATUM           (0)
1072b15cb3dSCy Schubert 
1082b15cb3dSCy Schubert /*
1092b15cb3dSCy Schubert ** TSYNC Time Scales type
1102b15cb3dSCy Schubert */
1112b15cb3dSCy Schubert typedef enum
1122b15cb3dSCy Schubert {
1132b15cb3dSCy Schubert     TIME_SCALE_UTC    = 0,   // Universal Coordinated Time
1142b15cb3dSCy Schubert     TIME_SCALE_TAI    = 1,   // International Atomic Time
1152b15cb3dSCy Schubert     TIME_SCALE_GPS    = 2,   // Global Positioning System
1162b15cb3dSCy Schubert     TIME_SCALE_LOCAL  = 3,   // UTC w/local rules for time zone and DST
1172b15cb3dSCy Schubert     NUM_TIME_SCALES   = 4,   // Number of time scales
1182b15cb3dSCy Schubert 
1192b15cb3dSCy Schubert     TIME_SCALE_MAX    = 15   // Maximum number of timescales
1202b15cb3dSCy Schubert 
1212b15cb3dSCy Schubert } TIME_SCALE;
1222b15cb3dSCy Schubert 
1232b15cb3dSCy Schubert /*
1242b15cb3dSCy Schubert ** TSYNC Board Object
1252b15cb3dSCy Schubert */
1262b15cb3dSCy Schubert typedef struct BoardObj {
1272b15cb3dSCy Schubert 
1282b15cb3dSCy Schubert   int            file_descriptor;
1292b15cb3dSCy Schubert   unsigned short devid;
1302b15cb3dSCy Schubert   unsigned short options;
1312b15cb3dSCy Schubert   unsigned char  firmware[5];
1322b15cb3dSCy Schubert   unsigned char  FPGA[5];
1332b15cb3dSCy Schubert   unsigned char  driver[7];
1342b15cb3dSCy Schubert 
1352b15cb3dSCy Schubert } BoardObj;
1362b15cb3dSCy Schubert 
1372b15cb3dSCy Schubert /*
1382b15cb3dSCy Schubert ** TSYNC Time Object
1392b15cb3dSCy Schubert */
1402b15cb3dSCy Schubert typedef struct TimeObj {
1412b15cb3dSCy Schubert 
1422b15cb3dSCy Schubert   unsigned char  syncOption;  /* -M option */
1432b15cb3dSCy Schubert   unsigned int   secsDouble;  /* seconds floating pt */
1442b15cb3dSCy Schubert   unsigned char  seconds;     /* seconds whole num */
1452b15cb3dSCy Schubert   unsigned char  minutes;
1462b15cb3dSCy Schubert   unsigned char  hours;
1472b15cb3dSCy Schubert   unsigned short days;
1482b15cb3dSCy Schubert   unsigned short year;
1492b15cb3dSCy Schubert   unsigned short flags;      /* bit 2 SYNC, bit 1 TCODE; all others 0 */
1502b15cb3dSCy Schubert 
1512b15cb3dSCy Schubert } TimeObj;
1522b15cb3dSCy Schubert 
1532b15cb3dSCy Schubert /*
1542b15cb3dSCy Schubert ** NTP Time Object
1552b15cb3dSCy Schubert */
1562b15cb3dSCy Schubert typedef struct NtpTimeObj {
1572b15cb3dSCy Schubert 
1582b15cb3dSCy Schubert     TimeObj        timeObj;
1592b15cb3dSCy Schubert     struct timeval tv;
1602b15cb3dSCy Schubert     unsigned int   refId;
1612b15cb3dSCy Schubert 
1622b15cb3dSCy Schubert } NtpTimeObj;
1632b15cb3dSCy Schubert /*
1642b15cb3dSCy Schubert ** TSYNC Supervisor Reference Object
1652b15cb3dSCy Schubert */
1662b15cb3dSCy Schubert typedef struct ReferenceObj {
1672b15cb3dSCy Schubert 
1682b15cb3dSCy Schubert     char time[TSYNC_REF_LEN];
1692b15cb3dSCy Schubert     char pps[TSYNC_REF_LEN];
1702b15cb3dSCy Schubert 
1712b15cb3dSCy Schubert } ReferenceObj;
1722b15cb3dSCy Schubert 
1732b15cb3dSCy Schubert /*
1742b15cb3dSCy Schubert ** TSYNC Seconds Time Object
1752b15cb3dSCy Schubert */
1762b15cb3dSCy Schubert typedef struct SecTimeObj
1772b15cb3dSCy Schubert {
1782b15cb3dSCy Schubert     unsigned int seconds;
1792b15cb3dSCy Schubert     unsigned int ns;
1802b15cb3dSCy Schubert }
1812b15cb3dSCy Schubert SecTimeObj;
1822b15cb3dSCy Schubert 
1832b15cb3dSCy Schubert /*
1842b15cb3dSCy Schubert ** TSYNC DOY Time Object
1852b15cb3dSCy Schubert */
1862b15cb3dSCy Schubert typedef struct DoyTimeObj
1872b15cb3dSCy Schubert {
1882b15cb3dSCy Schubert     unsigned int year;
1892b15cb3dSCy Schubert     unsigned int doy;
1902b15cb3dSCy Schubert     unsigned int hour;
1912b15cb3dSCy Schubert     unsigned int minute;
1922b15cb3dSCy Schubert     unsigned int second;
1932b15cb3dSCy Schubert     unsigned int ns;
1942b15cb3dSCy Schubert }
1952b15cb3dSCy Schubert DoyTimeObj;
1962b15cb3dSCy Schubert 
1972b15cb3dSCy Schubert /*
1982b15cb3dSCy Schubert ** TSYNC Leap Second Object
1992b15cb3dSCy Schubert */
2002b15cb3dSCy Schubert typedef struct LeapSecondObj
2012b15cb3dSCy Schubert {
2022b15cb3dSCy Schubert     int        offset;
2032b15cb3dSCy Schubert     DoyTimeObj utcDate;
2042b15cb3dSCy Schubert }
2052b15cb3dSCy Schubert LeapSecondObj;
2062b15cb3dSCy Schubert 
2072b15cb3dSCy Schubert /*
2082b15cb3dSCy Schubert  * structures for ioctl interactions with driver
2092b15cb3dSCy Schubert  */
2102b15cb3dSCy Schubert #define DI_PAYLOADS_STARTER_LENGTH 4
2112b15cb3dSCy Schubert typedef struct ioctl_trans_di {
2122b15cb3dSCy Schubert 
2132b15cb3dSCy Schubert     // input parameters
2142b15cb3dSCy Schubert     uint16_t        dest;
2152b15cb3dSCy Schubert     uint16_t        iid;
2162b15cb3dSCy Schubert 
2172b15cb3dSCy Schubert     uint32_t        inPayloadOffset;
2182b15cb3dSCy Schubert     uint32_t        inLength;
2192b15cb3dSCy Schubert     uint32_t        outPayloadOffset;
2202b15cb3dSCy Schubert     uint32_t        maxOutLength;
2212b15cb3dSCy Schubert 
2222b15cb3dSCy Schubert     // output parameters
2232b15cb3dSCy Schubert     uint32_t        actualOutLength;
2242b15cb3dSCy Schubert     int32_t         status;
2252b15cb3dSCy Schubert 
2262b15cb3dSCy Schubert     // Input and output
2272b15cb3dSCy Schubert 
2282b15cb3dSCy Schubert     // The payloads field MUST be last in ioctl_trans_di.
2292b15cb3dSCy Schubert     uint8_t         payloads[DI_PAYLOADS_STARTER_LENGTH];
2302b15cb3dSCy Schubert 
2312b15cb3dSCy Schubert }ioctl_trans_di;
2322b15cb3dSCy Schubert 
2332b15cb3dSCy Schubert /*
2342b15cb3dSCy Schubert  * structure for looking up a reference ID from a reference name
2352b15cb3dSCy Schubert  */
2362b15cb3dSCy Schubert typedef struct
2372b15cb3dSCy Schubert {
2382b15cb3dSCy Schubert     const char* pRef;           // KTS Reference Name
2392b15cb3dSCy Schubert     const char* pRefId;         // NTP Reference ID
2402b15cb3dSCy Schubert 
2412b15cb3dSCy Schubert } RefIdLookup;
2422b15cb3dSCy Schubert 
2432b15cb3dSCy Schubert /*
2442b15cb3dSCy Schubert  * unit control structure
2452b15cb3dSCy Schubert  */
2462b15cb3dSCy Schubert typedef struct  {
2472b15cb3dSCy Schubert     uint32_t refPrefer;         // Reference prefer flag
2482b15cb3dSCy Schubert     uint32_t refId;             // Host peer reference ID
2492b15cb3dSCy Schubert     uint8_t  refStratum;        // Host peer reference stratum
2502b15cb3dSCy Schubert 
2512b15cb3dSCy Schubert } TsyncUnit;
2522b15cb3dSCy Schubert 
2532b15cb3dSCy Schubert /*
2542b15cb3dSCy Schubert **  Function prototypes
2552b15cb3dSCy Schubert */
2562b15cb3dSCy Schubert static void tsync_poll     (int unit, struct peer *);
2572b15cb3dSCy Schubert static void tsync_shutdown (int, struct peer *);
2582b15cb3dSCy Schubert static int  tsync_start    (int, struct peer *);
2592b15cb3dSCy Schubert 
2602b15cb3dSCy Schubert /*
2612b15cb3dSCy Schubert **  Helper functions
2622b15cb3dSCy Schubert */
2632b15cb3dSCy Schubert static void ApplyTimeOffset    (DoyTimeObj* pDt, int off);
2642b15cb3dSCy Schubert static void SecTimeFromDoyTime (SecTimeObj* pSt, DoyTimeObj* pDt);
2652b15cb3dSCy Schubert static void DoyTimeFromSecTime (DoyTimeObj* pDt, SecTimeObj* pSt);
2662b15cb3dSCy Schubert 
2672b15cb3dSCy Schubert /*
2682b15cb3dSCy Schubert **  Transfer vector
2692b15cb3dSCy Schubert */
2702b15cb3dSCy Schubert struct refclock refclock_tsyncpci = {
2712b15cb3dSCy Schubert     tsync_start,    /* start up driver */
2722b15cb3dSCy Schubert     tsync_shutdown, /* shut down driver */
2732b15cb3dSCy Schubert     tsync_poll,     /* transmit poll message */
2742b15cb3dSCy Schubert     noentry,        /* not used (old tsync_control) */
2752b15cb3dSCy Schubert     noentry,        /* initialize driver (not used) */
2762b15cb3dSCy Schubert     noentry,        /* not used (old tsync_buginfo) */
2772b15cb3dSCy Schubert     NOFLAGS         /* not used */
2782b15cb3dSCy Schubert };
2792b15cb3dSCy Schubert 
2802b15cb3dSCy Schubert /*
2812b15cb3dSCy Schubert  * Reference ID lookup table
2822b15cb3dSCy Schubert  */
2832b15cb3dSCy Schubert static RefIdLookup RefIdLookupTbl[] =
2842b15cb3dSCy Schubert {
2852b15cb3dSCy Schubert     {"gps",  "GPS"},
2862b15cb3dSCy Schubert     {"ir",   "IRIG"},
2872b15cb3dSCy Schubert     {"hvq",  "HVQ"},
2882b15cb3dSCy Schubert     {"frq",  "FREQ"},
2892b15cb3dSCy Schubert     {"mdm",  "ACTS"},
2902b15cb3dSCy Schubert     {"epp",  "PPS"},
2912b15cb3dSCy Schubert     {"ptp",  "PTP"},
2922b15cb3dSCy Schubert     {"asc",  "ATC"},
2932b15cb3dSCy Schubert     {"hst0", "USER"},
2942b15cb3dSCy Schubert     {"hst",  TSYNC_REF_LOCAL},
2952b15cb3dSCy Schubert     {"self", TSYNC_REF_LOCAL},
2962b15cb3dSCy Schubert     {NULL,   NULL}
2972b15cb3dSCy Schubert };
2982b15cb3dSCy Schubert 
2992b15cb3dSCy Schubert /*******************************************************************************
3002b15cb3dSCy Schubert **          IOCTL DEFINITIONS
3012b15cb3dSCy Schubert *******************************************************************************/
3022b15cb3dSCy Schubert #define IOCTL_TPRO_ID            't'
3032b15cb3dSCy Schubert #define IOCTL_TPRO_OPEN          _IOWR(IOCTL_TPRO_ID, 0,  BoardObj)
3042b15cb3dSCy Schubert #define IOCTL_TPRO_GET_NTP_TIME  _IOWR(IOCTL_TPRO_ID, 25, NtpTimeObj)
3052b15cb3dSCy Schubert #define IOCTL_TSYNC_GET          _IOWR(IOCTL_TPRO_ID, 26, ioctl_trans_di)
3062b15cb3dSCy Schubert 
3072b15cb3dSCy Schubert /******************************************************************************
3082b15cb3dSCy Schubert  *
3092b15cb3dSCy Schubert  * Function:    tsync_start()
3102b15cb3dSCy Schubert  * Description: Used to intialize the Spectracom TSYNC reference driver.
3112b15cb3dSCy Schubert  *
3122b15cb3dSCy Schubert  * Parameters:
3132b15cb3dSCy Schubert  *     IN:  unit - not used.
3142b15cb3dSCy Schubert  *         *peer - pointer to this reference clock's peer structure
3152b15cb3dSCy Schubert  *     Returns: 0 - unsuccessful
3162b15cb3dSCy Schubert  *              1 - successful
3172b15cb3dSCy Schubert  *
3182b15cb3dSCy Schubert *******************************************************************************/
3192b15cb3dSCy Schubert static int tsync_start(int unit, struct peer *peer)
3202b15cb3dSCy Schubert {
3212b15cb3dSCy Schubert     struct refclockproc *pp;
3222b15cb3dSCy Schubert     TsyncUnit           *up;
3232b15cb3dSCy Schubert 
3242b15cb3dSCy Schubert 
3252b15cb3dSCy Schubert     /*
3262b15cb3dSCy Schubert     **  initialize reference clock and peer parameters
3272b15cb3dSCy Schubert     */
3282b15cb3dSCy Schubert     pp                = peer->procptr;
3292b15cb3dSCy Schubert     pp->clockdesc     = DESCRIPTION;
3302b15cb3dSCy Schubert     pp->io.clock_recv = noentry;
3312b15cb3dSCy Schubert     pp->io.srcclock   = peer;
3322b15cb3dSCy Schubert     pp->io.datalen    = 0;
3332b15cb3dSCy Schubert     peer->precision   = PRECISION;
3342b15cb3dSCy Schubert 
3352b15cb3dSCy Schubert     // Allocate and initialize unit structure
3362b15cb3dSCy Schubert     if (!(up = (TsyncUnit*)emalloc(sizeof(TsyncUnit))))
3372b15cb3dSCy Schubert     {
3382b15cb3dSCy Schubert         return (0);
3392b15cb3dSCy Schubert     }
3402b15cb3dSCy Schubert 
3412b15cb3dSCy Schubert     // Store reference preference
3422b15cb3dSCy Schubert     up->refPrefer = peer->flags & FLAG_PREFER;
3432b15cb3dSCy Schubert 
3442b15cb3dSCy Schubert     // Initialize reference stratum level and ID
3452b15cb3dSCy Schubert     up->refStratum = STRATUM_UNSPEC;
3462b15cb3dSCy Schubert     strncpy((char *)&up->refId, TSYNC_REF_LOCAL, TSYNC_REF_LEN);
3472b15cb3dSCy Schubert 
3482b15cb3dSCy Schubert     // Attach unit structure
3492b15cb3dSCy Schubert     pp->unitptr = (caddr_t)up;
3502b15cb3dSCy Schubert 
3512b15cb3dSCy Schubert     /* Declare our refId as local in the beginning because we do not know
3522b15cb3dSCy Schubert      * what our actual refid is yet.
3532b15cb3dSCy Schubert      */
3542b15cb3dSCy Schubert     strncpy((char *)&pp->refid, TSYNC_REF_LOCAL, TSYNC_REF_LEN);
3552b15cb3dSCy Schubert 
3562b15cb3dSCy Schubert     return (1);
3572b15cb3dSCy Schubert 
3582b15cb3dSCy Schubert } /* End - tsync_start() */
3592b15cb3dSCy Schubert 
3602b15cb3dSCy Schubert /*******************************************************************************
3612b15cb3dSCy Schubert **
3622b15cb3dSCy Schubert ** Function:    tsync_shutdown()
3632b15cb3dSCy Schubert ** Description: Handles anything related to shutting down the reference clock
3642b15cb3dSCy Schubert **              driver. Nothing at this point in time.
3652b15cb3dSCy Schubert **
3662b15cb3dSCy Schubert ** Parameters:
3672b15cb3dSCy Schubert **     IN:  unit - not used.
3682b15cb3dSCy Schubert **         *peer - pointer to this reference clock's peer structure
3692b15cb3dSCy Schubert **     Returns: none.
3702b15cb3dSCy Schubert **
3712b15cb3dSCy Schubert *******************************************************************************/
3722b15cb3dSCy Schubert static void tsync_shutdown(int unit, struct peer *peer)
3732b15cb3dSCy Schubert {
3742b15cb3dSCy Schubert 
3752b15cb3dSCy Schubert } /* End - tsync_shutdown() */
3762b15cb3dSCy Schubert 
3772b15cb3dSCy Schubert /******************************************************************************
3782b15cb3dSCy Schubert  *
3792b15cb3dSCy Schubert  * Function:    tsync_poll()
3802b15cb3dSCy Schubert  * Description: Retrieve time from the TSYNC device.
3812b15cb3dSCy Schubert  *
3822b15cb3dSCy Schubert  * Parameters:
3832b15cb3dSCy Schubert  *     IN:  unit - not used.
3842b15cb3dSCy Schubert  *         *peer - pointer to this reference clock's peer structure
3852b15cb3dSCy Schubert  *     Returns: none.
3862b15cb3dSCy Schubert  *
3872b15cb3dSCy Schubert *******************************************************************************/
3882b15cb3dSCy Schubert static void tsync_poll(int unit, struct peer *peer)
3892b15cb3dSCy Schubert {
3902b15cb3dSCy Schubert     char                 device[32];
3912b15cb3dSCy Schubert     struct refclockproc *pp;
3922b15cb3dSCy Schubert     struct calendar      jt;
3932b15cb3dSCy Schubert     TsyncUnit           *up;
3942b15cb3dSCy Schubert     unsigned char        synch;
3952b15cb3dSCy Schubert     double               seconds;
3962b15cb3dSCy Schubert     int                  err;
3972b15cb3dSCy Schubert     int                  err1;
3982b15cb3dSCy Schubert     int                  err2;
3992b15cb3dSCy Schubert     int                  err3;
4002b15cb3dSCy Schubert     int                  i;
4012b15cb3dSCy Schubert     int                  j;
4022b15cb3dSCy Schubert     unsigned int         itAllocationLength;
4032b15cb3dSCy Schubert     unsigned int         itAllocationLength1;
4042b15cb3dSCy Schubert     unsigned int         itAllocationLength2;
4052b15cb3dSCy Schubert     NtpTimeObj           TimeContext;
4062b15cb3dSCy Schubert     BoardObj             hBoard;
4072b15cb3dSCy Schubert     char                 timeRef[TSYNC_REF_LEN + 1];
4082b15cb3dSCy Schubert     char                 ppsRef [TSYNC_REF_LEN + 1];
4092b15cb3dSCy Schubert     TIME_SCALE           tmscl = TIME_SCALE_UTC;
4102b15cb3dSCy Schubert     LeapSecondObj        leapSec;
4112b15cb3dSCy Schubert     ioctl_trans_di      *it;
4122b15cb3dSCy Schubert     ioctl_trans_di      *it1;
4132b15cb3dSCy Schubert     ioctl_trans_di      *it2;
4142b15cb3dSCy Schubert     l_fp                 offset;
4152b15cb3dSCy Schubert     l_fp                 ltemp;
4162b15cb3dSCy Schubert     ReferenceObj *	 pRefObj;
4172b15cb3dSCy Schubert 
4182b15cb3dSCy Schubert 
4192b15cb3dSCy Schubert     /* Construct the device name */
4202b15cb3dSCy Schubert     sprintf(device, "%s%d", DEVICE, (int)peer->refclkunit);
4212b15cb3dSCy Schubert 
4222b15cb3dSCy Schubert     printf("Polling device number %d...\n", (int)peer->refclkunit);
4232b15cb3dSCy Schubert 
4242b15cb3dSCy Schubert     /* Open the TSYNC device */
4252b15cb3dSCy Schubert     hBoard.file_descriptor = open(device, O_RDONLY | O_NDELAY, 0777);
4262b15cb3dSCy Schubert 
4272b15cb3dSCy Schubert     /* If error opening TSYNC device... */
4282b15cb3dSCy Schubert     if (hBoard.file_descriptor < 0)
4292b15cb3dSCy Schubert     {
4302b15cb3dSCy Schubert         msyslog(LOG_ERR, "Couldn't open device");
4312b15cb3dSCy Schubert         return;
4322b15cb3dSCy Schubert     }
4332b15cb3dSCy Schubert 
4342b15cb3dSCy Schubert     /* If error while initializing the board... */
4352b15cb3dSCy Schubert     if (ioctl(hBoard.file_descriptor, IOCTL_TPRO_OPEN, &hBoard) < 0)
4362b15cb3dSCy Schubert     {
4372b15cb3dSCy Schubert         msyslog(LOG_ERR, "Couldn't initialize device");
4382b15cb3dSCy Schubert         close(hBoard.file_descriptor);
4392b15cb3dSCy Schubert         return;
4402b15cb3dSCy Schubert     }
4412b15cb3dSCy Schubert 
4422b15cb3dSCy Schubert     /* Allocate memory for ioctl message */
4432b15cb3dSCy Schubert     itAllocationLength =
4442b15cb3dSCy Schubert         (sizeof(ioctl_trans_di) - DI_PAYLOADS_STARTER_LENGTH) +
4452b15cb3dSCy Schubert         TSYNC_REF_IN_LEN + TSYNC_REF_MAX_OUT_LEN;
4462b15cb3dSCy Schubert 
4472b15cb3dSCy Schubert     it = (ioctl_trans_di*)alloca(itAllocationLength);
4482b15cb3dSCy Schubert     if (it == NULL) {
4492b15cb3dSCy Schubert         msyslog(LOG_ERR, "Couldn't allocate transaction memory - Reference");
4502b15cb3dSCy Schubert         return;
4512b15cb3dSCy Schubert     }
4522b15cb3dSCy Schubert 
4532b15cb3dSCy Schubert     /* Build SS_GetRef ioctl message */
4542b15cb3dSCy Schubert     it->dest             = TSYNC_REF_DEST_ID;
4552b15cb3dSCy Schubert     it->iid              = TSYNC_REF_IID;
4562b15cb3dSCy Schubert     it->inPayloadOffset  = TSYNC_REF_IN_PYLD_OFF;
4572b15cb3dSCy Schubert     it->inLength         = TSYNC_REF_IN_LEN;
4582b15cb3dSCy Schubert     it->outPayloadOffset = TSYNC_REF_OUT_PYLD_OFF;
4592b15cb3dSCy Schubert     it->maxOutLength     = TSYNC_REF_MAX_OUT_LEN;
4602b15cb3dSCy Schubert     it->actualOutLength  = 0;
4612b15cb3dSCy Schubert     it->status           = 0;
4622b15cb3dSCy Schubert     memset(it->payloads, 0, TSYNC_REF_MAX_OUT_LEN);
4632b15cb3dSCy Schubert 
4642b15cb3dSCy Schubert     /* Read the reference from the TSYNC-PCI device */
4652b15cb3dSCy Schubert     err = ioctl(hBoard.file_descriptor,
4662b15cb3dSCy Schubert                  IOCTL_TSYNC_GET,
4672b15cb3dSCy Schubert                 (char *)it);
4682b15cb3dSCy Schubert 
4692b15cb3dSCy Schubert     /* Allocate memory for ioctl message */
4702b15cb3dSCy Schubert     itAllocationLength1 =
4712b15cb3dSCy Schubert         (sizeof(ioctl_trans_di) - DI_PAYLOADS_STARTER_LENGTH) +
4722b15cb3dSCy Schubert         TSYNC_TMSCL_IN_LEN + TSYNC_TMSCL_MAX_OUT_LEN;
4732b15cb3dSCy Schubert 
4742b15cb3dSCy Schubert     it1 = (ioctl_trans_di*)alloca(itAllocationLength1);
4752b15cb3dSCy Schubert     if (it1 == NULL) {
4762b15cb3dSCy Schubert         msyslog(LOG_ERR, "Couldn't allocate transaction memory - Time Scale");
4772b15cb3dSCy Schubert         return;
4782b15cb3dSCy Schubert     }
4792b15cb3dSCy Schubert 
4802b15cb3dSCy Schubert     /* Build CS_GetTimeScale ioctl message */
4812b15cb3dSCy Schubert     it1->dest             = TSYNC_TMSCL_DEST_ID;
4822b15cb3dSCy Schubert     it1->iid              = TSYNC_TMSCL_IID;
4832b15cb3dSCy Schubert     it1->inPayloadOffset  = TSYNC_TMSCL_IN_PYLD_OFF;
4842b15cb3dSCy Schubert     it1->inLength         = TSYNC_TMSCL_IN_LEN;
4852b15cb3dSCy Schubert     it1->outPayloadOffset = TSYNC_TMSCL_OUT_PYLD_OFF;
4862b15cb3dSCy Schubert     it1->maxOutLength     = TSYNC_TMSCL_MAX_OUT_LEN;
4872b15cb3dSCy Schubert     it1->actualOutLength  = 0;
4882b15cb3dSCy Schubert     it1->status           = 0;
4892b15cb3dSCy Schubert     memset(it1->payloads, 0, TSYNC_TMSCL_MAX_OUT_LEN);
4902b15cb3dSCy Schubert 
4912b15cb3dSCy Schubert     /* Read the Time Scale info from the TSYNC-PCI device */
4922b15cb3dSCy Schubert     err1 = ioctl(hBoard.file_descriptor,
4932b15cb3dSCy Schubert                  IOCTL_TSYNC_GET,
4942b15cb3dSCy Schubert                  (char *)it1);
4952b15cb3dSCy Schubert 
4962b15cb3dSCy Schubert     /* Allocate memory for ioctl message */
4972b15cb3dSCy Schubert     itAllocationLength2 =
4982b15cb3dSCy Schubert         (sizeof(ioctl_trans_di) - DI_PAYLOADS_STARTER_LENGTH) +
4992b15cb3dSCy Schubert         TSYNC_LEAP_IN_LEN + TSYNC_LEAP_MAX_OUT_LEN;
5002b15cb3dSCy Schubert 
5012b15cb3dSCy Schubert     it2 = (ioctl_trans_di*)alloca(itAllocationLength2);
5022b15cb3dSCy Schubert     if (it2 == NULL) {
5032b15cb3dSCy Schubert         msyslog(LOG_ERR, "Couldn't allocate transaction memory - Leap Second");
5042b15cb3dSCy Schubert         return;
5052b15cb3dSCy Schubert     }
5062b15cb3dSCy Schubert 
5072b15cb3dSCy Schubert     /* Build CS_GetLeapSec ioctl message */
5082b15cb3dSCy Schubert     it2->dest             = TSYNC_LEAP_DEST_ID;
5092b15cb3dSCy Schubert     it2->iid              = TSYNC_LEAP_IID;
5102b15cb3dSCy Schubert     it2->inPayloadOffset  = TSYNC_LEAP_IN_PYLD_OFF;
5112b15cb3dSCy Schubert     it2->inLength         = TSYNC_LEAP_IN_LEN;
5122b15cb3dSCy Schubert     it2->outPayloadOffset = TSYNC_LEAP_OUT_PYLD_OFF;
5132b15cb3dSCy Schubert     it2->maxOutLength     = TSYNC_LEAP_MAX_OUT_LEN;
5142b15cb3dSCy Schubert     it2->actualOutLength  = 0;
5152b15cb3dSCy Schubert     it2->status           = 0;
5162b15cb3dSCy Schubert     memset(it2->payloads, 0, TSYNC_LEAP_MAX_OUT_LEN);
5172b15cb3dSCy Schubert 
5182b15cb3dSCy Schubert     /* Read the leap seconds info from the TSYNC-PCI device */
5192b15cb3dSCy Schubert     err2 = ioctl(hBoard.file_descriptor,
5202b15cb3dSCy Schubert                  IOCTL_TSYNC_GET,
5212b15cb3dSCy Schubert                  (char *)it2);
5222b15cb3dSCy Schubert 
5232b15cb3dSCy Schubert     pp = peer->procptr;
5242b15cb3dSCy Schubert     up = (TsyncUnit*)pp->unitptr;
5252b15cb3dSCy Schubert 
5262b15cb3dSCy Schubert     /* Read the time from the TSYNC-PCI device */
5272b15cb3dSCy Schubert     err3 = ioctl(hBoard.file_descriptor,
5282b15cb3dSCy Schubert                  IOCTL_TPRO_GET_NTP_TIME,
5292b15cb3dSCy Schubert                  (char *)&TimeContext);
5302b15cb3dSCy Schubert 
5312b15cb3dSCy Schubert     /* Close the TSYNC device */
5322b15cb3dSCy Schubert     close(hBoard.file_descriptor);
5332b15cb3dSCy Schubert 
5342b15cb3dSCy Schubert     // Check for errors
5352b15cb3dSCy Schubert     if ((err < 0) ||(err1 < 0) || (err2 < 0) || (err3 < 0) ||
5362b15cb3dSCy Schubert         (it->status != 0) || (it1->status != 0) || (it2->status != 0) ||
5372b15cb3dSCy Schubert         (it->actualOutLength  != TSYNC_REF_OUT_LEN) ||
5382b15cb3dSCy Schubert         (it1->actualOutLength != TSYNC_TMSCL_OUT_LEN) ||
5392b15cb3dSCy Schubert         (it2->actualOutLength != TSYNC_LEAP_OUT_LEN)) {
5402b15cb3dSCy Schubert         refclock_report(peer, CEVNT_FAULT);
5412b15cb3dSCy Schubert         return;
5422b15cb3dSCy Schubert     }
5432b15cb3dSCy Schubert 
5442b15cb3dSCy Schubert     // Extract reference identifiers from ioctl payload
5452b15cb3dSCy Schubert     memset(timeRef, '\0', sizeof(timeRef));
5462b15cb3dSCy Schubert     memset(ppsRef, '\0', sizeof(ppsRef));
5472b15cb3dSCy Schubert     pRefObj = (void *)it->payloads;
5482b15cb3dSCy Schubert     memcpy(timeRef, pRefObj->time, TSYNC_REF_LEN);
5492b15cb3dSCy Schubert     memcpy(ppsRef, pRefObj->pps, TSYNC_REF_LEN);
5502b15cb3dSCy Schubert 
5512b15cb3dSCy Schubert     // Extract the Clock Service Time Scale and convert to correct byte order
5523311ff84SXin LI     memcpy(&tmscl, it1->payloads, sizeof(tmscl));
5532b15cb3dSCy Schubert     tmscl = ntohl(tmscl);
5542b15cb3dSCy Schubert 
5552b15cb3dSCy Schubert     // Extract leap second info from ioctl payload and perform byte swapping
5562b15cb3dSCy Schubert     for (i = 0; i < (sizeof(leapSec) / 4); i++)
5572b15cb3dSCy Schubert     {
5582b15cb3dSCy Schubert         for (j = 0; j < 4; j++)
5592b15cb3dSCy Schubert         {
5602b15cb3dSCy Schubert             ((unsigned char*)&leapSec)[(i * 4) + j] =
5612b15cb3dSCy Schubert                     ((unsigned char*)(it2->payloads))[(i * 4) + (3 - j)];
5622b15cb3dSCy Schubert         }
5632b15cb3dSCy Schubert     }
5642b15cb3dSCy Schubert 
5652b15cb3dSCy Schubert     // Determine time reference ID from reference name
5662b15cb3dSCy Schubert     for (i = 0; RefIdLookupTbl[i].pRef != NULL; i++)
5672b15cb3dSCy Schubert     {
5682b15cb3dSCy Schubert        // Search RefID table
5692b15cb3dSCy Schubert        if (strstr(timeRef, RefIdLookupTbl[i].pRef) != NULL)
5702b15cb3dSCy Schubert        {
5712b15cb3dSCy Schubert           // Found the matching string
5722b15cb3dSCy Schubert           break;
5732b15cb3dSCy Schubert        }
5742b15cb3dSCy Schubert     }
5752b15cb3dSCy Schubert 
5762b15cb3dSCy Schubert     // Determine pps reference ID from reference name
5772b15cb3dSCy Schubert     for (j = 0; RefIdLookupTbl[j].pRef != NULL; j++)
5782b15cb3dSCy Schubert     {
5792b15cb3dSCy Schubert        // Search RefID table
5802b15cb3dSCy Schubert        if (strstr(ppsRef, RefIdLookupTbl[j].pRef) != NULL)
5812b15cb3dSCy Schubert        {
5822b15cb3dSCy Schubert           // Found the matching string
5832b15cb3dSCy Schubert           break;
5842b15cb3dSCy Schubert        }
5852b15cb3dSCy Schubert     }
5862b15cb3dSCy Schubert 
5872b15cb3dSCy Schubert     // Determine synchronization state from flags
5882b15cb3dSCy Schubert     synch = (TimeContext.timeObj.flags == 0x4) ? 1 : 0;
5892b15cb3dSCy Schubert 
5902b15cb3dSCy Schubert     // Pull seconds information from time object
5912b15cb3dSCy Schubert     seconds = (double) (TimeContext.timeObj.secsDouble);
5922b15cb3dSCy Schubert     seconds /= (double) 1000000.0;
5932b15cb3dSCy Schubert 
5942b15cb3dSCy Schubert     /*
5952b15cb3dSCy Schubert     ** Convert the number of microseconds to double and then place in the
5962b15cb3dSCy Schubert     ** peer's last received long floating point format.
5972b15cb3dSCy Schubert     */
5982b15cb3dSCy Schubert     DTOLFP(((double)TimeContext.tv.tv_usec / 1000000.0), &pp->lastrec);
5992b15cb3dSCy Schubert 
6002b15cb3dSCy Schubert     /*
6012b15cb3dSCy Schubert     ** The specTimeStamp is the number of seconds since 1/1/1970, while the
6022b15cb3dSCy Schubert     ** peer's lastrec time should be compatible with NTP which is seconds since
6032b15cb3dSCy Schubert     ** 1/1/1900.  So Add the number of seconds between 1900 and 1970 to the
6042b15cb3dSCy Schubert     ** specTimeStamp and place in the peer's lastrec long floating point struct.
6052b15cb3dSCy Schubert     */
6062b15cb3dSCy Schubert     pp->lastrec.Ul_i.Xl_ui += (unsigned int)TimeContext.tv.tv_sec +
6072b15cb3dSCy Schubert                                             SECONDS_1900_TO_1970;
6082b15cb3dSCy Schubert 
6092b15cb3dSCy Schubert     pp->polls++;
6102b15cb3dSCy Schubert 
6112b15cb3dSCy Schubert     /*
6122b15cb3dSCy Schubert     **  set the reference clock object
6132b15cb3dSCy Schubert     */
6142b15cb3dSCy Schubert     sprintf(pp->a_lastcode, "%03d %02d:%02d:%02.6f",
6152b15cb3dSCy Schubert             TimeContext.timeObj.days, TimeContext.timeObj.hours,
6162b15cb3dSCy Schubert             TimeContext.timeObj.minutes, seconds);
6172b15cb3dSCy Schubert 
6182b15cb3dSCy Schubert     pp->lencode = strlen (pp->a_lastcode);
6192b15cb3dSCy Schubert     pp->day     = TimeContext.timeObj.days;
6202b15cb3dSCy Schubert     pp->hour    = TimeContext.timeObj.hours;
6212b15cb3dSCy Schubert     pp->minute  = TimeContext.timeObj.minutes;
6222b15cb3dSCy Schubert     pp->second  = (int) seconds;
6232b15cb3dSCy Schubert     seconds     = (seconds - (double) (pp->second / 1.0)) * 1000000000;
6242b15cb3dSCy Schubert     pp->nsec    = (long) seconds;
6252b15cb3dSCy Schubert 
6262b15cb3dSCy Schubert     /*
6272b15cb3dSCy Schubert     **  calculate year start
6282b15cb3dSCy Schubert     */
6292b15cb3dSCy Schubert     jt.year       = TimeContext.timeObj.year;
6302b15cb3dSCy Schubert     jt.yearday    = 1;
6312b15cb3dSCy Schubert     jt.monthday   = 1;
6322b15cb3dSCy Schubert     jt.month      = 1;
6332b15cb3dSCy Schubert     jt.hour       = 0;
6342b15cb3dSCy Schubert     jt.minute     = 0;
6352b15cb3dSCy Schubert     jt.second     = 0;
6362b15cb3dSCy Schubert     pp->yearstart = caltontp(&jt);
6372b15cb3dSCy Schubert 
6382b15cb3dSCy Schubert     // Calculate and report reference clock offset
6392b15cb3dSCy Schubert     offset.l_ui = (long)(((pp->day - 1) * 24) + pp->hour + GMT);
6402b15cb3dSCy Schubert     offset.l_ui = (offset.l_ui * 60) + (long)pp->minute;
6412b15cb3dSCy Schubert     offset.l_ui = (offset.l_ui * 60) + (long)pp->second;
6422b15cb3dSCy Schubert     offset.l_ui = offset.l_ui + (long)pp->yearstart;
6432b15cb3dSCy Schubert     offset.l_uf = 0;
6442b15cb3dSCy Schubert     DTOLFP(pp->nsec / 1e9, &ltemp);
6452b15cb3dSCy Schubert     L_ADD(&offset, &ltemp);
6462b15cb3dSCy Schubert     refclock_process_offset(pp, offset, pp->lastrec,
6472b15cb3dSCy Schubert                             pp->fudgetime1);
6482b15cb3dSCy Schubert 
6492b15cb3dSCy Schubert     // KTS in sync
6502b15cb3dSCy Schubert     if (synch) {
6512b15cb3dSCy Schubert         // Subtract leap second info by one second to determine effective day
6522b15cb3dSCy Schubert         ApplyTimeOffset(&(leapSec.utcDate), -1);
6532b15cb3dSCy Schubert 
6542b15cb3dSCy Schubert         // If there is a leap second today and the KTS is using a time scale
6552b15cb3dSCy Schubert         // which handles leap seconds then
6562b15cb3dSCy Schubert         if ((tmscl != TIME_SCALE_GPS) && (tmscl != TIME_SCALE_TAI) &&
6572b15cb3dSCy Schubert             (leapSec.utcDate.year == (unsigned int)TimeContext.timeObj.year) &&
6582b15cb3dSCy Schubert             (leapSec.utcDate.doy  == (unsigned int)TimeContext.timeObj.days))
6592b15cb3dSCy Schubert         {
6602b15cb3dSCy Schubert             // If adding a second
6612b15cb3dSCy Schubert             if (leapSec.offset == 1)
6622b15cb3dSCy Schubert             {
6632b15cb3dSCy Schubert                 pp->leap = LEAP_ADDSECOND;
6642b15cb3dSCy Schubert             }
6652b15cb3dSCy Schubert             // Else if removing a second
6662b15cb3dSCy Schubert             else if (leapSec.offset == -1)
6672b15cb3dSCy Schubert             {
6682b15cb3dSCy Schubert                 pp->leap = LEAP_DELSECOND;
6692b15cb3dSCy Schubert             }
6702b15cb3dSCy Schubert             // Else report no leap second pending (no handling of offsets
6712b15cb3dSCy Schubert             // other than +1 or -1)
6722b15cb3dSCy Schubert             else
6732b15cb3dSCy Schubert             {
6742b15cb3dSCy Schubert                 pp->leap = LEAP_NOWARNING;
6752b15cb3dSCy Schubert             }
6762b15cb3dSCy Schubert         }
6772b15cb3dSCy Schubert         // Else report no leap second pending
6782b15cb3dSCy Schubert         else
6792b15cb3dSCy Schubert         {
6802b15cb3dSCy Schubert             pp->leap = LEAP_NOWARNING;
6812b15cb3dSCy Schubert         }
6822b15cb3dSCy Schubert 
6832b15cb3dSCy Schubert         peer->leap = pp->leap;
6842b15cb3dSCy Schubert         refclock_report(peer, CEVNT_NOMINAL);
6852b15cb3dSCy Schubert 
6862b15cb3dSCy Schubert         // If reference name reported, then not in holdover
6872b15cb3dSCy Schubert         if ((RefIdLookupTbl[i].pRef != NULL) &&
6882b15cb3dSCy Schubert             (RefIdLookupTbl[j].pRef != NULL))
6892b15cb3dSCy Schubert         {
6902b15cb3dSCy Schubert             // Determine if KTS being synchronized by host (identified as
6912b15cb3dSCy Schubert             // "LOCL")
6922b15cb3dSCy Schubert             if ((strcmp(RefIdLookupTbl[i].pRefId, TSYNC_REF_LOCAL) == 0) ||
6932b15cb3dSCy Schubert                 (strcmp(RefIdLookupTbl[j].pRefId, TSYNC_REF_LOCAL) == 0))
6942b15cb3dSCy Schubert             {
6952b15cb3dSCy Schubert                 // Clear prefer flag
6962b15cb3dSCy Schubert                 peer->flags &= ~FLAG_PREFER;
6972b15cb3dSCy Schubert 
6982b15cb3dSCy Schubert                 // Set reference clock stratum level as unusable
6992b15cb3dSCy Schubert                 pp->stratum   = STRATUM_UNSPEC;
7002b15cb3dSCy Schubert                 peer->stratum = pp->stratum;
7012b15cb3dSCy Schubert 
7022b15cb3dSCy Schubert                 // If a valid peer is available
7032b15cb3dSCy Schubert                 if ((sys_peer != NULL) && (sys_peer != peer))
7042b15cb3dSCy Schubert                 {
7052b15cb3dSCy Schubert                     // Store reference peer stratum level and ID
7062b15cb3dSCy Schubert                     up->refStratum = sys_peer->stratum;
7072b15cb3dSCy Schubert                     up->refId      = addr2refid(&sys_peer->srcadr);
7082b15cb3dSCy Schubert                 }
7092b15cb3dSCy Schubert             }
7102b15cb3dSCy Schubert             else
7112b15cb3dSCy Schubert             {
7122b15cb3dSCy Schubert                 // Restore prefer flag
7132b15cb3dSCy Schubert                 peer->flags |= up->refPrefer;
7142b15cb3dSCy Schubert 
7152b15cb3dSCy Schubert                 // Store reference stratum as local clock
7162b15cb3dSCy Schubert                 up->refStratum = TSYNC_LCL_STRATUM;
7172b15cb3dSCy Schubert                 strncpy((char *)&up->refId, RefIdLookupTbl[j].pRefId,
7182b15cb3dSCy Schubert                     TSYNC_REF_LEN);
7192b15cb3dSCy Schubert 
7202b15cb3dSCy Schubert                 // Set reference clock stratum level as local clock
7212b15cb3dSCy Schubert                 pp->stratum   = TSYNC_LCL_STRATUM;
7222b15cb3dSCy Schubert                 peer->stratum = pp->stratum;
7232b15cb3dSCy Schubert             }
7242b15cb3dSCy Schubert 
7252b15cb3dSCy Schubert             // Update reference name
7262b15cb3dSCy Schubert             strncpy((char *)&pp->refid, RefIdLookupTbl[j].pRefId,
7272b15cb3dSCy Schubert                 TSYNC_REF_LEN);
7282b15cb3dSCy Schubert             peer->refid = pp->refid;
7292b15cb3dSCy Schubert         }
7302b15cb3dSCy Schubert         // Else in holdover
7312b15cb3dSCy Schubert         else
7322b15cb3dSCy Schubert         {
7332b15cb3dSCy Schubert             // Restore prefer flag
7342b15cb3dSCy Schubert             peer->flags |= up->refPrefer;
7352b15cb3dSCy Schubert 
7362b15cb3dSCy Schubert             // Update reference ID to saved ID
7372b15cb3dSCy Schubert             pp->refid   = up->refId;
7382b15cb3dSCy Schubert             peer->refid = pp->refid;
7392b15cb3dSCy Schubert 
7402b15cb3dSCy Schubert             // Update stratum level to saved stratum level
7412b15cb3dSCy Schubert             pp->stratum   = up->refStratum;
7422b15cb3dSCy Schubert             peer->stratum = pp->stratum;
7432b15cb3dSCy Schubert         }
7442b15cb3dSCy Schubert     }
7452b15cb3dSCy Schubert     // Else KTS not in sync
7462b15cb3dSCy Schubert     else {
7472b15cb3dSCy Schubert         // Place local identifier in peer RefID
7482b15cb3dSCy Schubert         strncpy((char *)&pp->refid, TSYNC_REF_LOCAL, TSYNC_REF_LEN);
7492b15cb3dSCy Schubert         peer->refid = pp->refid;
7502b15cb3dSCy Schubert 
7512b15cb3dSCy Schubert         // Report not in sync
7522b15cb3dSCy Schubert         pp->leap   = LEAP_NOTINSYNC;
7532b15cb3dSCy Schubert         peer->leap = pp->leap;
7542b15cb3dSCy Schubert     }
7552b15cb3dSCy Schubert 
7562b15cb3dSCy Schubert     if (pp->coderecv == pp->codeproc) {
7572b15cb3dSCy Schubert         refclock_report(peer, CEVNT_TIMEOUT);
7582b15cb3dSCy Schubert         return;
7592b15cb3dSCy Schubert     }
7602b15cb3dSCy Schubert 
7612b15cb3dSCy Schubert     record_clock_stats(&peer->srcadr, pp->a_lastcode);
7622b15cb3dSCy Schubert     refclock_receive(peer);
7632b15cb3dSCy Schubert 
7642b15cb3dSCy Schubert     /* Increment the number of times the reference has been polled */
7652b15cb3dSCy Schubert     pp->polls++;
7662b15cb3dSCy Schubert 
7672b15cb3dSCy Schubert } /* End - tsync_poll() */
7682b15cb3dSCy Schubert 
7692b15cb3dSCy Schubert 
7702b15cb3dSCy Schubert ////////////////////////////////////////////////////////////////////////////////
7712b15cb3dSCy Schubert // Function:    ApplyTimeOffset
7722b15cb3dSCy Schubert // Description: The ApplyTimeOffset function adds an offset (in seconds) to a
7732b15cb3dSCy Schubert //              specified date and time.  The specified date and time is passed
7742b15cb3dSCy Schubert //              back after being modified.
7752b15cb3dSCy Schubert //
7762b15cb3dSCy Schubert // Assumptions: 1. Every fourth year is a leap year.  Therefore, this function
7772b15cb3dSCy Schubert //                 is only accurate through Feb 28, 2100.
7782b15cb3dSCy Schubert ////////////////////////////////////////////////////////////////////////////////
7792b15cb3dSCy Schubert void ApplyTimeOffset(DoyTimeObj* pDt, int off)
7802b15cb3dSCy Schubert {
7812b15cb3dSCy Schubert     SecTimeObj st;                  // Time, in seconds
7822b15cb3dSCy Schubert 
7832b15cb3dSCy Schubert 
7842b15cb3dSCy Schubert     // Convert date and time to seconds
7852b15cb3dSCy Schubert     SecTimeFromDoyTime(&st, pDt);
7862b15cb3dSCy Schubert 
7872b15cb3dSCy Schubert     // Apply offset
7882b15cb3dSCy Schubert     st.seconds = (int)((signed long long)st.seconds + (signed long long)off);
7892b15cb3dSCy Schubert 
7902b15cb3dSCy Schubert     // Convert seconds to date and time
7912b15cb3dSCy Schubert     DoyTimeFromSecTime(pDt, &st);
7922b15cb3dSCy Schubert 
7932b15cb3dSCy Schubert } // End ApplyTimeOffset
7942b15cb3dSCy Schubert 
7952b15cb3dSCy Schubert 
7962b15cb3dSCy Schubert ////////////////////////////////////////////////////////////////////////////////
7972b15cb3dSCy Schubert // Function:    SecTimeFromDoyTime
7982b15cb3dSCy Schubert // Description: The SecTimeFromDoyTime function converts a specified date
7992b15cb3dSCy Schubert //              and time into a count of seconds since the base time.  This
8002b15cb3dSCy Schubert //              function operates across the range Base Time to Max Time for
8012b15cb3dSCy Schubert //              the system.
8022b15cb3dSCy Schubert //
8032b15cb3dSCy Schubert // Assumptions: 1. A leap year is any year evenly divisible by 4.  Therefore,
8042b15cb3dSCy Schubert //                 this function is only accurate through Feb 28, 2100.
8052b15cb3dSCy Schubert //              2. Conversion does not account for leap seconds.
8062b15cb3dSCy Schubert ////////////////////////////////////////////////////////////////////////////////
8072b15cb3dSCy Schubert void SecTimeFromDoyTime(SecTimeObj* pSt, DoyTimeObj* pDt)
8082b15cb3dSCy Schubert {
8092b15cb3dSCy Schubert     unsigned int yrs;               // Years
8102b15cb3dSCy Schubert     unsigned int lyrs;              // Leap years
8112b15cb3dSCy Schubert 
8122b15cb3dSCy Schubert 
8132b15cb3dSCy Schubert     // Start with accumulated time of 0
8142b15cb3dSCy Schubert     pSt->seconds  = 0;
8152b15cb3dSCy Schubert 
8162b15cb3dSCy Schubert     // Calculate the number of years and leap years
8172b15cb3dSCy Schubert     yrs           = pDt->year - TSYNC_TIME_BASE_YEAR;
8182b15cb3dSCy Schubert     lyrs          = (yrs + 1) / 4;
8192b15cb3dSCy Schubert 
8202b15cb3dSCy Schubert     // Convert leap years and years
8212b15cb3dSCy Schubert     pSt->seconds += lyrs           * SECSPERLEAPYEAR;
8222b15cb3dSCy Schubert     pSt->seconds += (yrs - lyrs)   * SECSPERYEAR;
8232b15cb3dSCy Schubert 
8242b15cb3dSCy Schubert     // Convert days, hours, minutes and seconds
8252b15cb3dSCy Schubert     pSt->seconds += (pDt->doy - 1) * SECSPERDAY;
8262b15cb3dSCy Schubert     pSt->seconds += pDt->hour      * SECSPERHR;
8272b15cb3dSCy Schubert     pSt->seconds += pDt->minute    * SECSPERMIN;
8282b15cb3dSCy Schubert     pSt->seconds += pDt->second;
8292b15cb3dSCy Schubert 
8302b15cb3dSCy Schubert     // Copy the subseconds count
8312b15cb3dSCy Schubert     pSt->ns       = pDt->ns;
8322b15cb3dSCy Schubert 
8332b15cb3dSCy Schubert } // End SecTimeFromDoyTime
8342b15cb3dSCy Schubert 
8352b15cb3dSCy Schubert 
8362b15cb3dSCy Schubert ////////////////////////////////////////////////////////////////////////////////
8372b15cb3dSCy Schubert // Function:    DoyTimeFromSecTime
8382b15cb3dSCy Schubert // Description: The DoyTimeFromSecTime function converts a specified count
8392b15cb3dSCy Schubert //              of seconds since the start of our base time into a SecTimeObj
8402b15cb3dSCy Schubert //              structure.
8412b15cb3dSCy Schubert //
8422b15cb3dSCy Schubert // Assumptions: 1. A leap year is any year evenly divisible by 4.  Therefore,
8432b15cb3dSCy Schubert //                 this function is only accurate through Feb 28, 2100.
8442b15cb3dSCy Schubert //              2. Conversion does not account for leap seconds.
8452b15cb3dSCy Schubert ////////////////////////////////////////////////////////////////////////////////
8462b15cb3dSCy Schubert void DoyTimeFromSecTime(DoyTimeObj* pDt, SecTimeObj* pSt)
8472b15cb3dSCy Schubert {
8482b15cb3dSCy Schubert     signed long long secs;          // Seconds accumulator variable
8492b15cb3dSCy Schubert     unsigned int     yrs;           // Years accumulator variable
8502b15cb3dSCy Schubert     unsigned int     doys;          // Days accumulator variable
8512b15cb3dSCy Schubert     unsigned int     hrs;           // Hours accumulator variable
8522b15cb3dSCy Schubert     unsigned int     mins;          // Minutes accumulator variable
8532b15cb3dSCy Schubert 
8542b15cb3dSCy Schubert 
8552b15cb3dSCy Schubert     // Convert the seconds count into a signed 64-bit number for calculations
8562b15cb3dSCy Schubert     secs  = (signed long long)(pSt->seconds);
8572b15cb3dSCy Schubert 
8582b15cb3dSCy Schubert     // Calculate the number of 4 year chunks
8592b15cb3dSCy Schubert     yrs   = (unsigned int)((secs /
8602b15cb3dSCy Schubert                            ((SECSPERYEAR * 3) + SECSPERLEAPYEAR)) * 4);
8612b15cb3dSCy Schubert     secs %= ((SECSPERYEAR * 3) + SECSPERLEAPYEAR);
8622b15cb3dSCy Schubert 
8632b15cb3dSCy Schubert     // If there is at least a normal year worth of time left
8642b15cb3dSCy Schubert     if (secs >= SECSPERYEAR)
8652b15cb3dSCy Schubert     {
8662b15cb3dSCy Schubert         // Increment the number of years and subtract a normal year of time
8672b15cb3dSCy Schubert         yrs++;
8682b15cb3dSCy Schubert         secs -= SECSPERYEAR;
8692b15cb3dSCy Schubert     }
8702b15cb3dSCy Schubert 
8712b15cb3dSCy Schubert     // If there is still at least a normal year worth of time left
8722b15cb3dSCy Schubert     if (secs >= SECSPERYEAR)
8732b15cb3dSCy Schubert     {
8742b15cb3dSCy Schubert         // Increment the number of years and subtract a normal year of time
8752b15cb3dSCy Schubert         yrs++;
8762b15cb3dSCy Schubert         secs -= SECSPERYEAR;
8772b15cb3dSCy Schubert     }
8782b15cb3dSCy Schubert 
8792b15cb3dSCy Schubert     // If there is still at least a leap year worth of time left
8802b15cb3dSCy Schubert     if (secs >= SECSPERLEAPYEAR)
8812b15cb3dSCy Schubert     {
8822b15cb3dSCy Schubert         // Increment the number of years and subtract a leap year of time
8832b15cb3dSCy Schubert         yrs++;
8842b15cb3dSCy Schubert         secs -= SECSPERLEAPYEAR;
8852b15cb3dSCy Schubert     }
8862b15cb3dSCy Schubert 
8872b15cb3dSCy Schubert     // Calculate the day of year as the number of days left, then add 1
8882b15cb3dSCy Schubert     // because months start on the 1st.
8892b15cb3dSCy Schubert     doys  = (unsigned int)((secs / SECSPERDAY) + 1);
8902b15cb3dSCy Schubert     secs %= SECSPERDAY;
8912b15cb3dSCy Schubert 
8922b15cb3dSCy Schubert     // Calculate the hour
8932b15cb3dSCy Schubert     hrs   = (unsigned int)(secs / SECSPERHR);
8942b15cb3dSCy Schubert     secs %= SECSPERHR;
8952b15cb3dSCy Schubert 
8962b15cb3dSCy Schubert     // Calculate the minute
8972b15cb3dSCy Schubert     mins  = (unsigned int)(secs / SECSPERMIN);
8982b15cb3dSCy Schubert     secs %= SECSPERMIN;
8992b15cb3dSCy Schubert 
9002b15cb3dSCy Schubert     // Fill in the doytime structure
9012b15cb3dSCy Schubert     pDt->year   = yrs + TSYNC_TIME_BASE_YEAR;
9022b15cb3dSCy Schubert     pDt->doy    = doys;
9032b15cb3dSCy Schubert     pDt->hour   = hrs;
9042b15cb3dSCy Schubert     pDt->minute = mins;
9052b15cb3dSCy Schubert     pDt->second = (unsigned int)secs;
9062b15cb3dSCy Schubert     pDt->ns     = pSt->ns;
9072b15cb3dSCy Schubert 
9082b15cb3dSCy Schubert } // End DoyTimeFromSecTime
9092b15cb3dSCy Schubert 
9102b15cb3dSCy Schubert #else
911*f5f40dd6SCy Schubert NONEMPTY_TRANSLATION_UNIT
9122b15cb3dSCy Schubert #endif /* REFCLOCK */
913