xref: /freebsd/contrib/ntp/ntpd/refclock_oncore.c (revision daf1cffce2e07931f27c6c6998652e90df6ba87e)
1 /*
2  * ----------------------------------------------------------------------------
3  * "THE BEER-WARE LICENSE" (Revision 42):
4  * <phk@FreeBSD.ORG> wrote this file.  As long as you retain this notice you
5  * can do whatever you want with this stuff. If we meet some day, and you think
6  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
7  * ----------------------------------------------------------------------------
8  *
9  * refclock_oncore.c
10  *
11  * Driver for some of the various the Motorola Oncore GPS receivers.
12  *
13  * Tested with:
14  *
15  *		(UT)				   (VP)
16  *   COPYRIGHT 1991-1997 MOTOROLA INC.	COPYRIGHT 1991-1996 MOTOROLA INC.
17  *   SFTW P/N #     98-P36848P		SFTW P/N # 98-P36830P
18  *   SOFTWARE VER # 2			SOFTWARE VER # 8
19  *   SOFTWARE REV # 2			SOFTWARE REV # 8
20  *   SOFTWARE DATE  APR 24 1998 	SOFTWARE DATE  06 Aug 1996
21  *   MODEL #	R1121N1114		MODEL #    B4121P1155
22  *   HWDR P/N # 1			HDWR P/N # _
23  *   SERIAL #	R0010A			SERIAL #   SSG0226478
24  *   MANUFACTUR DATE 6H07		MANUFACTUR DATE 7E02
25  *					OPTIONS LIST	IB
26  *
27  * --------------------------------------------------------------------------
28  * This code uses the two devices
29  *      /dev/oncore.serial.n
30  *      /dev/oncore.pps.n
31  * which may be linked to the same device.
32  * and can read initialization data from the file
33  *      /etc/ntp.oncoreN (where n and N are the unit number, viz 127.127.30.N)
34  *  or	/etc/ntp.oncore
35  * --------------------------------------------------------------------------
36  * Reg.Clemens <reg@dwf.com> Sep98.
37  *  Original code written for FreeBSD.
38  *  With these mods it works on SunOS, Solaris (untested) and Linux
39  *    (RedHat 5.1 2.0.35 + PPSKit, 2.1.126 + changes).
40  *
41  *  Lat,Long,Ht, cable-delay, offset, and the ReceiverID (along with the
42  *  state machine state) are printed to CLOCKSTATS if that file is enabled
43  *  in /etc/ntp.conf.
44  *
45  * --------------------------------------------------------------------------
46  */
47 
48 /*
49  * According to the ONCORE manual (TRM0003, Rev 3.2, June 1998, page 3.13)
50  * doing an average of 10000 valid 2D and 3D fixes is what the automatic
51  * site survey mode does.  Looking at the output from the receiver
52  * it seems like it is only using 3D fixes.
53  * When we do it ourselves, take 10000 3D fixes.
54  */
55 
56 #define POS_HOLD_AVERAGE	10000	/* nb, 10000s ~= 2h45m */
57 
58 /*
59  * ONCORE_SHMEM_STATUS will create a mmap(2)'ed file named according to a
60  * "STATUS" line in the oncore config file, which contains the most recent
61  * copy of all types of messages we recognize.  This file can be mmap(2)'ed
62  * by monitoring and statistics programs.
63  */
64 
65 #ifdef HAVE_CONFIG_H
66 #include <config.h>
67 #endif
68 
69 #if defined(REFCLOCK) && defined(CLOCK_ONCORE)
70 
71 #include <stdio.h>
72 #include <ctype.h>
73 #include <sys/types.h>
74 #include <sys/time.h>
75 #include <sys/stat.h>
76 #ifdef ONCORE_SHMEM_STATUS
77 # ifdef HAVE_SYS_MMAN_H
78 #  include <sys/mman.h>
79 #  ifndef MAP_FAILED
80 #   define MAP_FAILED ((u_char *) -1)
81 #  endif  /* not MAP_FAILED */
82 # endif /* HAVE_SYS_MMAN_H */
83 #endif /* ONCORE_SHMEM_STATUS */
84 
85 #ifdef HAVE_PPSAPI
86 #  ifdef HAVE_TIMEPPS_H
87 #    include <timepps.h>
88 # else
89 #  ifdef HAVE_SYS_TIMEPPS_H
90 #    include <sys/timepps.h>
91 #  endif
92 # endif
93 #endif
94 
95 #ifdef HAVE_SYS_SIO_H
96 # include <sys/sio.h>
97 #endif
98 
99 #include "ntpd.h"
100 #include "ntp_io.h"
101 #include "ntp_unixtime.h"
102 #include "ntp_refclock.h"
103 #include "ntp_stdlib.h"
104 
105 #ifdef HAVE_SYS_TERMIOS_H
106 #include <sys/termios.h>
107 #endif
108 
109 #ifdef HAVE_SYS_PPSCLOCK_H
110 # include <sys/ppsclock.h>
111 #endif
112 
113 #ifndef HAVE_STRUCT_PPSCLOCKEV
114 struct ppsclockev {
115 # ifdef HAVE_TIMESPEC
116 	struct timespec tv;
117 # else
118 	struct timeval tv;
119 # endif
120 	u_int serial;
121 };
122 #endif /* not HAVE_STRUCT_PPSCLOCKEV */
123 
124 enum receive_state {
125 	ONCORE_NO_IDEA,
126 	ONCORE_RESET_SENT,
127 	ONCORE_TEST_SENT,
128 	ONCORE_ID_SENT,
129 	ONCORE_ALMANAC,
130 	ONCORE_RUN
131 };
132 
133 enum site_survey_state {
134 	ONCORE_SS_UNKNOWN,
135 	ONCORE_SS_HW,
136 	ONCORE_SS_SW,
137 	ONCORE_SS_DONE
138 };
139 
140 struct instance {
141 	int	unit;		/* 127.127.30.unit */
142 	int	ttyfd;		/* TTY file descriptor */
143 	int	ppsfd;		/* PPS file descriptor */
144 	int	statusfd;	/* Status shm descriptor */
145 	u_char	*shmem;
146 #ifdef HAVE_PPSAPI
147 	pps_handle_t pps_h;
148 	pps_params_t pps_p;
149 #endif
150 	enum receive_state o_state;		/* Receive state */
151 
152 	enum site_survey_state site_survey;	/* Site Survey state */
153 
154 	struct	refclockproc *pp;
155 	struct	peer *peer;
156 
157 	int	Bj_day;
158 
159 	long	delay;		/* ns */
160 	long	offset; 	/* ns */
161 
162 	double	ss_lat;
163 	double	ss_long;
164 	double	ss_ht;
165 	int	ss_count;
166 	u_char	ss_ht_type;
167 	u_char  posn_set;
168 
169 	u_char  printed;
170 	u_char  polled;
171 	int	pollcnt;
172 	u_int	ev_serial;
173 	int	Rcvptr;
174 	u_char	Rcvbuf[500];
175 	u_char	Ea[77];
176 	u_char	En[70];
177 	u_char	Cj[300];
178 	u_char	As;
179 	u_char	Ay;
180 	u_char	Az;
181 	u_char	init_type;
182 	s_char	saw_tooth;
183 	u_char  timeout;        /* flag to retry Cj after Fa reset */
184 	s_char  assert;
185 };
186 
187 #define rcvbuf	instance->Rcvbuf
188 #define rcvptr	instance->Rcvptr
189 
190 static	void	oncore_consume	  P((struct instance *));
191 static	void	oncore_poll	  P((int, struct peer *));
192 static	void	oncore_read_config	P((struct instance *));
193 static	void	oncore_receive	  P((struct recvbuf *));
194 static	void	oncore_sendmsg	  P((int fd, u_char *, u_int));
195 static	void	oncore_shutdown   P((int, struct peer *));
196 static	int	oncore_start	  P((int, struct peer *));
197 
198 static	void	oncore_msg_any	P((struct instance *, u_char *, u_int, int));
199 static	void	oncore_msg_As	P((struct instance *, u_char *, u_int));
200 static	void	oncore_msg_At	P((struct instance *, u_char *, u_int));
201 static	void	oncore_msg_Ay	P((struct instance *, u_char *, u_int));
202 static	void	oncore_msg_Az	P((struct instance *, u_char *, u_int));
203 static	void	oncore_msg_Bj	P((struct instance *, u_char *, u_int));
204 static	void	oncore_msg_Cb	P((struct instance *, u_char *, u_int));
205 static	void	oncore_msg_Cf	P((struct instance *, u_char *, u_int));
206 static	void	oncore_msg_Cj	P((struct instance *, u_char *, u_int));
207 static	void	oncore_msg_Ea	P((struct instance *, u_char *, u_int));
208 static	void	oncore_msg_En	P((struct instance *, u_char *, u_int));
209 static	void	oncore_msg_Fa	P((struct instance *, u_char *, u_int));
210 
211 struct	refclock refclock_oncore = {
212 	oncore_start,		/* start up driver */
213 	oncore_shutdown,	/* shut down driver */
214 	oncore_poll,		/* transmit poll message */
215 	noentry,		/* not used */
216 	noentry,		/* not used */
217 	noentry,		/* not used */
218 	NOFLAGS 		/* not used */
219 };
220 
221 /*
222  * Understanding the next bit here is not easy unless you have a manual
223  * for the the UT or VP Oncore.
224  */
225 
226 static struct msg_desc {
227 	const char	flag[3];
228 	const int	len;
229 	void		(*handler) P((struct instance *, u_char *, u_int));
230 	const char	*fmt;
231 	int		shmem;
232 } oncore_messages[] = {
233 	/* Ea and En first since they're most common */
234 	{ "Ea",  76,    oncore_msg_Ea,  "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdimsdimsdsC" },
235 	{ "En",  69,    oncore_msg_En,  "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffsffffsffffC" },
236 	{ "Ab",  10,    0,              "" },
237 	{ "Ac",  11,    0,              "" },
238 	{ "Ad",  11,    0,              "" },
239 	{ "Ae",  11,    0,              "" },
240 	{ "Af",  15,    0,              "" },
241 	{ "As",  20,    oncore_msg_As,  "" },
242 	{ "At",   8,    oncore_msg_At,  "" },
243 	{ "Aw",   8,    0,              "" },
244 	{ "Ay",  11,    oncore_msg_Ay,  "" },
245 	{ "Az",  11,    oncore_msg_Az,  "" },
246 	{ "AB",   8,    0,              "" },
247 	{ "Bb",  92,    0,              "" },
248 	{ "Bj",   8,    oncore_msg_Bj,  "" },
249 	{ "Cb",  33,    oncore_msg_Cb,  "" },
250 	{ "Cf",   7,    oncore_msg_Cf,  "" },
251 	{ "Cg",   8,    0,              "" },
252 	{ "Ch",   9,    0,              "" },
253 	{ "Cj", 294,    oncore_msg_Cj,  "" },
254 	{ "Ek",  71,    0,              "" },
255 	{ "Fa",   9,    oncore_msg_Fa,  "" },
256 	{ "Sz",   8,    0,              "" },
257 	{ {0},	  7,	0, ""}
258 };
259 
260 static unsigned int oncore_shmem_Cb;
261 
262 /*
263  * Position Set.
264  */
265 u_char oncore_cmd_Ad[] = { 'A', 'd', 0,0,0,0 };
266 u_char oncore_cmd_Ae[] = { 'A', 'e', 0,0,0,0 };
267 u_char oncore_cmd_Af[] = { 'A', 'f', 0,0,0,0, 0 };
268 
269 /*
270  * Position-Hold Mode
271  *    Start automatic site survey
272  */
273 static u_char oncore_cmd_At[] = { 'A', 't', 2 };
274 
275 /*
276  * Position-Hold Position
277  */
278 u_char oncore_cmd_As[] = { 'A', 's', 0,0,0,0, 0,0,0,0, 0,0,0,0, 0 };
279 u_char oncore_cmd_Asx[]= { 'A', 's', 0x7f, 0xff, 0xff, 0xff,
280 				     0x7f, 0xff, 0xff, 0xff,
281 				     0x7f, 0xff, 0xff, 0xff, 0xff };
282 
283 /*
284  * Set to UTC time (not GPS).
285  */
286 u_char oncore_cmd_Aw[] = { 'A', 'w', 1 };
287 
288 /*
289  * Output Almanac when it changes
290  */
291 u_char oncore_cmd_Be[] = { 'B', 'e', 1 };
292 
293 /*
294  * Read back PPS Offset for Output
295  */
296 u_char oncore_cmd_Ay[]	= { 'A', 'y', 0, 0, 0, 0 };
297 u_char oncore_cmd_Ayx[] = { 'A', 'y', 0xff, 0xff, 0xff, 0xff };
298 
299 /*
300  * Read back Cable Delay for Output
301  */
302 u_char oncore_cmd_Az[]	= { 'A', 'z', 0, 0, 0, 0 };
303 u_char oncore_cmd_Azx[] = { 'A', 'z', 0xff, 0xff, 0xff, 0xff };
304 
305 /*
306  * Application type = static.
307  */
308 u_char oncore_cmd_AB[] = { 'A', 'B', 4 };
309 
310 /*
311  * Visible Satellite Status Msg.
312  */
313 u_char oncore_cmd_Bb[] = { 'B', 'b', 1 };
314 
315 /*
316  * Leap Second Pending Message
317  *    Request message once
318  */
319 u_char oncore_cmd_Bj[] = { 'B', 'j', 0 };
320 
321 /*
322  * Set to Defaults
323  */
324 static u_char oncore_cmd_Cf[] = { 'C', 'f' };
325 
326 /*
327  * Set to Position Fix mode (only needed on VP).
328  */
329 u_char oncore_cmd_Cg[] = { 'C', 'g', 1 };
330 
331 /*
332  * Receiver Id
333  */
334 static u_char oncore_cmd_Cj[] = { 'C', 'j' };
335 
336 /*
337  * Position/Status/Data message
338  *    Send once per second
339  */
340 static u_char oncore_cmd_Ea[] = { 'E', 'a', 1 };
341 
342 /*
343  * Position/Status Extension Msg
344  */
345 u_char oncore_cmd_Ek[] = { 'E', 'k', 0 };	/* just turn off */
346 
347 /*
348  * Time Raim Setup & Status Message
349  *    Send once per second
350  *    Time-RAIM on
351  *    Alarm limit 1us
352  *    PPS on when we have the first sat
353  */
354 static u_char oncore_cmd_En[] = { 'E', 'n', 1, 1, 0,10, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
355 
356 /*
357  * Self-test
358  */
359 static u_char oncore_cmd_Fa[] = { 'F', 'a' };
360 
361 #define DEVICE1 	"/dev/oncore.serial.%d"   /* name of serial device */
362 #define DEVICE2 	"/dev/oncore.pps.%d"   /* name of pps device */
363 #define INIT_FILE	"/etc/ntp.oncore" /* optional init file */
364 
365 #define SPEED		B9600		/* Oncore Binary speed (9600 bps) */
366 
367 /*
368  * Assemble and disassemble 32bit signed quantities from a buffer.
369  *
370  */
371 
372 	/* to buffer, int w, u_char *buf */
373 #define w32_buf(buf,w)	{ unsigned int i_tmp;		   \
374 			  i_tmp = (w<0) ? (~(-w)+1) : (w); \
375 			  (buf)[0] = (i_tmp >> 24) & 0xff; \
376 			  (buf)[1] = (i_tmp >> 16) & 0xff; \
377 			  (buf)[2] = (i_tmp >>	8) & 0xff; \
378 			  (buf)[3] = (i_tmp	 ) & 0xff; \
379 			}
380 
381 #define w32(buf)      (((buf)[0]&0xff) << 24 | \
382 		       ((buf)[1]&0xff) << 16 | \
383 		       ((buf)[2]&0xff) <<  8 | \
384 		       ((buf)[3]&0xff) )
385 
386 	/* from buffer, char *buf, result to an int */
387 #define buf_w32(buf) (((buf)[0]&0200) ? (-(~w32(buf)+1)) : w32(buf))
388 
389 extern int pps_assert;
390 extern int pps_hardpps;
391 
392 
393 /*
394  * oncore_start - initialize data for processing
395  */
396 static int
397 oncore_start(
398 	int unit,
399 	struct peer *peer
400 	)
401 {
402 	register struct instance *instance;
403 	struct refclockproc *pp;
404 	int fd1, fd2, mode;
405 	char device1[30], device2[30];
406 	const char *cp;
407 	struct stat stat1, stat2;
408 
409 	/* OPEN DEVICES */
410 	/* opening different devices for fd1 and fd2 presents no problems */
411 	/* opening the SAME device twice, seems to be OS dependent.
412 		(a) on Linux (no streams) no problem
413 		(b) on SunOS (and possibly Solaris, untested), (streams)
414 			never see the line discipline.
415 	   Since things ALWAYS work if we only open the device once, we check
416 	     to see if the two devices are in fact the same, then proceed to
417 	     do one open or two.
418 	*/
419 
420 	(void)sprintf(device1, DEVICE1, unit);
421 	(void)sprintf(device2, DEVICE2, unit);
422 
423 	if (stat(device1, &stat1)) {
424 		perror("ONCORE: stat fd1");
425 		exit(1);
426 	}
427 
428 	if (stat(device2, &stat2)) {
429 		perror("ONCORE: stat fd2");
430 		exit(1);
431 	}
432 
433 	if ((stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino)) {
434 		/* same device here */
435 		if (!(fd1 = refclock_open(device1, SPEED, LDISC_RAW
436 #if !defined(HAVE_PPSAPI) && !defined(TIOCDCDTIMESTAMP)
437 		      | LDISC_PPS
438 #endif
439 		   ))) {
440 			perror("ONCORE: fd1");
441 			exit(1);
442 		}
443 		fd2 = fd1;
444 	} else { /* different devices here */
445 		if (!(fd1=refclock_open(device1, SPEED, LDISC_RAW))) {
446 			perror("ONCORE: fd1");
447 			exit(1);
448 		}
449 		if ((fd2=open(device2, O_RDWR)) < 0) {
450 			perror("ONCORE: fd2");
451 			exit(1);
452 		}
453 	}
454 
455 	/* Devices now open, initialize instance structure */
456 
457 	if (!(instance = (struct instance *)emalloc(sizeof *instance))) {
458 		perror("malloc");
459 		close(fd1);
460 		return (0);
461 	}
462 	memset((char *) instance, 0, sizeof *instance);
463 	pp = peer->procptr;
464 	pp->unitptr = (caddr_t)instance;
465 	instance->unit	= unit;
466 	instance->ttyfd = fd1;
467 	instance->ppsfd = fd2;
468 
469 	instance->Bj_day = -1;
470 	instance->assert = pps_assert;
471 
472 	/* go read any input data in /etc/ntp.oncoreX */
473 
474 	oncore_read_config(instance);
475 
476 #ifdef HAVE_PPSAPI
477 	if (time_pps_create(fd2, &instance->pps_h) < 0) {
478 		perror("time_pps_create");
479 		return(0);
480 	}
481 
482 	if (time_pps_getcap(instance->pps_h, &mode) < 0) {
483 		msyslog(LOG_ERR,
484 		    "refclock_ioctl: time_pps_getcap failed: %m");
485 		return (0);
486 	}
487 
488 	if (time_pps_getparams(instance->pps_h, &instance->pps_p) < 0) {
489 		msyslog(LOG_ERR,
490 		    "refclock_ioctl: time_pps_getparams failed: %m");
491 		return (0);
492 	}
493 
494 	/* nb. only turn things on, if someone else has turned something
495 	 *      on before we get here, leave it alone!
496 	 */
497 
498 	if (instance->assert) {         /* nb, default or ON */
499 		instance->pps_p.mode = PPS_CAPTUREASSERT | PPS_OFFSETASSERT;
500 		instance->pps_p.assert_offset.tv_sec = 0;
501 		instance->pps_p.assert_offset.tv_nsec = 0;
502 	} else {
503 		instance->pps_p.mode = PPS_CAPTURECLEAR  | PPS_OFFSETCLEAR;
504 		instance->pps_p.clear_offset.tv_sec = 0;
505 		instance->pps_p.clear_offset.tv_nsec = 0;
506 	}
507 	instance->pps_p.mode |= PPS_TSFMT_TSPEC;
508 	instance->pps_p.mode &= mode;           /* only do it if it is legal */
509 
510 	if (time_pps_setparams(instance->pps_h, &instance->pps_p) < 0) {
511 		perror("time_pps_setparams");
512 		exit(1);
513 	}
514 
515 	if (pps_device) {
516 		if (stat(pps_device, &stat1)) {
517 			perror("ONCORE: stat pps_device");
518 			return(0);
519 		}
520 
521 		/* must have hardpps ON, and fd2 must be the same device as on the pps line */
522 
523 		if (pps_hardpps && ((stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino))) {
524 			int     i;
525 
526 			if (instance->assert)
527 				i = PPS_CAPTUREASSERT;
528 			else
529 				i = PPS_CAPTURECLEAR;
530 
531 			if (i&mode) {
532 				if (time_pps_kcbind(instance->pps_h, PPS_KC_HARDPPS, i,
533 				    PPS_TSFMT_TSPEC) < 0) {
534 					msyslog(LOG_ERR,
535 					    "refclock_ioctl: time_pps_kcbind failed: %m");
536 					return (0);
537 				}
538 			}
539 		}
540 	}
541 #endif
542 
543 	instance->pp = pp;
544 	instance->peer = peer;
545 	instance->o_state = ONCORE_NO_IDEA;
546 	cp = "state = ONCORE_NO_IDEA";
547 	record_clock_stats(&(instance->peer->srcadr), cp);
548 
549 	/*
550 	 * Initialize miscellaneous variables
551 	 */
552 
553 	peer->precision = -26;
554 	peer->minpoll = 4;
555 	peer->maxpoll = 4;
556 	pp->clockdesc = "Motorola UT/VP Oncore GPS Receiver";
557 	memcpy((char *)&pp->refid, "GPS\0", 4);
558 
559 	pp->io.clock_recv = oncore_receive;
560 	pp->io.srcclock = (caddr_t)peer;
561 	pp->io.datalen = 0;
562 	pp->io.fd = fd1;
563 	if (!io_addclock(&pp->io)) {
564 		perror("io_addclock");
565 		(void) close(fd1);
566 		free(instance);
567 		return (0);
568 	}
569 	pp->unitptr = (caddr_t)instance;
570 
571 	/*
572 	 * This will start the Oncore receiver.
573 	 * We send info from config to Oncore later.
574 	 */
575 
576 	instance->timeout = 1;
577 	mode = instance->init_type;
578 	if (mode == 3 || mode == 4) {
579 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Cf, sizeof oncore_cmd_Cf);
580 		instance->o_state = ONCORE_RESET_SENT;
581 		cp = "state = ONCORE_RESET_SENT";
582 		record_clock_stats(&(instance->peer->srcadr), cp);
583 	} else {
584 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Fa, sizeof oncore_cmd_Fa);
585 		instance->o_state = ONCORE_TEST_SENT;
586 		cp = "state = ONCORE_TEST_SENT";
587 		record_clock_stats(&(instance->peer->srcadr), cp);
588 	}
589 
590 	instance->pollcnt = 2;
591 	return (1);
592 }
593 
594 
595 
596 static void
597 oncore_init_shmem(struct instance *instance, char *filename)
598 {
599 #ifdef ONCORE_SHMEM_STATUS
600 	int i, l, n;
601 	char *buf;
602 	struct msg_desc *mp;
603 	static unsigned int oncore_shmem_length;
604 
605 	if (oncore_messages[0].shmem == 0) {
606 		n = 1;
607 		for (mp = oncore_messages; mp->flag[0]; mp++) {
608 			mp->shmem = n;
609 			/* Allocate space for multiplexed almanac */
610 			if (!strcmp(mp->flag, "Cb")) {
611 				oncore_shmem_Cb = n;
612 				n += (mp->len + 2) * 34;
613 			}
614 			n += mp->len + 2;
615 		}
616 		oncore_shmem_length = n + 2;
617 		fprintf(stderr, "ONCORE: SHMEM length: %d bytes\n", oncore_shmem_length);
618 	}
619 	instance->statusfd = open(filename, O_RDWR|O_CREAT|O_TRUNC, 0644);
620 	if (instance->statusfd < 0) {
621 		perror(filename);
622 		exit(4);
623 	}
624 	buf = malloc(oncore_shmem_length);
625 	if (buf == NULL) {
626 		perror("malloc");
627 		exit(4);
628 	}
629 	memset(buf, 0, sizeof(buf));
630 	i = write(instance->statusfd, buf, oncore_shmem_length);
631 	if (i != oncore_shmem_length) {
632 		perror(filename);
633 		exit(4);
634 	}
635 	free(buf);
636 	instance->shmem = (u_char *) mmap(0, oncore_shmem_length,
637 	    PROT_READ | PROT_WRITE,
638 #ifdef MAP_HASSEMAPHORE
639 			       MAP_HASSEMAPHORE |
640 #endif
641 			       MAP_SHARED,
642 	    instance->statusfd, (off_t)0);
643 	if (instance->shmem == MAP_FAILED) {
644 		instance->shmem = 0;
645 		close (instance->statusfd);
646 		exit(4);
647 	}
648 	for (mp = oncore_messages; mp->flag[0]; mp++) {
649 		l = mp->shmem;
650 		instance->shmem[l + 0] = mp->len >> 8;
651 		instance->shmem[l + 1] = mp->len & 0xff;
652 		instance->shmem[l + 2] = '@';
653 		instance->shmem[l + 3] = '@';
654 		instance->shmem[l + 4] = mp->flag[0];
655 		instance->shmem[l + 5] = mp->flag[1];
656 		if (!strcmp(mp->flag, "Cb")) {
657 			for (i = 1; i < 35; i++) {
658 				instance->shmem[l + i * 35 + 0] = mp->len >> 8;
659 				instance->shmem[l + i * 35 + 1] = mp->len & 0xff;
660 				instance->shmem[l + i * 35 + 2] = '@';
661 				instance->shmem[l + i * 35 + 3] = '@';
662 				instance->shmem[l + i * 35 + 4] = mp->flag[0];
663 				instance->shmem[l + i * 35 + 5] = mp->flag[1];
664 			}
665 		}
666 	}
667 #endif /* ONCORE_SHMEM_STATUS */
668 }
669 
670 /*
671  * Read Input file if it exists.
672  */
673 static void
674 oncore_read_config(
675 	struct instance *instance
676 	)
677 {
678 /*
679  * First we try to open the configuration file /etc/ntp.oncoreN, where
680  * N is the unit number viz 127.127.30.N.
681  * If we don't find it, then we try the file /etc/ntp.oncore.
682  *
683  * If we find NEITHER then we don't have the cable delay or PPS offset
684  * and we choose MODE (4) below.
685  *
686  * Five Choices for MODE
687  *    (0) ONCORE is preinitialized, don't do anything to change it.
688  *	    nb, DON'T set 0D mode, DON'T set Delay, position...
689  *    (1) NO RESET, Read Position, delays from data file, lock it in, go to 0D mode.
690  *    (2) NO RESET, Read Delays from data file, do SITE SURVEY to get position,
691  *		    lock this in, go to 0D mode.
692  *    (3) HARD RESET, Read Position, delays from data file, lock it in, go to 0D mode.
693  *    (4) HARD RESET, Read Delays from data file, do SITE SURVEY to get position,
694  *		    lock this in, go to 0D mode.
695  *     NB. If a POSITION is specified in the config file with mode=(2,4) [SITE SURVEY]
696  *	   then this position is set as the INITIAL position of the ONCORE.
697  *	   This can reduce the time to first fix.
698  * -------------------------------------------------------------------------------
699  * Note that an Oncore UT without a battery backup retains NO information if it is
700  *   power cycled, with a Battery Backup it remembers the almanac, etc.
701  * For an Oncore VP, there is an eeprom that will contain this data, along with the
702  *   option of Battery Backup.
703  * So a UT without Battery Backup is equivalent to doing a HARD RESET on each
704  *   power cycle, since there is nowhere to store the data.
705  * -------------------------------------------------------------------------------
706  *
707  * If we open one or the other of the files, we read it looking for
708  *   MODE, LAT, LON, (HT, HTGPS, HTMSL), DELAY, OFFSET
709  * then initialize using method MODE.  For Mode = (1,3) all of (LAT, LON, HT) must
710  *   be present or mode reverts to (2,4).
711  *
712  * Read input file.
713  *
714  *	# is comment to end of line
715  *	= allowed between 1st and 2nd fields.
716  *
717  *	Expect to see one line with 'MODE' as first field, followed by an integer
718  *	   in the range 0-4 (default = 4).
719  *
720  *	Expect to see two lines with 'LONG', 'LAT' followed by 1-3 fields.
721  *	All numbers are floating point.
722  *		DDD.ddd
723  *		DDD  MMM.mmm
724  *		DDD  MMM  SSS.sss
725  *
726  *	Expect to see one line with 'HT' (or 'HTMSL' or 'HTGPS') as first field.
727  *	   followed by 1-2 fields.  First is a number, the second is 'FT' or 'M'.
728  *	   for feet or meters.	HT is the same as HTGPS.
729  *	     HTMSL = HT above mean_sea_level,
730  *	     HTGPS = HT above GPS ellipse.
731  *
732  *	There are two optional lines, starting with DELAY and OFFSET, followed
733  *	   by 1 or two fields.	The first is a number (a time) the second is
734  *	   'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds.
735  *	     DELAY  is cable delay, typically a few tens of ns.
736  *	     OFFSET is the offset of the PPS pulse from 0. (only fully implemented
737  *		with the PPSAPI, we need to be able to tell the Kernel about this
738  *		offset if the Kernel PLL is in use, but can only do this presently
739  *		when using the PPSAPI interface.  If not using the Kernel PLL,
740  *		then there is no problem.
741  *
742  *	There is another optional line, with either ASSERT or CLEAR on it, which
743  *	   determine which transition of the PPS signal is used for timing by the
744  *	   PPSAPI.  If neither is present, then ASSERT is assumed.
745  *
746  * So acceptable input would be
747  *	# these are my coordinates (RWC)
748  *	LON  -106 34.610
749  *	LAT    35 08.999
750  *	HT	1589	# could equally well say HT 5215 FT
751  *	DELAY  60 ns
752  */
753 
754 	FILE	*fd;
755 	char	*cp, *cc, *ca, line[100], units[2], device[20];
756 	int	i, sign, lat_flg, long_flg, ht_flg, mode;
757 	double	f1, f2, f3;
758 
759 	sprintf(device, "%s%d", INIT_FILE, instance->unit);
760 	if ((fd=fopen(device, "r")) == NULL)
761 		if ((fd=fopen(INIT_FILE, "r")) == NULL) {
762 			instance->init_type = 4;
763 			return;
764 		}
765 
766 	mode = 0;
767 	lat_flg = long_flg = ht_flg = 0;
768 	while (fgets(line, 100, fd)) {
769 
770 		/* Remove comments */
771 		if ((cp = strchr(line, '#')))
772 			*cp = '\0';
773 
774 		/* Remove trailing space */
775 		for (i = strlen(line);
776 		     i > 0 && isascii((int)line[i - 1]) && isspace((int)line[i - 1]);
777 			)
778 			line[--i] = '\0';
779 
780 		/* Remove leading space */
781 		for (cc = line; *cc && isascii((int)*cc) && isspace((int)*cc); cc++)
782 			continue;
783 
784 		/* Stop if nothing left */
785 		if (!*cc)
786 			continue;
787 
788 		/* Lowercase the command and find the arg */
789 		for (ca = cc; *ca; ca++) {
790 			if (isascii((int)*ca) && islower((int)*ca)) {
791 				*ca = toupper(*ca);
792 			} else if (isascii((int)*ca) && isspace((int)*ca)) {
793 				break;
794 			} else if (*ca == '=') {
795 				*ca = ' ';
796 				break;
797 			}
798 		}
799 
800 		/* Remove space leading the arg */
801 		for (; *ca && isascii((int)*ca) && isspace((int)*ca); ca++)
802 			continue;
803 
804 		if (!strncmp(cc, "STATUS", 6)) {
805 			oncore_init_shmem(instance, ca);
806 			continue;
807 		}
808 
809 		/* Uppercase argument as well */
810 		for (cp = ca; *cp; cp++)
811 			if (isascii((int)*cp) && islower((int)*cp))
812 				*cp = toupper(*cp);
813 
814 		if (!strncmp(cc, "LAT", 3)) {
815 			f1 = f2 = f3 = 0;
816 			sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3);
817 			sign = 1;
818 			if (f1 < 0) {
819 				f1 = -f1;
820 				sign = -1;
821 			}
822 			instance->ss_lat = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/
823 			lat_flg++;
824 		} else if (!strncmp(cc, "LON", 3)) {
825 			f1 = f2 = f3 = 0;
826 			sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3);
827 			sign = 1;
828 			if (f1 < 0) {
829 				f1 = -f1;
830 				sign = -1;
831 			}
832 			instance->ss_long = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/
833 			long_flg++;
834 		} else if (!strncmp(cc, "HT", 2)) {
835 			if (!strncmp(cc, "HTGPS", 5))
836 				instance->ss_ht_type = 0;
837 			else if (!strncmp(cc, "HTMSL", 5))
838 				instance->ss_ht_type = 1;
839 			else
840 				instance->ss_ht_type = 0;
841 			f1 = 0;
842 			units[0] = '\0';
843 			sscanf(ca, "%lf %1s", &f1, units);
844 			if (units[0] == 'F')
845 				f1 = 0.3048 * f1;
846 			instance->ss_ht = 100 * f1;    /* cm */
847 			ht_flg++;
848 		} else if (!strncmp(cc, "DELAY", 5)) {
849 			f1 = 0;
850 			units[0] = '\0';
851 			sscanf(ca, "%lf %1s", &f1, units);
852 			if (units[0] == 'N')
853 				;
854 			else if (units[0] == 'U')
855 				f1 = 1000 * f1;
856 			else if (units[0] == 'M')
857 				f1 = 1000000 * f1;
858 			else
859 				f1 = 1000000000 * f1;
860 			if (f1 < 0 || f1 > 1.e9)
861 				f1 = 0;
862 			instance->delay = f1;		/* delay in ns */
863 		} else if (!strncmp(cc, "OFFSET", 6)) {
864 			f1 = 0;
865 			units[0] = '\0';
866 			sscanf(ca, "%lf %1s", &f1, units);
867 			if (units[0] == 'N')
868 				;
869 			else if (units[0] == 'U')
870 				f1 = 1000 * f1;
871 			else if (units[0] == 'M')
872 				f1 = 1000000 * f1;
873 			else
874 				f1 = 1000000000 * f1;
875 			if (f1 < 0 || f1 > 1.e9)
876 				f1 = 0;
877 			instance->offset = f1;		/* offset in ns */
878 		} else if (!strncmp(cc, "MODE", 4)) {
879 			sscanf(ca, "%d", &mode);
880 			if (mode < 0 || mode > 4)
881 				mode = 4;
882 			instance->init_type = mode;
883 		} else if (!strncmp(cc, "ASSERT", 6)) {
884 			instance->assert = 1;
885 		} else if (!strncmp(cc, "CLEAR", 5)) {
886 			instance->assert = 0;
887 		}
888 	}
889 	fclose(fd);
890 
891 	/*
892 	 *    OK, have read all of data file, and extracted the good stuff.
893 	 *    If lat/long/ht specified they ALL must be specified for mode = (1,3).
894 	 */
895 
896 	instance->posn_set = 1;
897 	if ((lat_flg || long_flg || ht_flg) && !(lat_flg * long_flg * ht_flg)) {
898 		printf("ONCORE: incomplete data on %s\n", INIT_FILE);
899 		instance->posn_set = 0;
900 		if (mode == 1 || mode == 3)
901 			instance->init_type++;
902 	}
903 }
904 
905 
906 
907 /*
908  * oncore_shutdown - shut down the clock
909  */
910 static void
911 oncore_shutdown(
912 	int unit,
913 	struct peer *peer
914 	)
915 {
916 	register struct instance *instance;
917 	struct refclockproc *pp;
918 
919 	pp = peer->procptr;
920 	instance = (struct instance *) pp->unitptr;
921 	free(instance);
922 }
923 
924 
925 
926 /*
927  * oncore_poll - called by the transmit procedure
928  */
929 static void
930 oncore_poll(
931 	int unit,
932 	struct peer *peer
933 	)
934 {
935 	struct instance *instance;
936 
937 	instance = (struct instance *) peer->procptr->unitptr;
938 	if (instance->timeout) {
939 		char    *cp;
940 
941 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof oncore_cmd_Cj);
942 		instance->o_state = ONCORE_ID_SENT;
943 		cp = "state = ONCORE_ID_SENT";
944 		record_clock_stats(&(instance->peer->srcadr), cp);
945 		return;
946 	}
947 
948 	if (!instance->pollcnt)
949 		refclock_report(peer, CEVNT_TIMEOUT);
950 	else
951 		instance->pollcnt--;
952 	peer->procptr->polls++;
953 	instance->polled = 1;
954 }
955 
956 
957 
958 /*
959  * move dta from NTP to buffer (toss in unlikely case it wont fit)
960  */
961 static void
962 oncore_receive(
963 	struct recvbuf *rbufp
964 	)
965 {
966 	u_int	i;
967 	u_char *p;
968 	struct peer *peer;
969 	struct instance *instance;
970 
971 	peer = (struct peer *)rbufp->recv_srcclock;
972 	instance = (struct instance *) peer->procptr->unitptr;
973 	p = (u_char *) &rbufp->recv_space;
974 
975 #if 0
976 	if (debug > 4) {
977 		int i;
978 		printf("ONCORE: >>>");
979 		for(i=0; i<rbufp->recv_length; i++)
980 			printf("%02x ", p[i]);
981 		printf("\n");
982 		printf("ONCORE: >>>");
983 		for(i=0; i<rbufp->recv_length; i++)
984 			printf("%03o ", p[i]);
985 		printf("\n");
986 	}
987 #endif
988 
989 	i = rbufp->recv_length;
990 	if (rcvbuf+rcvptr+i > &rcvbuf[sizeof rcvbuf])
991 		i = sizeof(rcvbuf) - rcvptr;	/* and some char will be lost */
992 	memcpy(rcvbuf+rcvptr, p, i);
993 	rcvptr += i;
994 	oncore_consume(instance);
995 }
996 
997 
998 
999 /*
1000  * Deal with any complete messages
1001  */
1002 static void
1003 oncore_consume(
1004 	struct instance *instance
1005 	)
1006 {
1007 	int i, j, m;
1008 	unsigned l;
1009 
1010 	while (rcvptr >= 7) {
1011 		if (rcvbuf[0] != '@' || rcvbuf[1] != '@') {
1012 			/* We're not in sync, lets try to get there */
1013 			for (i=1; i < rcvptr-1; i++)
1014 				if (rcvbuf[i] == '@' && rcvbuf[i+1] == '@')
1015 					break;
1016 			if (debug > 4)
1017 				printf("ONCORE: >>> skipping %d chars\n", i);
1018 			if (i != rcvptr)
1019 				memcpy(rcvbuf, rcvbuf+i, (unsigned)(rcvptr-i));
1020 			rcvptr -= i;
1021 		}
1022 
1023 		/* Ok, we have a header now */
1024 		l = sizeof(oncore_messages)/sizeof(oncore_messages[0]) -1;
1025 		for(m=0; m<l; m++)
1026 			if (!strncmp(oncore_messages[m].flag, (char *)(rcvbuf+2), 2))
1027 				break;
1028 		l = oncore_messages[m].len;
1029 #if 0
1030 		if (debug > 3)
1031 			printf("ONCORE: GOT: %c%c  %d of %d entry %d\n", rcvbuf[2], rcvbuf[3], rcvptr, l, m);
1032 #endif
1033 		/* Got the entire message ? */
1034 
1035 		if (rcvptr < l)
1036 			return;
1037 
1038 		/* Check the checksum */
1039 
1040 		j = 0;
1041 		for (i = 2; i < l-3; i++)
1042 			j ^= rcvbuf[i];
1043 		if (j == rcvbuf[l-3]) {
1044 			if (instance->shmem != NULL)
1045 				memcpy(instance->shmem + oncore_messages[m].shmem + 2,
1046 				    rcvbuf, l);
1047 			oncore_msg_any(instance, rcvbuf, (unsigned) (l-3), m);
1048 			if (oncore_messages[m].handler)
1049 				oncore_messages[m].handler(instance, rcvbuf, (unsigned) (l-3));
1050 		} else if (debug) {
1051 			printf("ONCORE: Checksum mismatch! calc %o is %o\n", j, rcvbuf[l-3]);
1052 			printf("ONCORE: @@%c%c ", rcvbuf[2], rcvbuf[3]);
1053 			for (i=4; i<l; i++)
1054 				printf("%03o ", rcvbuf[i]);
1055 			printf("\n");
1056 		}
1057 
1058 		if (l != rcvptr)
1059 			memcpy(rcvbuf, rcvbuf+l, (unsigned) (rcvptr-l));
1060 		rcvptr -= l;
1061 	}
1062 }
1063 
1064 
1065 
1066 /*
1067  * write message to Oncore.
1068  */
1069 static void
1070 oncore_sendmsg(
1071 	int	fd,
1072 	u_char *ptr,
1073 	u_int len
1074 	)
1075 {
1076 	u_char cs = 0;
1077 
1078 	printf("ONCORE: Send @@%c%c %d\n", ptr[0], ptr[1], len);
1079 	write(fd, "@@", 2);
1080 	write(fd, ptr, len);
1081 	while (len--)
1082 		cs ^= *ptr++;
1083 	write(fd, &cs, 1);
1084 	write(fd, "\r\n", 2);
1085 }
1086 
1087 
1088 
1089 static void
1090 oncore_msg_any(
1091 	struct instance *instance,
1092 	u_char *buf,
1093 	u_int len,
1094 	int idx
1095 	)
1096 {
1097 	int i;
1098 	const char *fmt = oncore_messages[idx].fmt;
1099 	const char *p;
1100 	struct timeval tv;
1101 
1102 	if (debug > 3) {
1103 		GETTIMEOFDAY(&tv, 0);
1104 		printf("ONCORE: %ld.%06ld\n", (long) tv.tv_sec, (long) tv.tv_usec);
1105 
1106 		if (!*fmt) {
1107 			printf(">>@@%c%c ", buf[2], buf[3]);
1108 			for(i=2; i < len && i < 2400 ; i++)
1109 				printf("%02x", buf[i]);
1110 			printf("\n");
1111 			return;
1112 		} else {
1113 			printf("##");
1114 			for (p = fmt; *p; p++) {
1115 				putchar(*p);
1116 				putchar('_');
1117 			}
1118 			printf("\n%c%c", buf[2], buf[3]);
1119 			i = 4;
1120 			for (p = fmt; *p; p++) {
1121 				printf("%02x", buf[i++]);
1122 			}
1123 			printf("\n");
1124 		}
1125 	}
1126 }
1127 
1128 
1129 
1130 /*
1131  * Demultiplex the almanac into shmem
1132  */
1133 static void
1134 oncore_msg_Cb(
1135 	struct instance *instance,
1136 	u_char *buf,
1137 	u_int len
1138 	)
1139 {
1140 	int i;
1141 
1142 	if (instance->shmem == NULL)
1143 		return;
1144 
1145 	if (buf[4] == 5)
1146 		i = buf[5];
1147 	else if (buf[4] == 4 && buf[5] <= 5)
1148 		i = buf[5] + 24;
1149 	else if (buf[4] == 4 && buf[5] <= 10)
1150 		i = buf[5] + 23;
1151 	else
1152 		i = 34;
1153 	i *= 35;
1154 	memcpy(instance->shmem + oncore_shmem_Cb + i + 2, buf, len + 3);
1155 }
1156 
1157 /*
1158  * Set to Factory Defaults (Reasonable for UT w/ no Battery Backup
1159  *	not so for VP (eeprom) or UT with battery
1160  */
1161 static void
1162 oncore_msg_Cf(
1163 	struct instance *instance,
1164 	u_char *buf,
1165 	u_int len
1166 	)
1167 {
1168 	const char *cp;
1169 
1170 	if (instance->o_state == ONCORE_RESET_SENT) {
1171 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Fa, sizeof oncore_cmd_Fa);
1172 		instance->o_state = ONCORE_TEST_SENT;
1173 		cp = "state = ONCORE_TEST_SENT";
1174 		record_clock_stats(&(instance->peer->srcadr), cp);
1175 	}
1176 }
1177 
1178 
1179 
1180 /* there are good reasons NOT to do a @@Fa command with the ONCORE.
1181  * Doing it, it was found that under some circumstances the following
1182  * command would fail if issued immediately after the return from the
1183  * @@Fa, but a 2sec delay seemed to fix things.  Since simply calling
1184  * sleep(2) is wastefull, and may cause trouble for some OS's, repeating
1185  * itimer, we set a flag, and test it at the next POLL.  If it hasnt
1186  * been cleared, we reissue the @@Ca that is issued below.
1187  */
1188 
1189 static void
1190 oncore_msg_Fa(
1191 	struct instance *instance,
1192 	u_char *buf,
1193 	u_int len
1194 	)
1195 {
1196 	const char *cp;
1197 
1198 	if (instance->o_state == ONCORE_TEST_SENT) {
1199 		if (debug > 2)
1200 			printf("ONCORE: >>@@Fa %x %x\n", buf[4], buf[5]);
1201 		if (buf[4] || buf[5]) {
1202 			printf("ONCORE: SELF TEST FAILED\n");
1203 			exit(1);
1204 		}
1205 
1206 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof oncore_cmd_Cj);
1207 		instance->o_state = ONCORE_ID_SENT;
1208 		cp = "state = ONCORE_ID_SENT";
1209 		record_clock_stats(&(instance->peer->srcadr), cp);
1210 	}
1211 }
1212 
1213 
1214 
1215 /*
1216  * preliminaries out of the way, this is the REAL start of initialization
1217  */
1218 static void
1219 oncore_msg_Cj(
1220 	struct instance *instance,
1221 	u_char *buf,
1222 	u_int len
1223 	)
1224 {
1225 	char *cp, *cp1;
1226 	int	mode;
1227 
1228 	instance->timeout = 0;
1229 	if (instance->o_state != ONCORE_ID_SENT)
1230 		return;
1231 
1232 	memcpy(instance->Cj, buf, len);
1233 
1234 	/* Write Receiver ID to clockstats file */
1235 
1236 	instance->Cj[294] = '\0';
1237 	for (cp=(char *)instance->Cj; cp< (char *) &instance->Cj[294]; ) {
1238 		cp1 = strchr(cp, '\r');
1239 		if (!cp1)
1240 			cp1 = (char *)&instance->Cj[294];
1241 		*cp1 = '\0';
1242 		record_clock_stats(&(instance->peer->srcadr), cp);
1243 		*cp1 = '\r';
1244 		cp = cp1+2;
1245 	}
1246 #ifdef HAVE_PPSAPI
1247 	if (instance->assert)
1248 		cp = "Timing on Assert.";
1249 	else
1250 		cp = "Timing on Clear.";
1251 	record_clock_stats(&(instance->peer->srcadr), cp);
1252 #endif
1253 
1254 	oncore_sendmsg(instance->ttyfd, oncore_cmd_Cg, sizeof oncore_cmd_Cg); /* Set Posn Fix mode (not Idle (VP)) */
1255 	oncore_sendmsg(instance->ttyfd, oncore_cmd_Bb, sizeof oncore_cmd_Bb); /* turn off */
1256 	oncore_sendmsg(instance->ttyfd, oncore_cmd_Ek, sizeof oncore_cmd_Ek); /* turn off */
1257 	oncore_sendmsg(instance->ttyfd, oncore_cmd_Aw, sizeof oncore_cmd_Aw); /* UTC time */
1258 	oncore_sendmsg(instance->ttyfd, oncore_cmd_AB, sizeof oncore_cmd_AB); /* Appl type static */
1259 	oncore_sendmsg(instance->ttyfd, oncore_cmd_Be, sizeof oncore_cmd_Be); /* Tell us the Almanac */
1260 
1261 	mode = instance->init_type;
1262 	if (debug)
1263 		printf("ONCORE: INIT mode = %d\n", mode);
1264 
1265 	/* If there is Position input in the Config file
1266 	 * and mode = (1,3) set it as posn hold posn, goto 0D mode.
1267 	 *  or mode = (2,4) set it as INITIAL position, and Site Survey.
1268 	 */
1269 
1270 	switch (mode) {
1271 	case 0: /* NO initialization, don't change anything */
1272 		instance->site_survey = ONCORE_SS_DONE;
1273 		break;
1274 
1275 	case 1:
1276 	case 3:
1277 		w32_buf(&oncore_cmd_As[2],  (int) instance->ss_lat);
1278 		w32_buf(&oncore_cmd_As[6],  (int) instance->ss_long);
1279 		w32_buf(&oncore_cmd_As[10], (int) instance->ss_ht);
1280 		oncore_cmd_As[14] = instance->ss_ht_type;
1281 		oncore_sendmsg(instance->ttyfd, oncore_cmd_As,	sizeof oncore_cmd_As);
1282 
1283 		instance->site_survey = ONCORE_SS_DONE;
1284 		oncore_cmd_At[2] = 1;
1285 		oncore_sendmsg(instance->ttyfd, oncore_cmd_At,	sizeof oncore_cmd_At);
1286 		record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode");
1287 		break;
1288 
1289 	case 2:
1290 	case 4:
1291 		if (instance->posn_set) {
1292 			w32_buf(&oncore_cmd_Ad[2], (int) instance->ss_lat);
1293 			w32_buf(&oncore_cmd_Ae[2], (int) instance->ss_long);
1294 			w32_buf(&oncore_cmd_Af[2], (int) instance->ss_ht);
1295 			oncore_cmd_Af[6] = instance->ss_ht_type;
1296 			oncore_sendmsg(instance->ttyfd, oncore_cmd_Ad,	sizeof oncore_cmd_Ad);
1297 			oncore_sendmsg(instance->ttyfd, oncore_cmd_Ae,	sizeof oncore_cmd_Ae);
1298 			oncore_sendmsg(instance->ttyfd, oncore_cmd_Af,	sizeof oncore_cmd_Af);
1299 		}
1300 		instance->site_survey = ONCORE_SS_UNKNOWN;
1301 		oncore_cmd_At[2] = 2;
1302 		oncore_sendmsg(instance->ttyfd, oncore_cmd_At,	sizeof oncore_cmd_At);
1303 		break;
1304 	}
1305 
1306 	if (mode != 0) {
1307 			/* cable delay in ns */
1308 		w32_buf(&oncore_cmd_Az[2], instance->delay);
1309 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Az,	sizeof oncore_cmd_Az);
1310 
1311 			/* PPS offset in ns */
1312 		w32_buf(&oncore_cmd_Ay[2], instance->offset);
1313 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Ay,	sizeof oncore_cmd_Ay);
1314 	}
1315 
1316 	/* 8chan - Position/Status/Data Output Message, 1/s */
1317 
1318 	oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea,	sizeof oncore_cmd_Ea);
1319 
1320 	instance->o_state = ONCORE_ALMANAC;
1321 	cp = "state = ONCORE_ALMANAC";
1322 	record_clock_stats(&(instance->peer->srcadr), cp);
1323 }
1324 
1325 
1326 
1327 static void
1328 oncore_msg_Ea(
1329 	struct instance *instance,
1330 	u_char *buf,
1331 	u_int len
1332 	)
1333 {
1334 	const char	*cp;
1335 	char		Msg[160];
1336 
1337 	if (instance->o_state != ONCORE_ALMANAC && instance->o_state != ONCORE_RUN)
1338 		return;
1339 
1340 	memcpy(instance->Ea, buf, len);
1341 
1342 	/* When we have an almanac, start the En messages */
1343 
1344 	if (instance->o_state == ONCORE_ALMANAC) {
1345 		if ((instance->Ea[72] & 1)) {
1346 			if (debug)
1347 				printf("ONCORE: waiting for almanac\n");
1348 			return;
1349 		} else {
1350 			oncore_sendmsg(instance->ttyfd, oncore_cmd_En, sizeof oncore_cmd_En);
1351 			instance->o_state = ONCORE_RUN;
1352 			cp = "state = ONCORE_RUN";
1353 			record_clock_stats(&(instance->peer->srcadr), cp);
1354 		}
1355 	}
1356 
1357 	/* must be ONCORE_RUN if we are here */
1358 	/* First check if Hardware SiteSurvey has Finished */
1359 
1360 	if ((instance->site_survey == ONCORE_SS_HW) && !(instance->Ea[37] & 0x20)) {
1361 		instance->site_survey = ONCORE_SS_DONE;
1362 		record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode");
1363 	}
1364 
1365 	if (!instance->printed && instance->site_survey == ONCORE_SS_DONE) {	/* will print to clockstat when all */
1366 		instance->printed = 1;						/* three messages respond */
1367 			/* Read back Position Hold Params */
1368 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Asx,  sizeof oncore_cmd_Asx);
1369 			/* Read back PPS Offset for Output */
1370 			/* Nb. This will fail silently for early UT (no plus) model */
1371 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Ayx,  sizeof oncore_cmd_Ayx);
1372 			/* Read back Cable Delay for Output */
1373 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Azx,  sizeof oncore_cmd_Azx);
1374 	}
1375 
1376 	/* Check the leap second status once per day */
1377 
1378 	/*
1379 	 * The following additional check, checking for June/December, is a
1380 	 * workaround for incorrect ONCORE firmware.  The oncore starts
1381 	 * reporting the leap second when the GPS satellite data message
1382 	 * (page 18, subframe 4) is updated to a date in the future, which
1383 	 * which can be several months before the leap second.	WWV and other
1384 	 * services seem to wait until the month of the event to turn
1385 	 * on their indicators (which are usually a single bit).
1386 	 */
1387 
1388 	if ((buf[4] == 6) || (buf[4] == 12)) {
1389 		if (instance->Bj_day != buf[5]) {     /* do this 1/day */
1390 			instance->Bj_day = buf[5];
1391 			oncore_sendmsg(instance->ttyfd, oncore_cmd_Bj, sizeof oncore_cmd_Bj);
1392 		}
1393 	}
1394 	instance->pp->year = buf[6]*256+buf[7];
1395 	instance->pp->day = ymd2yd(buf[6]*256+buf[7], buf[4], buf[5]);
1396 	instance->pp->hour = buf[8];
1397 	instance->pp->minute = buf[9];
1398 	instance->pp->second = buf[10];
1399 
1400 	if (instance->site_survey != ONCORE_SS_SW)
1401 		return;
1402 
1403 	/*
1404 	 * We have to average our own position for the Position Hold Mode
1405 	 */
1406 
1407 	/* We only take PDOP/3D fixes */
1408 
1409 	if (instance->Ea[37] & 1)
1410 		return;
1411 
1412 	/* Not if poor geometry or less than 3 sats */
1413 
1414 	if (instance->Ea[72] & 0x52)
1415 		return;
1416 
1417 	/* Only 3D fix */
1418 
1419 	if (!(instance->Ea[72] & 0x20))
1420 		return;
1421 
1422 	instance->ss_lat  += buf_w32(&instance->Ea[15]);
1423 	instance->ss_long += buf_w32(&instance->Ea[19]);
1424 	instance->ss_ht   += buf_w32(&instance->Ea[23]);  /* GPS ellipse */
1425 	instance->ss_count++;
1426 
1427 	if (instance->ss_count != POS_HOLD_AVERAGE)
1428 		return;
1429 
1430 	instance->ss_lat  /= POS_HOLD_AVERAGE;
1431 	instance->ss_long /= POS_HOLD_AVERAGE;
1432 	instance->ss_ht   /= POS_HOLD_AVERAGE;
1433 
1434 	sprintf(Msg, "Surveyed posn:  lat %.3f long %.3f ht %.3f",
1435 			instance->ss_lat, instance->ss_long, instance->ss_ht);
1436 	record_clock_stats(&(instance->peer->srcadr), Msg);
1437 
1438 	w32_buf(&oncore_cmd_As[2],  (int) instance->ss_lat);
1439 	w32_buf(&oncore_cmd_As[6],  (int) instance->ss_long);
1440 	w32_buf(&oncore_cmd_As[10], (int) instance->ss_ht);
1441 	oncore_cmd_As[14] = 0;
1442 	oncore_sendmsg(instance->ttyfd, oncore_cmd_As, sizeof oncore_cmd_As);
1443 
1444 	oncore_cmd_At[2] = 1;
1445 	oncore_sendmsg(instance->ttyfd, oncore_cmd_At, sizeof oncore_cmd_At);
1446 	record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode");
1447 	instance->site_survey = ONCORE_SS_DONE;
1448 }
1449 
1450 
1451 
1452 static void
1453 oncore_msg_En(
1454 	struct instance *instance,
1455 	u_char *buf,
1456 	u_int len
1457 	)
1458 {
1459 	int	j;
1460 	l_fp ts, ts_tmp;
1461 	double dmy;
1462 #ifdef HAVE_TIMESPEC
1463 	struct timespec *tsp = 0;
1464 #else
1465 	struct timeval	*tsp = 0;
1466 #endif
1467 #ifdef HAVE_PPSAPI
1468 	struct timespec timeout;
1469 	pps_info_t pps_i;
1470 #else  /* ! HAVE_PPSAPI */
1471 #ifdef HAVE_CIOGETEV
1472 	struct ppsclockev ev;
1473 	int r = CIOGETEV;
1474 #endif
1475 #ifdef HAVE_TIOCGPPSEV
1476 	struct ppsclockev ev;
1477 	int r = TIOCGPPSEV;
1478 #endif
1479 #if	TIOCDCDTIMESTAMP
1480 	struct timeval	tv;
1481 #endif
1482 #endif	/* ! HAVE_PPS_API */
1483 
1484 	if (instance->o_state != ONCORE_RUN)
1485 		return;
1486 
1487 	memcpy(instance->En, buf, len);
1488 
1489 	/* Don't do anything without an almanac to define the GPS->UTC delta */
1490 
1491 	if (instance->Ea[72] & 1)
1492 		return;
1493 
1494 	/* If Time RAIM doesn't like it, don't trust it */
1495 
1496 	if (instance->En[21])
1497 		return;
1498 
1499 #ifdef HAVE_PPSAPI
1500 	j = instance->ev_serial;
1501 	timeout.tv_sec = 0;
1502 	timeout.tv_nsec = 0;
1503 	if (time_pps_fetch(instance->pps_h, PPS_TSFMT_TSPEC, &pps_i,
1504 	    &timeout) < 0) {
1505 		printf("ONCORE: time_pps_fetch failed\n");
1506 		return;
1507 	}
1508 
1509 	if (instance->assert) {
1510 		tsp = &pps_i.assert_timestamp;
1511 
1512 		if (debug > 2)
1513 			printf("ONCORE: serial/j (%d, %d) %ld.%09ld\n",
1514 			    pps_i.assert_sequence, j, tsp->tv_sec, tsp->tv_nsec);
1515 
1516 		if (pps_i.assert_sequence == j) {
1517 			printf("ONCORE: oncore_msg_En, error serial pps\n");
1518 			return;
1519 		}
1520 		instance->ev_serial = pps_i.assert_sequence;
1521 	} else {
1522 		tsp = &pps_i.clear_timestamp;
1523 
1524 		if (debug > 2)
1525 			printf("ONCORE: serial/j (%d, %d) %ld.%09ld\n",
1526 			    pps_i.clear_sequence, j, tsp->tv_sec, tsp->tv_nsec);
1527 
1528 		if (pps_i.clear_sequence == j) {
1529 			printf("ONCORE: oncore_msg_En, error serial pps\n");
1530 			return;
1531 		}
1532 		instance->ev_serial = pps_i.clear_sequence;
1533 	}
1534 
1535 	/* convert timespec -> ntp l_fp */
1536 
1537 	dmy = tsp->tv_nsec;
1538 	dmy /= 1e9;
1539 	ts.l_uf =  dmy * 4294967296.0;
1540 	ts.l_ui = tsp->tv_sec;
1541 #if 0
1542      alternate code for previous 4 lines is
1543 	dmy = 1.0e-9*tsp->tv_nsec;	/* fractional part */
1544 	DTOLFP(dmy, &ts);
1545 	dmy = tsp->tv_sec;		/* integer part */
1546 	DTOLFP(dmy, &ts_tmp);
1547 	L_ADD(&ts, &ts_tmp);
1548      or more simply
1549 	dmy = 1.0e-9*tsp->tv_nsec;	/* fractional part */
1550 	DTOLFP(dmy, &ts);
1551 	ts.l_ui = tsp->tv_sec;
1552 #endif	/* 0 */
1553 #else
1554 # if defined(HAVE_TIOCGPPSEV) || defined(HAVE_CIOGETEV)
1555 	j = instance->ev_serial;
1556 	if (ioctl(instance->ppsfd, r, (caddr_t) &ev) < 0) {
1557 		perror("ONCORE: IOCTL:");
1558 		return;
1559 	}
1560 
1561 	tsp = &ev.tv;
1562 
1563 	if (debug > 2)
1564 		printf("ONCORE: serial/j (%d, %d) %ld.%06ld\n",
1565 			ev.serial, j, tsp->tv_sec, tsp->tv_usec);
1566 
1567 	if (ev.serial == j) {
1568 		printf("ONCORE: oncore_msg_En, error serial pps\n");
1569 		return;
1570 	}
1571 	instance->ev_serial = ev.serial;
1572 
1573 	/* convert timeval -> ntp l_fp */
1574 
1575 	TVTOTS(tsp, &ts);
1576 # else
1577 #  if defined(TIOCDCDTIMESTAMP)
1578 	if(ioctl(instance->ppsfd, TIOCDCDTIMESTAMP, &tv) < 0) {
1579 		perror("ONCORE: ioctl(TIOCDCDTIMESTAMP)");
1580 		return;
1581 	}
1582 	tsp = &tv;
1583 	TVTOTS(tsp, &ts);
1584 #  else
1585 #error "Cannot compile -- no PPS mechanism configured!"
1586 #  endif
1587 # endif
1588 #endif
1589 	/* now have timestamp in ts */
1590 	/* add in saw_tooth and offset */
1591 
1592 	/* saw_tooth not really necessary if using TIMEVAL */
1593 	/* since its only precise to us, but do it anyway. */
1594 
1595 	/* offset in ns, and is positive (late), we subtract */
1596 	/* to put the PPS time transition back where it belongs */
1597 
1598 	j  = instance->saw_tooth + instance->offset;
1599 	instance->saw_tooth = (s_char) buf[25]; /* update for next time */
1600 #ifdef HAVE_PPSAPI
1601 	/* must hand this offset off to the Kernel to do the addition */
1602 	/* so that the Kernel PLL sees the offset too */
1603 
1604 	if (instance->assert) {
1605 		instance->pps_p.assert_offset.tv_nsec =
1606 			 -(instance->saw_tooth + instance->offset);
1607 	} else {
1608 		instance->pps_p.clear_offset.tv_nsec =
1609 			 -(instance->saw_tooth + instance->offset);
1610 	}
1611 
1612 	if (time_pps_setparams(instance->pps_h, &instance->pps_p))
1613 		perror("time_pps_setparams");
1614 #else
1615 	/* if not PPSAPI, no way to inform kernel of OFFSET, just do it */
1616 
1617 	dmy = -1.0e-9*j;
1618 	DTOLFP(dmy, &ts_tmp);
1619 	L_ADD(&ts, &ts_tmp);
1620 #endif
1621 	/* have time from UNIX origin, convert to NTP origin. */
1622 
1623 	ts.l_ui += JAN_1970;
1624 	instance->pp->lastrec = ts;
1625 	instance->pp->msec = 0;
1626 
1627 	ts_tmp = ts;
1628 	ts_tmp.l_ui = 0;        /* zero integer part */
1629 	LFPTOD(&ts_tmp, dmy);   /* convert fractional part to a double */
1630 	j = 1.0e9*dmy;          /* then to integer ns */
1631 	sprintf(instance->pp->a_lastcode,
1632 	    "%u.%09u %d %d %2d %2d %2d %2ld rstat %02x dop %d nsat %2d,%d raim %d sigma %d neg-sawtooth %3d sat %d%d%d%d%d%d%d%d",
1633 	    ts.l_ui, j,
1634 	    instance->pp->year, instance->pp->day,
1635 	    instance->pp->hour, instance->pp->minute, instance->pp->second,
1636 	    (long) tsp->tv_sec % 60,
1637 
1638 	    instance->Ea[72], instance->Ea[37], instance->Ea[38], instance->Ea[39], instance->En[21],
1639 	    /*rstat           dop               nsat visible,     nsat tracked,     raim */
1640 	    instance->En[23]*256+instance->En[24], (s_char) buf[25],
1641 	    /* sigma				   neg-sawtooth */
1642   /*sat*/   instance->Ea[41], instance->Ea[45], instance->Ea[49], instance->Ea[53],
1643 	    instance->Ea[57], instance->Ea[61], instance->Ea[65], instance->Ea[69]
1644 	    );
1645 
1646 	if (debug > 2) {
1647 		int i;
1648 		i = strlen(instance->pp->a_lastcode);
1649 		printf("ONCORE: len = %d %s\n", i, instance->pp->a_lastcode);
1650 	}
1651 
1652 	if (!refclock_process(instance->pp)) {
1653 		refclock_report(instance->peer, CEVNT_BADTIME);
1654 		return;
1655 	}
1656 
1657 	record_clock_stats(&(instance->peer->srcadr), instance->pp->a_lastcode);
1658 	instance->pollcnt = 2;
1659 
1660 	if (instance->polled) {
1661 		instance->polled = 0;
1662 /*
1663 		instance->pp->dispersion = instance->pp->skew = 0;
1664 */
1665 		refclock_receive(instance->peer);
1666 	}
1667 }
1668 
1669 
1670 
1671 /*
1672  * Try to use Oncore UT+ Auto Survey Feature
1673  *	If its not there (VP), set flag to do it ourselves.
1674  */
1675 static void
1676 oncore_msg_At(
1677 	struct instance *instance,
1678 	u_char *buf,
1679 	u_int len
1680 	)
1681 {
1682 	if (instance->site_survey != ONCORE_SS_UNKNOWN)
1683 		return;
1684 
1685 	if (buf[4] == 2) {
1686 		record_clock_stats(&(instance->peer->srcadr),
1687 				"Initiating hardware 3D site survey");
1688 		instance->site_survey = ONCORE_SS_HW;
1689 	} else {
1690 		char Msg[160];
1691 		/*
1692 		 * Probably a VP or an older UT which can't do site-survey.
1693 		 * We will have to do it ourselves
1694 		 */
1695 
1696 		sprintf(Msg, "Initiating software 3D site survey (%d samples)",
1697 				POS_HOLD_AVERAGE);
1698 		record_clock_stats(&(instance->peer->srcadr), Msg);
1699 		instance->site_survey = ONCORE_SS_SW;
1700 
1701 		oncore_cmd_At[2] = 0;
1702 		instance->ss_lat = instance->ss_long = instance->ss_ht = 0;
1703 		oncore_sendmsg(instance->ttyfd, oncore_cmd_At, sizeof oncore_cmd_At);
1704 	}
1705 }
1706 
1707 
1708 
1709 /* get leap-second warning message */
1710 
1711 /*
1712  * @@Bj does NOT behave as documented in current Oncore firmware.
1713  * It turns on the LEAP indicator when the data is set, and does not,
1714  * as documented, wait until the beginning of the month when the
1715  * leap second will occur.
1716  * Until this firmware bug is fixed, @@Bj is only called in June/December.
1717  */
1718 
1719 static void
1720 oncore_msg_Bj(
1721 	struct instance *instance,
1722 	u_char *buf,
1723 	u_int len
1724 	)
1725 {
1726 	const char	*cp;
1727 
1728 	switch(buf[4]) {
1729 	case 1:
1730 		instance->peer->leap = LEAP_ADDSECOND;
1731 		cp = "Set peer.leap to LEAP_ADDSECOND";
1732 		break;
1733 	case 2:
1734 		instance->peer->leap = LEAP_DELSECOND;
1735 		cp = "Set peer.leap to LEAP_DELSECOND";
1736 		break;
1737 	case 0:
1738 	default:
1739 		instance->peer->leap = LEAP_NOWARNING;
1740 		cp = "Set peer.leap to LEAP_NOWARNING";
1741 		break;
1742 	}
1743 	record_clock_stats(&(instance->peer->srcadr), cp);
1744 }
1745 
1746 
1747 
1748 /*
1749  * get Position hold position
1750  */
1751 static void
1752 oncore_msg_As(
1753 	struct instance *instance,
1754 	u_char *buf,
1755 	u_int len
1756 	)
1757 {
1758 	char Msg[120], ew, ns;
1759 	const char *Ht;
1760 	double xd, xm, xs, yd, ym, ys, hm, hft;
1761 	int idx, idy, is, imx, imy;
1762 	long lat, lon, ht;
1763 
1764 	if (!instance->printed || instance->As)
1765 		return;
1766 
1767 	instance->As = 1;
1768 
1769 	lat = buf_w32(&buf[4]);
1770 	instance->ss_lat = lat;
1771 
1772 	lon = buf_w32(&buf[8]);
1773 	instance->ss_long = lon;
1774 
1775 	ht = buf_w32(&buf[12]);
1776 	instance->ss_ht = ht;
1777 
1778 	instance->ss_ht_type = buf[16];
1779 
1780 	/* Print out Position */
1781 
1782 	record_clock_stats(&(instance->peer->srcadr), "Posn:");
1783 	ew = 'E';
1784 	lon = instance->ss_long;
1785 	if (lon < 0) {
1786 		ew = 'W';
1787 		lon = -lon;
1788 	}
1789 
1790 	ns = 'N';
1791 	lat = instance->ss_lat;
1792 	if (lat < 0) {
1793 		ns = 'S';
1794 		lat = -lat;
1795 	}
1796 
1797 	hm = instance->ss_ht/100.;
1798 	hft= hm/0.3048;
1799 	Ht = instance->ss_ht_type ? "MSL" : "GPS";
1800 
1801 	xd = lat/3600000.;	/* lat, lon in int msec arc, ht in cm. */
1802 	yd = lon/3600000.;
1803 	sprintf(Msg, "Lat = %c %11.7fdeg,    Long = %c %11.7fdeg,    Alt = %5.2fm (%5.2fft) %s", ns, xd, ew, yd, hm, hft, Ht);
1804 	record_clock_stats(&(instance->peer->srcadr), Msg);
1805 
1806 	idx = xd;
1807 	idy = yd;
1808 	imx = lat%3600000;
1809 	imy = lon%3600000;
1810 	xm = imx/60000.;
1811 	ym = imy/60000.;
1812 	sprintf(Msg, "Lat = %c %3ddeg %7.4fm,   Long = %c %3ddeg %8.5fm,  Alt = %5.2fm (%5.2fft) %s", ns, idx, xm, ew, idy, ym, hm, hft, Ht);
1813 	record_clock_stats(&(instance->peer->srcadr), Msg);
1814 
1815 	imx = xm;
1816 	imy = ym;
1817 	is  = lat%60000;
1818 	xs  = is/1000.;
1819 	is  = lon%60000;
1820 	ys  = is/1000.;
1821 	sprintf(Msg, "Lat = %c %3ddeg %2dm %5.2fs, Long = %c %3ddeg %2dm %5.2fs, Alt = %5.2fm (%5.2fft) %s", ns, idx, imx, xs, ew, idy, imy, ys, hm, hft, Ht);
1822 	record_clock_stats(&(instance->peer->srcadr), Msg);
1823 }
1824 
1825 
1826 
1827 /*
1828  * get PPS Offset
1829  * Nb. @@Ay is not supported for early UT (no plus) model
1830  */
1831 static void
1832 oncore_msg_Ay(
1833 	struct instance *instance,
1834 	u_char *buf,
1835 	u_int len
1836 	)
1837 {
1838 	char Msg[120];
1839 
1840 	if (!instance->printed || instance->Ay)
1841 		return;
1842 
1843 	instance->Ay = 1;
1844 
1845 	instance->offset = buf_w32(&buf[4]);
1846 
1847 	sprintf(Msg, "PPS Offset  is set to %ld ns", instance->offset);
1848 	record_clock_stats(&(instance->peer->srcadr), Msg);
1849 }
1850 
1851 
1852 
1853 /*
1854  * get Cable Delay
1855  */
1856 static void
1857 oncore_msg_Az(
1858 	struct instance *instance,
1859 	u_char *buf,
1860 	u_int len
1861 	)
1862 {
1863 	char Msg[120];
1864 
1865 	if (!instance->printed || instance->Az)
1866 		return;
1867 
1868 	instance->Az = 1;
1869 
1870 	instance->delay = buf_w32(&buf[4]);
1871 
1872 	sprintf(Msg, "Cable delay is set to %ld ns", instance->delay);
1873 	record_clock_stats(&(instance->peer->srcadr), Msg);
1874 }
1875 #else
1876 int refclock_oncore_bs;
1877 #endif /* REFCLOCK */
1878