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