xref: /freebsd/contrib/ntp/ntpd/refclock_oncore.c (revision ae83180158c4c937f170e31eff311b18c0286a93)
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  *   should work with Basic, PVT6, VP, UT, UT+, GT, GT+, SL, M12.
13  *	The receivers with TRAIM (VP, UT, UT+), will be more accurate than the others.
14  *	The receivers without position hold (GT, GT+) will be less accurate.
15  *
16  * Tested with:
17  *
18  *		(UT)				   (VP)
19  *   COPYRIGHT 1991-1997 MOTOROLA INC.	COPYRIGHT 1991-1996 MOTOROLA INC.
20  *   SFTW P/N #     98-P36848P		SFTW P/N # 98-P36830P
21  *   SOFTWARE VER # 2			SOFTWARE VER # 8
22  *   SOFTWARE REV # 2			SOFTWARE REV # 8
23  *   SOFTWARE DATE  APR 24 1998 	SOFTWARE DATE  06 Aug 1996
24  *   MODEL #	R1121N1114		MODEL #    B4121P1155
25  *   HWDR P/N # 1			HDWR P/N # _
26  *   SERIAL #	R0010A			SERIAL #   SSG0226478
27  *   MANUFACTUR DATE 6H07		MANUFACTUR DATE 7E02
28  *					OPTIONS LIST	IB
29  *
30  *	      (Basic)				   (M12)
31  *   COPYRIGHT 1991-1996 MOTOROLA INC.	COPYRIGHT 1991-2000 MOTOROLA INC.
32  *   SFTW P/N # 98-P36830P		SFTW P/N # 61-G10002A
33  *   SOFTWARE VER # 8			SOFTWARE VER # 1
34  *   SOFTWARE REV # 8			SOFTWARE REV # 3
35  *   SOFTWARE DATE  06 Aug 1996 	SOFTWARE DATE  Mar 13 2000
36  *   MODEL #	B4121P1155		MODEL #    P143T12NR1
37  *   HDWR P/N # _			HWDR P/N # 1
38  *   SERIAL #	SSG0226478		SERIAL #   P003UD
39  *   MANUFACTUR DATE 7E02		MANUFACTUR DATE 0C27
40  *   OPTIONS LIST    IB
41  *
42  * --------------------------------------------------------------------------
43  * This code uses the two devices
44  *	/dev/oncore.serial.n
45  *	/dev/oncore.pps.n
46  * which may be linked to the same device.
47  * and can read initialization data from the file
48  *	/etc/ntp.oncoreN, /etc/ntp.oncore.N, or /etc/ntp.oncore, where
49  *	n or N are the unit number, viz 127.127.30.N.
50  * --------------------------------------------------------------------------
51  * Reg.Clemens <reg@dwf.com> Sep98.
52  *  Original code written for FreeBSD.
53  *  With these mods it works on FreeBSD, SunOS, Solaris and Linux
54  *    (SunOS 4.1.3 + ppsclock)
55  *    (Solaris7 + MU4)
56  *    (RedHat 5.1 2.0.35 + PPSKit, 2.1.126 + or later).
57  *
58  *  Lat,Long,Ht, cable-delay, offset, and the ReceiverID (along with the
59  *  state machine state) are printed to CLOCKSTATS if that file is enabled
60  *  in /etc/ntp.conf.
61  *
62  * --------------------------------------------------------------------------
63  *
64  * According to the ONCORE manual (TRM0003, Rev 3.2, June 1998, page 3.13)
65  * doing an average of 10000 valid 2D and 3D fixes is what the automatic
66  * site survey mode does.  Looking at the output from the receiver
67  * it seems like it is only using 3D fixes.
68  * When we do it ourselves, take 10000 3D fixes.
69  */
70 
71 #define POS_HOLD_AVERAGE	10000	/* nb, 10000s ~= 2h45m */
72 
73 /*
74  * ONCORE_SHMEM_STATUS will create a mmap(2)'ed file named according to a
75  * "STATUS" line in the oncore config file, which contains the most recent
76  * copy of all types of messages we recognize.	This file can be mmap(2)'ed
77  * by monitoring and statistics programs.
78  *
79  * See separate HTML documentation for this option.
80  */
81 
82 #ifdef HAVE_CONFIG_H
83 #include <config.h>
84 #endif
85 
86 #if defined(REFCLOCK) && defined(CLOCK_ONCORE) && defined(HAVE_PPSAPI)
87 
88 #include "ntpd.h"
89 #include "ntp_io.h"
90 #include "ntp_unixtime.h"
91 #include "ntp_refclock.h"
92 #include "ntp_stdlib.h"
93 
94 #include <stdio.h>
95 #include <ctype.h>
96 #include <sys/stat.h>
97 #ifdef ONCORE_SHMEM_STATUS
98 # ifdef HAVE_SYS_MMAN_H
99 #  include <sys/mman.h>
100 #  ifndef MAP_FAILED
101 #   define MAP_FAILED ((u_char *) -1)
102 #  endif  /* not MAP_FAILED */
103 # endif /* HAVE_SYS_MMAN_H */
104 #endif /* ONCORE_SHMEM_STATUS */
105 
106 #ifdef HAVE_PPSAPI
107 # ifdef HAVE_TIMEPPS_H
108 #  include <timepps.h>
109 # else
110 #  ifdef HAVE_SYS_TIMEPPS_H
111 #   include <sys/timepps.h>
112 #  endif
113 # endif
114 #endif
115 
116 #ifdef HAVE_SYS_SIO_H
117 # include <sys/sio.h>
118 #endif
119 
120 #ifdef HAVE_SYS_TERMIOS_H
121 # include <sys/termios.h>
122 #endif
123 
124 #ifdef HAVE_SYS_PPSCLOCK_H
125 # include <sys/ppsclock.h>
126 #endif
127 
128 #ifndef HAVE_STRUCT_PPSCLOCKEV
129 struct ppsclockev {
130 # ifdef HAVE_STRUCT_TIMESPEC
131 	struct timespec tv;
132 # else
133 	struct timeval tv;
134 # endif
135 	u_int serial;
136 };
137 #endif /* not HAVE_STRUCT_PPSCLOCKEV */
138 
139 enum receive_state {
140 	ONCORE_NO_IDEA,
141 	ONCORE_ID_SENT,
142 	ONCORE_RESET_SENT,
143 	ONCORE_TEST_SENT,
144 	ONCORE_INIT,
145 	ONCORE_ALMANAC,
146 	ONCORE_RUN
147 };
148 
149 enum site_survey_state {
150 	ONCORE_SS_UNKNOWN,
151 	ONCORE_SS_TESTING,
152 	ONCORE_SS_HW,
153 	ONCORE_SS_SW,
154 	ONCORE_SS_DONE
155 };
156 
157 /* Model Name, derived from the @@Cj message.
158  * Used to initialize some variables.
159  */
160 
161 enum oncore_model {
162 	ONCORE_BASIC,
163 	ONCORE_PVT6,
164 	ONCORE_VP,
165 	ONCORE_UT,
166 	ONCORE_UTPLUS,
167 	ONCORE_GT,
168 	ONCORE_GTPLUS,
169 	ONCORE_SL,
170 	ONCORE_M12,
171 	ONCORE_UNKNOWN
172 };
173 
174 /* the bits that describe these properties are in the same place
175  * on the VP/UT, but have moved on the M12.  As such we extract
176  * them, and use them from this struct.
177  *
178  */
179 
180 struct RSM {
181 	u_char	posn0D;
182 	u_char	posn2D;
183 	u_char	posn3D;
184 	u_char	bad_almanac;
185 	u_char	bad_fix;
186 };
187 
188 /* It is possible to test the VP/UT each cycle (@@Ea or equivalent) to
189  * see what mode it is in.  The bits on the M12 are multiplexed with
190  * other messages, so we have to 'keep' the last known mode here.
191  */
192 
193 enum posn_mode {
194 	MODE_UNKNOWN,
195 	MODE_0D,
196 	MODE_2D,
197 	MODE_3D
198 };
199 
200 struct instance {
201 	int	unit;		/* 127.127.30.unit */
202 	struct	refclockproc *pp;
203 	struct	peer *peer;
204 
205 	int	ttyfd;		/* TTY file descriptor */
206 	int	ppsfd;		/* PPS file descriptor */
207 	int	statusfd;	/* Status shm descriptor */
208 #ifdef HAVE_PPSAPI
209 	pps_handle_t pps_h;
210 	pps_params_t pps_p;
211 #endif
212 	enum receive_state o_state;		/* Receive state */
213 	enum posn_mode mode;			/* 0D, 2D, 3D */
214 	enum site_survey_state site_survey;	/* Site Survey state */
215 
216 	int	Bj_day;
217 
218 	u_long	delay;		/* ns */
219 	long	offset; 	/* ns */
220 
221 	u_char	*shmem;
222 	char	*shmem_fname;
223 	u_int	shmem_Cb;
224 	u_int	shmem_Ba;
225 	u_int	shmem_Ea;
226 	u_int	shmem_Ha;
227 	u_char	shmem_first;
228 	u_char	shmem_reset;
229 	u_char	shmem_Posn;
230 
231 	double	ss_lat;
232 	double	ss_long;
233 	double	ss_ht;
234 	double	dH;
235 	int	ss_count;
236 	u_char	posn_set;
237 
238 	enum oncore_model model;
239 	u_int	version;
240 	u_int	revision;
241 
242 	u_char	chan;		/* 6 for PVT6 or BASIC, 8 for UT/VP, 12 for m12, 0 if unknown */
243 	s_char	traim;		/* do we have traim? yes UT/VP, no BASIC, GT, -1 unknown, 0 no, +1 yes */
244 	u_char	traim_delay;	/* seconds counter, waiting for reply */
245 
246 	struct	RSM rsm;	/* bits extracted from Receiver Status Msg in @@Ea */
247 	u_char	printed;
248 	u_char	polled;
249 	int	pollcnt;
250 	u_int	ev_serial;
251 	int	Rcvptr;
252 	u_char	Rcvbuf[500];
253 	u_char	Ea[160];	/* Ba, Ea or Ha */
254 	u_char	En[70]; 	/* Bn or En */
255 	u_char	Cj[300];
256 	u_char	As;
257 	u_char	Ay;
258 	u_char	Az;
259 	u_char	have_dH;
260 	u_char	init_type;
261 	s_char	saw_tooth;
262 	u_int	timeout;	/* count to retry Cj after Fa self-test */
263 	u_char	count;		/* cycles thru Ea before starting */
264 	s_char	assert;
265 	u_int	saw_At;
266 };
267 
268 #define rcvbuf	instance->Rcvbuf
269 #define rcvptr	instance->Rcvptr
270 
271 static	void	oncore_consume	     P((struct instance *));
272 static	void	oncore_poll	     P((int, struct peer *));
273 static	void	oncore_read_config   P((struct instance *));
274 static	void	oncore_receive	     P((struct recvbuf *));
275 static	void	oncore_sendmsg	     P((int fd, u_char *, size_t));
276 static	void	oncore_shutdown      P((int, struct peer *));
277 static	int	oncore_start	     P((int, struct peer *));
278 static	void	oncore_get_timestamp P((struct instance *, long, long));
279 static	void	oncore_init_shmem    P((struct instance *));
280 static	void	oncore_print_As      P((struct instance *));
281 
282 static	void	oncore_msg_any	   P((struct instance *, u_char *, size_t, int));
283 static	void	oncore_msg_As	   P((struct instance *, u_char *, size_t));
284 static	void	oncore_msg_At	   P((struct instance *, u_char *, size_t));
285 static	void	oncore_msg_Ay	   P((struct instance *, u_char *, size_t));
286 static	void	oncore_msg_Az	   P((struct instance *, u_char *, size_t));
287 static	void	oncore_msg_BaEaHa  P((struct instance *, u_char *, size_t));
288 static	void	oncore_msg_Bj	   P((struct instance *, u_char *, size_t));
289 static	void	oncore_msg_BnEn    P((struct instance *, u_char *, size_t));
290 static	void	oncore_msg_CaFaIa  P((struct instance *, u_char *, size_t));
291 static	void	oncore_msg_Cb	   P((struct instance *, u_char *, size_t));
292 static	void	oncore_msg_Cf	   P((struct instance *, u_char *, size_t));
293 static	void	oncore_msg_Cj	   P((struct instance *, u_char *, size_t));
294 static	void	oncore_msg_Cj_id   P((struct instance *, u_char *, size_t));
295 static	void	oncore_msg_Cj_init P((struct instance *, u_char *, size_t));
296 static	void	oncore_msg_Gj	   P((struct instance *, u_char *, size_t));
297 static	void	oncore_msg_Sz	   P((struct instance *, u_char *, size_t));
298 
299 struct	refclock refclock_oncore = {
300 	oncore_start,		/* start up driver */
301 	oncore_shutdown,	/* shut down driver */
302 	oncore_poll,		/* transmit poll message */
303 	noentry,		/* not used */
304 	noentry,		/* not used */
305 	noentry,		/* not used */
306 	NOFLAGS 		/* not used */
307 };
308 
309 /*
310  * Understanding the next bit here is not easy unless you have a manual
311  * for the the various Oncore Models.
312  */
313 
314 static struct msg_desc {
315 	const char	flag[3];
316 	const int	len;
317 	void		(*handler) P((struct instance *, u_char *, size_t));
318 	const char	*fmt;
319 	int		shmem;
320 } oncore_messages[] = {
321 			/* Ea and En first since they're most common */
322 	{ "Ea",  76,    oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdimsdimsdsC" },
323 	{ "Ba",  68,    oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdsC" },
324 	{ "Ha", 154,    oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmaaaaoooohhhhmmmmVVvvhhddntimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddssrrccooooTTushmvvvvvvC" },
325 	{ "En",  69,    oncore_msg_BnEn,   "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffsffffsffffC" },
326 	{ "Bn",  59,    oncore_msg_BnEn,   "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffC" },
327 	{ "Ab",  10,    0,                 "" },
328 	{ "Ac",  11,    0,                 "" },
329 	{ "Ad",  11,    0,                 "" },
330 	{ "Ae",  11,    0,                 "" },
331 	{ "Af",  15,    0,                 "" },
332 	{ "As",  20,    oncore_msg_As,     "" },
333 	{ "At",   8,    oncore_msg_At,     "" },
334 	{ "Au",  12,    0,                 "" },
335 	{ "Av",   8,    0,                 "" },
336 	{ "Aw",   8,    0,                 "" },
337 	{ "Ay",  11,    oncore_msg_Ay,     "" },
338 	{ "Az",  11,    oncore_msg_Az,     "" },
339 	{ "AB",   8,    0,                 "" },
340 	{ "Bb",  92,    0,                 "" },
341 	{ "Bj",   8,    oncore_msg_Bj,     "" },
342 	{ "Ca",   9,    oncore_msg_CaFaIa, "" },
343 	{ "Cb",  33,    oncore_msg_Cb,     "" },
344 	{ "Cf",   7,    oncore_msg_Cf,     "" },
345 	{ "Cg",   8,    0,                 "" },
346 	{ "Ch",   9,    0,                 "" },
347 	{ "Cj", 294,    oncore_msg_Cj,     "" },
348 	{ "Ek",  71,    0,                 "" },
349 	{ "Fa",   9,    oncore_msg_CaFaIa, "" },
350 	{ "Gd",   8,    0,                 "" },
351 	{ "Gj",  21,    oncore_msg_Gj,     "" },
352 	{ "Ia",  10,    oncore_msg_CaFaIa, "" },
353 	{ "Sz",   8,    oncore_msg_Sz,     "" },
354 	{ {0},	  7,	0,		   "" }
355 };
356 
357 /*
358  * Position Set.
359  */
360 u_char oncore_cmd_Ad[] = { 'A', 'd', 0,0,0,0 };
361 u_char oncore_cmd_Ae[] = { 'A', 'e', 0,0,0,0 };
362 u_char oncore_cmd_Af[] = { 'A', 'f', 0,0,0,0, 0 };
363 u_char oncore_cmd_Ga[] = { 'G', 'a', 0,0,0,0, 0,0,0,0, 0,0,0,0, 0 };
364 
365 /*
366  * Position-Hold Mode
367  *    Start automatic site survey
368  */
369 static u_char oncore_cmd_At0[] = { 'A', 't', 0 };	/* Posn Hold off */
370 static u_char oncore_cmd_At1[] = { 'A', 't', 1 };	/* Posn Hold on  */
371 static u_char oncore_cmd_At2[] = { 'A', 't', 2 };	/* Start Site Survey */
372 
373 /*
374  * 0D/2D Position and Set.
375  */
376 u_char oncore_cmd_As[] = { 'A', 's', 0,0,0,0, 0,0,0,0, 0,0,0,0, 0 };
377 u_char oncore_cmd_Asx[]= { 'A', 's', 0x7f, 0xff, 0xff, 0xff,
378 				     0x7f, 0xff, 0xff, 0xff,
379 				     0x7f, 0xff, 0xff, 0xff, 0xff };
380 u_char oncore_cmd_Au[] = { 'A', 'u', 0,0,0,0,0 };
381 
382 u_char oncore_cmd_Av0[] = { 'A', 'v', 0 };
383 u_char oncore_cmd_Av1[] = { 'A', 'v', 1 };
384 
385 u_char oncore_cmd_Gd0[] = { 'G', 'd', 0 };	/* 3D */
386 u_char oncore_cmd_Gd1[] = { 'G', 'd', 1 };	/* 0D */
387 u_char oncore_cmd_Gd2[] = { 'G', 'd', 2 };	/* 2D */
388 
389 /*
390  * Set to UTC time (not GPS).
391  */
392 u_char oncore_cmd_Aw[] = { 'A', 'w', 1 };
393 
394 /*
395  * Output Almanac when it changes
396  */
397 u_char oncore_cmd_Be[] = { 'B', 'e', 1 };
398 
399 /*
400  * Read back PPS Offset for Output
401  */
402 u_char oncore_cmd_Ay[]	= { 'A', 'y', 0, 0, 0, 0 };
403 u_char oncore_cmd_Ayx[] = { 'A', 'y', 0xff, 0xff, 0xff, 0xff };
404 
405 /*
406  * Read back Cable Delay for Output
407  */
408 u_char oncore_cmd_Az[]	= { 'A', 'z', 0, 0, 0, 0 };
409 u_char oncore_cmd_Azx[] = { 'A', 'z', 0xff, 0xff, 0xff, 0xff };
410 
411 /*
412  * Application type = static.
413  */
414 u_char oncore_cmd_AB[] = { 'A', 'B', 4 };
415 
416 /*
417  * Visible Satellite Status Msg.
418  */
419 u_char oncore_cmd_Bb[] = { 'B', 'b', 1 };
420 
421 /*
422  * Leap Second Pending Message
423  *    Request message once
424  */
425 u_char oncore_cmd_Bj[] = { 'B', 'j', 0 };
426 u_char oncore_cmd_Gj[] = { 'G', 'j' };
427 
428 /*
429  * Set to Defaults
430  */
431 static u_char oncore_cmd_Cf[] = { 'C', 'f' };
432 
433 /*
434  * Set to Position Fix mode (only needed on VP).
435  */
436 u_char oncore_cmd_Cg[] = { 'C', 'g', 1 };
437 
438 /*
439  * Receiver Id
440  */
441 static u_char oncore_cmd_Cj[] = { 'C', 'j' };
442 
443 /*
444  * Position/Status/Data message
445  *    Send once per second
446  */
447 static u_char oncore_cmd_Ea[]  = { 'E', 'a', 1 };
448 static u_char oncore_cmd_Ba[]  = { 'B', 'a', 1 };
449 static u_char oncore_cmd_Ha[]  = { 'H', 'a', 1 };
450 static u_char oncore_cmd_Ea0[] = { 'E', 'a', 0 };
451 static u_char oncore_cmd_Ba0[] = { 'B', 'a', 0 };
452 
453 /*
454  * Position/Status Extension Msg
455  */
456 u_char oncore_cmd_Ek[] = { 'E', 'k', 0 };	/* just turn off */
457 
458 /*
459  * Time Raim Setup & Status Message
460  *    Send once per second
461  *    Time-RAIM on
462  *    Alarm limit 1us
463  *    PPS on when we have the first sat
464  */
465 static u_char oncore_cmd_En[]  = { 'E', 'n', 1, 1, 0,10, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
466 static u_char oncore_cmd_En0[] = { 'E', 'n', 0, 1, 0,10, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
467 static u_char oncore_cmd_Bn[]  = { 'B', 'n', 1, 1, 0,10, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
468 static u_char oncore_cmd_Bn0[] = { 'B', 'n', 0, 1, 0,10, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
469 
470 /*
471  * Self-test
472  */
473 static u_char oncore_cmd_Ca[] = { 'C', 'a' };	/*  6 Chan */
474 static u_char oncore_cmd_Fa[] = { 'F', 'a' };	/*  8 Chan */
475 static u_char oncore_cmd_Ia[] = { 'I', 'a' };	/* 12 Chan */
476 
477 #define DEVICE1 	"/dev/oncore.serial.%d"   /* name of serial device */
478 #define DEVICE2 	"/dev/oncore.pps.%d"   /* name of pps device */
479 #define INIT_FILE	"/etc/ntp.oncore" /* optional init file */
480 
481 #define SPEED		B9600		/* Oncore Binary speed (9600 bps) */
482 
483 /*
484  * Assemble and disassemble 32bit signed quantities from a buffer.
485  *
486  */
487 
488 	/* to buffer, int w, u_char *buf */
489 #define w32_buf(buf,w)	{ u_int i_tmp;			   \
490 			  i_tmp = (w<0) ? (~(-w)+1) : (w); \
491 			  (buf)[0] = (i_tmp >> 24) & 0xff; \
492 			  (buf)[1] = (i_tmp >> 16) & 0xff; \
493 			  (buf)[2] = (i_tmp >>	8) & 0xff; \
494 			  (buf)[3] = (i_tmp	 ) & 0xff; \
495 			}
496 
497 #define w32(buf)      (((buf)[0]&0xff) << 24 | \
498 		       ((buf)[1]&0xff) << 16 | \
499 		       ((buf)[2]&0xff) <<  8 | \
500 		       ((buf)[3]&0xff) )
501 
502 	/* from buffer, char *buf, result to an int */
503 #define buf_w32(buf) (((buf)[0]&0200) ? (-(~w32(buf)+1)) : w32(buf))
504 
505 extern int pps_assert;
506 extern int pps_hardpps;
507 
508 
509 
510 /*
511  * oncore_start - initialize data for processing
512  */
513 
514 static int
515 oncore_start(
516 	int unit,
517 	struct peer *peer
518 	)
519 {
520 	register struct instance *instance;
521 	struct refclockproc *pp;
522 	int fd1, fd2, mode;
523 	char device1[30], device2[30];
524 	const char *cp;
525 	struct stat stat1, stat2;
526 
527 	/* OPEN DEVICES */
528 	/* opening different devices for fd1 and fd2 presents no problems */
529 	/* opening the SAME device twice, seems to be OS dependent.
530 		(a) on Linux (no streams) no problem
531 		(b) on SunOS (and possibly Solaris, untested), (streams)
532 			never see the line discipline.
533 	   Since things ALWAYS work if we only open the device once, we check
534 	     to see if the two devices are in fact the same, then proceed to
535 	     do one open or two.
536 	*/
537 
538 	(void)sprintf(device1, DEVICE1, unit);
539 	(void)sprintf(device2, DEVICE2, unit);
540 
541 	if (stat(device1, &stat1)) {
542 		perror("ONCORE: stat fd1");
543 		exit(1);
544 	}
545 
546 	if (stat(device2, &stat2)) {
547 		perror("ONCORE: stat fd2");
548 		exit(1);
549 	}
550 
551 	if ((stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino)) {
552 		/* same device here */
553 		if (!(fd1 = refclock_open(device1, SPEED, LDISC_RAW
554 #if !defined(HAVE_PPSAPI) && !defined(TIOCDCDTIMESTAMP)
555 		      | LDISC_PPS
556 #endif
557 		   ))) {
558 			perror("ONCORE: fd1");
559 			exit(1);
560 		}
561 		fd2 = fd1;
562 	} else { /* different devices here */
563 		if (!(fd1=refclock_open(device1, SPEED, LDISC_RAW))) {
564 			perror("ONCORE: fd1");
565 			exit(1);
566 		}
567 		if ((fd2=open(device2, O_RDWR)) < 0) {
568 			perror("ONCORE: fd2");
569 			exit(1);
570 		}
571 	}
572 
573 	/* Devices now open, create instance structure for this unit */
574 
575 	if (!(instance = (struct instance *) malloc(sizeof *instance))) {
576 		perror("malloc");
577 		close(fd1);
578 		return (0);
579 	}
580 	memset((char *) instance, 0, sizeof *instance);
581 
582 	/* link instance up and down */
583 
584 	pp = peer->procptr;
585 	pp->unitptr    = (caddr_t) instance;
586 	instance->pp   = pp;
587 	instance->unit = unit;
588 	instance->peer = peer;
589 
590 	/* initialize miscellaneous variables */
591 
592 	instance->o_state = ONCORE_NO_IDEA;
593 	cp = "state = ONCORE_NO_IDEA";
594 	record_clock_stats(&(instance->peer->srcadr), cp);
595 
596 	instance->ttyfd = fd1;
597 	instance->ppsfd = fd2;
598 
599 	instance->Bj_day = -1;
600 	instance->assert = pps_assert;
601 	instance->traim = -1;
602 	instance->model = ONCORE_UNKNOWN;
603 	instance->mode = MODE_UNKNOWN;
604 	instance->site_survey = ONCORE_SS_UNKNOWN;
605 
606 	peer->precision = -26;
607 	peer->minpoll = 4;
608 	peer->maxpoll = 4;
609 	pp->clockdesc = "Motorola Oncore GPS Receiver";
610 	memcpy((char *)&pp->refid, "GPS\0", (size_t) 4);
611 
612 	/* go read any input data in /etc/ntp.oncoreX */
613 
614 	oncore_read_config(instance);
615 
616 #ifdef HAVE_PPSAPI
617 	if (time_pps_create(fd2, &instance->pps_h) < 0) {
618 		perror("time_pps_create");
619 		return(0);
620 	}
621 
622 	if (time_pps_getcap(instance->pps_h, &mode) < 0) {
623 		msyslog(LOG_ERR,
624 		    "refclock_ioctl: time_pps_getcap failed: %m");
625 		return (0);
626 	}
627 
628 	if (time_pps_getparams(instance->pps_h, &instance->pps_p) < 0) {
629 		msyslog(LOG_ERR,
630 		    "refclock_ioctl: time_pps_getparams failed: %m");
631 		return (0);
632 	}
633 
634 	/* nb. only turn things on, if someone else has turned something
635 	 *	on before we get here, leave it alone!
636 	 */
637 
638 	if (instance->assert) { 	/* nb, default or ON */
639 		instance->pps_p.mode = PPS_CAPTUREASSERT | PPS_OFFSETASSERT;
640 		instance->pps_p.assert_offset.tv_sec = 0;
641 		instance->pps_p.assert_offset.tv_nsec = 0;
642 	} else {
643 		instance->pps_p.mode = PPS_CAPTURECLEAR  | PPS_OFFSETCLEAR;
644 		instance->pps_p.clear_offset.tv_sec = 0;
645 		instance->pps_p.clear_offset.tv_nsec = 0;
646 	}
647 	instance->pps_p.mode |= PPS_TSFMT_TSPEC;
648 	instance->pps_p.mode &= mode;		/* only set what is legal */
649 
650 	if (time_pps_setparams(instance->pps_h, &instance->pps_p) < 0) {
651 		perror("time_pps_setparams");
652 		exit(1);
653 	}
654 
655 	if (pps_device) {
656 		if (stat(pps_device, &stat1)) {
657 			perror("ONCORE: stat pps_device");
658 			return(0);
659 		}
660 
661 		/* must have hardpps ON, and fd2 must be the same device as on the pps line */
662 
663 		if (pps_hardpps && ((stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino))) {
664 			int	i;
665 
666 			if (instance->assert)
667 				i = PPS_CAPTUREASSERT;
668 			else
669 				i = PPS_CAPTURECLEAR;
670 
671 			if (i&mode) {
672 				if (time_pps_kcbind(instance->pps_h, PPS_KC_HARDPPS, i,
673 				    PPS_TSFMT_TSPEC) < 0) {
674 					msyslog(LOG_ERR,
675 					    "refclock_ioctl: time_pps_kcbind failed: %m");
676 					return (0);
677 				}
678 				pps_enable = 1;
679 			}
680 		}
681 	}
682 #endif
683 
684 	pp->io.clock_recv = oncore_receive;
685 	pp->io.srcclock = (caddr_t)peer;
686 	pp->io.datalen = 0;
687 	pp->io.fd = fd1;
688 	if (!io_addclock(&pp->io)) {
689 		perror("io_addclock");
690 		(void) close(fd1);
691 		free(instance);
692 		return (0);
693 	}
694 
695 	/*
696 	 * This will return the Model Number of the Oncore receiver.
697 	 */
698 
699 	oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
700 	instance->o_state = ONCORE_ID_SENT;
701 	cp = "state = ONCORE_ID SENT";
702 	record_clock_stats(&(instance->peer->srcadr), cp);
703 	instance->timeout = 4;
704 
705 	instance->pollcnt = 2;
706 	return (1);
707 }
708 
709 
710 
711 /*
712  * Read Input file if it exists.
713  */
714 
715 static void
716 oncore_read_config(
717 	struct instance *instance
718 	)
719 {
720 /*
721  * First we try to open the configuration file
722  *    /etc/oncoreN
723  * where N is the unit number viz 127.127.30.N.
724  * If we don't find it we try
725  *    /etc/ntp.oncore.N
726  * and then
727  *    /etc/ntp.oncore
728  *
729  * If we don't find any then we don't have the cable delay or PPS offset
730  * and we choose MODE (4) below.
731  *
732  * Five Choices for MODE
733  *    (0) ONCORE is preinitialized, don't do anything to change it.
734  *	    nb, DON'T set 0D mode, DON'T set Delay, position...
735  *    (1) NO RESET, Read Position, delays from data file, lock it in, go to 0D mode.
736  *    (2) NO RESET, Read Delays from data file, do SITE SURVEY to get position,
737  *		    lock this in, go to 0D mode.
738  *    (3) HARD RESET, Read Position, delays from data file, lock it in, go to 0D mode.
739  *    (4) HARD RESET, Read Delays from data file, do SITE SURVEY to get position,
740  *		    lock this in, go to 0D mode.
741  *     NB. If a POSITION is specified in the config file with mode=(2,4) [SITE SURVEY]
742  *	   then this position is set as the INITIAL position of the ONCORE.
743  *	   This can reduce the time to first fix.
744  * -------------------------------------------------------------------------------
745  * Note that an Oncore UT without a battery backup retains NO information if it is
746  *   power cycled, with a Battery Backup it remembers the almanac, etc.
747  * For an Oncore VP, there is an eeprom that will contain this data, along with the
748  *   option of Battery Backup.
749  * So a UT without Battery Backup is equivalent to doing a HARD RESET on each
750  *   power cycle, since there is nowhere to store the data.
751  * -------------------------------------------------------------------------------
752  *
753  * If we open one or the other of the files, we read it looking for
754  *   MODE, LAT, LON, (HT, HTGPS, HTMSL), DELAY, OFFSET, ASSERT, CLEAR, STATUS,
755  *   POSN3D, POSN2D, CHAN, TRAIM
756  * then initialize using method MODE.  For Mode = (1,3) all of (LAT, LON, HT) must
757  *   be present or mode reverts to (2,4).
758  *
759  * Read input file.
760  *
761  *	# is comment to end of line
762  *	= allowed between 1st and 2nd fields.
763  *
764  *	Expect to see one line with 'MODE' as first field, followed by an integer
765  *	   in the range 0-4 (default = 4).
766  *
767  *	Expect to see two lines with 'LONG', 'LAT' followed by 1-3 fields.
768  *	All numbers are floating point.
769  *		DDD.ddd
770  *		DDD  MMM.mmm
771  *		DDD  MMM  SSS.sss
772  *
773  *	Expect to see one line with 'HT' as first field,
774  *	   followed by 1-2 fields.  First is a number, the second is 'FT' or 'M'
775  *	   for feet or meters.	HT is the height above the GPS ellipsoid.
776  *	   If the reciever reports height in both GPS and MSL, then we will report
777  *	   the difference GPS-MSL on the clockstats file.
778  *
779  *	There is an optional line, starting with DELAY, followed
780  *	   by 1 or two fields.	The first is a number (a time) the second is
781  *	   'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds.
782  *	    DELAY  is cable delay, typically a few tens of ns.
783  *
784  *	There is an optional line, starting with OFFSET, followed
785  *	   by 1 or two fields.	The first is a number (a time) the second is
786  *	   'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds.
787  *	   OFFSET is the offset of the PPS pulse from 0. (only fully implemented
788  *		with the PPSAPI, we need to be able to tell the Kernel about this
789  *		offset if the Kernel PLL is in use, but can only do this presently
790  *		when using the PPSAPI interface.  If not using the Kernel PLL,
791  *		then there is no problem.
792  *
793  *	There is an optional line, with either ASSERT or CLEAR on it, which
794  *	   determine which transition of the PPS signal is used for timing by the
795  *	   PPSAPI.  If neither is present, then ASSERT is assumed.
796  *
797  *	There are three options that have to do with using the shared memory opition.
798  *	   First, to enable the option there must be an ASSERT line with a file name.
799  *	   The file name is the file associated with the shared memory.
800  *
801  *	In the shared memory there are three 'records' containing the @@Ea (or equivalent)
802  *	   data, and this contains the position data.  There will always be data in the
803  *	   record cooresponding to the '0D' @@Ea record, and the user has a choice of
804  *	   filling the '3D' @@Ea record by specifying POSN3D, or the '2D' record by
805  *	   specifying POSN2D.  In either case the '2D' or '3D' record is filled once
806  *	   every 15s.
807  *
808  *	Two additional variables that can be set are CHAN and TRAIM.  These should be
809  *	   set correctly by the code examining the @@Cj record, but we bring them out here
810  *	   to allow the user to override either the # of channels, or the existance of TRAIM.
811  *	   CHAN expects to be followed by in integer: 6, 8, or 12. TRAIM expects to be
812  *	   followed by YES or NO.
813  *
814  * So acceptable input would be
815  *	# these are my coordinates (RWC)
816  *	LON  -106 34.610
817  *	LAT    35 08.999
818  *	HT	1589	# could equally well say HT 5215 FT
819  *	DELAY  60 ns
820  */
821 
822 	FILE	*fd;
823 	char	*cp, *cc, *ca, line[100], units[2], device[20], Msg[160];
824 	int	i, sign, lat_flg, long_flg, ht_flg, mode;
825 	double	f1, f2, f3;
826 
827 	sprintf(device, "%s%d", INIT_FILE, instance->unit);             /* try "ntp.oncore0" first */
828 	if ((fd=fopen(device, "r")) == NULL) {                          /*   it was in the original documentation */
829 		sprintf(device, "%s.%d", INIT_FILE, instance->unit);    /* then try "ntp.oncore.0 */
830 		if ((fd=fopen(device, "r")) == NULL) {
831 			if ((fd=fopen(INIT_FILE, "r")) == NULL) {       /* and finally "ntp.oncore" */
832 				instance->init_type = 4;
833 				return;
834 			}
835 		}
836 	}
837 
838 	mode = 0;
839 	lat_flg = long_flg = ht_flg = 0;
840 	while (fgets(line, 100, fd)) {
841 
842 		/* Remove comments */
843 		if ((cp = strchr(line, '#')))
844 			*cp = '\0';
845 
846 		/* Remove trailing space */
847 		for (i = strlen(line);
848 		     i > 0 && isascii((int)line[i - 1]) && isspace((int)line[i - 1]);
849 			)
850 			line[--i] = '\0';
851 
852 		/* Remove leading space */
853 		for (cc = line; *cc && isascii((int)*cc) && isspace((int)*cc); cc++)
854 			continue;
855 
856 		/* Stop if nothing left */
857 		if (!*cc)
858 			continue;
859 
860 		/* Uppercase the command and find the arg */
861 		for (ca = cc; *ca; ca++) {
862 			if (isascii((int)*ca)) {
863 				if (islower((int)*ca)) {
864 					*ca = toupper(*ca);
865 				} else if (isspace((int)*ca) || (*ca == '='))
866 					break;
867 			}
868 		}
869 
870 		/* Remove space (and possible =) leading the arg */
871 		for (; *ca && isascii((int)*ca) && (isspace((int)*ca) || (*ca == '=')); ca++)
872 			continue;
873 
874 		/*
875 		 * move call to oncore_shmem_init() from here to after
876 		 * we have determined Oncore Model, so we can ignore
877 		 * request if model doesnt 'support' it
878 		 */
879 
880 		if (!strncmp(cc, "STATUS", (size_t) 6) || !strncmp(cc, "SHMEM", (size_t) 5)) {
881 			i = strlen(ca);
882 			instance->shmem_fname = (char *) malloc((unsigned) (i+1));
883 			strcpy(instance->shmem_fname, ca);
884 			continue;
885 		}
886 
887 		/* Uppercase argument as well */
888 		for (cp = ca; *cp; cp++)
889 			if (isascii((int)*cp) && islower((int)*cp))
890 				*cp = toupper(*cp);
891 
892 		if (!strncmp(cc, "LAT", (size_t) 3)) {
893 			f1 = f2 = f3 = 0;
894 			sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3);
895 			sign = 1;
896 			if (f1 < 0) {
897 				f1 = -f1;
898 				sign = -1;
899 			}
900 			instance->ss_lat = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/
901 			lat_flg++;
902 		} else if (!strncmp(cc, "LON", (size_t) 3)) {
903 			f1 = f2 = f3 = 0;
904 			sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3);
905 			sign = 1;
906 			if (f1 < 0) {
907 				f1 = -f1;
908 				sign = -1;
909 			}
910 			instance->ss_long = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/
911 			long_flg++;
912 		} else if (!strncmp(cc, "HT", (size_t) 2)) {
913 			f1 = 0;
914 			units[0] = '\0';
915 			sscanf(ca, "%lf %1s", &f1, units);
916 			if (units[0] == 'F')
917 				f1 = 0.3048 * f1;
918 			instance->ss_ht = 100 * f1;    /* cm */
919 			ht_flg++;
920 		} else if (!strncmp(cc, "DELAY", (size_t) 5)) {
921 			f1 = 0;
922 			units[0] = '\0';
923 			sscanf(ca, "%lf %1s", &f1, units);
924 			if (units[0] == 'N')
925 				;
926 			else if (units[0] == 'U')
927 				f1 = 1000 * f1;
928 			else if (units[0] == 'M')
929 				f1 = 1000000 * f1;
930 			else
931 				f1 = 1000000000 * f1;
932 			if (f1 < 0 || f1 > 1.e9)
933 				f1 = 0;
934 			if (f1 < 0 || f1 > 999999) {
935 				sprintf(Msg, "PPS Cable delay of %fns out of Range, ignored", f1);
936 				record_clock_stats(&(instance->peer->srcadr), Msg);
937 			} else
938 				instance->delay = f1;		/* delay in ns */
939 		} else if (!strncmp(cc, "OFFSET", (size_t) 6)) {
940 			f1 = 0;
941 			units[0] = '\0';
942 			sscanf(ca, "%lf %1s", &f1, units);
943 			if (units[0] == 'N')
944 				;
945 			else if (units[0] == 'U')
946 				f1 = 1000 * f1;
947 			else if (units[0] == 'M')
948 				f1 = 1000000 * f1;
949 			else
950 				f1 = 1000000000 * f1;
951 			if (f1 < 0 || f1 > 1.e9)
952 				f1 = 0;
953 			if (f1 < 0 || f1 > 999999999.) {
954 				sprintf(Msg, "PPS Offset of %fns out of Range, ignored", f1);
955 				record_clock_stats(&(instance->peer->srcadr), Msg);
956 			} else
957 				instance->offset = f1;		/* offset in ns */
958 		} else if (!strncmp(cc, "MODE", (size_t) 4)) {
959 			sscanf(ca, "%d", &mode);
960 			if (mode < 0 || mode > 4)
961 				mode = 4;
962 		} else if (!strncmp(cc, "ASSERT", (size_t) 6)) {
963 			instance->assert = 1;
964 		} else if (!strncmp(cc, "CLEAR", (size_t) 5)) {
965 			instance->assert = 0;
966 		} else if (!strncmp(cc, "POSN2D", (size_t) 6)) {
967 			instance->shmem_Posn = 2;
968 		} else if (!strncmp(cc, "POSN3D", (size_t) 6)) {
969 			instance->shmem_Posn = 3;
970 		} else if (!strncmp(cc, "CHAN", (size_t) 4)) {
971 			sscanf(ca, "%d", &i);
972 			if ((i == 6) || (i == 8) || (i == 12))
973 				instance->chan = i;
974 		} else if (!strncmp(cc, "TRAIM", (size_t) 5)) {
975 			instance->traim = 1;				/* so TRAIM alone is YES */
976 			if (!strcmp(ca, "NO") || !strcmp(ca, "OFF"))    /* Yes/No, On/Off */
977 				instance->traim = 0;
978 		}
979 	}
980 	fclose(fd);
981 
982 	/*
983 	 *    OK, have read all of data file, and extracted the good stuff.
984 	 *    If lat/long/ht specified they ALL must be specified for mode = (1,3).
985 	 */
986 
987 	instance->posn_set = 1;
988 	if ((lat_flg || long_flg || ht_flg) && !(lat_flg * long_flg * ht_flg)) {
989 		printf("ONCORE: incomplete data on %s\n", INIT_FILE);
990 		instance->posn_set = 0;
991 		if (mode == 1 || mode == 3) {
992 			sprintf(Msg, "Input Mode = %d, but no/incomplete position, mode set to %d", mode, mode+1);
993 			record_clock_stats(&(instance->peer->srcadr), Msg);
994 			mode++;
995 		}
996 	}
997 	instance->init_type = mode;
998 
999 	sprintf(Msg, "Input mode = %d", mode);
1000 	record_clock_stats(&(instance->peer->srcadr), Msg);
1001 }
1002 
1003 
1004 
1005 static void
1006 oncore_init_shmem(
1007 	struct instance *instance
1008 	)
1009 {
1010 #ifdef ONCORE_SHMEM_STATUS
1011 	int i, l, n;
1012 	char *buf;
1013 	struct msg_desc *mp;
1014 	size_t oncore_shmem_length;
1015 
1016 	if (instance->shmem_first)
1017 		return;
1018 
1019 	instance->shmem_first++;
1020 
1021 	if ((instance->statusfd = open(instance->shmem_fname, O_RDWR|O_CREAT|O_TRUNC, 0644)) < 0) {
1022 		perror(instance->shmem_fname);
1023 		return;
1024 	}
1025 
1026 	n = 1;
1027 	for (mp = oncore_messages; mp->flag[0]; mp++) {
1028 		mp->shmem = n;
1029 		/* Allocate space for multiplexed almanac, and 0D/2D/3D @@Ea records */
1030 		if (!strcmp(mp->flag, "Cb")) {
1031 			instance->shmem_Cb = n;
1032 			n += (mp->len + 3) * 34;
1033 		}
1034 		if (!strcmp(mp->flag, "Ba")) {
1035 			instance->shmem_Ba = n;
1036 			n += (mp->len + 3) * 3;
1037 		}
1038 		if (!strcmp(mp->flag, "Ea")) {
1039 			instance->shmem_Ea = n;
1040 			n += (mp->len + 3) * 3;
1041 		}
1042 		if (!strcmp(mp->flag, "Ha")) {
1043 			instance->shmem_Ha = n;
1044 			n += (mp->len + 3) * 3;
1045 		}
1046 		n += (mp->len + 3);
1047 	}
1048 	oncore_shmem_length = n + 2;
1049 	fprintf(stderr, "ONCORE: SHMEM length: %d bytes\n", (int) oncore_shmem_length);
1050 
1051 	buf = malloc(oncore_shmem_length);
1052 	if (buf == NULL) {
1053 		perror("malloc");
1054 		return;
1055 	}
1056 	memset(buf, 0, sizeof(buf));
1057 	i = write(instance->statusfd, buf, oncore_shmem_length);
1058 	if (i != oncore_shmem_length) {
1059 		perror(instance->shmem_fname);
1060 		return;
1061 	}
1062 	free(buf);
1063 	instance->shmem = (u_char *) mmap(0, oncore_shmem_length,
1064 	    PROT_READ | PROT_WRITE,
1065 #ifdef MAP_HASSEMAPHORE
1066 			       MAP_HASSEMAPHORE |
1067 #endif
1068 			       MAP_SHARED,
1069 	    instance->statusfd, (off_t)0);
1070 	if (instance->shmem == (u_char *)MAP_FAILED) {
1071 		instance->shmem = 0;
1072 		close (instance->statusfd);
1073 		return;
1074 	}
1075 	for (mp = oncore_messages; mp->flag[0]; mp++) {
1076 		l = mp->shmem;
1077 		instance->shmem[l + 0] = mp->len >> 8;
1078 		instance->shmem[l + 1] = mp->len & 0xff;
1079 		instance->shmem[l + 2] = 0;
1080 		instance->shmem[l + 3] = '@';
1081 		instance->shmem[l + 4] = '@';
1082 		instance->shmem[l + 5] = mp->flag[0];
1083 		instance->shmem[l + 6] = mp->flag[1];
1084 		if (!strcmp(mp->flag, "Cb") || !strcmp(mp->flag, "Ba") || !strcmp(mp->flag, "Ea") || !strcmp(mp->flag, "Ha")) {
1085 			if (!strcmp(mp->flag, "Cb"))
1086 				n = 35;
1087 			else
1088 				n = 4;
1089 			for (i = 1; i < n; i++) {
1090 				instance->shmem[l + i * (mp->len+3) + 0] = mp->len >> 8;
1091 				instance->shmem[l + i * (mp->len+3) + 1] = mp->len & 0xff;
1092 				instance->shmem[l + i * (mp->len+3) + 2] = 0;
1093 				instance->shmem[l + i * (mp->len+3) + 3] = '@';
1094 				instance->shmem[l + i * (mp->len+3) + 4] = '@';
1095 				instance->shmem[l + i * (mp->len+3) + 5] = mp->flag[0];
1096 				instance->shmem[l + i * (mp->len+3) + 6] = mp->flag[1];
1097 			}
1098 		}
1099 	}
1100 #endif /* ONCORE_SHMEM_STATUS */
1101 }
1102 
1103 
1104 
1105 /*
1106  * oncore_shutdown - shut down the clock
1107  */
1108 
1109 static void
1110 oncore_shutdown(
1111 	int unit,
1112 	struct peer *peer
1113 	)
1114 {
1115 	register struct instance *instance;
1116 	struct refclockproc *pp;
1117 
1118 	pp = peer->procptr;
1119 	instance = (struct instance *) pp->unitptr;
1120 
1121 	io_closeclock(&pp->io);
1122 
1123 	free(instance);
1124 }
1125 
1126 
1127 
1128 /*
1129  * oncore_poll - called by the transmit procedure
1130  */
1131 
1132 static void
1133 oncore_poll(
1134 	int unit,
1135 	struct peer *peer
1136 	)
1137 {
1138 	struct instance *instance;
1139 
1140 	instance = (struct instance *) peer->procptr->unitptr;
1141 	if (instance->timeout) {
1142 		char	*cp;
1143 
1144 		instance->timeout--;
1145 		if (instance->timeout == 0) {
1146 			cp = "Oncore: No response from @@Cj, shutting down driver";
1147 			record_clock_stats(&(instance->peer->srcadr), cp);
1148 			oncore_shutdown(unit, peer);
1149 		} else {
1150 			oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
1151 			cp = "Oncore: Resend @@Cj";
1152 			record_clock_stats(&(instance->peer->srcadr), cp);
1153 		}
1154 		return;
1155 	}
1156 
1157 	if (!instance->pollcnt)
1158 		refclock_report(peer, CEVNT_TIMEOUT);
1159 	else
1160 		instance->pollcnt--;
1161 	peer->procptr->polls++;
1162 	instance->polled = 1;
1163 }
1164 
1165 
1166 
1167 /*
1168  * move data from NTP to buffer (toss in unlikely case it wont fit)
1169  */
1170 
1171 static void
1172 oncore_receive(
1173 	struct recvbuf *rbufp
1174 	)
1175 {
1176 	size_t i;
1177 	u_char *p;
1178 	struct peer *peer;
1179 	struct instance *instance;
1180 
1181 	peer = (struct peer *)rbufp->recv_srcclock;
1182 	instance = (struct instance *) peer->procptr->unitptr;
1183 	p = (u_char *) &rbufp->recv_space;
1184 
1185 #if 0
1186 	if (debug > 4) {
1187 		int i;
1188 		printf("ONCORE: >>>");
1189 		for(i=0; i<rbufp->recv_length; i++)
1190 			printf("%02x ", p[i]);
1191 		printf("\n");
1192 		printf("ONCORE: >>>");
1193 		for(i=0; i<rbufp->recv_length; i++)
1194 			printf("%03o ", p[i]);
1195 		printf("\n");
1196 	}
1197 #endif
1198 
1199 	i = rbufp->recv_length;
1200 	if (rcvbuf+rcvptr+i > &rcvbuf[sizeof rcvbuf])
1201 		i = sizeof(rcvbuf) - rcvptr;	/* and some char will be lost */
1202 	memcpy(rcvbuf+rcvptr, p, i);
1203 	rcvptr += i;
1204 	oncore_consume(instance);
1205 }
1206 
1207 
1208 
1209 /*
1210  * Deal with any complete messages
1211  */
1212 
1213 static void
1214 oncore_consume(
1215 	struct instance *instance
1216 	)
1217 {
1218 	int i, j, m;
1219 	unsigned l;
1220 
1221 	while (rcvptr >= 7) {
1222 		if (rcvbuf[0] != '@' || rcvbuf[1] != '@') {
1223 			/* We're not in sync, lets try to get there */
1224 			for (i=1; i < rcvptr-1; i++)
1225 				if (rcvbuf[i] == '@' && rcvbuf[i+1] == '@')
1226 					break;
1227 			if (debug > 4)
1228 				printf("ONCORE[%d]: >>> skipping %d chars\n", instance->unit, i);
1229 			if (i != rcvptr)
1230 				memcpy(rcvbuf, rcvbuf+i, (size_t)(rcvptr-i));
1231 			rcvptr -= i;
1232 			continue;
1233 		}
1234 
1235 		/* Ok, we have a header now */
1236 		l = sizeof(oncore_messages)/sizeof(oncore_messages[0]) -1;
1237 		for(m=0; m<l; m++)
1238 			if (!strncmp(oncore_messages[m].flag, (char *)(rcvbuf+2), (size_t) 2))
1239 				break;
1240 		if (m == l) {
1241 			if (debug > 4)
1242 				printf("ONCORE[%d]: >>> Unknown MSG, skipping 4 (%c%c)\n", instance->unit, rcvbuf[2], rcvbuf[3]);
1243 			memcpy(rcvbuf, rcvbuf+4, (size_t) 4);
1244 			rcvptr -= 4;
1245 			continue;
1246 		}
1247 
1248 		l = oncore_messages[m].len;
1249 #if 0
1250 		if (debug > 3)
1251 			printf("ONCORE[%d]: GOT: %c%c  %d of %d entry %d\n", instance->unit, rcvbuf[2], rcvbuf[3], rcvptr, l, m);
1252 #endif
1253 		/* Got the entire message ? */
1254 
1255 		if (rcvptr < l)
1256 			return;
1257 
1258 		/* are we at the end of message? should be <Cksum><CR><LF> */
1259 
1260 		if (rcvbuf[l-2] != '\r' || rcvbuf[l-1] != '\n') {
1261 			if (debug)
1262 				printf("ONCORE[%d]: NO <CR><LF> at end of message\n", instance->unit);
1263 		} else {	/* check the CheckSum */
1264 			j = 0;
1265 			for (i = 2; i < l-3; i++)
1266 				j ^= rcvbuf[i];
1267 			if (j == rcvbuf[l-3]) {
1268 				if (instance->shmem != NULL) {
1269 					instance->shmem[oncore_messages[m].shmem + 2]++;
1270 					memcpy(instance->shmem + oncore_messages[m].shmem + 3,
1271 					    rcvbuf, (size_t) l);
1272 				}
1273 				oncore_msg_any(instance, rcvbuf, (size_t) (l-3), m);
1274 				if (oncore_messages[m].handler)
1275 					oncore_messages[m].handler(instance, rcvbuf, (size_t) (l-3));
1276 			} else if (debug) {
1277 				printf("ONCORE[%d]: Checksum mismatch! calc %o is %o\n", instance->unit, j, rcvbuf[l-3]);
1278 				printf("ONCORE[%d]: @@%c%c ", instance->unit, rcvbuf[2], rcvbuf[3]);
1279 				for (i=4; i<l; i++)
1280 					printf("%03o ", rcvbuf[i]);
1281 				printf("\n");
1282 			}
1283 		}
1284 
1285 		if (l != rcvptr)
1286 			memcpy(rcvbuf, rcvbuf+l, (size_t) (rcvptr-l));
1287 		rcvptr -= l;
1288 	}
1289 }
1290 
1291 
1292 
1293 /*
1294  * write message to Oncore.
1295  */
1296 
1297 static void
1298 oncore_sendmsg(
1299 	int	fd,
1300 	u_char *ptr,
1301 	size_t len
1302 	)
1303 {
1304 	u_char cs = 0;
1305 
1306 	printf("ONCORE: Send @@%c%c %d\n", ptr[0], ptr[1], (int) len);
1307 	write(fd, "@@", (size_t) 2);
1308 	write(fd, ptr, len);
1309 	while (len--)
1310 		cs ^= *ptr++;
1311 	write(fd, &cs, (size_t) 1);
1312 	write(fd, "\r\n", (size_t) 2);
1313 }
1314 
1315 
1316 
1317 /*
1318  * print Oncore response message.
1319  */
1320 
1321 static void
1322 oncore_msg_any(
1323 	struct instance *instance,
1324 	u_char *buf,
1325 	size_t len,
1326 	int idx
1327 	)
1328 {
1329 	int i;
1330 	const char *fmt = oncore_messages[idx].fmt;
1331 	const char *p;
1332 #ifdef HAVE_GETCLOCK
1333 	struct timespec ts;
1334 #endif
1335 	struct timeval tv;
1336 
1337 	if (debug > 3) {
1338 #ifdef HAVE_GETCLOCK
1339 		(void) getclock(TIMEOFDAY, &ts);
1340 		tv.tv_sec = ts.tv_sec;
1341 		tv.tv_usec = ts.tv_nsec / 1000;
1342 #else
1343 		GETTIMEOFDAY(&tv, 0);
1344 #endif
1345 		printf("ONCORE[%d]: %ld.%06ld\n", instance->unit, (long) tv.tv_sec, (long) tv.tv_usec);
1346 
1347 		if (!*fmt) {
1348 			printf(">>@@%c%c ", buf[2], buf[3]);
1349 			for(i=2; i < len && i < 2400 ; i++)
1350 				printf("%02x", buf[i]);
1351 			printf("\n");
1352 			return;
1353 		} else {
1354 			printf("##");
1355 			for (p = fmt; *p; p++) {
1356 				putchar(*p);
1357 				putchar('_');
1358 			}
1359 			printf("\n%c%c", buf[2], buf[3]);
1360 			i = 4;
1361 			for (p = fmt; *p; p++) {
1362 				printf("%02x", buf[i++]);
1363 			}
1364 			printf("\n");
1365 		}
1366 	}
1367 }
1368 
1369 
1370 
1371 /*
1372  * Demultiplex the almanac into shmem
1373  */
1374 
1375 static void
1376 oncore_msg_Cb(
1377 	struct instance *instance,
1378 	u_char *buf,
1379 	size_t len
1380 	)
1381 {
1382 	int i;
1383 
1384 	if (instance->shmem == NULL)
1385 		return;
1386 
1387 	if (buf[4] == 5)
1388 		i = buf[5];
1389 	else if (buf[4] == 4 && buf[5] <= 5)
1390 		i = buf[5] + 24;
1391 	else if (buf[4] == 4 && buf[5] <= 10)
1392 		i = buf[5] + 23;
1393 	else
1394 		i = 34;
1395 	i *= 36;
1396 	instance->shmem[instance->shmem_Cb + i + 2]++;
1397 	memcpy(instance->shmem + instance->shmem_Cb + i + 3, buf, (size_t) (len + 3));
1398 }
1399 
1400 
1401 
1402 /*
1403  * We do an @@Cj twice in the initialization sequence.
1404  * o Once at the very beginning to get the Model number so we know what commands
1405  *   we can issue,
1406  * o And once later after we have done a reset and test, (which may hang),
1407  *   as we are about to initialize the Oncore and start it running.
1408  * o We have one routine below for each case.
1409  */
1410 
1411 
1412 /*
1413  * Determine the Type from the Model #, this determines #chan and if TRAIM is
1414  *   available.  We use ONLY the #chans, and determint TRAIM by trying it.
1415  */
1416 
1417 static void
1418 oncore_msg_Cj(
1419 	struct instance *instance,
1420 	u_char *buf,
1421 	size_t len
1422 	)
1423 {
1424 	memcpy(instance->Cj, buf, len);
1425 
1426 	instance->timeout = 0;
1427 	if (instance->o_state == ONCORE_ID_SENT)
1428 		oncore_msg_Cj_id(instance, buf, len);
1429 	else if (instance->o_state == ONCORE_INIT)
1430 		oncore_msg_Cj_init(instance, buf, len);
1431 }
1432 
1433 
1434 
1435 /* The information on determing a Oncore 'Model', viz VP, UT, etc, from
1436  *	the Model Number comes from "Richard M. Hambly" <rick@cnssys.com>
1437  *	and from Motorola.  Until recently Rick was the only source of
1438  *	this information as Motorola didnt give the information out.
1439  */
1440 
1441 static void
1442 oncore_msg_Cj_id(
1443 	struct instance *instance,
1444 	u_char *buf,
1445 	size_t len
1446 	)
1447 {
1448 	char *cp, *cp1, *cp2, Model[21], Msg[160];
1449 	int	mode;
1450 
1451 	/* Write Receiver ID message to clockstats file */
1452 
1453 	instance->Cj[294] = '\0';
1454 	for (cp=(char *)instance->Cj; cp< (char *) &instance->Cj[294]; ) {
1455 		cp1 = strchr(cp, '\r');
1456 		if (!cp1)
1457 			cp1 = (char *)&instance->Cj[294];
1458 		*cp1 = '\0';
1459 		record_clock_stats(&(instance->peer->srcadr), cp);
1460 		*cp1 = '\r';
1461 		cp = cp1+2;
1462 	}
1463 
1464 	/* next, the Firmware Version and Revision numbers */
1465 
1466 	instance->version  = atoi(&instance->Cj[83]);
1467 	instance->revision = atoi(&instance->Cj[111]);
1468 
1469 	/* from model number decide which Oncore this is,
1470 		and then the number of channels */
1471 
1472 	for (cp=&instance->Cj[160]; *cp == ' '; cp++)	/* start right after 'Model #' */
1473 		;
1474 	cp1 = cp;
1475 	cp2 = Model;
1476 	for (; !isspace((int)*cp) && cp-cp1 < 20; cp++, cp2++)
1477 		*cp2 = *cp;
1478 	*cp2 = '\0';
1479 
1480 	cp = 0;
1481 	if (!strncmp(Model, "PVT6", (size_t) 4)) {
1482 		cp = "PVT6";
1483 		instance->model = ONCORE_PVT6;
1484 	} else if (Model[0] == 'A') {
1485 		cp = "Basic";
1486 		instance->model = ONCORE_BASIC;
1487 	} else if (Model[0] == 'B' || !strncmp(Model, "T8", (size_t) 2)) {
1488 		cp = "VP";
1489 		instance->model = ONCORE_VP;
1490 	} else if (!strncmp(Model, "P1", (size_t) 2)) {
1491 		cp = "M12";
1492 		instance->model = ONCORE_M12;
1493 	} else if (Model[0] == 'R') {
1494 		if (Model[5] == 'N') {
1495 			cp = "GT";
1496 			instance->model = ONCORE_GT;
1497 		} else if ((Model[1] == '3' || Model[1] == '4') && Model[5] == 'G') {
1498 			cp = "GT+";
1499 			instance->model = ONCORE_GTPLUS;
1500 		} else if ((Model[1] == '5' && Model[5] == 'U') || (Model[1] == '1' && Model[5] == 'A')) {
1501 				cp = "UT";
1502 				instance->model = ONCORE_UT;
1503 		} else if (Model[1] == '5' && Model[5] == 'G') {
1504 			cp = "UT+";
1505 			instance->model = ONCORE_UTPLUS;
1506 		} else if (Model[1] == '6' && Model[5] == 'G') {
1507 			cp = "SL";
1508 			instance->model = ONCORE_SL;
1509 		} else {
1510 			cp = "Unknown";
1511 			instance->model = ONCORE_UNKNOWN;
1512 		}
1513 	} else	{
1514 		cp = "Unknown";
1515 		instance->model = ONCORE_UNKNOWN;
1516 	}
1517 
1518 	sprintf(Msg, "This looks like an Oncore %s with version %d.%d firmware.", cp, instance->version, instance->revision);
1519 	record_clock_stats(&(instance->peer->srcadr), Msg);
1520 
1521 	if (instance->chan == 0) {	/* dont reset if set in input data */
1522 		instance->chan = 8;	/* default */
1523 		if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6)
1524 			instance->chan = 6;
1525 		else if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || instance->model == ONCORE_UTPLUS)
1526 			instance->chan = 8;
1527 		else if (instance->model == ONCORE_M12)
1528 			instance->chan = 12;
1529 	}
1530 
1531 	if (instance->traim == -1) {	/* dont reset if set in input data */
1532 		instance->traim = 0;	/* default */
1533 		if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6)
1534 			instance->traim = 0;
1535 		else if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || instance->model == ONCORE_UTPLUS)
1536 			instance->traim = 1;
1537 		else if (instance->model == ONCORE_M12)
1538 			instance->traim = 0;
1539 	}
1540 
1541 	sprintf(Msg, "Channels = %d, TRAIM = %s", instance->chan,
1542 		((instance->traim < 0) ? "UNKNOWN" : ((instance->traim > 0) ? "ON" : "OFF")));
1543 	record_clock_stats(&(instance->peer->srcadr), Msg);
1544 
1545 	/* The M12 with 1.3 Firmware, looses track of all Satellites and has to
1546 	 * start again if we go from 0D -> 3D, then looses them again when we
1547 	 * go from 3D -> 0D.  We do this to get a @@Ea message for SHMEM.
1548 	 * For NOW we have SHMEM turned off for the M12, v1.3
1549 	 */
1550 
1551 /*BAD M12*/ if (instance->model == ONCORE_M12 && instance->version == 1 && instance->revision <= 3) {
1552 		instance->shmem_fname = 0;
1553 		cp = "*** SHMEM turned off for ONCORE M12 ***";
1554 		record_clock_stats(&(instance->peer->srcadr), cp);
1555 	}
1556 
1557 	/*
1558 	 * we now know model number and have zeroed
1559 	 * instance->shmem_fname if SHMEM is not supported
1560 	 */
1561 
1562 	if (instance->shmem_fname);
1563 		oncore_init_shmem(instance);
1564 
1565 	if (instance->shmem)
1566 		cp = "SHMEM is available";
1567 	else
1568 		cp = "SHMEM is NOT available";
1569 	record_clock_stats(&(instance->peer->srcadr), cp);
1570 
1571 #ifdef HAVE_PPSAPI
1572 	if (instance->assert)
1573 		cp = "Timing on Assert.";
1574 	else
1575 		cp = "Timing on Clear.";
1576 	record_clock_stats(&(instance->peer->srcadr), cp);
1577 #endif
1578 
1579 	mode = instance->init_type;
1580 	if (mode == 3 || mode == 4) {	/* Cf will call Fa */
1581 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Cf, sizeof(oncore_cmd_Cf));
1582 		instance->o_state = ONCORE_RESET_SENT;
1583 		cp = "state = ONCORE_RESET_SENT";
1584 		record_clock_stats(&(instance->peer->srcadr), cp);
1585 	} else {
1586 		if (instance->chan == 6)
1587 			oncore_sendmsg(instance->ttyfd, oncore_cmd_Ca, sizeof(oncore_cmd_Ca));
1588 		else if (instance->chan == 8)
1589 			oncore_sendmsg(instance->ttyfd, oncore_cmd_Fa, sizeof(oncore_cmd_Fa));
1590 		else if (instance->chan == 12)
1591 			oncore_sendmsg(instance->ttyfd, oncore_cmd_Ia, sizeof(oncore_cmd_Ia));
1592 
1593 		instance->o_state = ONCORE_TEST_SENT;
1594 		cp = "state = ONCORE_TEST_SENT";
1595 		record_clock_stats(&(instance->peer->srcadr), cp);
1596 		instance->timeout = 4;
1597 	}
1598 }
1599 
1600 
1601 
1602 static void
1603 oncore_msg_Cj_init(
1604 	struct instance *instance,
1605 	u_char *buf,
1606 	size_t len
1607 	)
1608 {
1609 	char *cp, Cmd[20], Msg[160];
1610 	int	mode;
1611 
1612 	/* OK, know type of Oncore, have possibly reset, and have tested.
1613 	 * If we have or don't have TRAIM and position hold may still be unknown.
1614 	 * Now initialize.
1615 	 */
1616 
1617 	oncore_sendmsg(instance->ttyfd, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Set Posn Fix mode (not Idle (VP)) */
1618 	oncore_sendmsg(instance->ttyfd, oncore_cmd_Bb, sizeof(oncore_cmd_Bb)); /* turn on for shmem */
1619 	oncore_sendmsg(instance->ttyfd, oncore_cmd_Ek, sizeof(oncore_cmd_Ek)); /* turn off */
1620 	oncore_sendmsg(instance->ttyfd, oncore_cmd_Aw, sizeof(oncore_cmd_Aw)); /* UTC time */
1621 	oncore_sendmsg(instance->ttyfd, oncore_cmd_AB, sizeof(oncore_cmd_AB)); /* Appl type static */
1622 	oncore_sendmsg(instance->ttyfd, oncore_cmd_Be, sizeof(oncore_cmd_Be)); /* Tell us the Almanac for shmem */
1623 
1624 	/* Turn OFF position hold, it needs to be off to set position (for some units),
1625 	   will get set ON in @@Ea later */
1626 
1627 	if (instance->chan == 12)
1628 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0));
1629 	else {
1630 		oncore_sendmsg(instance->ttyfd, oncore_cmd_At0, sizeof(oncore_cmd_At0));
1631 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0));
1632 	}
1633 
1634 	mode = instance->init_type;
1635 	if (debug) {
1636 		printf("ONCORE[%d]: INIT mode = %d\n", instance->unit, mode);
1637 		printf("ONCORE[%d]: chan = %d\n", instance->unit, instance->chan);
1638 	}
1639 
1640 	/* If there is Position input in the Config file
1641 	 * and mode = (1,3) set it as posn hold posn, goto 0D mode.
1642 	 *  or mode = (2,4) set it as INITIAL position, and do Site Survey.
1643 	 */
1644 
1645 
1646 	if (instance->posn_set) {
1647 		switch (mode) { /* if we have a position, put it in as posn and posn-hold posn */
1648 		case 0:
1649 			break;
1650 		case 1:
1651 		case 2:
1652 		case 3:
1653 		case 4:
1654 			memcpy(Cmd, oncore_cmd_As, sizeof(oncore_cmd_As));	/* dont modify static variables */
1655 			w32_buf(&Cmd[2],  (int) instance->ss_lat);
1656 			w32_buf(&Cmd[6],  (int) instance->ss_long);
1657 			w32_buf(&Cmd[10], (int) instance->ss_ht);
1658 			Cmd[14] = 0;
1659 			oncore_sendmsg(instance->ttyfd, Cmd,  sizeof(oncore_cmd_As));
1660 
1661 			memcpy(Cmd, oncore_cmd_Au, sizeof(oncore_cmd_Au));
1662 			w32_buf(&Cmd[2], (int) instance->ss_ht);
1663 			Cmd[6] = 0;
1664 			oncore_sendmsg(instance->ttyfd, Cmd,  sizeof(oncore_cmd_Au));
1665 
1666 			if (instance->chan == 12) {
1667 				memcpy(Cmd, oncore_cmd_Ga, sizeof(oncore_cmd_Ga));
1668 				w32_buf(&Cmd[2], (int) instance->ss_lat);
1669 				w32_buf(&Cmd[6], (int) instance->ss_long);
1670 				w32_buf(&Cmd[10], (int) instance->ss_ht);
1671 				Cmd[14] = 0;
1672 				oncore_sendmsg(instance->ttyfd, Cmd,  sizeof(oncore_cmd_Ga));
1673 				oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd1,  sizeof(oncore_cmd_Gd1));
1674 			} else {
1675 				memcpy(Cmd, oncore_cmd_Ad, sizeof(oncore_cmd_Ad));
1676 				w32_buf(&Cmd[2], (int) instance->ss_lat);
1677 				oncore_sendmsg(instance->ttyfd, Cmd,  sizeof(oncore_cmd_Ad));
1678 
1679 				memcpy(Cmd, oncore_cmd_Ae, sizeof(oncore_cmd_Ae));
1680 				w32_buf(&Cmd[2], (int) instance->ss_long);
1681 				oncore_sendmsg(instance->ttyfd, Cmd,  sizeof(oncore_cmd_Ae));
1682 
1683 				memcpy(Cmd, oncore_cmd_Af, sizeof(oncore_cmd_Af));
1684 				w32_buf(&Cmd[2], (int) instance->ss_ht);
1685 				Cmd[6] = 0;
1686 				oncore_sendmsg(instance->ttyfd, Cmd,  sizeof(oncore_cmd_Af));
1687 				oncore_sendmsg(instance->ttyfd, oncore_cmd_At1,  sizeof(oncore_cmd_At1));
1688 			}
1689 			break;
1690 		}
1691 	}
1692 
1693 
1694 	switch (mode) {
1695 	case 0: /* NO initialization, don't change anything */
1696 		instance->site_survey = ONCORE_SS_DONE;
1697 		break;
1698 
1699 	case 1:
1700 	case 3: /* Use given Position */
1701 		instance->site_survey = ONCORE_SS_DONE;
1702 		break;
1703 
1704 	case 2:
1705 	case 4: /* Site Survey */
1706 		if (instance->chan == 12) {	/* no 12chan site survey command */
1707 			instance->site_survey = ONCORE_SS_SW;
1708 			sprintf(Msg, "Initiating software 3D site survey (%d samples)", POS_HOLD_AVERAGE);
1709 			record_clock_stats(&(instance->peer->srcadr), Msg);
1710 		} else {
1711 			instance->site_survey = ONCORE_SS_TESTING;
1712 			oncore_sendmsg(instance->ttyfd, oncore_cmd_At2,  sizeof(oncore_cmd_At2));
1713 		}
1714 		break;
1715 	}
1716 
1717 	if (mode != 0) {
1718 			/* cable delay in ns */
1719 		memcpy(Cmd, oncore_cmd_Az, sizeof(oncore_cmd_Az));
1720 		w32_buf(&Cmd[2], instance->delay);
1721 		oncore_sendmsg(instance->ttyfd, Cmd,  sizeof(oncore_cmd_Az));
1722 
1723 			/* PPS offset in ns */
1724 		if (instance->offset) {
1725 			if (instance->model == ONCORE_VP || instance->model == ONCORE_UT ||
1726 			   instance->model == ONCORE_UTPLUS) {
1727 				memcpy(Cmd, oncore_cmd_Ay, sizeof(oncore_cmd_Ay));
1728 				w32_buf(&Cmd[2], instance->offset);
1729 				oncore_sendmsg(instance->ttyfd, Cmd,  sizeof(oncore_cmd_Ay));
1730 			} else {
1731 				cp = "Can only set PPS OFFSET for VP/UT/UT+, offset ignored";
1732 				record_clock_stats(&(instance->peer->srcadr), cp);
1733 				instance->offset = 0;
1734 			}
1735 		}
1736 	}
1737 
1738 	/* 6, 8 12 chan - Position/Status/Data Output Message, 1/s */
1739 	/* now we're really running */
1740 
1741 	if (instance->chan == 6) { /* kill 8 chan commands, possibly testing VP in 6chan mode */
1742 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Ba,	sizeof(oncore_cmd_Ba));
1743 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea0, sizeof(oncore_cmd_Ea0));
1744 		oncore_sendmsg(instance->ttyfd, oncore_cmd_En0, sizeof(oncore_cmd_En0));
1745 	} else if (instance->chan == 8) {  /* kill 6chan commands */
1746 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea,	sizeof(oncore_cmd_Ea));
1747 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Ba0, sizeof(oncore_cmd_Ba0));
1748 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Bn0, sizeof(oncore_cmd_Bn0));
1749 	} else if (instance->chan == 12)
1750 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Ha, sizeof(oncore_cmd_Ha));
1751 
1752 	instance->count = 1;
1753 	instance->o_state = ONCORE_ALMANAC;
1754 	cp = "state = ONCORE_ALMANAC";
1755 	record_clock_stats(&(instance->peer->srcadr), cp);
1756 }
1757 
1758 
1759 
1760 /*
1761  * Set to Factory Defaults (Reasonable for UT w/ no Battery Backup
1762  *	not so for VP (eeprom) or any unit with a battery
1763  */
1764 
1765 static void
1766 oncore_msg_Cf(
1767 	struct instance *instance,
1768 	u_char *buf,
1769 	size_t len
1770 	)
1771 {
1772 	const char *cp;
1773 
1774 	if (instance->o_state == ONCORE_RESET_SENT) {
1775 		if (instance->chan == 6)
1776 			oncore_sendmsg(instance->ttyfd, oncore_cmd_Ca, sizeof(oncore_cmd_Ca));
1777 		else if (instance->chan == 8)
1778 			oncore_sendmsg(instance->ttyfd, oncore_cmd_Fa, sizeof(oncore_cmd_Fa));
1779 		else if (instance->chan == 12)
1780 			oncore_sendmsg(instance->ttyfd, oncore_cmd_Ia, sizeof(oncore_cmd_Ia));
1781 
1782 		instance->o_state = ONCORE_TEST_SENT;
1783 		cp = "state = ONCORE_TEST_SENT";
1784 		record_clock_stats(&(instance->peer->srcadr), cp);
1785 	}
1786 }
1787 
1788 
1789 
1790 /* Here for @@Ca, @@Fa and @@Ia messages */
1791 
1792 /* There are good reasons NOT to do a @@Ca or @@Fa command with the ONCORE.
1793  * Doing it, it was found that under some circumstances the following
1794  * command would fail if issued immediately after the return from the
1795  * @@Fa, but a 2sec delay seemed to fix things.  Since simply calling
1796  * sleep(2) is wastefull, and may cause trouble for some OS's, repeating
1797  * itimer, we set a flag, and test it at the next POLL.  If it hasnt
1798  * been cleared, we reissue the @@Cj that is issued below.
1799  * Note that we do a @@Cj at the beginning, and again here.
1800  * The first is to get the info, the 2nd is just used as a safe command
1801  * after the @@Fa for all Oncores (and it was in this posn in the
1802  * original code).
1803  */
1804 
1805 static void
1806 oncore_msg_CaFaIa(
1807 	struct instance *instance,
1808 	u_char *buf,
1809 	size_t len
1810 	)
1811 {
1812 	char *cp;
1813 
1814 	if (instance->o_state == ONCORE_TEST_SENT) {
1815 		int	antenna;
1816 
1817 		instance->timeout = 0;
1818 
1819 		if (debug > 2) {
1820 			if (buf[2] == 'I')
1821 				printf("ONCORE[%d]: >>@@%ca %x %x %x\n", instance->unit, buf[2], buf[4], buf[5], buf[6]);
1822 			else
1823 				printf("ONCORE[%d]: >>@@%ca %x %x\n", instance->unit, buf[2], buf[4], buf[5]);
1824 		}
1825 
1826 		antenna = buf[4] & 0xc0;
1827 		antenna >>= 6;
1828 		buf[4] &= ~0xc0;
1829 
1830 		if (buf[4] || buf[5] || ((buf[2] == 'I') && buf[6])) {
1831 			cp = "ONCORE: Self Test Failed, shutting down driver";
1832 			record_clock_stats(&(instance->peer->srcadr), cp);
1833 			oncore_shutdown(instance->unit, instance->peer);
1834 			return;
1835 		}
1836 		if (antenna) {
1837 			char *cp1, Msg[160];
1838 
1839 			cp1 = (antenna == 0x1) ? "(Over Current)" :
1840 				((antenna == 0x2) ? "(Under Current)" : "(No Voltage)");
1841 
1842 			cp = "ONCORE: Self Test, NonFatal Antenna Problems ";
1843 			strcpy(Msg, cp);
1844 			strcat(Msg, cp1);
1845 			record_clock_stats(&(instance->peer->srcadr), Msg);
1846 		}
1847 
1848 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
1849 		instance->o_state = ONCORE_INIT;
1850 		cp = "state = ONCORE_INIT";
1851 		record_clock_stats(&(instance->peer->srcadr), cp);
1852 	}
1853 }
1854 
1855 
1856 
1857 /* Ba, Ea and Ha come here */
1858 
1859 static void
1860 oncore_msg_BaEaHa(
1861 	struct instance *instance,
1862 	u_char *buf,
1863 	size_t len
1864 	)
1865 {
1866 	const char	*cp;
1867 	char		Msg[160], Cmd[20];
1868 	u_char		*vp;	/* pointer to start of shared mem for Ba/Ea/Ha */
1869 	size_t		Len;
1870 
1871 	/* At the beginning of Ea here there are various 'timers'.
1872 	 * We enter Ea 1/sec, and since the upper levels of NTP have usurped
1873 	 * the use of timers, we use the 1/sec entry to Ea to do things that
1874 	 * we would normally do with timers...
1875 	 */
1876 
1877 	if (instance->count) {
1878 		if (instance->count++ < 5)	/* make sure results are stable, using position */
1879 			return;
1880 		instance->count = 0;
1881 	}
1882 
1883 	if (instance->o_state != ONCORE_ALMANAC && instance->o_state != ONCORE_RUN)
1884 		return;
1885 
1886 	Len = len+3;		/* message length @@ -> CR,LF */
1887 	memcpy(instance->Ea, buf, Len); 	/* Ba, Ea or Ha */
1888 
1889 	if (buf[2] == 'B') {			/* 6chan */
1890 		if (instance->Ea[64]&0x8)
1891 			instance->mode = MODE_0D;
1892 		else if (instance->Ea[64]&0x10)
1893 			instance->mode = MODE_2D;
1894 		else if (instance->Ea[64]&0x20)
1895 			instance->mode = MODE_3D;
1896 	} else if (buf[2] == 'E') {		/* 8chan */
1897 		if (instance->Ea[72]&0x8)
1898 			instance->mode = MODE_0D;
1899 		else if (instance->Ea[72]&0x10)
1900 			instance->mode = MODE_2D;
1901 		else if (instance->Ea[72]&0x20)
1902 			instance->mode = MODE_3D;
1903 	} else if (buf[2] == 'H') {		/* 12chan */
1904 		int bits;
1905 
1906 		bits = (instance->Ea[129]>>5) & 0x7;	    /* actually Ha */
1907 		if (bits == 0x4)
1908 			instance->mode = MODE_0D;
1909 		else if (bits == 0x6)
1910 			instance->mode = MODE_2D;
1911 		else if (bits == 0x7)
1912 			instance->mode = MODE_3D;
1913 	}
1914 
1915 	vp = (u_char) 0;	/* just to keep compiler happy */
1916 	if (instance->chan == 6) {
1917 		instance->rsm.bad_almanac = instance->Ea[64]&0x1;
1918 		instance->rsm.bad_fix	  = instance->Ea[64]&0x52;
1919 		vp = &instance->shmem[instance->shmem_Ba];
1920 	} else if (instance->chan == 8) {
1921 		instance->rsm.bad_almanac = instance->Ea[72]&0x1;
1922 		instance->rsm.bad_fix	  = instance->Ea[72]&0x52;
1923 		vp = &instance->shmem[instance->shmem_Ea];
1924 	} else if (instance->chan == 12) {
1925 		int bits1, bits2;
1926 
1927 		bits1 = (instance->Ea[129]>>5) & 0x7;	     /* actually Ha */
1928 		bits2 = instance->Ea[130];
1929 		instance->rsm.bad_almanac = (bits2 & 0x80);
1930 		instance->rsm.bad_fix	  = (bits2 & 0x8) || (bits1 == 0x2);
1931 					  /* too few sat     Bad Geom	  */
1932 		vp = &instance->shmem[instance->shmem_Ha];
1933 #if 0
1934 fprintf(stderr, "ONCORE: DEBUG BITS: (%x %x), (%x %x),  %x %x %x %x %x\n",
1935 		instance->Ea[129], instance->Ea[130], bits1, bits2, instance->mode == MODE_0D, instance->mode == MODE_2D,
1936 		instance->mode == MODE_3D, instance->rsm.bad_almanac, instance->rsm.bad_fix);
1937 #endif
1938 	}
1939 
1940 	/* Here calculate dH = GPS - MSL for output message */
1941 	/* also set Altitude Hold mode if GT */
1942 
1943 	if (!instance->have_dH) {
1944 		int	GPS, MSL;
1945 
1946 		instance->have_dH++;
1947 		if (instance->chan == 12) {
1948 			GPS = buf_w32(&instance->Ea[39]);
1949 			MSL = buf_w32(&instance->Ea[43]);
1950 		} else {
1951 			GPS = buf_w32(&instance->Ea[23]);
1952 			MSL = buf_w32(&instance->Ea[27]);
1953 		}
1954 		instance->dH = GPS - MSL;
1955 		instance->dH /= 100.;
1956 
1957 		if (MSL) {	/* not set ! */
1958 			sprintf(Msg, "dH = (GPS - MSL) = %.2fm", instance->dH);
1959 			record_clock_stats(&(instance->peer->srcadr), Msg);
1960 		}
1961 
1962 		/* stuck in here as it only gets done once */
1963 
1964 		if (instance->chan != 12 && !instance->saw_At) {
1965 			cp = "Not Good, no @@At command, must be a GT/GT+";
1966 			record_clock_stats(&(instance->peer->srcadr), cp);
1967 			oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1));
1968 		}
1969 	}
1970 
1971 	/*
1972 	 * For instance->site_survey to be ONCORE_SS_TESTING, this must be the first
1973 	 * time thru @@Ea.  There are two choices
1974 	 *   (a) We did not get a response to the @@At0 or @@At2 commands,
1975 	 *	   must be a GT/GT+/SL with no position hold mode.
1976 	 *   (b) Saw the @@At0, @@At2 commands, but @@At2 failed,
1977 	 *	   must be a VP or older UT which doesnt have Site Survey mode.
1978 	 *	   We will have to do it ourselves.
1979 	 */
1980 
1981 	if (instance->site_survey == ONCORE_SS_TESTING) {	/* first time thru Ea */
1982 		sprintf(Msg, "Initiating software 3D site survey (%d samples)",
1983 				POS_HOLD_AVERAGE);
1984 		record_clock_stats(&(instance->peer->srcadr), Msg);
1985 		instance->site_survey = ONCORE_SS_SW;
1986 
1987 		instance->ss_lat = instance->ss_long = instance->ss_ht = 0;
1988 		oncore_sendmsg(instance->ttyfd, oncore_cmd_At0, sizeof(oncore_cmd_At0)); /* disable */
1989 	}
1990 
1991 	if (instance->shmem) {
1992 		int	i;
1993 
1994 		i = 0;
1995 		if (instance->mode == MODE_0D)	       /* 0D, Position Hold */
1996 			i = 1;
1997 		else if (instance->mode == MODE_2D)    /* 2D, Altitude Hold */
1998 			i = 2;
1999 		else if (instance->mode == MODE_3D)    /* 3D fix */
2000 			i = 3;
2001 		if (i) {
2002 			i *= (Len+3);
2003 			vp[i + 2]++;
2004 			memcpy(&vp[i+3], buf, Len);
2005 		}
2006 	}
2007 
2008 	/* Almanac mode, waiting for Almanac, cant do anything till we have it */
2009 	/* When we have an almanac, start the En/Bn messages */
2010 
2011 	if (instance->o_state == ONCORE_ALMANAC) {
2012 		if (instance->rsm.bad_almanac) {
2013 			if (debug)
2014 				printf("ONCORE: waiting for almanac\n");
2015 			return;
2016 		} else {  /* Here we have almanac.
2017 			     Start TRAIM (@@En/@@Bn) dependant on TRAIM flag.
2018 			     If flag == -1, then we dont know if this unit supports
2019 			     traim, and we issue the command and then wait up to
2020 			     5sec to see if we get a reply */
2021 
2022 			if (instance->traim != 0) {	/* either yes or unknown */
2023 				if (instance->chan == 6)
2024 					oncore_sendmsg(instance->ttyfd, oncore_cmd_Bn, sizeof(oncore_cmd_Bn));
2025 				else if (instance->chan == 8)
2026 					oncore_sendmsg(instance->ttyfd, oncore_cmd_En, sizeof(oncore_cmd_En));
2027 
2028 				if (instance->traim == -1)
2029 					instance->traim_delay = 1;
2030 			}
2031 			instance->o_state = ONCORE_RUN;
2032 			cp = "state = ONCORE_RUN";
2033 			record_clock_stats(&(instance->peer->srcadr), cp);
2034 		}
2035 	}
2036 
2037 	/*
2038 	 * check if timer active
2039 	 * if it hasnt been cleared, then @@En/@@Bn did not respond
2040 	 */
2041 
2042 	if (instance->traim_delay) {
2043 		if (instance->traim_delay++ > 5) {
2044 			instance->traim = 0;
2045 			instance->traim_delay = 0;
2046 			cp = "ONCORE: Did not detect TRAIM response, TRAIM = OFF";
2047 			record_clock_stats(&(instance->peer->srcadr), cp);
2048 		}
2049 	}
2050 
2051 	/*
2052 	 * must be ONCORE_RUN if we are here.
2053 	 */
2054 
2055 	instance->pp->year = buf[6]*256+buf[7];
2056 	instance->pp->day = ymd2yd(buf[6]*256+buf[7], buf[4], buf[5]);
2057 	instance->pp->hour = buf[8];
2058 	instance->pp->minute = buf[9];
2059 	instance->pp->second = buf[10];
2060 
2061 	/*
2062 	 * Check to see if Hardware SiteSurvey has Finished.
2063 	 */
2064 
2065 	if ((instance->site_survey == ONCORE_SS_HW) && !(instance->Ea[37] & 0x20)) {
2066 		record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode");
2067 		instance->site_survey = ONCORE_SS_DONE;
2068 	}
2069 
2070 	if (!instance->printed && instance->site_survey == ONCORE_SS_DONE) {
2071 		instance->printed = 1;
2072 			/* Read back Position Hold Params (cant for GT) */
2073 		if (instance->saw_At)
2074 			oncore_sendmsg(instance->ttyfd, oncore_cmd_Asx,  sizeof(oncore_cmd_Asx));
2075 		else
2076 			oncore_print_As(instance);
2077 
2078 			/* Read back PPS Offset for Output */
2079 			/* Nb. This will fail silently for early UT (no plus) and M12 models */
2080 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Ayx,  sizeof(oncore_cmd_Ayx));
2081 
2082 			/* Read back Cable Delay for Output */
2083 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Azx,  sizeof(oncore_cmd_Azx));
2084 	}
2085 
2086 	/*
2087 	 * Check the leap second status once per day.
2088 	 */
2089 
2090 	if (instance->Bj_day != buf[5]) {     /* do this 1/day */
2091 		instance->Bj_day = buf[5];
2092 
2093 		if (instance->chan == 12)
2094 			oncore_sendmsg(instance->ttyfd, oncore_cmd_Gj, sizeof(oncore_cmd_Gj));
2095 		else {
2096 			/*
2097 			 * The following additional check, checking for June/December, is a
2098 			 * workaround for incorrect ONCORE firmware.  The oncore starts
2099 			 * reporting the leap second when the GPS satellite data message
2100 			 * (page 18, subframe 4) is updated to a date in the future, which
2101 			 * can be several months before the leap second.  WWV and other
2102 			 * services seem to wait until the month of the event to turn
2103 			 * on their indicators (which is usually a single bit).
2104 			 */
2105 
2106 			if ((buf[4] == 6) || (buf[4] == 12))
2107 				oncore_sendmsg(instance->ttyfd, oncore_cmd_Bj, sizeof(oncore_cmd_Bj));
2108 		}
2109 	}
2110 
2111 	/*
2112 	 * if SHMEM active, every 15s, steal one 'tick' to get 2D or 3D posn.
2113 	 */
2114 
2115 	if (instance->shmem && instance->shmem_Posn && (instance->site_survey == ONCORE_SS_DONE)) {	/* dont screw up the SS by changing mode */
2116 		if (instance->pp->second%15 == 3) {	/* start the sequence */
2117 			instance->shmem_reset = 1;
2118 			if (instance->chan == 12) {
2119 				if (instance->shmem_Posn == 2)
2120 					oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd2,  sizeof(oncore_cmd_Gd2));  /* 2D */
2121 				else
2122 					oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd0,  sizeof(oncore_cmd_Gd0));  /* 3D */
2123 			} else {
2124 				if (instance->saw_At) {
2125 					oncore_sendmsg(instance->ttyfd, oncore_cmd_At0, sizeof(oncore_cmd_At0)); /* out of 0D to 3D mode */
2126 					if (instance->shmem_Posn == 2)
2127 						oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1));   /* 3D to 2D mode */
2128 				} else
2129 					oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0));
2130 			}
2131 		} else if (instance->shmem_reset || (instance->mode != MODE_0D)) {
2132 			instance->shmem_reset = 0;
2133 			if (instance->chan == 12)
2134 				oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd1,  sizeof(oncore_cmd_Gd1));	/* 0D */
2135 			else {
2136 				if (instance->saw_At) {
2137 					if (instance->mode == MODE_2D)
2138 						oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); /* 2D -> 3D or 0D */
2139 					oncore_sendmsg(instance->ttyfd, oncore_cmd_At1,  sizeof(oncore_cmd_At1));	 /* to 0D mode */
2140 				} else
2141 					oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1,  sizeof(oncore_cmd_Av1));
2142 			}
2143 		}
2144 	}
2145 
2146 	if (instance->traim == 0)	/* NO traim, go get tick */
2147 		oncore_get_timestamp(instance, instance->offset, instance->offset);
2148 
2149 	if (instance->site_survey != ONCORE_SS_SW)
2150 		return;
2151 
2152 	/*
2153 	 * We have to average our own position for the Position Hold Mode
2154 	 *   We use Heights from the GPS ellipsoid.
2155 	 */
2156 
2157 	if (instance->rsm.bad_fix)	/* Not if poor geometry or less than 3 sats */
2158 		return;
2159 
2160 	if (instance->mode != MODE_3D)	/* Only 3D Fix */
2161 		return;
2162 
2163 	instance->ss_lat  += buf_w32(&instance->Ea[15]);
2164 	instance->ss_long += buf_w32(&instance->Ea[19]);
2165 	instance->ss_ht   += buf_w32(&instance->Ea[23]);  /* GPS ellipsoid */
2166 	instance->ss_count++;
2167 
2168 	if (instance->ss_count != POS_HOLD_AVERAGE)
2169 		return;
2170 
2171 	instance->ss_lat  /= POS_HOLD_AVERAGE;
2172 	instance->ss_long /= POS_HOLD_AVERAGE;
2173 	instance->ss_ht   /= POS_HOLD_AVERAGE;
2174 
2175 	sprintf(Msg, "Surveyed posn:  lat %.3f long %.3f ht %.3f",
2176 			instance->ss_lat, instance->ss_long, instance->ss_ht);
2177 	record_clock_stats(&(instance->peer->srcadr), Msg);
2178 
2179 	/* set newly determined position as 3D Position hold position */
2180 
2181 	memcpy(Cmd, oncore_cmd_As, sizeof(oncore_cmd_As));
2182 	w32_buf(&Cmd[2],  (int) instance->ss_lat);
2183 	w32_buf(&Cmd[6],  (int) instance->ss_long);
2184 	w32_buf(&Cmd[10], (int) instance->ss_ht);
2185 	Cmd[14] = 0;
2186 	oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_As));
2187 
2188 	/* set height seperately for 2D */
2189 
2190 	memcpy(Cmd, oncore_cmd_Au, sizeof(oncore_cmd_Au));
2191 	w32_buf(&Cmd[2], (int) instance->ss_ht);
2192 	Cmd[6] = 0;
2193 	oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Au));
2194 
2195 	/* and set Position Hold */
2196 
2197 	if (instance->chan == 12)
2198 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd1, sizeof(oncore_cmd_Gd1));
2199 	else {
2200 		if (instance->saw_At)
2201 			oncore_sendmsg(instance->ttyfd, oncore_cmd_At1, sizeof(oncore_cmd_At1));
2202 		else
2203 			oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1));
2204 	}
2205 
2206 	record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode");
2207 	instance->site_survey = ONCORE_SS_DONE;
2208 }
2209 
2210 
2211 
2212 static void
2213 oncore_msg_BnEn(
2214 	struct instance *instance,
2215 	u_char *buf,
2216 	size_t len
2217 	)
2218 {
2219 	long	dt1, dt2;
2220 	char	*cp;
2221 
2222 	if (instance->o_state != ONCORE_RUN)
2223 		return;
2224 
2225 	if (instance->traim_delay) {	 /* flag that @@En/@@Bn returned */
2226 			instance->traim = 1;
2227 			instance->traim_delay = 0;
2228 			cp = "ONCORE: Detected TRAIM, TRAIM = ON";
2229 			record_clock_stats(&(instance->peer->srcadr), cp);
2230 	}
2231 
2232 	memcpy(instance->En, buf, len); 	/* En or Bn */
2233 
2234 	/* If Time RAIM doesn't like it, don't trust it */
2235 
2236 	if (instance->En[21])
2237 		return;
2238 
2239 	dt1 = instance->saw_tooth + instance->offset;	 /* dt this time step */
2240 	instance->saw_tooth = (s_char) instance->En[25]; /* update for next time */
2241 	dt2 = instance->saw_tooth + instance->offset;	 /* dt next time step */
2242 
2243 	oncore_get_timestamp(instance, dt1, dt2);
2244 }
2245 
2246 
2247 
2248 static void
2249 oncore_get_timestamp(
2250 	struct instance *instance,
2251 	long dt1,	/* tick offset THIS time step */
2252 	long dt2	/* tick offset NEXT time step */
2253 	)
2254 {
2255 	int     Rsm;
2256 	u_long  i, j;
2257 	l_fp ts, ts_tmp;
2258 	double dmy;
2259 #ifdef HAVE_STRUCT_TIMESPEC
2260 	struct timespec *tsp = 0;
2261 #else
2262 	struct timeval	*tsp = 0;
2263 #endif
2264 #ifdef HAVE_PPSAPI
2265 	int	current_mode;
2266 	pps_params_t current_params;
2267 	struct timespec timeout;
2268 	pps_info_t pps_i;
2269 #else  /* ! HAVE_PPSAPI */
2270 #ifdef HAVE_CIOGETEV
2271 	struct ppsclockev ev;
2272 	int r = CIOGETEV;
2273 #endif
2274 #ifdef HAVE_TIOCGPPSEV
2275 	struct ppsclockev ev;
2276 	int r = TIOCGPPSEV;
2277 #endif
2278 #if	TIOCDCDTIMESTAMP
2279 	struct timeval	tv;
2280 #endif
2281 #endif	/* ! HAVE_PPS_API */
2282 
2283 	if ((instance->site_survey == ONCORE_SS_DONE) && (instance->mode != MODE_0D))
2284 		return;
2285 
2286 	/* Don't do anything without an almanac to define the GPS->UTC delta */
2287 
2288 	if (instance->rsm.bad_almanac)
2289 		return;
2290 
2291 #ifdef HAVE_PPSAPI
2292 	j = instance->ev_serial;
2293 	timeout.tv_sec = 0;
2294 	timeout.tv_nsec = 0;
2295 	if (time_pps_fetch(instance->pps_h, PPS_TSFMT_TSPEC, &pps_i,
2296 	    &timeout) < 0) {
2297 		printf("ONCORE: time_pps_fetch failed\n");
2298 		return;
2299 	}
2300 
2301 	if (instance->assert) {
2302 		tsp = &pps_i.assert_timestamp;
2303 
2304 		if (debug > 2) {
2305 			i = (u_long) pps_i.assert_sequence;
2306 #ifdef HAVE_STRUCT_TIMESPEC
2307 			printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%09ld\n",
2308 			    instance->unit, i, j,
2309 			    (long)tsp->tv_sec, (long)tsp->tv_nsec);
2310 #else
2311 			printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%06ld\n",
2312 			    instance->unit, i, j,
2313 			    (long)tsp->tv_sec, (long)tsp->tv_usec);
2314 #endif
2315 		}
2316 
2317 		if (pps_i.assert_sequence == j) {
2318 			printf("ONCORE: oncore_get_timestamp, error serial pps\n");
2319 			return;
2320 		}
2321 		instance->ev_serial = pps_i.assert_sequence;
2322 	} else {
2323 		tsp = &pps_i.clear_timestamp;
2324 
2325 		if (debug > 2) {
2326 			i = (u_long) pps_i.clear_sequence;
2327 #ifdef HAVE_STRUCT_TIMESPEC
2328 			printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%09ld\n",
2329 			    instance->unit, i, j, (long)tsp->tv_sec, (long)tsp->tv_nsec);
2330 #else
2331 			printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%06ld\n",
2332 			    instance->unit, i, j, (long)tsp->tv_sec, (long)tsp->tv_usec);
2333 #endif
2334 		}
2335 
2336 		if (pps_i.clear_sequence == j) {
2337 			printf("ONCORE: oncore_get_timestamp, error serial pps\n");
2338 			return;
2339 		}
2340 		instance->ev_serial = pps_i.clear_sequence;
2341 	}
2342 
2343 	/* convert timespec -> ntp l_fp */
2344 
2345 	dmy = tsp->tv_nsec;
2346 	dmy /= 1e9;
2347 	ts.l_uf =  dmy * 4294967296.0;
2348 	ts.l_ui = tsp->tv_sec;
2349 #if 0
2350      alternate code for previous 4 lines is
2351 	dmy = 1.0e-9*tsp->tv_nsec;	/* fractional part */
2352 	DTOLFP(dmy, &ts);
2353 	dmy = tsp->tv_sec;		/* integer part */
2354 	DTOLFP(dmy, &ts_tmp);
2355 	L_ADD(&ts, &ts_tmp);
2356      or more simply
2357 	dmy = 1.0e-9*tsp->tv_nsec;	/* fractional part */
2358 	DTOLFP(dmy, &ts);
2359 	ts.l_ui = tsp->tv_sec;
2360 #endif	/* 0 */
2361 #else
2362 # if defined(HAVE_TIOCGPPSEV) || defined(HAVE_CIOGETEV)
2363 	j = instance->ev_serial;
2364 	if (ioctl(instance->ppsfd, r, (caddr_t) &ev) < 0) {
2365 		perror("ONCORE: IOCTL:");
2366 		return;
2367 	}
2368 
2369 	tsp = &ev.tv;
2370 
2371 	if (debug > 2)
2372 #ifdef HAVE_STRUCT_TIMESPEC
2373 		printf("ONCORE: serial/j (%d, %d) %ld.%09ld\n",
2374 			ev.serial, j, tsp->tv_sec, tsp->tv_nsec);
2375 #else
2376 		printf("ONCORE: serial/j (%d, %d) %ld.%06ld\n",
2377 			ev.serial, j, tsp->tv_sec, tsp->tv_usec);
2378 #endif
2379 
2380 	if (ev.serial == j) {
2381 		printf("ONCORE: oncore_get_timestamp, error serial pps\n");
2382 		return;
2383 	}
2384 	instance->ev_serial = ev.serial;
2385 
2386 	/* convert timeval -> ntp l_fp */
2387 
2388 	TVTOTS(tsp, &ts);
2389 # else
2390 #  if defined(TIOCDCDTIMESTAMP)
2391 	if(ioctl(instance->ppsfd, TIOCDCDTIMESTAMP, &tv) < 0) {
2392 		perror("ONCORE: ioctl(TIOCDCDTIMESTAMP)");
2393 		return;
2394 	}
2395 	tsp = &tv;
2396 	TVTOTS(tsp, &ts);
2397 #  else
2398 #error "Cannot compile -- no PPS mechanism configured!"
2399 #  endif
2400 # endif
2401 #endif
2402 	/* now have timestamp in ts */
2403 	/* add in saw_tooth and offset, these will be ZERO if no TRAIM */
2404 
2405 	/* saw_tooth not really necessary if using TIMEVAL */
2406 	/* since its only precise to us, but do it anyway. */
2407 
2408 	/* offset in ns, and is positive (late), we subtract */
2409 	/* to put the PPS time transition back where it belongs */
2410 
2411 #ifdef HAVE_PPSAPI
2412 	/* must hand the offset for the NEXT sec off to the Kernel to do */
2413 	/* the addition, so that the Kernel PLL sees the offset too */
2414 
2415 	if (instance->assert)
2416 		instance->pps_p.assert_offset.tv_nsec = -dt2;
2417 	else
2418 		instance->pps_p.clear_offset.tv_nsec  = -dt2;
2419 
2420 	/* The following code is necessary, and not just a time_pps_setparams,
2421 	 * using the saved instance->pps_p, since some other process on the
2422 	 * machine may have diddled with the mode bits (say adding something
2423 	 * that it needs).  We take what is there and ADD what we need.
2424 	 * [[ The results from the time_pps_getcap is unlikely to change so
2425 	 *    we could probably just save it, but I choose to do the call ]]
2426 	 * Unfortunately, there is only ONE set of mode bits in the kernel per
2427 	 * interface, and not one set for each open handle.
2428 	 *
2429 	 * There is still a race condition here where we might mess up someone
2430 	 * elses mode, but if he is being careful too, he should survive.
2431 	 */
2432 
2433 	if (time_pps_getcap(instance->pps_h, &current_mode) < 0) {
2434 		msyslog(LOG_ERR,
2435 		    "refclock_ioctl: time_pps_getcap failed: %m");
2436 		return;
2437 	}
2438 
2439 	if (time_pps_getparams(instance->pps_h, &current_params) < 0) {
2440 		msyslog(LOG_ERR,
2441 		    "refclock_ioctl: time_pps_getparams failed: %m");
2442 		return;
2443 	}
2444 
2445 		/* or current and mine */
2446 	current_params.mode |= instance->pps_p.mode;
2447 		/* but only set whats legal */
2448 	current_params.mode &= current_mode;
2449 
2450 	current_params.assert_offset.tv_sec = 0;
2451 	current_params.assert_offset.tv_nsec = -dt2;
2452 	current_params.clear_offset.tv_sec = 0;
2453 	current_params.clear_offset.tv_nsec = -dt2;
2454 
2455 	if (time_pps_setparams(instance->pps_h, &current_params))
2456 		perror("time_pps_setparams");
2457 #else
2458 	/* if not PPSAPI, no way to inform kernel of OFFSET, just add the */
2459 	/* offset for THIS second */
2460 
2461 	dmy = -1.0e-9*dt1;
2462 	DTOLFP(dmy, &ts_tmp);
2463 	L_ADD(&ts, &ts_tmp);
2464 #endif
2465 	/* have time from UNIX origin, convert to NTP origin. */
2466 
2467 	ts.l_ui += JAN_1970;
2468 	instance->pp->lastrec = ts;
2469 	instance->pp->msec = 0;
2470 
2471 	ts_tmp = ts;
2472 	ts_tmp.l_ui = 0;	/* zero integer part */
2473 	LFPTOD(&ts_tmp, dmy);	/* convert fractional part to a double */
2474 	j = 1.0e9*dmy;		/* then to integer ns */
2475 
2476 	Rsm = 0;
2477 	if (instance->chan == 6)
2478 		Rsm = instance->Ea[64];
2479 	else if (instance->chan == 8)
2480 		Rsm = instance->Ea[72];
2481 	else if (instance->chan == 12)
2482 		Rsm = ((instance->Ea[129]<<8) | instance->Ea[130]);
2483 
2484 	if (instance->chan == 6 || instance->chan == 8) {
2485 		sprintf(instance->pp->a_lastcode,	/* MAX length 128, currently at 117 */
2486 		    "%u.%09lu %d %d %2d %2d %2d %2ld rstat   %02x dop %4.1f nsat %2d,%d traim %d sigma %d neg-sawtooth %3d sat %d%d%d%d%d%d%d%d",
2487 		    ts.l_ui, j,
2488 		    instance->pp->year, instance->pp->day,
2489 		    instance->pp->hour, instance->pp->minute, instance->pp->second,
2490 		    (long) tsp->tv_sec % 60,
2491 		    Rsm, 0.1*(256*instance->Ea[35]+instance->Ea[36]),
2492 		    /*rsat	dop */
2493 		    instance->Ea[38], instance->Ea[39], instance->En[21],
2494 		    /*	nsat visible,	  nsat tracked,     traim */
2495 		    instance->En[23]*256+instance->En[24], (s_char) instance->En[25],
2496 		    /* sigma				   neg-sawtooth */
2497 	  /*sat*/   instance->Ea[41], instance->Ea[45], instance->Ea[49], instance->Ea[53],
2498 		    instance->Ea[57], instance->Ea[61], instance->Ea[65], instance->Ea[69]
2499 		    );					/* will be 0 for 6 chan */
2500 	} else if (instance->chan == 12) {
2501 		sprintf(instance->pp->a_lastcode,
2502 		    "%u.%09lu %d %d %2d %2d %2d %2ld rstat %02x dop %4.1f nsat %2d,%d sat %d%d%d%d%d%d%d%d%d%d%d%d",
2503 		    ts.l_ui, j,
2504 		    instance->pp->year, instance->pp->day,
2505 		    instance->pp->hour, instance->pp->minute, instance->pp->second,
2506 		    (long) tsp->tv_sec % 60,
2507 		    Rsm, 0.1*(256*instance->Ea[53]+instance->Ea[54]),
2508 		    /*rsat	dop */
2509 		    instance->Ea[55], instance->Ea[56],
2510 		    /*	nsat visible,	  nsat tracked	*/
2511 	  /*sat*/   instance->Ea[58], instance->Ea[64], instance->Ea[70], instance->Ea[76],
2512 		    instance->Ea[82], instance->Ea[88], instance->Ea[94], instance->Ea[100],
2513 		    instance->Ea[106], instance->Ea[112], instance->Ea[118], instance->Ea[124]
2514 		    );
2515 	}
2516 
2517 	if (debug > 2) {
2518 		int n;
2519 		n = strlen(instance->pp->a_lastcode);
2520 		printf("ONCORE[%d]: len = %d %s\n", instance->unit, n, instance->pp->a_lastcode);
2521 	}
2522 
2523 	if (!refclock_process(instance->pp)) {
2524 		refclock_report(instance->peer, CEVNT_BADTIME);
2525 		return;
2526 	}
2527 
2528 	record_clock_stats(&(instance->peer->srcadr), instance->pp->a_lastcode);
2529 	instance->pollcnt = 2;
2530 
2531 	if (instance->polled) {
2532 		instance->polled = 0;
2533 /*
2534 		instance->pp->dispersion = instance->pp->skew = 0;
2535 */
2536 		refclock_receive(instance->peer);
2537 	}
2538 }
2539 
2540 
2541 
2542 /*
2543  * Try to use Oncore UT+ Auto Survey Feature
2544  *	If its not there (VP), set flag to do it ourselves.
2545  */
2546 
2547 static void
2548 oncore_msg_At(
2549 	struct instance *instance,
2550 	u_char *buf,
2551 	size_t len
2552 	)
2553 {
2554 	instance->saw_At = 1;
2555 	if (instance->site_survey == ONCORE_SS_TESTING) {
2556 		if (buf[4] == 2) {
2557 			record_clock_stats(&(instance->peer->srcadr),
2558 					"Initiating hardware 3D site survey");
2559 			instance->site_survey = ONCORE_SS_HW;
2560 		}
2561 	}
2562 }
2563 
2564 
2565 
2566 /* get leap-second warning message */
2567 
2568 /*
2569  * @@Bj does NOT behave as documented in current Oncore firmware.
2570  * It turns on the LEAP indicator when the data is set, and does not,
2571  * as documented, wait until the beginning of the month when the
2572  * leap second will occur.
2573  * Until this firmware bug is fixed, @@Bj is only called in June/December.
2574  */
2575 
2576 static void
2577 oncore_msg_Bj(
2578 	struct instance *instance,
2579 	u_char *buf,
2580 	size_t len
2581 	)
2582 {
2583 	const char	*cp;
2584 
2585 	switch(buf[4]) {
2586 	case 1:
2587 		instance->peer->leap = LEAP_ADDSECOND;
2588 		cp = "Set peer.leap to LEAP_ADDSECOND";
2589 		break;
2590 	case 2:
2591 		instance->peer->leap = LEAP_DELSECOND;
2592 		cp = "Set peer.leap to LEAP_DELSECOND";
2593 		break;
2594 	case 0:
2595 	default:
2596 		instance->peer->leap = LEAP_NOWARNING;
2597 		cp = "Set peer.leap to LEAP_NOWARNING";
2598 		break;
2599 	}
2600 	record_clock_stats(&(instance->peer->srcadr), cp);
2601 }
2602 
2603 /* Leap Second for M12, gives all info from satellite message */
2604 
2605 static void
2606 oncore_msg_Gj(
2607 	struct instance *instance,
2608 	u_char *buf,
2609 	size_t len
2610 	)
2611 {
2612 	int dt;
2613 	char Msg[160], *cp;
2614 	static char *Month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jly",
2615 		"Aug", "Sep", "Oct", "Nov", "Dec" };
2616 
2617 	/* print the message to verify whats there */
2618 
2619 	dt = buf[5] - buf[4];
2620 
2621 #if 1
2622 	sprintf(Msg, "ONCORE[%d]: Leap Sec Msg: %d %d %d %d %d %d %d %d %d %d",
2623 			instance->unit,
2624 			buf[4], buf[5], 256*buf[6]+buf[7], buf[8], buf[9], buf[10],
2625 			(buf[14]+256*(buf[13]+256*(buf[12]+256*buf[11]))),
2626 			buf[15], buf[16], buf[17]);
2627 	record_clock_stats(&(instance->peer->srcadr), Msg);
2628 #endif
2629 	if (dt) {
2630 		sprintf(Msg, "ONCORE[%d]: Leap second (%d) scheduled for %d%s%d at %d:%d:%d",
2631 			instance->unit,
2632 			dt, buf[9], Month[buf[8]], 256*buf[6]+buf[7],
2633 			buf[15], buf[16], buf[17]);
2634 		record_clock_stats(&(instance->peer->srcadr), Msg);
2635 	}
2636 
2637 	/* Only raise warning within a month of the leap second */
2638 
2639 	instance->peer->leap = LEAP_NOWARNING;
2640 	cp = "Set peer.leap to LEAP_NOWARNING";
2641 
2642 	if (buf[6] == instance->Ea[6] && buf[7] == instance->Ea[7] && /* year */
2643 	    buf[8] == instance->Ea[4]) {	/* month */
2644 		if (dt) {
2645 			if (dt < 0) {
2646 				instance->peer->leap = LEAP_DELSECOND;
2647 				cp = "Set peer.leap to LEAP_DELSECOND";
2648 			} else {
2649 				instance->peer->leap = LEAP_ADDSECOND;
2650 				cp = "Set peer.leap to LEAP_ADDSECOND";
2651 			}
2652 		}
2653 	}
2654 	record_clock_stats(&(instance->peer->srcadr), cp);
2655 }
2656 
2657 
2658 
2659 /*
2660  * get Position hold position
2661  */
2662 
2663 static void
2664 oncore_msg_As(
2665 	struct instance *instance,
2666 	u_char *buf,
2667 	size_t len
2668 	)
2669 {
2670 	if (!instance->printed || instance->As)
2671 		return;
2672 
2673 	instance->As = 1;
2674 
2675 	instance->ss_lat  = buf_w32(&buf[4]);
2676 	instance->ss_long = buf_w32(&buf[8]);
2677 	instance->ss_ht   = buf_w32(&buf[12]);
2678 
2679 	/* Print out Position */
2680 	oncore_print_As(instance);
2681 }
2682 
2683 
2684 
2685 static void
2686 oncore_print_As(
2687 	struct instance *instance
2688 	)
2689 {
2690 	char Msg[120], ew, ns;
2691 	double xd, xm, xs, yd, ym, ys, hm, hft;
2692 	int idx, idy, is, imx, imy;
2693 	long lat, lon;
2694 
2695 	record_clock_stats(&(instance->peer->srcadr), "Posn:");
2696 	ew = 'E';
2697 	lon = instance->ss_long;
2698 	if (lon < 0) {
2699 		ew = 'W';
2700 		lon = -lon;
2701 	}
2702 
2703 	ns = 'N';
2704 	lat = instance->ss_lat;
2705 	if (lat < 0) {
2706 		ns = 'S';
2707 		lat = -lat;
2708 	}
2709 
2710 	hm = instance->ss_ht/100.;
2711 	hft= hm/0.3048;
2712 
2713 	xd = lat/3600000.;	/* lat, lon in int msec arc, ht in cm. */
2714 	yd = lon/3600000.;
2715 	sprintf(Msg, "Lat = %c %11.7fdeg,    Long = %c %11.7fdeg,    Alt = %5.2fm (%5.2fft) GPS", ns, xd, ew, yd, hm, hft);
2716 	record_clock_stats(&(instance->peer->srcadr), Msg);
2717 
2718 	idx = xd;
2719 	idy = yd;
2720 	imx = lat%3600000;
2721 	imy = lon%3600000;
2722 	xm = imx/60000.;
2723 	ym = imy/60000.;
2724 	sprintf(Msg, "Lat = %c %3ddeg %7.4fm,   Long = %c %3ddeg %8.5fm,  Alt = %7.2fm (%7.2fft) GPS", ns, idx, xm, ew, idy, ym, hm, hft);
2725 	record_clock_stats(&(instance->peer->srcadr), Msg);
2726 
2727 	imx = xm;
2728 	imy = ym;
2729 	is  = lat%60000;
2730 	xs  = is/1000.;
2731 	is  = lon%60000;
2732 	ys  = is/1000.;
2733 	sprintf(Msg, "Lat = %c %3ddeg %2dm %5.2fs, Long = %c %3ddeg %2dm %5.2fs, Alt = %7.2fm (%7.2fft) GPS", ns, idx, imx, xs, ew, idy, imy, ys, hm, hft);
2734 	record_clock_stats(&(instance->peer->srcadr), Msg);
2735 }
2736 
2737 
2738 
2739 /*
2740  * get PPS Offset
2741  * Nb. @@Ay is not supported for early UT (no plus) model
2742  */
2743 
2744 static void
2745 oncore_msg_Ay(
2746 	struct instance *instance,
2747 	u_char *buf,
2748 	size_t len
2749 	)
2750 {
2751 	char Msg[120];
2752 
2753 	if (!instance->printed || instance->Ay)
2754 		return;
2755 
2756 	instance->Ay = 1;
2757 
2758 	instance->offset = buf_w32(&buf[4]);
2759 
2760 	sprintf(Msg, "PPS Offset  is set to %ld ns", instance->offset);
2761 	record_clock_stats(&(instance->peer->srcadr), Msg);
2762 }
2763 
2764 
2765 
2766 /*
2767  * get Cable Delay
2768  */
2769 
2770 static void
2771 oncore_msg_Az(
2772 	struct instance *instance,
2773 	u_char *buf,
2774 	size_t len
2775 	)
2776 {
2777 	char Msg[120];
2778 
2779 	if (!instance->printed || instance->Az)
2780 		return;
2781 
2782 	instance->Az = 1;
2783 
2784 	instance->delay = buf_w32(&buf[4]);
2785 
2786 	sprintf(Msg, "Cable delay is set to %ld ns", instance->delay);
2787 	record_clock_stats(&(instance->peer->srcadr), Msg);
2788 }
2789 
2790 static void
2791 oncore_msg_Sz(
2792 	struct instance *instance,
2793 	u_char *buf,
2794 	size_t len
2795 	)
2796 {
2797 	const char *cp;
2798 
2799 	cp = "Oncore: System Failure at Power On";
2800 	if (instance && instance->peer) {
2801 		record_clock_stats(&(instance->peer->srcadr), cp);
2802 		oncore_shutdown(instance->unit, instance->peer);
2803 	}
2804 }
2805 
2806 #else
2807 int refclock_oncore_bs;
2808 #endif /* REFCLOCK */
2809