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 *******************************************************************************/
tsync_start(int unit,struct peer * peer)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 *******************************************************************************/
tsync_shutdown(int unit,struct peer * peer)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 *******************************************************************************/
tsync_poll(int unit,struct peer * peer)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, <emp);
6452b15cb3dSCy Schubert L_ADD(&offset, <emp);
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 ////////////////////////////////////////////////////////////////////////////////
ApplyTimeOffset(DoyTimeObj * pDt,int off)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 ////////////////////////////////////////////////////////////////////////////////
SecTimeFromDoyTime(SecTimeObj * pSt,DoyTimeObj * pDt)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 ////////////////////////////////////////////////////////////////////////////////
DoyTimeFromSecTime(DoyTimeObj * pDt,SecTimeObj * pSt)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