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, <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 //////////////////////////////////////////////////////////////////////////////// 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