xref: /freebsd/contrib/ntp/ntpd/refclock_oncore.c (revision b1f9167f94059fd55c630891d359bcff987bd7eb)
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, M12+T
13  *	The receivers with TRAIM (VP, UT, UT+, M12+T), will be more accurate
14  *	than the others.
15  *	The receivers without position hold (GT, GT+) will be less accurate.
16  *
17  * Tested with:
18  *
19  *		(UT)				   (VP)
20  *   COPYRIGHT 1991-1997 MOTOROLA INC.	COPYRIGHT 1991-1996 MOTOROLA INC.
21  *   SFTW P/N #     98-P36848P		SFTW P/N # 98-P36830P
22  *   SOFTWARE VER # 2			SOFTWARE VER # 8
23  *   SOFTWARE REV # 2			SOFTWARE REV # 8
24  *   SOFTWARE DATE  APR 24 1998 	SOFTWARE DATE  06 Aug 1996
25  *   MODEL #	R1121N1114		MODEL #    B4121P1155
26  *   HWDR P/N # 1			HDWR P/N # _
27  *   SERIAL #	R0010A			SERIAL #   SSG0226478
28  *   MANUFACTUR DATE 6H07		MANUFACTUR DATE 7E02
29  *					OPTIONS LIST	IB
30  *
31  *	      (Basic)				   (M12)
32  *   COPYRIGHT 1991-1994 MOTOROLA INC.	COPYRIGHT 1991-2000 MOTOROLA INC.
33  *   SFTW P/N # 98-P39949M		SFTW P/N # 61-G10002A
34  *   SOFTWARE VER # 5			SOFTWARE VER # 1
35  *   SOFTWARE REV # 0			SOFTWARE REV # 3
36  *   SOFTWARE DATE  20 JAN 1994 	SOFTWARE DATE  Mar 13 2000
37  *   MODEL #	A11121P116		MODEL #    P143T12NR1
38  *   HDWR P/N # _			HWDR P/N # 1
39  *   SERIAL #	SSG0049809		SERIAL #   P003UD
40  *   MANUFACTUR DATE 417AMA199		MANUFACTUR DATE 0C27
41  *   OPTIONS LIST    AB
42  *
43  *	      (M12+T)				  (M12+T later version)
44  *   COPYRIGHT 1991-2002 MOTOROLA INC.	COPYRIGHT 1991-2003 MOTOROLA INC.
45  *   SFTW P/N #     61-G10268A		SFTW P/N #     61-G10268A
46  *   SOFTWARE VER # 2			SOFTWARE VER # 2
47  *   SOFTWARE REV # 0			SOFTWARE REV # 1
48  *   SOFTWARE DATE  AUG 14 2002 	SOFTWARE DATE  APR 16 2003
49  *   MODEL #	P283T12T11		MODEL #    P273T12T12
50  *   HWDR P/N # 2			HWDR P/N # 2
51  *   SERIAL #	P04DC2			SERIAL #   P05Z7Z
52  *   MANUFACTUR DATE 2J17		MANUFACTUR DATE 3G15
53  *
54  * --------------------------------------------------------------------------
55  * Reg Clemens (Feb 2006)
56  * Fix some gcc4 compiler complaints
57  * Fix possible segfault in oncore_init_shmem
58  * change all (possible) fprintf(stderr, to record_clock_stats
59  * Apply patch from Russell J. Yount <rjy@cmu.edu> Fixed (new) MT12+T UTC not correct
60  *   immediately after new Almanac Read.
61  * Apply patch for new PPS implementation by Rodolfo Giometti <giometti@linux.it>
62  *   now code can use old Ulrich Windl <Ulrich.Windl@rz.uni-regensburg.de> or
63  *   the new one.  Compiles depending on timepps.h seen.
64  * --------------------------------------------------------------------------
65  * Luis Batanero Guerrero <luisba@rao.es> (Dec 2005) Patch for leap seconds
66  * (the oncore driver was setting the wrong ntpd variable)
67  * --------------------------------------------------------------------------
68  * Reg.Clemens (Mar 2004)
69  * Support for interfaces other than PPSAPI removed, for Solaris, SunOS,
70  * SCO, you now need to use one of the timepps.h files in the root dir.
71  * this driver will 'grab' it for you if you dont have one in /usr/include
72  * --------------------------------------------------------------------------
73  * This code uses the two devices
74  *	/dev/oncore.serial.n
75  *	/dev/oncore.pps.n
76  * which may be linked to the same device.
77  * and can read initialization data from the file
78  *	/etc/ntp.oncoreN, /etc/ntp.oncore.N, or /etc/ntp.oncore, where
79  *	n or N are the unit number, viz 127.127.30.N.
80  * --------------------------------------------------------------------------
81  * Reg.Clemens <reg@dwf.com> Sep98.
82  *  Original code written for FreeBSD.
83  *  With these mods it works on FreeBSD, SunOS, Solaris and Linux
84  *    (SunOS 4.1.3 + ppsclock)
85  *    (Solaris7 + MU4)
86  *    (RedHat 5.1 2.0.35 + PPSKit, 2.1.126 + or later).
87  *
88  *  Lat,Long,Ht, cable-delay, offset, and the ReceiverID (along with the
89  *  state machine state) are printed to CLOCKSTATS if that file is enabled
90  *  in /etc/ntp.conf.
91  *
92  * --------------------------------------------------------------------------
93  *
94  * According to the ONCORE manual (TRM0003, Rev 3.2, June 1998, page 3.13)
95  * doing an average of 10000 valid 2D and 3D fixes is what the automatic
96  * site survey mode does.  Looking at the output from the receiver
97  * it seems like it is only using 3D fixes.
98  * When we do it ourselves, take 10000 3D fixes.
99  */
100 
101 #define POS_HOLD_AVERAGE	10000	/* nb, 10000s ~= 2h45m */
102 
103 /*
104  * ONCORE_SHMEM_STATUS will create a mmap(2)'ed file named according to a
105  * "STATUS" line in the oncore config file, which contains the most recent
106  * copy of all types of messages we recognize.	This file can be mmap(2)'ed
107  * by monitoring and statistics programs.
108  *
109  * See separate HTML documentation for this option.
110  */
111 
112 #ifdef HAVE_CONFIG_H
113 #include <config.h>
114 #endif
115 
116 #if defined(REFCLOCK) && defined(CLOCK_ONCORE)
117 
118 #include "ntpd.h"
119 #include "ntp_io.h"
120 #include "ntp_unixtime.h"
121 #include "ntp_refclock.h"
122 #include "ntp_stdlib.h"
123 
124 #include <stdio.h>
125 #include <ctype.h>
126 #include <sys/stat.h>
127 #ifdef ONCORE_SHMEM_STATUS
128 # ifdef HAVE_SYS_MMAN_H
129 #  include <sys/mman.h>
130 #  ifndef MAP_FAILED
131 #   define MAP_FAILED ((u_char *) -1)
132 #  endif  /* MAP_FAILED */
133 # endif /* HAVE_SYS_MMAN_H */
134 #endif /* ONCORE_SHMEM_STATUS */
135 
136 #ifdef HAVE_PPSAPI
137 # include "ppsapi_timepps.h"
138 #endif
139 
140 #ifdef HAVE_SYS_SIO_H
141 # include <sys/sio.h>
142 #endif
143 
144 enum receive_state {
145 	ONCORE_NO_IDEA,
146 	ONCORE_CHECK_ID,
147 	ONCORE_CHECK_CHAN,
148 	ONCORE_HAVE_CHAN,
149 	ONCORE_RESET_SENT,
150 	ONCORE_TEST_SENT,
151 	ONCORE_INIT,
152 	ONCORE_ALMANAC,
153 	ONCORE_RUN
154 };
155 
156 enum site_survey_state {
157 	ONCORE_SS_UNKNOWN,
158 	ONCORE_SS_TESTING,
159 	ONCORE_SS_HW,
160 	ONCORE_SS_SW,
161 	ONCORE_SS_DONE
162 };
163 
164 enum antenna_state {
165       ONCORE_ANTENNA_UNKNOWN = -1,
166       ONCORE_ANTENNA_OK      =	0,
167       ONCORE_ANTENNA_OC      =	1,
168       ONCORE_ANTENNA_UC      =	2,
169       ONCORE_ANTENNA_NV      =	3
170 };
171 
172 /* Model Name, derived from the @@Cj message.
173  * Used to initialize some variables.
174  */
175 
176 enum oncore_model {
177 	ONCORE_BASIC,
178 	ONCORE_PVT6,
179 	ONCORE_VP,
180 	ONCORE_UT,
181 	ONCORE_UTPLUS,
182 	ONCORE_GT,
183 	ONCORE_GTPLUS,
184 	ONCORE_SL,
185 	ONCORE_M12,
186 	ONCORE_UNKNOWN
187 };
188 
189 /* the bits that describe these properties are in the same place
190  * on the VP/UT, but have moved on the M12.  As such we extract
191  * them, and use them from this struct.
192  *
193  */
194 
195 struct RSM {
196 	u_char	posn0D;
197 	u_char	posn2D;
198 	u_char	posn3D;
199 	u_char	bad_almanac;
200 	u_char	bad_fix;
201 };
202 
203 /* It is possible to test the VP/UT each cycle (@@Ea or equivalent) to
204  * see what mode it is in.  The bits on the M12 are multiplexed with
205  * other messages, so we have to 'keep' the last known mode here.
206  */
207 
208 enum posn_mode {
209 	MODE_UNKNOWN,
210 	MODE_0D,
211 	MODE_2D,
212 	MODE_3D
213 };
214 
215 struct instance {
216 	int	unit;		/* 127.127.30.unit */
217 	struct	refclockproc *pp;
218 	struct	peer *peer;
219 
220 	int	ttyfd;		/* TTY file descriptor */
221 	int	ppsfd;		/* PPS file descriptor */
222 	int	shmemfd;	/* Status shm descriptor */
223 	pps_handle_t pps_h;
224 	pps_params_t pps_p;
225 	enum receive_state o_state;		/* Receive state */
226 	enum posn_mode mode;			/* 0D, 2D, 3D */
227 	enum site_survey_state site_survey;	/* Site Survey state */
228 	enum antenna_state ant_state;		/* antenna state */
229 
230 	int	Bj_day;
231 
232 	u_long	delay;		/* ns */
233 	long	offset; 	/* ns */
234 
235 	u_char	*shmem;
236 	char	*shmem_fname;
237 	u_int	shmem_Cb;
238 	u_int	shmem_Ba;
239 	u_int	shmem_Ea;
240 	u_int	shmem_Ha;
241 	u_char	shmem_reset;
242 	u_char	shmem_Posn;
243 	u_char	shmem_bad_Ea;
244 	u_char	almanac_from_shmem;
245 
246 	double	ss_lat;
247 	double	ss_long;
248 	double	ss_ht;
249 	double	dH;
250 	int	ss_count;
251 	u_char	posn_set;
252 
253 	enum oncore_model model;
254 	u_int	version;
255 	u_int	revision;
256 
257 	u_char	chan;		/* 6 for PVT6 or BASIC, 8 for UT/VP, 12 for m12, 0 if unknown */
258 	s_char	traim;		/* do we have traim? yes UT/VP, M12+T, no BASIC, GT, M12, -1 unknown, 0 no, +1 yes */
259 				/* the following 7 are all timing counters */
260 	u_char	traim_delay;	/* seconds counter, waiting for reply */
261 	u_char	count;		/* cycles thru Ea before starting */
262 	u_char	count1; 	/* cycles thru Ea after SS_TESTING, waiting for SS_HW */
263 	u_char	count2; 	/* cycles thru Ea after count, to check for @@Ea */
264 	u_char	count3; 	/* cycles thru Ea checking for # channels */
265 	u_char	count4; 	/* cycles thru leap after Gj to issue Bj */
266 	u_char	count5; 	/* cycles thru get_timestamp waiting for valid UTC correction */
267 	u_char	count5_set;	/* only set count5 once */
268 	u_char	pollcnt;
269 	u_char	timeout;	/* count to retry Cj after Fa self-test */
270 
271 	struct	RSM rsm;	/* bits extracted from Receiver Status Msg in @@Ea */
272 	u_char	printed;
273 	u_char	polled;
274 	u_long	ev_serial;
275 	int	Rcvptr;
276 	u_char	Rcvbuf[500];
277 	u_char	BEHa[160];	/* Ba, Ea or Ha */
278 	u_char	BEHn[80];	/* Bn , En , or Hn */
279 	u_char	Cj[300];
280 	u_char	Ag;		/* Satellite mask angle */
281 	u_char	saw_At;
282 	u_char	saw_Ay;
283 	u_char	saw_Az;
284 	s_char	saw_Gj;
285 	u_char	have_dH;
286 	u_char	init_type;
287 	s_char	saw_tooth;
288 	s_char	chan_in;	/* chan number from INPUT, will always use it */
289 	u_char	chan_id;	/* chan number determined from part number */
290 	u_char	chan_ck;	/* chan number determined by sending commands to hardware */
291 	s_char	traim_in;	/* TRAIM from INPUT, will always use ON/OFF specified */
292 	s_char	traim_id;	/* TRAIM determined from part number */
293 	u_char	traim_ck;	/* TRAIM determined by sending commands to hardware */
294 	u_char	once;		/* one pass code at top of BaEaHa */
295 	s_char	assert;
296 	u_char	hardpps;
297 };
298 
299 #define rcvbuf	instance->Rcvbuf
300 #define rcvptr	instance->Rcvptr
301 
302 static	int	oncore_start	      P((int, struct peer *));
303 static	void	oncore_poll	      P((int, struct peer *));
304 static	void	oncore_shutdown       P((int, struct peer *));
305 static	void	oncore_consume	      P((struct instance *));
306 static	void	oncore_read_config    P((struct instance *));
307 static	void	oncore_receive	      P((struct recvbuf *));
308 static	int	oncore_ppsapi	      P((struct instance *));
309 static	void	oncore_get_timestamp  P((struct instance *, long, long));
310 static	void	oncore_init_shmem     P((struct instance *));
311 
312 static	void	oncore_antenna_report P((struct instance *, enum antenna_state));
313 static	void	oncore_chan_test      P((struct instance *));
314 static	void	oncore_check_almanac  P((struct instance *));
315 static	void	oncore_check_antenna  P((struct instance *));
316 static	void	oncore_check_leap_sec P((struct instance *));
317 static	int	oncore_checksum_ok    P((u_char *, int));
318 static	void	oncore_compute_dH     P((struct instance *));
319 static	void	oncore_load_almanac   P((struct instance *));
320 static	void	oncore_print_Cb       P((struct instance *, u_char *));
321 /* static  void    oncore_print_array	 P((u_char *, int));	*/
322 static	void	oncore_print_posn     P((struct instance *));
323 static	void	oncore_sendmsg	      P((int, u_char *, size_t));
324 static	void	oncore_set_posn       P((struct instance *));
325 static	void	oncore_set_traim      P((struct instance *));
326 static	void	oncore_shmem_get_3D   P((struct instance *));
327 static	void	oncore_ss	      P((struct instance *));
328 static	int	oncore_wait_almanac   P((struct instance *));
329 
330 static	void	oncore_msg_any	   P((struct instance *, u_char *, size_t, int));
331 static	void	oncore_msg_Adef    P((struct instance *, u_char *, size_t));
332 static	void	oncore_msg_Ag	   P((struct instance *, u_char *, size_t));
333 static	void	oncore_msg_As	   P((struct instance *, u_char *, size_t));
334 static	void	oncore_msg_At	   P((struct instance *, u_char *, size_t));
335 static	void	oncore_msg_Ay	   P((struct instance *, u_char *, size_t));
336 static	void	oncore_msg_Az	   P((struct instance *, u_char *, size_t));
337 static	void	oncore_msg_BaEaHa  P((struct instance *, u_char *, size_t));
338 static	void	oncore_msg_Bd	   P((struct instance *, u_char *, size_t));
339 static	void	oncore_msg_Bj	   P((struct instance *, u_char *, size_t));
340 static	void	oncore_msg_BnEnHn  P((struct instance *, u_char *, size_t));
341 static	void	oncore_msg_CaFaIa  P((struct instance *, u_char *, size_t));
342 static	void	oncore_msg_Cb	   P((struct instance *, u_char *, size_t));
343 static	void	oncore_msg_Cf	   P((struct instance *, u_char *, size_t));
344 static	void	oncore_msg_Cj	   P((struct instance *, u_char *, size_t));
345 static	void	oncore_msg_Cj_id   P((struct instance *, u_char *, size_t));
346 static	void	oncore_msg_Cj_init P((struct instance *, u_char *, size_t));
347 static	void	oncore_msg_Ga	   P((struct instance *, u_char *, size_t));
348 static	void	oncore_msg_Gb	   P((struct instance *, u_char *, size_t));
349 static	void	oncore_msg_Gj	   P((struct instance *, u_char *, size_t));
350 static	void	oncore_msg_Sz	   P((struct instance *, u_char *, size_t));
351 
352 struct	refclock refclock_oncore = {
353 	oncore_start,		/* start up driver */
354 	oncore_shutdown,	/* shut down driver */
355 	oncore_poll,		/* transmit poll message */
356 	noentry,		/* not used */
357 	noentry,		/* not used */
358 	noentry,		/* not used */
359 	NOFLAGS 		/* not used */
360 };
361 
362 /*
363  * Understanding the next bit here is not easy unless you have a manual
364  * for the the various Oncore Models.
365  */
366 
367 static struct msg_desc {
368 	const char	flag[3];
369 	const int	len;
370 	void		(*handler) P((struct instance *, u_char *, size_t));
371 	const char	*fmt;
372 	int		shmem;
373 } oncore_messages[] = {
374 			/* Ea and En first since they're most common */
375 	{ "Ea",  76,    oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdimsdimsdsC" },
376 	{ "Ba",  68,    oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdsC" },
377 	{ "Ha", 154,    oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmaaaaoooohhhhmmmmVVvvhhddntimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddssrrccooooTTushmvvvvvvC" },
378 	{ "Bn",  59,    oncore_msg_BnEnHn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffC" },
379 	{ "En",  69,    oncore_msg_BnEnHn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffsffffsffffC" },
380 	{ "Hn",  78,    oncore_msg_BnEnHn, "" },
381 	{ "Ab",  10,    0,                 "" },
382 	{ "Ac",  11,    0,                 "" },
383 	{ "Ad",  11,    oncore_msg_Adef,   "" },
384 	{ "Ae",  11,    oncore_msg_Adef,   "" },
385 	{ "Af",  15,    oncore_msg_Adef,   "" },
386 	{ "Ag",   8,    oncore_msg_Ag,     "" }, /* Satellite mask angle */
387 	{ "As",  20,    oncore_msg_As,     "" },
388 	{ "At",   8,    oncore_msg_At,     "" },
389 	{ "Au",  12,    0,                 "" },
390 	{ "Av",   8,    0,                 "" },
391 	{ "Aw",   8,    0,                 "" },
392 	{ "Ay",  11,    oncore_msg_Ay,     "" },
393 	{ "Az",  11,    oncore_msg_Az,     "" },
394 	{ "AB",   8,    0,                 "" },
395 	{ "Bb",  92,    0,                 "" },
396 	{ "Bd",  23,    oncore_msg_Bd,     "" },
397 	{ "Bj",   8,    oncore_msg_Bj,     "" },
398 	{ "Ca",   9,    oncore_msg_CaFaIa, "" },
399 	{ "Cb",  33,    oncore_msg_Cb,     "" },
400 	{ "Cf",   7,    oncore_msg_Cf,     "" },
401 	{ "Cg",   8,    0,                 "" },
402 	{ "Ch",   9,    0,                 "" },
403 	{ "Cj", 294,    oncore_msg_Cj,     "" },
404 	{ "Ek",  71,    0,                 "" },
405 	{ "Fa",   9,    oncore_msg_CaFaIa, "" },
406 	{ "Ga",  20,    oncore_msg_Ga,     "" },
407 	{ "Gb",  17,    oncore_msg_Gb,     "" },
408 	{ "Gc",   8,    0,                 "" },
409 	{ "Gd",   8,    0,                 "" },
410 	{ "Ge",   8,    0,                 "" },
411 	{ "Gj",  21,    oncore_msg_Gj,     "" },
412 	{ "Ia",  10,    oncore_msg_CaFaIa, "" },
413 	{ "Sz",   8,    oncore_msg_Sz,     "" },
414 	{ {0},	  7,	0,		   "" }
415 };
416 
417 
418 static u_char oncore_cmd_Aa[]  = { 'A', 'a', 0, 0, 0 }; 			    /* 6/8	Time of Day				*/
419 static u_char oncore_cmd_Ab[]  = { 'A', 'b', 0, 0, 0 }; 			    /* 6/8	GMT Correction				*/
420 static u_char oncore_cmd_AB[]  = { 'A', 'B', 4 };				    /* VP	Application Type: Static		*/
421 static u_char oncore_cmd_Ac[]  = { 'A', 'c', 0, 0, 0, 0 };			    /* 6/8	Date					*/
422 static u_char oncore_cmd_Ad[]  = { 'A', 'd', 0,0,0,0 }; 			    /* 6/8	Latitude				*/
423 static u_char oncore_cmd_Ae[]  = { 'A', 'e', 0,0,0,0 }; 			    /* 6/8	Longitude				*/
424 static u_char oncore_cmd_Af[]  = { 'A', 'f', 0,0,0,0, 0 };			    /* 6/8	Height					*/
425 static u_char oncore_cmd_Ag[]  = { 'A', 'g', 0 };				    /* 6/8/12	Satellite Mask Angle			*/
426 static u_char oncore_cmd_Agx[] = { 'A', 'g', 0xff };				    /* 6/8/12	Satellite Mask Angle: read		*/
427 static u_char oncore_cmd_As[]  = { 'A', 's', 0,0,0,0, 0,0,0,0, 0,0,0,0, 0 };	    /* 6/8/12	Posn Hold Parameters			*/
428 static u_char oncore_cmd_Asx[] = { 'A', 's', 0x7f,0xff,0xff,0xff,		    /* 6/8/12	Posn Hold Readback			*/
429 					     0x7f,0xff,0xff,0xff,		    /*		 on UT+ this doesnt work with 0xff	*/
430 					     0x7f,0xff,0xff,0xff, 0xff };	    /*		 but does work with 0x7f (sigh).	*/
431 static u_char oncore_cmd_At0[] = { 'A', 't', 0 };				    /* 6/8	Posn Hold: off				*/
432 static u_char oncore_cmd_At1[] = { 'A', 't', 1 };				    /* 6/8	Posn Hold: on				*/
433 static u_char oncore_cmd_At2[] = { 'A', 't', 2 };				    /* 6/8	Posn Hold: Start Site Survey		*/
434 static u_char oncore_cmd_Atx[] = { 'A', 't', 0xff };				    /* 6/8	Posn Hold: Read Back			*/
435 static u_char oncore_cmd_Au[]  = { 'A', 'u', 0,0,0,0, 0 };			    /* GT/M12	Altitude Hold Ht.			*/
436 static u_char oncore_cmd_Av0[] = { 'A', 'v', 0 };				    /* VP/GT	Altitude Hold: off			*/
437 static u_char oncore_cmd_Av1[] = { 'A', 'v', 1 };				    /* VP/GT	Altitude Hold: on			*/
438 static u_char oncore_cmd_Aw[]  = { 'A', 'w', 1 };				    /* 6/8/12	UTC/GPS time selection			*/
439 static u_char oncore_cmd_Ay[]  = { 'A', 'y', 0, 0, 0, 0 };			    /* Timing	1PPS time offset: set			*/
440 static u_char oncore_cmd_Ayx[] = { 'A', 'y', 0xff, 0xff, 0xff, 0xff };		    /* Timing	1PPS time offset: Read			*/
441 static u_char oncore_cmd_Az[]  = { 'A', 'z', 0, 0, 0, 0 };			    /* 6/8UT/12 1PPS Cable Delay: set			*/
442 static u_char oncore_cmd_Azx[] = { 'A', 'z', 0xff, 0xff, 0xff, 0xff };		    /* 6/8UT/12 1PPS Cable Delay: Read			*/
443 static u_char oncore_cmd_Ba0[] = { 'B', 'a', 0 };				    /* 6	Position/Data/Status: off		*/
444 static u_char oncore_cmd_Ba[]  = { 'B', 'a', 1 };				    /* 6	Position/Data/Status: on		*/
445 static u_char oncore_cmd_Bb[]  = { 'B', 'b', 1 };				    /* 6/8/12	Visible Satellites			*/
446 static u_char oncore_cmd_Bd[]  = { 'B', 'd', 1 };				    /* 6/8/12?	Almanac Status Msg.			*/
447 static u_char oncore_cmd_Be[]  = { 'B', 'e', 1 };				    /* 6/8/12	Request Almanac Data			*/
448 static u_char oncore_cmd_Bj[]  = { 'B', 'j', 0 };				    /* 6/8	Leap Second Pending			*/
449 static u_char oncore_cmd_Bn0[] = { 'B', 'n', 0, 1, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 6	TRAIM setup/status: msg off, traim on	*/
450 static u_char oncore_cmd_Bn[]  = { 'B', 'n', 1, 1, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 6	TRAIM setup/status: msg on,  traim on	*/
451 static u_char oncore_cmd_Bnx[] = { 'B', 'n', 0, 0, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 6	TRAIM setup/status: msg off, traim off	*/
452 static u_char oncore_cmd_Ca[]  = { 'C', 'a' };					    /* 6	Self Test				*/
453 static u_char oncore_cmd_Cf[]  = { 'C', 'f' };					    /* 6/8/12	Set to Defaults 			*/
454 static u_char oncore_cmd_Cg[]  = { 'C', 'g', 1 };				    /* VP	Posn Fix/Idle Mode			*/
455 static u_char oncore_cmd_Cj[]  = { 'C', 'j' };					    /* 6/8/12	Receiver ID				*/
456 static u_char oncore_cmd_Ea0[] = { 'E', 'a', 0 };				    /* 8	Position/Data/Status: off		*/
457 static u_char oncore_cmd_Ea[]  = { 'E', 'a', 1 };				    /* 8	Position/Data/Status: on		*/
458 static u_char oncore_cmd_Ek[]  = { 'E', 'k', 0 }; /* just turn off */		    /* 8	Posn/Status/Data - extension		*/
459 static u_char oncore_cmd_En0[] = { 'E', 'n', 0, 1, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 8/GT	TRAIM setup/status: msg off, traim on	*/
460 static u_char oncore_cmd_En[]  = { 'E', 'n', 1, 1, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 8/GT	TRAIM setup/status: msg on,  traim on	*/
461 static u_char oncore_cmd_Enx[] = { 'E', 'n', 0, 0, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 8/GT	TRAIM setup/status: msg off, traim off	*/
462 static u_char oncore_cmd_Fa[]  = { 'F', 'a' };					    /* 8	Self Test				*/
463 static u_char oncore_cmd_Ga[]  = { 'G', 'a', 0,0,0,0, 0,0,0,0, 0,0,0,0, 0 };	    /* 12	Position Set				*/
464 static u_char oncore_cmd_Gax[] = { 'G', 'a', 0xff, 0xff, 0xff, 0xff,		    /* 12	Position Set: Read			*/
465 					     0xff, 0xff, 0xff, 0xff,		    /*							*/
466 					     0xff, 0xff, 0xff, 0xff, 0xff };	    /*							*/
467 static u_char oncore_cmd_Gb[]  = { 'G', 'b', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };	    /* 12	set Date/Time				*/
468 static u_char oncore_cmd_Gc[]  = { 'G', 'c', 1 };				    /* 12	PPS Control: On Cont			*/
469 static u_char oncore_cmd_Gd0[] = { 'G', 'd', 0 };				    /* 12	Position Control: 3D (no hold)		*/
470 static u_char oncore_cmd_Gd1[] = { 'G', 'd', 1 };				    /* 12	Position Control: 0D (3D hold)		*/
471 static u_char oncore_cmd_Gd2[] = { 'G', 'd', 2 };				    /* 12	Position Control: 2D (Alt Hold) 	*/
472 static u_char oncore_cmd_Gd3[] = { 'G', 'd', 3 };				    /* 12	Position Coltrol: Start Site Survey	*/
473 static u_char oncore_cmd_Ge0[] = { 'G', 'e', 0 };				    /* M12+T	TRAIM: off				*/
474 static u_char oncore_cmd_Ge[]  = { 'G', 'e', 1 };				    /* M12+T	TRAIM: on				*/
475 static u_char oncore_cmd_Gj[]  = { 'G', 'j' };					    /* 8?/12	Leap Second Pending			*/
476 static u_char oncore_cmd_Ha0[] = { 'H', 'a', 0 };				    /* 12	Position/Data/Status: off		*/
477 static u_char oncore_cmd_Ha[]  = { 'H', 'a', 1 };				    /* 12	Position/Data/Status: on		*/
478 static u_char oncore_cmd_Hn0[] = { 'H', 'n', 0 };				    /* 12	TRAIM Status: off			*/
479 static u_char oncore_cmd_Hn[]  = { 'H', 'n', 1 };				    /* 12	TRAIM Status: on			*/
480 static u_char oncore_cmd_Ia[]  = { 'I', 'a' };					    /* 12	Self Test				*/
481 
482 /* it appears that as of 1997/1998, the UT had As,At, but not Au,Av
483  *				    the GT had Au,Av, but not As,At
484  * This was as of v2.0 of both firmware sets. possibly 1.3 for UT.
485  * Bj in UT at v1.3
486  * dont see Bd in UT/GT thru 1999
487  * Gj in UT as of 3.0, 1999 , Bj as of 1.3
488  */
489 
490 static char *Month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jly",
491 	"Aug", "Sep", "Oct", "Nov", "Dec" };
492 
493 #define DEVICE1 	"/dev/oncore.serial.%d" /* name of serial device */
494 #define DEVICE2 	"/dev/oncore.pps.%d"    /* name of pps device */
495 
496 #define SPEED		B9600		/* Oncore Binary speed (9600 bps) */
497 
498 /*
499  * Assemble and disassemble 32bit signed quantities from a buffer.
500  *
501  */
502 
503 	/* to buffer, int w, u_char *buf */
504 #define w32_buf(buf,w)	{ u_int i_tmp;			   \
505 			  i_tmp = (w<0) ? (~(-w)+1) : (w); \
506 			  (buf)[0] = (i_tmp >> 24) & 0xff; \
507 			  (buf)[1] = (i_tmp >> 16) & 0xff; \
508 			  (buf)[2] = (i_tmp >>	8) & 0xff; \
509 			  (buf)[3] = (i_tmp	 ) & 0xff; \
510 			}
511 
512 #define w32(buf)      (((buf)[0]&0xff) << 24 | \
513 		       ((buf)[1]&0xff) << 16 | \
514 		       ((buf)[2]&0xff) <<  8 | \
515 		       ((buf)[3]&0xff) )
516 
517 	/* from buffer, char *buf, result to an int */
518 #define buf_w32(buf) (((buf)[0]&0200) ? (-(~w32(buf)+1)) : w32(buf))
519 
520 
521 /*
522  * oncore_start - initialize data for processing
523  */
524 
525 static int
526 oncore_start(
527 	int unit,
528 	struct peer *peer
529 	)
530 {
531 #define STRING_LEN	32
532 	register struct instance *instance;
533 	struct refclockproc *pp;
534 	int fd1, fd2, num;
535 	char device1[STRING_LEN], device2[STRING_LEN], Msg[160];
536 	const char *cp;
537 	struct stat stat1, stat2;
538 
539 	/* create instance structure for this unit */
540 
541 	if (!(instance = (struct instance *) malloc(sizeof *instance))) {
542 		perror("malloc");
543 		return (0);
544 	}
545 	memset((char *) instance, 0, sizeof *instance);
546 
547 	/* initialize miscellaneous variables */
548 
549 	pp = peer->procptr;
550 	pp->unitptr    = (caddr_t) instance;
551 	instance->pp   = pp;
552 	instance->unit = unit;
553 	instance->peer = peer;
554 	instance->assert = 1;
555 	instance->once = 1;
556 
557 	instance->Bj_day = -1;
558 	instance->traim = -1;
559 	instance->traim_in = -1;
560 	instance->chan_in = -1;
561 	instance->model = ONCORE_UNKNOWN;
562 	instance->mode = MODE_UNKNOWN;
563 	instance->site_survey = ONCORE_SS_UNKNOWN;
564 	instance->Ag = 0xff;		/* Satellite mask angle, unset by user */
565 	instance->ant_state = ONCORE_ANTENNA_UNKNOWN;
566 
567 	peer->precision = -26;
568 	peer->minpoll = 4;
569 	peer->maxpoll = 4;
570 	pp->clockdesc = "Motorola Oncore GPS Receiver";
571 	memcpy((char *)&pp->refid, "GPS\0", (size_t) 4);
572 
573 	cp = "ONCORE DRIVER -- CONFIGURING";
574 	record_clock_stats(&(instance->peer->srcadr), cp);
575 
576 	instance->o_state = ONCORE_NO_IDEA;
577 	cp = "state = ONCORE_NO_IDEA";
578 	record_clock_stats(&(instance->peer->srcadr), cp);
579 
580 	/* Now open files.
581 	 * This is a bit complicated, a we dont want to open the same file twice
582 	 * (its a problem on some OS), and device2 may not exist for the new PPS
583 	 */
584 
585 	(void)sprintf(device1, DEVICE1, unit);
586 	(void)sprintf(device2, DEVICE2, unit);
587 
588 	/* OPEN DEVICES */
589 	/* opening different devices for fd1 and fd2 presents no problems */
590 	/* opening the SAME device twice, seems to be OS dependent.
591 		(a) on Linux (no streams) no problem
592 		(b) on SunOS (and possibly Solaris, untested), (streams)
593 			never see the line discipline.
594 	   Since things ALWAYS work if we only open the device once, we check
595 	     to see if the two devices are in fact the same, then proceed to
596 	     do one open or two.
597 	*/
598 
599 	if (stat(device1, &stat1)) {
600 		sprintf(Msg, "Can't stat fd1 (%s)\n", device1);
601 		record_clock_stats(&(instance->peer->srcadr), Msg);
602 		exit(1);
603 	}
604 
605 	if (stat(device2, &stat2)) {
606 		sprintf(Msg, "Can't stat fd2 (%s)\n", device2);
607 		record_clock_stats(&(instance->peer->srcadr), Msg);
608 		exit(1);
609 	}
610 
611 	if (!(fd1 = refclock_open(device1, SPEED, LDISC_RAW))) {
612 		sprintf(Msg, "Can't open fd1 (%s)\n", device1);
613 		record_clock_stats(&(instance->peer->srcadr), Msg);
614 		exit(1);
615 	}
616 
617 	if ((stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino))	/* same device here */
618 		fd2 = fd1;
619 	else {	/* different devices here */
620 		if ((fd2=open(device2, O_RDWR)) < 0) {
621 			sprintf(Msg, "Can't open fd2 (%s)\n", device2);
622 			record_clock_stats(&(instance->peer->srcadr), Msg);
623 			exit(1);
624 		}
625 	}
626 	num = fd2;
627 
628 	/* open ppsapi soure */
629 
630 	if (time_pps_create(num, &instance->pps_h) < 0) {
631 		record_clock_stats(&(instance->peer->srcadr), "PPSAPI not found in kernel");
632 		return(0);
633 	}
634 
635 	/* continue initialization */
636 
637 	instance->ttyfd = fd1;
638 	instance->ppsfd = fd2;
639 
640 	/* go read any input data in /etc/ntp.oncoreX or /etc/ntp/oncore.X */
641 
642 	oncore_read_config(instance);
643 
644 	if (!oncore_ppsapi(instance))
645 		return(0);
646 
647 	pp->io.clock_recv = oncore_receive;
648 	pp->io.srcclock = (caddr_t)peer;
649 	pp->io.datalen = 0;
650 	pp->io.fd = fd1;
651 	if (!io_addclock(&pp->io)) {
652 		record_clock_stats(&(instance->peer->srcadr), "ONCORE: io_addclock");
653 		(void) close(fd1);
654 		free(instance);
655 		return (0);
656 	}
657 
658 #ifdef ONCORE_SHMEM_STATUS
659 	/*
660 	 * Before starting ONCORE, lets setup SHMEM
661 	 * This will include merging an old SHMEM into the new one if
662 	 * an old one is found.
663 	 */
664 
665 	oncore_init_shmem(instance);
666 #endif
667 
668 	/*
669 	 * This will return the Model of the Oncore receiver.
670 	 * and start the Initialization loop in oncore_msg_Cj.
671 	 */
672 
673 	instance->o_state = ONCORE_CHECK_ID;
674 	cp = "state = ONCORE_CHECK_ID";
675 	record_clock_stats(&(instance->peer->srcadr), cp);
676 
677 	instance->timeout = 4;
678 	oncore_sendmsg(instance->ttyfd, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Set Posn Fix mode (not Idle (VP)) */
679 	oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
680 
681 	instance->pollcnt = 2;
682 	return (1);
683 }
684 
685 
686 /*
687  * oncore_shutdown - shut down the clock
688  */
689 
690 static void
691 oncore_shutdown(
692 	int unit,
693 	struct peer *peer
694 	)
695 {
696 	register struct instance *instance;
697 	struct refclockproc *pp;
698 
699 	pp = peer->procptr;
700 	instance = (struct instance *) pp->unitptr;
701 
702 	io_closeclock(&pp->io);
703 
704 	time_pps_destroy (instance->pps_h);
705 
706 	close(instance->ttyfd);
707 
708 	if ((instance->ppsfd != -1) && (instance->ppsfd != instance->ttyfd))
709 		close(instance->ppsfd);
710 
711 	if (instance->shmemfd)
712 		close(instance->shmemfd);
713 
714 	free(instance);
715 }
716 
717 
718 
719 /*
720  * oncore_poll - called by the transmit procedure
721  */
722 
723 static void
724 oncore_poll(
725 	int unit,
726 	struct peer *peer
727 	)
728 {
729 	struct instance *instance;
730 
731 	instance = (struct instance *) peer->procptr->unitptr;
732 	if (instance->timeout) {
733 		char	*cp;
734 
735 		instance->timeout--;
736 		if (instance->timeout == 0) {
737 			cp = "Oncore: No response from @@Cj, shutting down driver";
738 			record_clock_stats(&(instance->peer->srcadr), cp);
739 			oncore_shutdown(unit, peer);
740 		} else {
741 			oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
742 			cp = "Oncore: Resend @@Cj";
743 			record_clock_stats(&(instance->peer->srcadr), cp);
744 		}
745 		return;
746 	}
747 
748 	if (!instance->pollcnt)
749 		refclock_report(peer, CEVNT_TIMEOUT);
750 	else
751 		instance->pollcnt--;
752 	peer->procptr->polls++;
753 	instance->polled = 1;
754 }
755 
756 
757 
758 /*
759  * Initialize PPSAPI
760  */
761 
762 static int
763 oncore_ppsapi(
764 	struct instance *instance
765 	)
766 {
767 	int cap, mode, mode1;
768 	char *cp, Msg[160];
769 
770 	if (time_pps_getcap(instance->pps_h, &cap) < 0) {
771 		msyslog(LOG_ERR, "time_pps_getcap failed: %m");
772 		return (0);
773 	}
774 
775 	if (time_pps_getparams(instance->pps_h, &instance->pps_p) < 0) {
776 		msyslog(LOG_ERR, "time_pps_getparams failed: %m");
777 		return (0);
778 	}
779 
780 	/* nb. only turn things on, if someone else has turned something
781 	 *	on before we get here, leave it alone!
782 	 */
783 
784 	if (instance->assert) {
785 		cp = "Assert.";
786 		mode = PPS_CAPTUREASSERT;
787 		mode1 = PPS_OFFSETASSERT;
788 	} else {
789 		cp = "Clear.";
790 		mode = PPS_CAPTURECLEAR;
791 		mode1 = PPS_OFFSETCLEAR;
792 	}
793 	sprintf(Msg, "Initializing timeing to %s.", cp);
794 	record_clock_stats(&(instance->peer->srcadr), Msg);
795 
796 	if (!(mode & cap)) {
797 		sprintf(Msg, "Can't set timeing to %s, exiting...", cp);
798 		record_clock_stats(&(instance->peer->srcadr), Msg);
799 		return(0);
800 	}
801 
802 	if (!(mode1 & cap)) {
803 		sprintf(Msg, "Can't set PPS_%sCLEAR, this will increase jitter.", cp);
804 		record_clock_stats(&(instance->peer->srcadr), Msg);
805 		mode1 = 0;
806 	}
807 
808 	/* only set what is legal */
809 
810 	instance->pps_p.mode = (mode | mode1 | PPS_TSFMT_TSPEC) & cap;
811 
812 	if (time_pps_setparams(instance->pps_h, &instance->pps_p) < 0) {
813 		record_clock_stats(&(instance->peer->srcadr), "ONCORE: time_pps_setparams fails");
814 		exit(1);
815 	}
816 
817 	/* If HARDPPS is on, we tell kernel */
818 
819 	if (instance->hardpps) {
820 		int	i;
821 
822 		record_clock_stats(&(instance->peer->srcadr), "HARDPPS Set.");
823 
824 		if (instance->assert)
825 			i = PPS_CAPTUREASSERT;
826 		else
827 			i = PPS_CAPTURECLEAR;
828 
829 		/* we know that 'i' is legal from above */
830 
831 		if (time_pps_kcbind(instance->pps_h, PPS_KC_HARDPPS, i,
832 		    PPS_TSFMT_TSPEC) < 0) {
833 			msyslog(LOG_ERR, "time_pps_kcbind failed: %m");
834 			record_clock_stats(&(instance->peer->srcadr), "HARDPPS failed, abort...");
835 			return (0);
836 		}
837 		pps_enable = 1;
838 	}
839 	return(1);
840 }
841 
842 
843 
844 #ifdef ONCORE_SHMEM_STATUS
845 static void
846 oncore_init_shmem(
847 	struct instance *instance
848 	)
849 {
850 	int i, l, n, fd, shmem_old_size, n1;
851 	char Msg[160];
852 	u_char *cp, *cp1, *buf, *shmem_old;
853 	struct msg_desc *mp;
854 	struct stat sbuf;
855 	size_t shmem_length;
856 
857        /*
858 	* The first thing we do is see if there is an instance->shmem_fname file (still)
859 	* out there from a previous run.  If so, we copy it in and use it to initialize
860 	* shmem (so we won't lose our almanac if we need it).
861 	*/
862 
863 	shmem_old = 0;
864 	shmem_old_size = 0;
865 	if ((fd = open(instance->shmem_fname, O_RDONLY)) < 0)
866 		record_clock_stats(&(instance->peer->srcadr), "ONCORE: Can't open SHMEM file");
867 	else {
868 		fstat(fd, &sbuf);
869 		shmem_old_size = sbuf.st_size;
870 		if (shmem_old_size != 0) {
871 			shmem_old = (u_char *) malloc((unsigned) sbuf.st_size);
872 			if (shmem_old == NULL)
873 				record_clock_stats(&(instance->peer->srcadr), "ONCORE: Can't malloc buffer for shmem_old");
874 			else
875 				read(fd, shmem_old, shmem_old_size);
876 		}
877 		close(fd);
878 	}
879 
880 	/* OK, we now create the NEW SHMEM. */
881 
882 	if ((instance->shmemfd = open(instance->shmem_fname, O_RDWR|O_CREAT|O_TRUNC, 0644)) < 0) {
883 		record_clock_stats(&(instance->peer->srcadr), "ONCORE: Can't open shmem");
884 		if (shmem_old)
885 			free(shmem_old);
886 
887 		return;
888 	}
889 
890 	/* see how big it needs to be */
891 
892 	n = 1;
893 	for (mp=oncore_messages; mp->flag[0]; mp++) {
894 		mp->shmem = n;
895 		/* Allocate space for multiplexed almanac, and 0D/2D/3D @@Ea records */
896 		if (!strcmp(mp->flag, "Cb")) {
897 			instance->shmem_Cb = n;
898 			n += (mp->len + 3) * 34;
899 		}
900 		if (!strcmp(mp->flag, "Ba")) {
901 			instance->shmem_Ba = n;
902 			n += (mp->len + 3) * 3;
903 		}
904 		if (!strcmp(mp->flag, "Ea")) {
905 			instance->shmem_Ea = n;
906 			n += (mp->len + 3) * 3;
907 		}
908 		if (!strcmp(mp->flag, "Ha")) {
909 			instance->shmem_Ha = n;
910 			n += (mp->len + 3) * 3;
911 		}
912 		n += (mp->len + 3);
913 	}
914 	shmem_length = n + 2;
915 
916 	buf = malloc(shmem_length);
917 	if (buf == NULL) {
918 		record_clock_stats(&(instance->peer->srcadr), "ONCORE: Can't malloc buffer for shmem");
919 		close(instance->shmemfd);
920 		if (shmem_old)
921 			free(shmem_old);
922 
923 		return;
924 	}
925 
926 	memset(buf, 0, shmem_length);
927 
928 	/* next build the new SHMEM buffer in memory */
929 
930 	for (mp=oncore_messages; mp->flag[0]; mp++) {
931 		l = mp->shmem;
932 		buf[l + 0] = mp->len >> 8;
933 		buf[l + 1] = mp->len & 0xff;
934 		buf[l + 2] = 0;
935 		buf[l + 3] = '@';
936 		buf[l + 4] = '@';
937 		buf[l + 5] = mp->flag[0];
938 		buf[l + 6] = mp->flag[1];
939 		if (!strcmp(mp->flag, "Cb") || !strcmp(mp->flag, "Ba") || !strcmp(mp->flag, "Ea") || !strcmp(mp->flag, "Ha")) {
940 			if (!strcmp(mp->flag, "Cb"))
941 				n = 35;
942 			else
943 				n = 4;
944 			for (i=1; i<n; i++) {
945 				buf[l + i * (mp->len+3) + 0] = mp->len >> 8;
946 				buf[l + i * (mp->len+3) + 1] = mp->len & 0xff;
947 				buf[l + i * (mp->len+3) + 2] = 0;
948 				buf[l + i * (mp->len+3) + 3] = '@';
949 				buf[l + i * (mp->len+3) + 4] = '@';
950 				buf[l + i * (mp->len+3) + 5] = mp->flag[0];
951 				buf[l + i * (mp->len+3) + 6] = mp->flag[1];
952 			}
953 		}
954 	}
955 
956 	/* we now walk thru the two buffers (shmem_old and buf, soon to become shmem)
957 	 * copying the data in shmem_old to buf.
958 	 * When we are done we write it out and free both buffers.
959 	 * If the structure sizes dont agree, I will not copy.
960 	 * This could be due to an addition/deletion or a problem with the disk file.
961 	 */
962 
963 	if (shmem_old) {
964 		if (shmem_old_size == shmem_length) {
965 			for (cp=buf+4, cp1=shmem_old+4; (n = 256*(*(cp-3)) + *(cp-2));	cp+=(n+3), cp1+=(n+3)) {
966 				n1 = 256*(*(cp1-3)) + *(cp1-2);
967 				if (n == 0 || n1 != n || strncmp((char *) cp, (char *) cp1, 4))
968 					break;
969 
970 				memcpy(cp, cp1, (size_t) n);
971 			}
972 		}
973 		free(shmem_old);
974 	}
975 
976 	i = write(instance->shmemfd, buf, shmem_length);
977 	free(buf);
978 
979 	if (i != shmem_length) {
980 		record_clock_stats(&(instance->peer->srcadr), "ONCORE: error writing shmem");
981 		close(instance->shmemfd);
982 		return;
983 	}
984 
985 	instance->shmem = (u_char *) mmap(0, shmem_length,
986 		PROT_READ | PROT_WRITE,
987 #ifdef MAP_HASSEMAPHORE
988 		MAP_HASSEMAPHORE |
989 #endif
990 		MAP_SHARED, instance->shmemfd, (off_t)0);
991 
992 	if (instance->shmem == (u_char *)MAP_FAILED) {
993 		instance->shmem = 0;
994 		close(instance->shmemfd);
995 		return;
996 	}
997 
998 	sprintf(Msg, "SHMEM (size = %ld) is CONFIGURED and available as %s",
999 		(u_long) shmem_length, instance->shmem_fname);
1000 	record_clock_stats(&(instance->peer->srcadr), Msg);
1001 }
1002 #endif /* ONCORE_SHMEM_STATUS */
1003 
1004 
1005 
1006 /*
1007  * Read Input file if it exists.
1008  */
1009 
1010 static void
1011 oncore_read_config(
1012 	struct instance *instance
1013 	)
1014 {
1015 /*
1016  * First we try to open the configuration file
1017  *    /etc/oncoreN
1018  * where N is the unit number viz 127.127.30.N.
1019  * If we don't find it we try
1020  *    /etc/ntp.oncore.N
1021  * and then
1022  *    /etc/ntp.oncore
1023  *
1024  * If we don't find any then we don't have the cable delay or PPS offset
1025  * and we choose MODE (4) below.
1026  *
1027  * Five Choices for MODE
1028  *    (0) ONCORE is preinitialized, don't do anything to change it.
1029  *	    nb, DON'T set 0D mode, DON'T set Delay, position...
1030  *    (1) NO RESET, Read Position, delays from data file, lock it in, go to 0D mode.
1031  *    (2) NO RESET, Read Delays from data file, do SITE SURVEY to get position,
1032  *		    lock this in, go to 0D mode.
1033  *    (3) HARD RESET, Read Position, delays from data file, lock it in, go to 0D mode.
1034  *    (4) HARD RESET, Read Delays from data file, do SITE SURVEY to get position,
1035  *		    lock this in, go to 0D mode.
1036  *     NB. If a POSITION is specified in the config file with mode=(2,4) [SITE SURVEY]
1037  *	   then this position is set as the INITIAL position of the ONCORE.
1038  *	   This can reduce the time to first fix.
1039  * -------------------------------------------------------------------------------
1040  * Note that an Oncore UT without a battery backup retains NO information if it is
1041  *   power cycled, with a Battery Backup it remembers the almanac, etc.
1042  * For an Oncore VP, there is an eeprom that will contain this data, along with the
1043  *   option of Battery Backup.
1044  * So a UT without Battery Backup is equivalent to doing a HARD RESET on each
1045  *   power cycle, since there is nowhere to store the data.
1046  * -------------------------------------------------------------------------------
1047  *
1048  * If we open one or the other of the files, we read it looking for
1049  *   MODE, LAT, LON, (HT, HTGPS, HTMSL), DELAY, OFFSET, ASSERT, CLEAR, HARDPPS,
1050  *   STATUS, POSN3D, POSN2D, CHAN, TRAIM
1051  * then initialize using method MODE.  For Mode = (1,3) all of (LAT, LON, HT) must
1052  *   be present or mode reverts to (2,4).
1053  *
1054  * Read input file.
1055  *
1056  *	# is comment to end of line
1057  *	= allowed between 1st and 2nd fields.
1058  *
1059  *	Expect to see one line with 'MODE' as first field, followed by an integer
1060  *	   in the range 0-4 (default = 4).
1061  *
1062  *	Expect to see two lines with 'LONG', 'LAT' followed by 1-3 fields.
1063  *	All numbers are floating point.
1064  *		DDD.ddd
1065  *		DDD  MMM.mmm
1066  *		DDD  MMM  SSS.sss
1067  *
1068  *	Expect to see one line with 'HT' as first field,
1069  *	   followed by 1-2 fields.  First is a number, the second is 'FT' or 'M'
1070  *	   for feet or meters.	HT is the height above the GPS ellipsoid.
1071  *	   If the receiver reports height in both GPS and MSL, then we will report
1072  *	   the difference GPS-MSL on the clockstats file.
1073  *
1074  *	There is an optional line, starting with DELAY, followed
1075  *	   by 1 or two fields.	The first is a number (a time) the second is
1076  *	   'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds.
1077  *	    DELAY  is cable delay, typically a few tens of ns.
1078  *
1079  *	There is an optional line, starting with OFFSET, followed
1080  *	   by 1 or two fields.	The first is a number (a time) the second is
1081  *	   'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds.
1082  *	   OFFSET is the offset of the PPS pulse from 0. (only fully implemented
1083  *		with the PPSAPI, we need to be able to tell the Kernel about this
1084  *		offset if the Kernel PLL is in use, but can only do this presently
1085  *		when using the PPSAPI interface.  If not using the Kernel PLL,
1086  *		then there is no problem.
1087  *
1088  *	There is an optional line, with either ASSERT or CLEAR on it, which
1089  *	   determine which transition of the PPS signal is used for timing by the
1090  *	   PPSAPI.  If neither is present, then ASSERT is assumed.
1091  *	   ASSERT/CLEAR can also be set with FLAG2 of the ntp.conf input.
1092  *	   For Flag2, ASSERT=0, and hence is default.
1093  *
1094  *	There is an optional line, with HARDPPS on it.	Including this line causes
1095  *	   the PPS signal to control the kernel PLL.
1096  *	   HARDPPS can also be set with FLAG3 of the ntp.conf input.
1097  *	   For Flag3, 0 is disabled, and the default.
1098  *
1099  *	There are three options that have to do with using the shared memory option.
1100  *	   First, to enable the option there must be a SHMEM line with a file name.
1101  *	   The file name is the file associated with the shared memory.
1102  *
1103  *	In shared memory, there is one 'record' for each returned variable.
1104  *	For the @@Ea data there are three 'records' containing position data.
1105  *	   There will always be data in the record corresponding to the '0D' @@Ea record,
1106  *	   and the user has a choice of filling the '3D' record by specifying POSN3D,
1107  *	   or the '2D' record by specifying POSN2D.  In either case the '2D' or '3D'
1108  *	   record is filled once every 15s.
1109  *
1110  *	Two additional variables that can be set are CHAN and TRAIM.  These should be
1111  *	   set correctly by the code examining the @@Cj record, but we bring them out here
1112  *	   to allow the user to override either the # of channels, or the existence of TRAIM.
1113  *	   CHAN expects to be followed by in integer: 6, 8, or 12. TRAIM expects to be
1114  *	   followed by YES or NO.
1115  *
1116  *	There is an optional line with MASK on it followed by one integer field in the
1117  *	   range 0 to 89. This sets the satellite mask angle and will determine the minimum
1118  *	   elevation angle for satellites to be tracked by the receiver. The default value
1119  *	   is 10 deg for the VP and 0 deg for all other receivers.
1120  *
1121  * So acceptable input would be
1122  *	# these are my coordinates (RWC)
1123  *	LON  -106 34.610
1124  *	LAT    35 08.999
1125  *	HT	1589	# could equally well say HT 5215 FT
1126  *	DELAY  60 ns
1127  */
1128 
1129 	FILE	*fd;
1130 	char	*cp, *cc, *ca, line[100], units[2], device[20], Msg[160], **cpp;
1131 	char	*dirs[] = { "/etc/ntp", "/etc", 0 };
1132 	int	i, sign, lat_flg, long_flg, ht_flg, mode, mask;
1133 	double	f1, f2, f3;
1134 
1135 	fd = NULL;	/* just to shutup gcc complaint */
1136 	for (cpp=dirs; *cpp; cpp++) {
1137 		cp = *cpp;
1138 		sprintf(device, "%s/ntp.oncore.%d", cp, instance->unit); /* try "ntp.oncore.0 */
1139 		if ((fd=fopen(device, "r")))
1140 			break;
1141 		sprintf(device, "%s/ntp.oncore%d", cp, instance->unit);  /* try "ntp.oncore0" */
1142 		if ((fd=fopen(device, "r")))
1143 			break;
1144 		sprintf(device, "%s/ntp.oncore", cp);   /* and finally "ntp.oncore" */
1145 		if ((fd=fopen(device, "r")))
1146 			break;
1147 	}
1148 
1149 	if (!fd) {	/* no inputfile, default to the works ... */
1150 		instance->init_type = 4;
1151 		return;
1152 	}
1153 
1154 	mode = mask = 0;
1155 	lat_flg = long_flg = ht_flg = 0;
1156 	while (fgets(line, 100, fd)) {
1157 
1158 		/* Remove comments */
1159 		if ((cp = strchr(line, '#')))
1160 			*cp = '\0';
1161 
1162 		/* Remove trailing space */
1163 		for (i = strlen(line);
1164 		     i > 0 && isascii((int)line[i - 1]) && isspace((int)line[i - 1]);
1165 			)
1166 			line[--i] = '\0';
1167 
1168 		/* Remove leading space */
1169 		for (cc = line; *cc && isascii((int)*cc) && isspace((int)*cc); cc++)
1170 			continue;
1171 
1172 		/* Stop if nothing left */
1173 		if (!*cc)
1174 			continue;
1175 
1176 		/* Uppercase the command and find the arg */
1177 		for (ca = cc; *ca; ca++) {
1178 			if (isascii((int)*ca)) {
1179 				if (islower((int)*ca)) {
1180 					*ca = toupper(*ca);
1181 				} else if (isspace((int)*ca) || (*ca == '='))
1182 					break;
1183 			}
1184 		}
1185 
1186 		/* Remove space (and possible =) leading the arg */
1187 		for (; *ca && isascii((int)*ca) && (isspace((int)*ca) || (*ca == '=')); ca++)
1188 			continue;
1189 
1190 		if (!strncmp(cc, "STATUS", (size_t) 6) || !strncmp(cc, "SHMEM", (size_t) 5)) {
1191 			i = strlen(ca);
1192 			instance->shmem_fname = (char *) malloc((unsigned) (i+1));
1193 			strcpy(instance->shmem_fname, ca);
1194 			continue;
1195 		}
1196 
1197 		/* Uppercase argument as well */
1198 		for (cp = ca; *cp; cp++)
1199 			if (isascii((int)*cp) && islower((int)*cp))
1200 				*cp = toupper(*cp);
1201 
1202 		if (!strncmp(cc, "LAT", (size_t) 3)) {
1203 			f1 = f2 = f3 = 0;
1204 			sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3);
1205 			sign = 1;
1206 			if (f1 < 0) {
1207 				f1 = -f1;
1208 				sign = -1;
1209 			}
1210 			instance->ss_lat = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/
1211 			lat_flg++;
1212 		} else if (!strncmp(cc, "LON", (size_t) 3)) {
1213 			f1 = f2 = f3 = 0;
1214 			sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3);
1215 			sign = 1;
1216 			if (f1 < 0) {
1217 				f1 = -f1;
1218 				sign = -1;
1219 			}
1220 			instance->ss_long = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/
1221 			long_flg++;
1222 		} else if (!strncmp(cc, "HT", (size_t) 2)) {
1223 			f1 = 0;
1224 			units[0] = '\0';
1225 			sscanf(ca, "%lf %1s", &f1, units);
1226 			if (units[0] == 'F')
1227 				f1 = 0.3048 * f1;
1228 			instance->ss_ht = 100 * f1;    /* cm */
1229 			ht_flg++;
1230 		} else if (!strncmp(cc, "DELAY", (size_t) 5)) {
1231 			f1 = 0;
1232 			units[0] = '\0';
1233 			sscanf(ca, "%lf %1s", &f1, units);
1234 			if (units[0] == 'N')
1235 				;
1236 			else if (units[0] == 'U')
1237 				f1 = 1000 * f1;
1238 			else if (units[0] == 'M')
1239 				f1 = 1000000 * f1;
1240 			else
1241 				f1 = 1000000000 * f1;
1242 			if (f1 < 0 || f1 > 1.e9)
1243 				f1 = 0;
1244 			if (f1 < 0 || f1 > 999999) {
1245 				sprintf(Msg, "PPS Cable delay of %fns out of Range, ignored", f1);
1246 				record_clock_stats(&(instance->peer->srcadr), Msg);
1247 			} else
1248 				instance->delay = f1;		/* delay in ns */
1249 		} else if (!strncmp(cc, "OFFSET", (size_t) 6)) {
1250 			f1 = 0;
1251 			units[0] = '\0';
1252 			sscanf(ca, "%lf %1s", &f1, units);
1253 			if (units[0] == 'N')
1254 				;
1255 			else if (units[0] == 'U')
1256 				f1 = 1000 * f1;
1257 			else if (units[0] == 'M')
1258 				f1 = 1000000 * f1;
1259 			else
1260 				f1 = 1000000000 * f1;
1261 			if (f1 < 0 || f1 > 1.e9)
1262 				f1 = 0;
1263 			if (f1 < 0 || f1 > 999999999.) {
1264 				sprintf(Msg, "PPS Offset of %fns out of Range, ignored", f1);
1265 				record_clock_stats(&(instance->peer->srcadr), Msg);
1266 			} else
1267 				instance->offset = f1;		/* offset in ns */
1268 		} else if (!strncmp(cc, "MODE", (size_t) 4)) {
1269 			sscanf(ca, "%d", &mode);
1270 			if (mode < 0 || mode > 4)
1271 				mode = 4;
1272 		} else if (!strncmp(cc, "ASSERT", (size_t) 6)) {
1273 			instance->assert = 1;
1274 		} else if (!strncmp(cc, "CLEAR", (size_t) 5)) {
1275 			instance->assert = 0;
1276 		} else if (!strncmp(cc, "HARDPPS", (size_t) 7)) {
1277 			instance->hardpps = 1;
1278 		} else if (!strncmp(cc, "POSN2D", (size_t) 6)) {
1279 			instance->shmem_Posn = 2;
1280 		} else if (!strncmp(cc, "POSN3D", (size_t) 6)) {
1281 			instance->shmem_Posn = 3;
1282 		} else if (!strncmp(cc, "CHAN", (size_t) 4)) {
1283 			sscanf(ca, "%d", &i);
1284 			if ((i == 6) || (i == 8) || (i == 12))
1285 				instance->chan_in = i;
1286 		} else if (!strncmp(cc, "TRAIM", (size_t) 5)) {
1287 			instance->traim_in = 1; 	/* so TRAIM alone is YES */
1288 			if (!strcmp(ca, "NO") || !strcmp(ca, "OFF"))    /* Yes/No, On/Off */
1289 				instance->traim_in = 0;
1290 		} else if (!strncmp(cc, "MASK", (size_t) 4)) {
1291 			sscanf(ca, "%d", &mask);
1292 			if (mask > -1 && mask < 90)
1293 				instance->Ag = mask;			/* Satellite mask angle */
1294 		}
1295 	}
1296 	fclose(fd);
1297 
1298 	/*
1299 	 *    OK, have read all of data file, and extracted the good stuff.
1300 	 *    If lat/long/ht specified they ALL must be specified for mode = (1,3).
1301 	 */
1302 
1303 	instance->posn_set = 1;
1304 	if (!( lat_flg && long_flg && ht_flg )) {
1305 		printf("ONCORE: incomplete data on %s\n", device);
1306 		instance->posn_set = 0;
1307 		if (mode == 1 || mode == 3) {
1308 			sprintf(Msg, "Input Mode = %d, but no/incomplete position, mode set to %d", mode, mode+1);
1309 			record_clock_stats(&(instance->peer->srcadr), Msg);
1310 			mode++;
1311 		}
1312 	}
1313 	instance->init_type = mode;
1314 
1315 	sprintf(Msg, "Input mode = %d", mode);
1316 	record_clock_stats(&(instance->peer->srcadr), Msg);
1317 }
1318 
1319 
1320 
1321 /*
1322  * move data from NTP to buffer (toss the extra in the unlikely case it won't fit)
1323  */
1324 
1325 static void
1326 oncore_receive(
1327 	struct recvbuf *rbufp
1328 	)
1329 {
1330 	size_t i;
1331 	u_char *p;
1332 	struct peer *peer;
1333 	struct instance *instance;
1334 
1335 	peer = (struct peer *)rbufp->recv_srcclock;
1336 	instance = (struct instance *) peer->procptr->unitptr;
1337 	p = (u_char *) &rbufp->recv_space;
1338 
1339 #if 0
1340 	if (debug > 4) {
1341 		int i;
1342 		printf("ONCORE: >>>");
1343 		for(i=0; i<rbufp->recv_length; i++)
1344 			printf("%02x ", p[i]);
1345 		printf("\n");
1346 		printf("ONCORE: >>>");
1347 		for(i=0; i<rbufp->recv_length; i++)
1348 			printf("%03o ", p[i]);
1349 		printf("\n");
1350 	}
1351 #endif
1352 
1353 	i = rbufp->recv_length;
1354 	if (rcvbuf+rcvptr+i > &rcvbuf[sizeof rcvbuf])
1355 		i = sizeof(rcvbuf) - rcvptr;	/* and some char will be lost */
1356 	memcpy(rcvbuf+rcvptr, p, i);
1357 	rcvptr += i;
1358 	oncore_consume(instance);
1359 }
1360 
1361 
1362 
1363 /*
1364  * Deal with any complete messages
1365  */
1366 
1367 static void
1368 oncore_consume(
1369 	struct instance *instance
1370 	)
1371 {
1372 	int i, m;
1373 	unsigned l;
1374 
1375 	while (rcvptr >= 7) {
1376 		if (rcvbuf[0] != '@' || rcvbuf[1] != '@') {
1377 			/* We're not in sync, lets try to get there */
1378 			for (i=1; i < rcvptr-1; i++)
1379 				if (rcvbuf[i] == '@' && rcvbuf[i+1] == '@')
1380 					break;
1381 #ifdef DEBUG
1382 			if (debug > 4)
1383 				printf("ONCORE[%d]: >>> skipping %d chars\n", instance->unit, i);
1384 #endif
1385 			if (i != rcvptr)
1386 				memcpy(rcvbuf, rcvbuf+i, (size_t)(rcvptr-i));
1387 			rcvptr -= i;
1388 			continue;
1389 		}
1390 
1391 		/* Ok, we have a header now */
1392 		l = sizeof(oncore_messages)/sizeof(oncore_messages[0]) -1;
1393 		for(m=0; m<l; m++)
1394 			if (!strncmp(oncore_messages[m].flag, (char *)(rcvbuf+2), (size_t) 2))
1395 				break;
1396 		if (m == l) {
1397 #ifdef DEBUG
1398 			if (debug > 4)
1399 				printf("ONCORE[%d]: >>> Unknown MSG, skipping 4 (%c%c)\n", instance->unit, rcvbuf[2], rcvbuf[3]);
1400 #endif
1401 			memcpy(rcvbuf, rcvbuf+4, (size_t) 4);
1402 			rcvptr -= 4;
1403 			continue;
1404 		}
1405 
1406 		l = oncore_messages[m].len;
1407 #if 0
1408 		if (debug > 3)
1409 			printf("ONCORE[%d]: GOT: %c%c  %d of %d entry %d\n", instance->unit, rcvbuf[2], rcvbuf[3], rcvptr, l, m);
1410 #endif
1411 		/* Got the entire message ? */
1412 
1413 		if (rcvptr < l)
1414 			return;
1415 
1416 		/* are we at the end of message? should be <Cksum><CR><LF> */
1417 
1418 		if (rcvbuf[l-2] != '\r' || rcvbuf[l-1] != '\n') {
1419 #ifdef DEBUG
1420 			if (debug)
1421 				printf("ONCORE[%d]: NO <CR><LF> at end of message\n", instance->unit);
1422 #endif
1423 		} else {	/* check the CheckSum */
1424 			if (oncore_checksum_ok(rcvbuf, l)) {
1425 				if (instance->shmem != NULL) {
1426 					instance->shmem[oncore_messages[m].shmem + 2]++;
1427 					memcpy(instance->shmem + oncore_messages[m].shmem + 3,
1428 					    rcvbuf, (size_t) l);
1429 				}
1430 				oncore_msg_any(instance, rcvbuf, (size_t) (l-3), m);
1431 				if (oncore_messages[m].handler)
1432 					oncore_messages[m].handler(instance, rcvbuf, (size_t) (l-3));
1433 			}
1434 #ifdef DEBUG
1435 			else if (debug) {
1436 				printf("ONCORE[%d]: Checksum mismatch!\n", instance->unit);
1437 				printf("ONCORE[%d]: @@%c%c ", instance->unit, rcvbuf[2], rcvbuf[3]);
1438 				for (i=4; i<l; i++)
1439 					printf("%03o ", rcvbuf[i]);
1440 				printf("\n");
1441 			}
1442 #endif
1443 		}
1444 
1445 		if (l != rcvptr)
1446 			memcpy(rcvbuf, rcvbuf+l, (size_t) (rcvptr-l));
1447 		rcvptr -= l;
1448 	}
1449 }
1450 
1451 
1452 
1453 static void
1454 oncore_get_timestamp(
1455 	struct instance *instance,
1456 	long dt1,	/* tick offset THIS time step */
1457 	long dt2	/* tick offset NEXT time step */
1458 	)
1459 {
1460 	int	Rsm;
1461 	u_long	j;
1462 	l_fp ts, ts_tmp;
1463 	double dmy;
1464 #ifdef HAVE_STRUCT_TIMESPEC
1465 	struct timespec *tsp = 0;
1466 #else
1467 	struct timeval	*tsp = 0;
1468 #endif
1469 	int	current_mode;
1470 	u_long	i;
1471 	pps_params_t current_params;
1472 	struct timespec timeout;
1473 	pps_info_t pps_i;
1474 
1475 #if 1
1476 	/* If we are in SiteSurvey mode, then we are in 3D mode, and we fall thru.
1477 	 * If we have Finished the SiteSurvey, then we fall thru for the 14/15
1478 	 *  times we get here in 0D mode (the 1/15 is in 3D for SHMEM).
1479 	 * This gives good time, which gets better when the SS is done.
1480 	 */
1481 
1482 	if ((instance->site_survey == ONCORE_SS_DONE) && (instance->mode != MODE_0D))
1483 #else
1484 	/* old check, only fall thru for SS_DONE and 0D mode, 2h45m wait for ticks */
1485 
1486 	if ((instance->site_survey != ONCORE_SS_DONE) || (instance->mode != MODE_0D))
1487 #endif
1488 		return;
1489 
1490 	/* Don't do anything without an almanac to define the GPS->UTC delta */
1491 
1492 	if (instance->rsm.bad_almanac)
1493 		return;
1494 
1495 	/* Once the Almanac is valid, the M12+T does not produce valid UTC
1496 	 * immediately.
1497 	 * Wait for UTC offset decode valid, then wait one message more
1498 	 * so we are not off by 13 seconds after  reset.
1499 	 */
1500 
1501 	if (instance->count5) {
1502 		instance->count5--;
1503 		return;
1504 	}
1505 
1506 	j = instance->ev_serial;
1507 	timeout.tv_sec = 0;
1508 	timeout.tv_nsec = 0;
1509 	if (time_pps_fetch(instance->pps_h, PPS_TSFMT_TSPEC, &pps_i,
1510 	    &timeout) < 0) {
1511 		printf("ONCORE: time_pps_fetch failed\n");
1512 		return;
1513 	}
1514 
1515 	if (instance->assert) {
1516 		tsp = &pps_i.assert_timestamp;
1517 
1518 #ifdef DEBUG
1519 		if (debug > 2) {
1520 			i = (u_long) pps_i.assert_sequence;
1521 # ifdef HAVE_STRUCT_TIMESPEC
1522 			printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%09ld\n",
1523 			    instance->unit, i, j,
1524 			    (long)tsp->tv_sec, (long)tsp->tv_nsec);
1525 # else
1526 			printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%06ld\n",
1527 			    instance->unit, i, j,
1528 			    (long)tsp->tv_sec, (long)tsp->tv_usec);
1529 # endif
1530 		}
1531 #endif
1532 
1533 		if (pps_i.assert_sequence == j) {
1534 			printf("ONCORE: oncore_get_timestamp, error serial pps\n");
1535 			return;
1536 		}
1537 		instance->ev_serial = pps_i.assert_sequence;
1538 	} else {
1539 		tsp = &pps_i.clear_timestamp;
1540 
1541 #ifdef DEBUG
1542 		if (debug > 2) {
1543 			i = (u_long) pps_i.clear_sequence;
1544 # ifdef HAVE_STRUCT_TIMESPEC
1545 			printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%09ld\n",
1546 			    instance->unit, i, j, (long)tsp->tv_sec, (long)tsp->tv_nsec);
1547 # else
1548 			printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%06ld\n",
1549 			    instance->unit, i, j, (long)tsp->tv_sec, (long)tsp->tv_usec);
1550 # endif
1551 		}
1552 #endif
1553 
1554 		if (pps_i.clear_sequence == j) {
1555 			printf("ONCORE: oncore_get_timestamp, error serial pps\n");
1556 			return;
1557 		}
1558 		instance->ev_serial = pps_i.clear_sequence;
1559 	}
1560 
1561 	/* convert timespec -> ntp l_fp */
1562 
1563 	dmy = tsp->tv_nsec;
1564 	dmy /= 1e9;
1565 	ts.l_uf = dmy * 4294967296.0;
1566 	ts.l_ui = tsp->tv_sec;
1567 
1568 #if 0
1569      alternate code for previous 4 lines is
1570 	dmy = 1.0e-9*tsp->tv_nsec;	/* fractional part */
1571 	DTOLFP(dmy, &ts);
1572 	dmy = tsp->tv_sec;		/* integer part */
1573 	DTOLFP(dmy, &ts_tmp);
1574 	L_ADD(&ts, &ts_tmp);
1575      or more simply
1576 	dmy = 1.0e-9*tsp->tv_nsec;	/* fractional part */
1577 	DTOLFP(dmy, &ts);
1578 	ts.l_ui = tsp->tv_sec;
1579 #endif	/* 0 */
1580 
1581 	/* now have timestamp in ts */
1582 	/* add in saw_tooth and offset, these will be ZERO if no TRAIM */
1583 	/* they will be IGNORED if the PPSAPI cant do PPS_OFFSET/ASSERT/CLEAR */
1584 	/* we just try to add them in and dont test for that here */
1585 
1586 	/* saw_tooth not really necessary if using TIMEVAL */
1587 	/* since its only precise to us, but do it anyway. */
1588 
1589 	/* offset in ns, and is positive (late), we subtract */
1590 	/* to put the PPS time transition back where it belongs */
1591 
1592 	/* must hand the offset for the NEXT sec off to the Kernel to do */
1593 	/* the addition, so that the Kernel PLL sees the offset too */
1594 
1595 	if (instance->assert)
1596 		instance->pps_p.assert_offset.tv_nsec = -dt2;
1597 	else
1598 		instance->pps_p.clear_offset.tv_nsec  = -dt2;
1599 
1600 	/* The following code is necessary, and not just a time_pps_setparams,
1601 	 * using the saved instance->pps_p, since some other process on the
1602 	 * machine may have diddled with the mode bits (say adding something
1603 	 * that it needs).  We take what is there and ADD what we need.
1604 	 * [[ The results from the time_pps_getcap is unlikely to change so
1605 	 *    we could probably just save it, but I choose to do the call ]]
1606 	 * Unfortunately, there is only ONE set of mode bits in the kernel per
1607 	 * interface, and not one set for each open handle.
1608 	 *
1609 	 * There is still a race condition here where we might mess up someone
1610 	 * elses mode, but if he is being careful too, he should survive.
1611 	 */
1612 
1613 	if (time_pps_getcap(instance->pps_h, &current_mode) < 0) {
1614 		msyslog(LOG_ERR, "time_pps_getcap failed: %m");
1615 		return;
1616 	}
1617 
1618 	if (time_pps_getparams(instance->pps_h, &current_params) < 0) {
1619 		msyslog(LOG_ERR, "time_pps_getparams failed: %m");
1620 		return;
1621 	}
1622 
1623 		/* or current and mine */
1624 	current_params.mode |= instance->pps_p.mode;
1625 		/* but only set whats legal */
1626 	current_params.mode &= current_mode;
1627 
1628 	current_params.assert_offset.tv_sec = 0;
1629 	current_params.assert_offset.tv_nsec = -dt2;
1630 	current_params.clear_offset.tv_sec = 0;
1631 	current_params.clear_offset.tv_nsec = -dt2;
1632 
1633 	if (time_pps_setparams(instance->pps_h, &current_params))
1634 		record_clock_stats(&(instance->peer->srcadr), "ONCORE: Error doing time_pps_setparams");
1635 
1636 	/* have time from UNIX origin, convert to NTP origin. */
1637 
1638 	ts.l_ui += JAN_1970;
1639 	instance->pp->lastrec = ts;
1640 
1641 	/* print out information about this timestamp (long line) */
1642 
1643 	ts_tmp = ts;
1644 	ts_tmp.l_ui = 0;	/* zero integer part */
1645 	LFPTOD(&ts_tmp, dmy);	/* convert fractional part to a double */
1646 	j = 1.0e9*dmy;		/* then to integer ns */
1647 
1648 	Rsm = 0;
1649 	if (instance->chan == 6)
1650 		Rsm = instance->BEHa[64];
1651 	else if (instance->chan == 8)
1652 		Rsm = instance->BEHa[72];
1653 	else if (instance->chan == 12)
1654 		Rsm = ((instance->BEHa[129]<<8) | instance->BEHa[130]);
1655 
1656 	if (instance->chan == 6 || instance->chan == 8) {
1657 		char	f1[5], f2[5], f3[5], f4[5];
1658 		if (instance->traim) {
1659 			sprintf(f1, "%d", instance->BEHn[21]);
1660 			sprintf(f2, "%d", instance->BEHn[22]);
1661 			sprintf(f3, "%2d", instance->BEHn[23]*256+instance->BEHn[24]);
1662 			sprintf(f4, "%3d", (s_char) instance->BEHn[25]);
1663 		} else {
1664 			strcpy(f1, "x");
1665 			strcpy(f2, "x");
1666 			strcpy(f3, "xx");
1667 			strcpy(f4, "xxx");
1668 		}
1669 		sprintf(instance->pp->a_lastcode,	/* MAX length 128, currently at 121 */
1670  "%u.%09lu %d %d %2d %2d %2d %2ld rstat   %02x dop %4.1f nsat %2d,%d traim %d,%s,%s sigma %s neg-sawtooth %s sat %d%d%d%d%d%d%d%d",
1671 		    ts.l_ui, j,
1672 		    instance->pp->year, instance->pp->day,
1673 		    instance->pp->hour, instance->pp->minute, instance->pp->second,
1674 		    (long) tsp->tv_sec % 60,
1675 		    Rsm, 0.1*(256*instance->BEHa[35]+instance->BEHa[36]),
1676 		    /*rsat	dop */
1677 		    instance->BEHa[38], instance->BEHa[39], instance->traim, f1, f2,
1678 		    /*	nsat visible,	  nsat tracked,     traim,traim,traim */
1679 		    f3, f4,
1680 		    /* sigma neg-sawtooth */
1681 	  /*sat*/   instance->BEHa[41], instance->BEHa[45], instance->BEHa[49], instance->BEHa[53],
1682 		    instance->BEHa[57], instance->BEHa[61], instance->BEHa[65], instance->BEHa[69]
1683 		    );					/* will be 0 for 6 chan */
1684 	} else if (instance->chan == 12) {
1685 		char	f1[5], f2[5], f3[5], f4[5];
1686 		if (instance->traim) {
1687 			sprintf(f1, "%d", instance->BEHn[6]);
1688 			sprintf(f2, "%d", instance->BEHn[7]);
1689 			sprintf(f3, "%d", instance->BEHn[12]*256+instance->BEHn[13]);
1690 			sprintf(f4, "%3d", (s_char) instance->BEHn[14]);
1691 		} else {
1692 			strcpy(f1, "x");
1693 			strcpy(f2, "x");
1694 			strcpy(f3, "x");
1695 			strcpy(f4, "xxx");
1696 		}
1697 		sprintf(instance->pp->a_lastcode,
1698  "%u.%09lu %d %d %2d %2d %2d %2ld rstat %02x dop %4.1f nsat %2d,%d traim %d,%s,%s sigma %s neg-sawtooth %s sat %d%d%d%d%d%d%d%d%d%d%d%d",
1699 		    ts.l_ui, j,
1700 		    instance->pp->year, instance->pp->day,
1701 		    instance->pp->hour, instance->pp->minute, instance->pp->second,
1702 		    (long) tsp->tv_sec % 60,
1703 		    Rsm, 0.1*(256*instance->BEHa[53]+instance->BEHa[54]),
1704 		    /*rsat	dop */
1705 		    instance->BEHa[55], instance->BEHa[56], instance->traim, f1, f2,
1706 		    /*	nsat visible,	  nsat tracked	 traim,traim,traim */
1707 		    f3, f4,
1708 		    /* sigma neg-sawtooth */
1709 	  /*sat*/   instance->BEHa[58], instance->BEHa[64], instance->BEHa[70], instance->BEHa[76],
1710 		    instance->BEHa[82], instance->BEHa[88], instance->BEHa[94], instance->BEHa[100],
1711 		    instance->BEHa[106], instance->BEHa[112], instance->BEHa[118], instance->BEHa[124]
1712 		    );
1713 	}
1714 
1715 #ifdef DEBUG
1716 	if (debug > 2) {
1717 		int n;
1718 
1719 		n = strlen(instance->pp->a_lastcode);
1720 		printf("ONCORE[%d]: len = %d %s\n", instance->unit, n, instance->pp->a_lastcode);
1721 	}
1722 #endif
1723 
1724 	/* and some things I dont understand (magic ntp things) */
1725 
1726 	if (!refclock_process(instance->pp)) {
1727 		refclock_report(instance->peer, CEVNT_BADTIME);
1728 		return;
1729 	}
1730 
1731 	record_clock_stats(&(instance->peer->srcadr), instance->pp->a_lastcode);
1732 	instance->pollcnt = 2;
1733 
1734 	if (instance->polled) {
1735 		instance->polled = 0;
1736 	     /* instance->pp->dispersion = instance->pp->skew = 0;	*/
1737 		instance->pp->lastref = instance->pp->lastrec;
1738 		refclock_receive(instance->peer);
1739 	}
1740 }
1741 
1742 
1743 /*************** oncore_msg_XX routines start here *******************/
1744 
1745 
1746 /*
1747  * print Oncore response message.
1748  */
1749 
1750 static void
1751 oncore_msg_any(
1752 	struct instance *instance,
1753 	u_char *buf,
1754 	size_t len,
1755 	int idx
1756 	)
1757 {
1758 	int i;
1759 	const char *fmt = oncore_messages[idx].fmt;
1760 	const char *p;
1761 #ifdef HAVE_GETCLOCK
1762 	struct timespec ts;
1763 #endif
1764 	struct timeval tv;
1765 
1766 #ifdef DEBUG
1767 	if (debug > 3) {
1768 # ifdef HAVE_GETCLOCK
1769 		(void) getclock(TIMEOFDAY, &ts);
1770 		tv.tv_sec = ts.tv_sec;
1771 		tv.tv_usec = ts.tv_nsec / 1000;
1772 # else
1773 		GETTIMEOFDAY(&tv, 0);
1774 # endif
1775 		printf("ONCORE[%d]: %ld.%06ld\n", instance->unit, (long) tv.tv_sec, (long) tv.tv_usec);
1776 
1777 		if (!*fmt) {
1778 			printf(">>@@%c%c ", buf[2], buf[3]);
1779 			for(i=2; i < len && i < 2400 ; i++)
1780 				printf("%02x", buf[i]);
1781 			printf("\n");
1782 			return;
1783 		} else {
1784 			printf("##");
1785 			for (p = fmt; *p; p++) {
1786 				putchar(*p);
1787 				putchar('_');
1788 			}
1789 			printf("\n%c%c", buf[2], buf[3]);
1790 			i = 4;
1791 			for (p = fmt; *p; p++) {
1792 				printf("%02x", buf[i++]);
1793 			}
1794 			printf("\n");
1795 		}
1796 	}
1797 #endif
1798 }
1799 
1800 
1801 
1802 /* Latitude, Longitude, Height */
1803 
1804 static void
1805 oncore_msg_Adef(
1806 	struct instance *instance,
1807 	u_char *buf,
1808 	size_t len
1809 	)
1810 {
1811 }
1812 
1813 
1814 
1815 /* Mask Angle */
1816 
1817 static void
1818 oncore_msg_Ag(
1819 	struct instance *instance,
1820 	u_char *buf,
1821 	size_t len
1822 	)
1823 {		char  Msg[160], *cp;
1824 
1825 		cp = "set to";
1826 		if (instance->o_state == ONCORE_RUN)
1827 			cp = "is";
1828 
1829 		instance->Ag = buf[4];
1830 		sprintf(Msg, "Satellite mask angle %s %d degrees", cp, (int) instance->Ag);
1831 		record_clock_stats(&(instance->peer->srcadr), Msg);
1832 }
1833 
1834 
1835 
1836 /*
1837  * get Position hold position
1838  */
1839 
1840 static void
1841 oncore_msg_As(
1842 	struct instance *instance,
1843 	u_char *buf,
1844 	size_t len
1845 	)
1846 {
1847 	instance->ss_lat  = buf_w32(&buf[4]);
1848 	instance->ss_long = buf_w32(&buf[8]);
1849 	instance->ss_ht   = buf_w32(&buf[12]);
1850 
1851 	/* Print out Position */
1852 	oncore_print_posn(instance);
1853 }
1854 
1855 
1856 
1857 /*
1858  * Try to use Oncore UT+ Auto Survey Feature
1859  *	If its not there (VP), set flag to do it ourselves.
1860  */
1861 
1862 static void
1863 oncore_msg_At(
1864 	struct instance *instance,
1865 	u_char *buf,
1866 	size_t len
1867 	)
1868 {
1869 	char	*cp;
1870 
1871 	instance->saw_At = 1;
1872 	if (instance->site_survey == ONCORE_SS_TESTING) {
1873 		if (buf[4] == 2) {
1874 			record_clock_stats(&(instance->peer->srcadr),
1875 					"Initiating hardware 3D site survey");
1876 
1877 			cp = "SSstate = ONCORE_SS_HW";
1878 			record_clock_stats(&(instance->peer->srcadr), cp);
1879 			instance->site_survey = ONCORE_SS_HW;
1880 		}
1881 	}
1882 }
1883 
1884 
1885 
1886 /*
1887  * get PPS Offset
1888  * Nb. @@Ay is not supported for early UT (no plus) model
1889  */
1890 
1891 static void
1892 oncore_msg_Ay(
1893 	struct instance *instance,
1894 	u_char *buf,
1895 	size_t len
1896 	)
1897 {
1898 	char Msg[120];
1899 
1900 	if (instance->saw_Ay)
1901 		return;
1902 
1903 	instance->saw_Ay = 1;
1904 
1905 	instance->offset = buf_w32(&buf[4]);
1906 
1907 	sprintf(Msg, "PPS Offset is set to %ld ns", instance->offset);
1908 	record_clock_stats(&(instance->peer->srcadr), Msg);
1909 }
1910 
1911 
1912 
1913 /*
1914  * get Cable Delay
1915  */
1916 
1917 static void
1918 oncore_msg_Az(
1919 	struct instance *instance,
1920 	u_char *buf,
1921 	size_t len
1922 	)
1923 {
1924 	char Msg[120];
1925 
1926 	if (instance->saw_Az)
1927 		return;
1928 
1929 	instance->saw_Az = 1;
1930 
1931 	instance->delay = buf_w32(&buf[4]);
1932 
1933 	sprintf(Msg, "Cable delay is set to %ld ns", instance->delay);
1934 	record_clock_stats(&(instance->peer->srcadr), Msg);
1935 }
1936 
1937 
1938 
1939 /* Ba, Ea and Ha come here, these contain Position */
1940 
1941 static void
1942 oncore_msg_BaEaHa(
1943 	struct instance *instance,
1944 	u_char *buf,
1945 	size_t len
1946 	)
1947 {
1948 	const char	*cp;
1949 	char		Msg[160];
1950 	int		mode;
1951 
1952 	/* OK, we are close to the RUN state now.
1953 	 * But we have a few more items to initialize first.
1954 	 *
1955 	 * At the beginning of this routine there are several 'timers'.
1956 	 * We enter this routine 1/sec, and since the upper levels of NTP have usurped
1957 	 * the use of timers, we use the 1/sec entry to do things that
1958 	 * we would normally do with timers...
1959 	 */
1960 
1961 	if (instance->o_state == ONCORE_CHECK_CHAN) {	/* here while checking for the # chan */
1962 		if (buf[2] == 'B') {		/* 6chan */
1963 			if (instance->chan_ck < 6) instance->chan_ck = 6;
1964 		} else if (buf[2] == 'E') {	/* 8chan */
1965 			if (instance->chan_ck < 8) instance->chan_ck = 8;
1966 		} else if (buf[2] == 'H') {	/* 12chan */
1967 			if (instance->chan_ck < 12) instance->chan_ck = 12;
1968 		}
1969 
1970 		if (instance->count3++ < 5)
1971 			return;
1972 
1973 		instance->count3 = 0;
1974 
1975 		if (instance->chan_in != -1)	/* set in Input */
1976 			instance->chan = instance->chan_in;
1977 		else				/* set from test */
1978 			instance->chan = instance->chan_ck;
1979 
1980 		sprintf(Msg, "Input   says chan = %d", instance->chan_in);
1981 		record_clock_stats(&(instance->peer->srcadr), Msg);
1982 		sprintf(Msg, "Model # says chan = %d", instance->chan_id);
1983 		record_clock_stats(&(instance->peer->srcadr), Msg);
1984 		sprintf(Msg, "Testing says chan = %d", instance->chan_ck);
1985 		record_clock_stats(&(instance->peer->srcadr), Msg);
1986 		sprintf(Msg, "Using        chan = %d", instance->chan);
1987 		record_clock_stats(&(instance->peer->srcadr), Msg);
1988 
1989 		instance->o_state = ONCORE_HAVE_CHAN;
1990 		cp = "state = ONCORE_HAVE_CHAN";
1991 		record_clock_stats(&(instance->peer->srcadr), cp);
1992 
1993 		instance->timeout = 4;
1994 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
1995 		return;
1996 	}
1997 
1998 	if (instance->o_state != ONCORE_ALMANAC && instance->o_state != ONCORE_RUN)
1999 		return;
2000 
2001 	/* PAUSE 5sec - make sure results are stable, before using position */
2002 
2003 	if (instance->count) {
2004 		if (instance->count++ < 5)
2005 			return;
2006 		instance->count = 0;
2007 	}
2008 
2009 	memcpy(instance->BEHa, buf, (size_t) (len+3));	/* Ba, Ea or Ha */
2010 
2011 	/* check the antenna (did it get unplugged) and almanac (is it ready) for changes. */
2012 
2013 	oncore_check_almanac(instance);
2014 	oncore_check_antenna(instance);
2015 
2016 	/* If we are in Almanac mode, waiting for Almanac, we can't do anything till we have it */
2017 	/* When we have an almanac, we will start the Bn/En/@@Hn messages */
2018 
2019 	if (instance->o_state == ONCORE_ALMANAC)
2020 		if (oncore_wait_almanac(instance))
2021 			return;
2022 
2023 	/* do some things once when we get this far in BaEaHa */
2024 
2025 	if (instance->once) {
2026 		instance->once = 0;
2027 		instance->count2 = 1;
2028 
2029 		/* Have we seen an @@At (position hold) command response */
2030 		/* if not, message out */
2031 
2032 		if (instance->chan != 12 && !instance->saw_At) {
2033 			cp = "Not Good, no @@At command (no Position Hold), must be a GT/GT+";
2034 			record_clock_stats(&(instance->peer->srcadr), cp);
2035 			oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1));
2036 		}
2037 
2038 		/* have an Almanac, can start the SiteSurvey
2039 		 * (actually only need to get past the almanac_load where we diddle with At
2040 		 *  command,- we can't change it after we start the HW_SS below
2041 		 */
2042 
2043 		mode = instance->init_type;
2044 		switch (mode) {
2045 		case 0: /* NO initialization, don't change anything */
2046 		case 1: /* Use given Position */
2047 		case 3:
2048 			instance->site_survey = ONCORE_SS_DONE;
2049 			cp = "SSstate = ONCORE_SS_DONE";
2050 			record_clock_stats(&(instance->peer->srcadr), cp);
2051 			break;
2052 
2053 		case 2:
2054 		case 4: /* Site Survey */
2055 			cp = "SSstate = ONCORE_SS_TESTING";
2056 			record_clock_stats(&(instance->peer->srcadr), cp);
2057 			instance->site_survey = ONCORE_SS_TESTING;
2058 			instance->count1 = 1;
2059 			if (instance->chan == 12)
2060 				oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd3,  sizeof(oncore_cmd_Gd3));  /* M12+T */
2061 			else
2062 				oncore_sendmsg(instance->ttyfd, oncore_cmd_At2,  sizeof(oncore_cmd_At2));  /* not GT, arg not VP */
2063 			break;
2064 		}
2065 
2066 		/* Read back PPS Offset for Output */
2067 		/* Nb. This will fail silently for early UT (no plus) and M12 models */
2068 
2069 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Ayx,  sizeof(oncore_cmd_Ayx));
2070 
2071 		/* Read back Cable Delay for Output */
2072 
2073 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Azx,  sizeof(oncore_cmd_Azx));
2074 
2075 		/* Read back Satellite Mask Angle for Output */
2076 
2077 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Agx,  sizeof(oncore_cmd_Agx));
2078 	}
2079 
2080 
2081 	/* Unfortunately, the Gd3 command returns '3' for the M12 v1.3 firmware where it is
2082 	 * out-of-range and it should return 0-2. (v1.3 can't do a HW Site Survey)
2083 	 * We must do the Gd3, and then wait a cycle or two for things to settle,
2084 	 * then check Ha[130]&0x10 to see if a SS is in progress.
2085 	 * We will set SW if HW has not been set after an appropriate delay.
2086 	 */
2087 
2088 	if (instance->site_survey == ONCORE_SS_TESTING) {
2089 		if (instance->chan == 12) {
2090 			if (instance->count1) {
2091 				if (instance->count1++ > 5 || instance->BEHa[130]&0x10) {
2092 					instance->count1 = 0;
2093 					if (instance->BEHa[130]&0x10) {
2094 						record_clock_stats(&(instance->peer->srcadr),
2095 								"Initiating hardware 3D site survey");
2096 
2097 						record_clock_stats(&(instance->peer->srcadr), "SSstate = ONCORE_SS_HW");
2098 						instance->site_survey = ONCORE_SS_HW;
2099 					} else {
2100 						record_clock_stats(&(instance->peer->srcadr), "SSstate = ONCORE_SS_SW");
2101 						instance->site_survey = ONCORE_SS_SW;
2102 					}
2103 				}
2104 			}
2105 		} else {
2106 			if (instance->count1) {
2107 				if (instance->count1++ > 5) {
2108 					instance->count1 = 0;
2109 					/*
2110 					 * For instance->site_survey to still be ONCORE_SS_TESTING, then after a 5sec
2111 					 * wait after the @@At2/@@Gd3 command we have not changed the state to
2112 					 * ONCORE_SS_HW.  If the Hardware is capable of doing a Site Survey, then
2113 					 * the variable would have been changed by now.
2114 					 * There are three possibilities:
2115 					 * 6/8chan
2116 					 *   (a) We did not get a response to the @@At0 or @@At2 commands,
2117 					 *	   and it must be a GT/GT+/SL with no position hold mode.
2118 					 *	   We will have to do it ourselves.
2119 					 *   (b) We saw the @@At0, @@At2 commands, but @@At2 failed,
2120 					 *	   must be a VP or older UT which doesn't have Site Survey mode.
2121 					 *	   We will have to do it ourselves.
2122 					 * 12chan
2123 					 *   (c) We saw the @@Gd command, and saw H[13]*0x10
2124 					 *	   We will have to do it ourselves (done above)
2125 					 */
2126 
2127 					sprintf(Msg, "Initiating software 3D site survey (%d samples)",
2128 						POS_HOLD_AVERAGE);
2129 					record_clock_stats(&(instance->peer->srcadr), Msg);
2130 
2131 					record_clock_stats(&(instance->peer->srcadr), "SSstate = ONCORE_SS_SW");
2132 					instance->site_survey = ONCORE_SS_SW;
2133 
2134 					instance->ss_lat = instance->ss_long = instance->ss_ht = 0;
2135 					if (instance->chan == 12)
2136 						oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* disable */
2137 					else {
2138 						oncore_sendmsg(instance->ttyfd, oncore_cmd_At0, sizeof(oncore_cmd_At0)); /* disable */
2139 						oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); /* disable */
2140 					}
2141 				}
2142 			}
2143 		}
2144 	}
2145 
2146 	/* check the mode we are in 0/2/3D */
2147 
2148 	if (instance->chan == 6) {
2149 		if (instance->BEHa[64]&0x8)
2150 			instance->mode = MODE_0D;
2151 		else if (instance->BEHa[64]&0x10)
2152 			instance->mode = MODE_2D;
2153 		else if (instance->BEHa[64]&0x20)
2154 			instance->mode = MODE_3D;
2155 	} else if (instance->chan == 8) {
2156 		if (instance->BEHa[72]&0x8)
2157 			instance->mode = MODE_0D;
2158 		else if (instance->BEHa[72]&0x10)
2159 			instance->mode = MODE_2D;
2160 		else if (instance->BEHa[72]&0x20)
2161 			instance->mode = MODE_3D;
2162 	} else if (instance->chan == 12) {
2163 		int bits;
2164 
2165 		bits = (instance->BEHa[129]>>5) & 0x7;	/* actually Ha */
2166 		if (bits == 0x4)
2167 			instance->mode = MODE_0D;
2168 		else if (bits == 0x6)
2169 			instance->mode = MODE_2D;
2170 		else if (bits == 0x7)
2171 			instance->mode = MODE_3D;
2172 	}
2173 
2174 	/* copy the record to the (extra) location in SHMEM */
2175 
2176 	if (instance->shmem) {
2177 		int	i;
2178 		u_char	*smp;	 /* pointer to start of shared mem for Ba/Ea/Ha */
2179 
2180 		switch(instance->chan) {
2181 		case 6:   smp = &instance->shmem[instance->shmem_Ba]; break;
2182 		case 8:   smp = &instance->shmem[instance->shmem_Ea]; break;
2183 		case 12:  smp = &instance->shmem[instance->shmem_Ha]; break;
2184 		default:  smp = (u_char *) NULL;		      break;
2185 		}
2186 
2187 		switch (instance->mode) {
2188 		case MODE_0D:	i = 1; break;	/* 0D, Position Hold */
2189 		case MODE_2D:	i = 2; break;	/* 2D, Altitude Hold */
2190 		case MODE_3D:	i = 3; break;	/* 3D fix */
2191 		default:	i = 0; break;
2192 		}
2193 
2194 		if (i && smp != NULL) {
2195 			i *= (len+6);
2196 			smp[i + 2]++;
2197 			memcpy(&smp[i+3], buf, (size_t) (len+3));
2198 		}
2199 	}
2200 
2201 	/*
2202 	 * check if traim timer active
2203 	 * if it hasn't been cleared, then @@Bn/@@En/@@Hn did not respond
2204 	 */
2205 
2206 	if (instance->traim_delay) {
2207 		if (instance->traim_delay++ > 5) {
2208 			instance->traim = 0;
2209 			instance->traim_delay = 0;
2210 			cp = "ONCORE: Did not detect TRAIM response, TRAIM = OFF";
2211 			record_clock_stats(&(instance->peer->srcadr), cp);
2212 
2213 			oncore_set_traim(instance);
2214 		} else
2215 			return;
2216 
2217 	}
2218 
2219 	/* by now should have a @@Ba/@@Ea/@@Ha with good data in it */
2220 
2221 	if (!instance->have_dH && !instance->traim_delay)
2222 		oncore_compute_dH(instance);
2223 
2224 	/*
2225 	 * must be ONCORE_RUN if we are here.
2226 	 * Have # chan and TRAIM by now.
2227 	 */
2228 
2229 	instance->pp->year   = buf[6]*256+buf[7];
2230 	instance->pp->day    = ymd2yd(buf[6]*256+buf[7], buf[4], buf[5]);
2231 	instance->pp->hour   = buf[8];
2232 	instance->pp->minute = buf[9];
2233 	instance->pp->second = buf[10];
2234 
2235 	/*
2236 	 * Are we doing a Hardware or Software Site Survey?
2237 	 */
2238 
2239 	if (instance->site_survey == ONCORE_SS_HW || instance->site_survey == ONCORE_SS_SW)
2240 		oncore_ss(instance);
2241 
2242 	/* see if we ever saw a response from the @@Ayx above */
2243 
2244 	if (instance->count2) {
2245 		if (instance->count2++ > 5) {	/* this delay to check on @@Ay command */
2246 			instance->count2 = 0;
2247 
2248 			/* Have we seen an Ay (1PPS time offset) command response */
2249 			/* if not, and non-zero offset, zero the offset, and send message */
2250 
2251 			if (!instance->saw_Ay && instance->offset) {
2252 				cp = "No @@Ay command, PPS OFFSET ignored";
2253 				record_clock_stats(&(instance->peer->srcadr), cp);
2254 				instance->offset = 0;
2255 			}
2256 		}
2257 	}
2258 
2259 	/*
2260 	 * Check the leap second status once per day.
2261 	 */
2262 
2263 	oncore_check_leap_sec(instance);
2264 
2265 	/*
2266 	 * if SHMEM active, every 15s, steal one 'tick' to get 2D or 3D posn.
2267 	 */
2268 
2269 	if (instance->shmem && !instance->shmem_bad_Ea && instance->shmem_Posn && (instance->site_survey == ONCORE_SS_DONE))
2270 		oncore_shmem_get_3D(instance);
2271 
2272 	if (!instance->traim)	/* NO traim, no BnEnHn, go get tick */
2273 		oncore_get_timestamp(instance, instance->offset, instance->offset);
2274 }
2275 
2276 
2277 
2278 /* Almanac Status */
2279 
2280 static void
2281 oncore_msg_Bd(
2282 	struct instance *instance,
2283 	u_char *buf,
2284 	size_t len
2285 	)
2286 {
2287 	char Msg[160];
2288 
2289 	sprintf(Msg, "Bd: Almanac %s, week = %d, t = %d, %d SVs: %x",
2290 		((buf[4]) ? "LOADED" : "(NONE)"), buf[5], buf[6], buf[7], w32(&buf[8]) );
2291 	record_clock_stats(&(instance->peer->srcadr), Msg);
2292 }
2293 
2294 
2295 
2296 /* get leap-second warning message */
2297 
2298 /*
2299  * @@Bj does NOT behave as documented in current Oncore firmware.
2300  * It turns on the LEAP indicator when the data is set, and does not,
2301  * as documented, wait until the beginning of the month when the
2302  * leap second will occur.
2303  * Since this firmware bug will never be fixed in all the outstanding Oncore receivers
2304  * @@Bj is only called in June/December.
2305  */
2306 
2307 static void
2308 oncore_msg_Bj(
2309 	struct instance *instance,
2310 	u_char *buf,
2311 	size_t len
2312 	)
2313 {
2314 	const char	*cp;
2315 
2316 	switch(buf[4]) {
2317 	case 1:
2318 		instance->pp->leap = LEAP_ADDSECOND;
2319 		cp = "Set pp.leap to LEAP_ADDSECOND";
2320 		break;
2321 	case 2:
2322 		instance->pp->leap = LEAP_DELSECOND;
2323 		cp = "Set pp.leap to LEAP_DELSECOND";
2324 		break;
2325 	case 0:
2326 	default:
2327 		instance->pp->leap = LEAP_NOWARNING;
2328 		cp = "Set pp.leap to LEAP_NOWARNING";
2329 		break;
2330 	}
2331 	record_clock_stats(&(instance->peer->srcadr), cp);
2332 }
2333 
2334 
2335 
2336 static void
2337 oncore_msg_BnEnHn(
2338 	struct instance *instance,
2339 	u_char *buf,
2340 	size_t	len
2341 	)
2342 {
2343 	long	dt1, dt2;
2344 	char	*cp;
2345 
2346 	if (instance->o_state != ONCORE_RUN)
2347 		return;
2348 
2349 	if (instance->traim_delay) {	 /* flag that @@Bn/@@En/Hn returned */
2350 			instance->traim_ck = 1;
2351 			instance->traim_delay = 0;
2352 			cp = "ONCORE: Detected TRAIM, TRAIM = ON";
2353 			record_clock_stats(&(instance->peer->srcadr), cp);
2354 
2355 			oncore_set_traim(instance);
2356 	}
2357 
2358 	memcpy(instance->BEHn, buf, (size_t) len);	/* Bn or En or Hn */
2359 
2360 	if (!instance->traim)	/* BnEnHn will be turned off in any case */
2361 		return;
2362 
2363 	/* If Time RAIM doesn't like it, don't trust it */
2364 
2365 	if (buf[2] == 'H') {
2366 		if (instance->BEHn[6])	/* bad TRAIM */
2367 			return;
2368 
2369 		dt1 = instance->saw_tooth + instance->offset;	 /* dt this time step */
2370 		instance->saw_tooth = (s_char) instance->BEHn[14]; /* update for next time Hn[14] */
2371 		dt2 = instance->saw_tooth + instance->offset;	 /* dt next time step */
2372 	} else {
2373 		if (instance->BEHn[21]) /* bad TRAIM */
2374 			return;
2375 
2376 		dt1 = instance->saw_tooth + instance->offset;	 /* dt this time step */
2377 		instance->saw_tooth = (s_char) instance->BEHn[25]; /* update for next time Bn[25], En[25] */
2378 		dt2 = instance->saw_tooth + instance->offset;	 /* dt next time step */
2379 	}
2380 
2381 	oncore_get_timestamp(instance, dt1, dt2);
2382 }
2383 
2384 
2385 
2386 /* Here for @@Ca, @@Fa and @@Ia messages */
2387 
2388 /* These are Self test Commands for 6, 8, and 12 chan receivers.
2389  * There are good reasons NOT to do a @@Ca, @@Fa or @@Ia command with the ONCORE.
2390  * It was found that under some circumstances the following
2391  * command would fail if issued immediately after the return from the
2392  * @@Fa, but a 2sec delay seemed to fix things.  Since simply calling
2393  * sleep(2) is wasteful, and may cause trouble for some OS's, repeating
2394  * itimer, we set a flag, and test it at the next POLL.  If it hasn't
2395  * been cleared, we reissue the @@Cj that is issued below.
2396  * Note that we do a @@Cj at the beginning, and again here.
2397  * The first is to get the info, the 2nd is just used as a safe command
2398  * after the @@Fa for all Oncores (and it was in this posn in the
2399  * original code).
2400  */
2401 
2402 static void
2403 oncore_msg_CaFaIa(
2404 	struct instance *instance,
2405 	u_char *buf,
2406 	size_t len
2407 	)
2408 {
2409 	char *cp;
2410 	int	i;
2411 
2412 	if (instance->o_state == ONCORE_TEST_SENT) {
2413 		enum antenna_state antenna;
2414 
2415 		instance->timeout = 0;
2416 
2417 #ifdef DEBUG
2418 		if (debug > 2) {
2419 			if (buf[2] == 'I')
2420 				printf("ONCORE[%d]: >>@@%ca %x %x %x\n", instance->unit, buf[2], buf[4], buf[5], buf[6]);
2421 			else
2422 				printf("ONCORE[%d]: >>@@%ca %x %x\n", instance->unit, buf[2], buf[4], buf[5]);
2423 		}
2424 #endif
2425 
2426 		antenna = (buf[4] & 0xc0) >> 6;
2427 		buf[4] &= ~0xc0;
2428 
2429 		i = buf[4] || buf[5];
2430 		if (buf[2] == 'I') i = i || buf[6];
2431 		if (i) {
2432 			if (buf[2] == 'I') {
2433 				msyslog(LOG_ERR, "ONCORE[%d]: self test failed: result %02x %02x %02x",
2434 					instance->unit, buf[4], buf[5], buf[6]);
2435 			} else {
2436 				msyslog(LOG_ERR, "ONCORE[%d]: self test failed: result %02x %02x",
2437 					instance->unit, buf[4], buf[5]);
2438 			}
2439 			cp = "ONCORE: self test failed, shutting down driver";
2440 			record_clock_stats(&instance->peer->srcadr, cp);
2441 
2442 			refclock_report(instance->peer, CEVNT_FAULT);
2443 			oncore_shutdown(instance->unit, instance->peer);
2444 			return;
2445 		}
2446 
2447 		/* report the current antenna state */
2448 
2449 		oncore_antenna_report(instance, antenna);
2450 
2451 		instance->o_state = ONCORE_INIT;
2452 		cp = "state = ONCORE_INIT";
2453 		record_clock_stats(&(instance->peer->srcadr), cp);
2454 
2455 		instance->timeout = 4;
2456 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
2457 	}
2458 }
2459 
2460 
2461 
2462 /*
2463  * Demultiplex the almanac into shmem
2464  */
2465 
2466 static void
2467 oncore_msg_Cb(
2468 	struct instance *instance,
2469 	u_char *buf,
2470 	size_t len
2471 	)
2472 {
2473 	int i;
2474 
2475 	if (instance->shmem == NULL)
2476 		return;
2477 
2478 	if (buf[4] == 5 && buf[5] > 0 && buf[5] < 26)
2479 		i = buf[5];
2480 	else if (buf[4] == 4 && buf[5] <= 5)
2481 		i = buf[5] + 24;
2482 	else if (buf[4] == 4 && buf[5] <= 10)
2483 		i = buf[5] + 23;
2484 	else if (buf[4] == 4 && buf[5] == 25)
2485 		i = 34;
2486 	else {
2487 		char *cp;
2488 
2489 		cp = "Cb: Response is NO ALMANAC";
2490 		record_clock_stats(&(instance->peer->srcadr), cp);
2491 		return;
2492 	}
2493 
2494 	i *= 36;
2495 	instance->shmem[instance->shmem_Cb + i + 2]++;
2496 	memcpy(instance->shmem + instance->shmem_Cb + i + 3, buf, (size_t) (len + 3));
2497 
2498 #if 1
2499 	{
2500 	char Msg[160];
2501 	sprintf(Msg, "See Cb [%d,%d]", buf[4], buf[5]);
2502 	record_clock_stats(&(instance->peer->srcadr), Msg);
2503 	}
2504 #endif
2505 }
2506 
2507 
2508 
2509 /*
2510  * Set to Factory Defaults (Reasonable for UT w/ no Battery Backup
2511  *	not so for VP (eeprom) or any unit with a battery
2512  */
2513 
2514 static void
2515 oncore_msg_Cf(
2516 	struct instance *instance,
2517 	u_char *buf,
2518 	size_t len
2519 	)
2520 {
2521 	const char *cp;
2522 
2523 	if (instance->o_state == ONCORE_RESET_SENT) {
2524 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Return to  Posn Fix mode */
2525 										       /* Reset set VP to IDLE */
2526 		instance->o_state = ONCORE_TEST_SENT;
2527 		cp = "state = ONCORE_TEST_SENT";
2528 		record_clock_stats(&(instance->peer->srcadr), cp);
2529 
2530 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
2531 	}
2532 }
2533 
2534 
2535 
2536 /*
2537  * This is the Grand Central Station for the Preliminary Initialization.
2538  * Once done here we move on to oncore_msg_BaEaHa for final Initialization and Running.
2539  *
2540  * We do an @@Cj whenever we need a safe command for all Oncores.
2541  * The @@Cj gets us back here where we can switch to the next phase of setup.
2542  *
2543  * o Once at the very beginning (in start) to get the Model number.
2544  *   This info is printed, but no longer used.
2545  * o Again after we have determined the number of Channels in the receiver.
2546  * o And once later after we have done a reset and test, (which may hang),
2547  *   as we are about to initialize the Oncore and start it running.
2548  * o We have one routine below for each case.
2549  */
2550 
2551 static void
2552 oncore_msg_Cj(
2553 	struct instance *instance,
2554 	u_char *buf,
2555 	size_t len
2556 	)
2557 {
2558 	int	mode;
2559 	char	*cp;
2560 
2561 	memcpy(instance->Cj, buf, len);
2562 
2563 	instance->timeout = 0;
2564 	if (instance->o_state == ONCORE_CHECK_ID) {
2565 		oncore_msg_Cj_id(instance, buf, len);
2566 		oncore_chan_test(instance);
2567 	} else if (instance->o_state == ONCORE_HAVE_CHAN) {
2568 		mode = instance->init_type;
2569 		if (mode == 3 || mode == 4) {	/* Cf will return here to check for TEST */
2570 			instance->o_state = ONCORE_RESET_SENT;
2571 			cp = "state = ONCORE_RESET_SENT";
2572 			record_clock_stats(&(instance->peer->srcadr), cp);
2573 			oncore_sendmsg(instance->ttyfd, oncore_cmd_Cf, sizeof(oncore_cmd_Cf));
2574 		} else {
2575 			instance->o_state = ONCORE_TEST_SENT;
2576 			cp = "state = ONCORE_TEST_SENT";
2577 			record_clock_stats(&(instance->peer->srcadr), cp);
2578 		}
2579 	}
2580 
2581 	if (instance->o_state == ONCORE_TEST_SENT) {
2582 		if (instance->chan == 6)
2583 			oncore_sendmsg(instance->ttyfd, oncore_cmd_Ca, sizeof(oncore_cmd_Ca));
2584 		else if (instance->chan == 8)
2585 			oncore_sendmsg(instance->ttyfd, oncore_cmd_Fa, sizeof(oncore_cmd_Fa));
2586 		else if (instance->chan == 12)
2587 			oncore_sendmsg(instance->ttyfd, oncore_cmd_Ia, sizeof(oncore_cmd_Ia));
2588 	} else if (instance->o_state == ONCORE_INIT)
2589 		oncore_msg_Cj_init(instance, buf, len);
2590 }
2591 
2592 
2593 
2594 /* The information on determining a Oncore 'Model', viz VP, UT, etc, from
2595  *	the Model Number comes from "Richard M. Hambly" <rick@cnssys.com>
2596  *	and from Motorola.  Until recently Rick was the only source of
2597  *	this information as Motorola didn't give the information out.
2598  *
2599  * Determine the Type from the Model #, this determines #chan and if TRAIM is
2600  *   available.
2601  *
2602  * The Information from this routine is NO LONGER USED.
2603  * The RESULTS are PRINTED, BUT NOT USED, and the routine COULD BE DELETED
2604  */
2605 
2606 static void
2607 oncore_msg_Cj_id(
2608 	struct instance *instance,
2609 	u_char *buf,
2610 	size_t len
2611 	)
2612 {
2613 	char *cp, *cp1, *cp2, Model[21], Msg[160];
2614 
2615 	/* Write Receiver ID message to clockstats file */
2616 
2617 	instance->Cj[294] = '\0';
2618 	for (cp=(char *)instance->Cj; cp< (char *) &instance->Cj[294]; ) {
2619 		cp1 = strchr(cp, '\r');
2620 		if (!cp1)
2621 			cp1 = (char *)&instance->Cj[294];
2622 		*cp1 = '\0';
2623 		record_clock_stats(&(instance->peer->srcadr), cp);
2624 		*cp1 = '\r';
2625 		cp = cp1+2;
2626 	}
2627 
2628 	/* next, the Firmware Version and Revision numbers */
2629 
2630 	instance->version  = atoi((char *) &instance->Cj[83]);
2631 	instance->revision = atoi((char *) &instance->Cj[111]);
2632 
2633 	/* from model number decide which Oncore this is,
2634 		and then the number of channels */
2635 
2636 	for (cp= (char *) &instance->Cj[160]; *cp == ' '; cp++)   /* start right after 'Model #' */
2637 		;
2638 	cp1 = cp;
2639 	cp2 = Model;
2640 	for (; !isspace((int)*cp) && cp-cp1 < 20; cp++, cp2++)
2641 		*cp2 = *cp;
2642 	*cp2 = '\0';
2643 
2644 	cp = 0;
2645 	if (!strncmp(Model, "PVT6", (size_t) 4)) {
2646 		cp = "PVT6";
2647 		instance->model = ONCORE_PVT6;
2648 	} else if (Model[0] == 'A') {
2649 		cp = "Basic";
2650 		instance->model = ONCORE_BASIC;
2651 	} else if (Model[0] == 'B' || !strncmp(Model, "T8", (size_t) 2)) {
2652 		cp = "VP";
2653 		instance->model = ONCORE_VP;
2654 	} else if (Model[0] == 'P') {
2655 		cp = "M12";
2656 		instance->model = ONCORE_M12;
2657 	} else if (Model[0] == 'R' || Model[0] == 'D' || Model[0] == 'S') {
2658 		if (Model[5] == 'N') {
2659 			cp = "GT";
2660 			instance->model = ONCORE_GT;
2661 		} else if ((Model[1] == '3' || Model[1] == '4') && Model[5] == 'G') {
2662 			cp = "GT+";
2663 			instance->model = ONCORE_GTPLUS;
2664 		} else if ((Model[1] == '5' && Model[5] == 'U') || (Model[1] == '1' && Model[5] == 'A')) {
2665 				cp = "UT";
2666 				instance->model = ONCORE_UT;
2667 		} else if (Model[1] == '5' && Model[5] == 'G') {
2668 			cp = "UT+";
2669 			instance->model = ONCORE_UTPLUS;
2670 		} else if (Model[1] == '6' && Model[5] == 'G') {
2671 			cp = "SL";
2672 			instance->model = ONCORE_SL;
2673 		} else {
2674 			cp = "Unknown";
2675 			instance->model = ONCORE_UNKNOWN;
2676 		}
2677 	} else	{
2678 		cp = "Unknown";
2679 		instance->model = ONCORE_UNKNOWN;
2680 	}
2681 
2682 	/* use MODEL to set CHAN and TRAIM and possibly zero SHMEM */
2683 
2684 	sprintf(Msg, "This looks like an Oncore %s with version %d.%d firmware.", cp, instance->version, instance->revision);
2685 	record_clock_stats(&(instance->peer->srcadr), Msg);
2686 
2687 	instance->chan_id = 8;	   /* default */
2688 	if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6)
2689 		instance->chan_id = 6;
2690 	else if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || instance->model == ONCORE_UTPLUS)
2691 		instance->chan_id = 8;
2692 	else if (instance->model == ONCORE_M12)
2693 		instance->chan_id = 12;
2694 
2695 	instance->traim_id = 0;    /* default */
2696 	if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6)
2697 		instance->traim_id = 0;
2698 	else if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || instance->model == ONCORE_UTPLUS)
2699 		instance->traim_id = 1;
2700 	else if (instance->model == ONCORE_M12)
2701 		instance->traim_id = -1;
2702 
2703 	sprintf(Msg, "Channels = %d, TRAIM = %s", instance->chan_id,
2704 		((instance->traim_id < 0) ? "UNKNOWN" : ((instance->traim_id > 0) ? "ON" : "OFF")));
2705 	record_clock_stats(&(instance->peer->srcadr), Msg);
2706 }
2707 
2708 
2709 
2710 /* OK, know type of Oncore, have possibly reset it, and have tested it.
2711  * We know the number of channels.
2712  * We will determine whether we have TRAIM before we actually start.
2713  * Now initialize.
2714  */
2715 
2716 static void
2717 oncore_msg_Cj_init(
2718 	struct instance *instance,
2719 	u_char *buf,
2720 	size_t len
2721 	)
2722 {
2723 	char *cp, Msg[160];
2724 	u_char Cmd[20];
2725 	int	mode;
2726 
2727 
2728 	/* The M12 with 1.3 or 2.0 Firmware, loses track of all Satellites and has to
2729 	 * start again if we go from 0D -> 3D, then loses them again when we
2730 	 * go from 3D -> 0D.  We do this to get a @@Ea message for SHMEM.
2731 	 * For NOW we will turn this aspect of filling SHMEM off for the M12
2732 	 */
2733 
2734 	if (instance->chan == 12) {
2735 		instance->shmem_bad_Ea = 1;
2736 		sprintf(Msg, "*** SHMEM partially enabled for ONCORE M12 s/w v%d.%d ***", instance->version, instance->revision);
2737 		record_clock_stats(&(instance->peer->srcadr), Msg);
2738 	}
2739 
2740 	oncore_sendmsg(instance->ttyfd, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Return to  Posn Fix mode */
2741 	oncore_sendmsg(instance->ttyfd, oncore_cmd_Bb, sizeof(oncore_cmd_Bb)); /* turn on for shmem (6/8/12) */
2742 	oncore_sendmsg(instance->ttyfd, oncore_cmd_Ek, sizeof(oncore_cmd_Ek)); /* turn off (VP) */
2743 	oncore_sendmsg(instance->ttyfd, oncore_cmd_Aw, sizeof(oncore_cmd_Aw)); /* UTC time (6/8/12) */
2744 	oncore_sendmsg(instance->ttyfd, oncore_cmd_AB, sizeof(oncore_cmd_AB)); /* Appl type static (VP) */
2745 	oncore_sendmsg(instance->ttyfd, oncore_cmd_Be, sizeof(oncore_cmd_Be)); /* Tell us the Almanac for shmem (6/8/12) */
2746 	oncore_sendmsg(instance->ttyfd, oncore_cmd_Bd, sizeof(oncore_cmd_Bd)); /* Tell us when Almanac changes */
2747 
2748 	mode = instance->init_type;
2749 
2750 	/* If there is Position input in the Config file
2751 	 * and mode = (1,3) set it as posn hold posn, goto 0D mode.
2752 	 *  or mode = (2,4) set it as INITIAL position, and do Site Survey.
2753 	 */
2754 
2755 	if (instance->posn_set) {
2756 		record_clock_stats(&(instance->peer->srcadr), "Setting Posn from input data");
2757 		oncore_set_posn(instance);	/* this should print posn indirectly thru the As cmd */
2758 	} else	/* must issue an @@At here to check on 6/8 Position Hold, set_posn would have */
2759 		if (instance->chan != 12)
2760 			oncore_sendmsg(instance->ttyfd, oncore_cmd_Atx, sizeof(oncore_cmd_Atx));
2761 
2762 	if (mode != 0) {
2763 			/* cable delay in ns */
2764 		memcpy(Cmd, oncore_cmd_Az, (size_t) sizeof(oncore_cmd_Az));
2765 		w32_buf(&Cmd[-2+4], instance->delay);
2766 		oncore_sendmsg(instance->ttyfd, Cmd,  sizeof(oncore_cmd_Az));	/* 6,8,12 */
2767 
2768 			/* PPS offset in ns */
2769 		if (instance->offset) {
2770 			memcpy(Cmd, oncore_cmd_Ay, (size_t) sizeof(oncore_cmd_Ay));	/* some have it, some don't */
2771 			w32_buf(&Cmd[-2+4], instance->offset);			/* will check for hw response */
2772 			oncore_sendmsg(instance->ttyfd, Cmd,  sizeof(oncore_cmd_Ay));
2773 		}
2774 
2775 		/* Satellite mask angle */
2776 
2777 		if (instance->Ag != 0xff) {	/* will have 0xff in it if not set by user */
2778 			memcpy(Cmd, oncore_cmd_Ag, (size_t) sizeof(oncore_cmd_Ag));
2779 			Cmd[-2+4] = instance->Ag;
2780 			oncore_sendmsg(instance->ttyfd, Cmd,  sizeof(oncore_cmd_Ag));
2781 		}
2782 	}
2783 
2784 	/* 6, 8 12 chan - Position/Status/Data Output Message, 1/s
2785 	 * now we're really running
2786 	 * these were ALL started in the chan test,
2787 	 * However, if we had mode=3,4 then commands got turned off, so we turn
2788 	 * them on again here just in case
2789 	 */
2790 
2791 	if (instance->chan == 6) { /* start 6chan, kill 8,12chan commands, possibly testing VP in 6chan mode */
2792 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea0, sizeof(oncore_cmd_Ea0));
2793 		oncore_sendmsg(instance->ttyfd, oncore_cmd_En0, sizeof(oncore_cmd_En0));
2794 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Ha0, sizeof(oncore_cmd_Ha0));
2795 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0));
2796 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Ba,	sizeof(oncore_cmd_Ba ));
2797 	} else if (instance->chan == 8) {  /* start 8chan, kill 6,12chan commands */
2798 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Ba0, sizeof(oncore_cmd_Ba0));
2799 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Bn0, sizeof(oncore_cmd_Bn0));
2800 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Ha0, sizeof(oncore_cmd_Ha0));
2801 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0));
2802 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea,	sizeof(oncore_cmd_Ea ));
2803 	} else if (instance->chan == 12){  /* start 12chan, kill 6,12chan commands */
2804 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Ba0, sizeof(oncore_cmd_Ba0));
2805 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Bn0, sizeof(oncore_cmd_Bn0));
2806 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea0, sizeof(oncore_cmd_Ea0));
2807 		oncore_sendmsg(instance->ttyfd, oncore_cmd_En0, sizeof(oncore_cmd_En0));
2808 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Ha,	sizeof(oncore_cmd_Ha ));
2809 	}
2810 
2811 	instance->count = 1;
2812 	instance->o_state = ONCORE_ALMANAC;
2813 	cp = "state = ONCORE_ALMANAC";
2814 	record_clock_stats(&(instance->peer->srcadr), cp);
2815 }
2816 
2817 
2818 
2819 /* 12chan position */
2820 
2821 static void
2822 oncore_msg_Ga(
2823 	struct instance *instance,
2824 	u_char *buf,
2825 	size_t len
2826 	)
2827 {
2828 	char Msg[160];
2829 	long lat, lon, ht;
2830 	double Lat, Lon, Ht;
2831 
2832 
2833 	lat = buf_w32(&buf[4]);
2834 	lon = buf_w32(&buf[8]);
2835 	ht  = buf_w32(&buf[12]);  /* GPS ellipsoid */
2836 
2837 	Lat = lat;
2838 	Lon = lon;
2839 	Ht  = ht;
2840 
2841 	Lat /= 3600000;
2842 	Lon /= 3600000;
2843 	Ht  /= 100;
2844 
2845 
2846 	sprintf(Msg, "Ga Posn Lat = %.7f, Lon = %.7f, Ht  = %.2f", Lat, Lon, Ht);
2847 	record_clock_stats(&(instance->peer->srcadr), Msg);
2848 
2849 	instance->ss_lat  = lat;
2850 	instance->ss_long = lon;
2851 	instance->ss_ht   = ht;
2852 
2853 	oncore_print_posn(instance);
2854 }
2855 
2856 
2857 
2858 /* 12 chan time/date */
2859 
2860 static void
2861 oncore_msg_Gb(
2862 	struct instance *instance,
2863 	u_char *buf,
2864 	size_t len
2865 	)
2866 {
2867 	char	Msg[160], *gmts;
2868 	int	mo, d, y, h, m, s, gmth, gmtm;
2869 
2870 	mo = buf[4];
2871 	d  = buf[5];
2872 	y  = 256*buf[6]+buf[7];
2873 
2874 	h  = buf[8];
2875 	m  = buf[9];
2876 	s  = buf[10];
2877 
2878 	gmts = ((buf[11] == 0) ? "+" : "-");
2879 	gmth = buf[12];
2880 	gmtm = buf[13];
2881 
2882 	sprintf(Msg, "Date/Time set to: %d%s%d %2d:%02d:%02d GMT (GMT offset is %s%02d:%02d)",
2883 		d, Month[mo-1], y, h, m, s, gmts, gmth, gmtm);
2884 	record_clock_stats(&(instance->peer->srcadr), Msg);
2885 }
2886 
2887 
2888 
2889 /* Leap Second for M12, gives all info from satellite message */
2890 /* also in UT v3.0 */
2891 
2892 static void
2893 oncore_msg_Gj(
2894 	struct instance *instance,
2895 	u_char *buf,
2896 	size_t len
2897 	)
2898 {
2899 	int dt;
2900 	char Msg[160], *cp;
2901 
2902 	instance->saw_Gj = 1; /* flag, saw_Gj, dont need to try Bj in check_leap */
2903 
2904 	/* print the message to verify whats there */
2905 
2906 	dt = buf[5] - buf[4];
2907 
2908 #if 1
2909 	sprintf(Msg, "ONCORE[%d]: Leap Sec Msg: %d %d %d %d %d %d %d %d %d %d",
2910 			instance->unit,
2911 			buf[4], buf[5], 256*buf[6]+buf[7], buf[8], buf[9], buf[10],
2912 			(buf[14]+256*(buf[13]+256*(buf[12]+256*buf[11]))),
2913 			buf[15], buf[16], buf[17]);
2914 	record_clock_stats(&(instance->peer->srcadr), Msg);
2915 #endif
2916 	if (dt) {
2917 		sprintf(Msg, "ONCORE[%d]: Leap second (%d) scheduled for %d%s%d at %d:%d:%d",
2918 			instance->unit,
2919 			dt, buf[9], Month[buf[8]-1], 256*buf[6]+buf[7],
2920 			buf[15], buf[16], buf[17]);
2921 		record_clock_stats(&(instance->peer->srcadr), Msg);
2922 	}
2923 
2924 	/* Only raise warning within a month of the leap second */
2925 
2926 	instance->pp->leap = LEAP_NOWARNING;
2927 	cp = "Set pp.leap to LEAP_NOWARNING";
2928 
2929 	if (buf[6] == instance->BEHa[6] && buf[7] == instance->BEHa[7] && /* year */
2930 	    buf[8] == instance->BEHa[4]) {	/* month */
2931 		if (dt) {
2932 			if (dt < 0) {
2933 				instance->pp->leap = LEAP_DELSECOND;
2934 				cp = "Set pp.leap to LEAP_DELSECOND";
2935 			} else {
2936 				instance->pp->leap = LEAP_ADDSECOND;
2937 				cp = "Set pp.leap to LEAP_ADDSECOND";
2938 			}
2939 		}
2940 	}
2941 	record_clock_stats(&(instance->peer->srcadr), cp);
2942 }
2943 
2944 
2945 
2946 /* Power on failure */
2947 
2948 static void
2949 oncore_msg_Sz(
2950 	struct instance *instance,
2951 	u_char *buf,
2952 	size_t len
2953 	)
2954 {
2955 	const char *cp;
2956 
2957 	cp = "Oncore: System Failure at Power On";
2958 	if (instance && instance->peer) {
2959 		record_clock_stats(&(instance->peer->srcadr), cp);
2960 		oncore_shutdown(instance->unit, instance->peer);
2961 	}
2962 }
2963 
2964 /************** Small Subroutines ***************/
2965 
2966 
2967 static void
2968 oncore_antenna_report(
2969 	struct instance *instance,
2970 	enum antenna_state new_state)
2971 {
2972 	char *cp;
2973 
2974 	if (instance->ant_state == new_state)
2975 		return;
2976 
2977 	switch (new_state) {
2978 	case ONCORE_ANTENNA_OK: cp = "GPS antenna: OK";                   break;
2979 	case ONCORE_ANTENNA_OC: cp = "GPS antenna: short (overcurrent)";  break;
2980 	case ONCORE_ANTENNA_UC: cp = "GPS antenna: open (not connected)"; break;
2981 	case ONCORE_ANTENNA_NV: cp = "GPS antenna: short (no voltage)";   break;
2982 	default:		cp = "GPS antenna: ?";                    break;
2983 	}
2984 
2985 	instance->ant_state = new_state;
2986 	record_clock_stats(&instance->peer->srcadr, cp);
2987 }
2988 
2989 
2990 
2991 static void
2992 oncore_chan_test(
2993 	struct instance *instance
2994 	)
2995 {
2996 	char	*cp;
2997 
2998 	/* subroutine oncore_Cj_id has determined the number of channels from the
2999 	 * model number of the attached oncore.  This is not always correct since
3000 	 * the oncore could have non-standard firmware.  Here we check (independently) by
3001 	 * trying a 6, 8, and 12 chan command, and see which responds.
3002 	 * Caution: more than one CAN respond.
3003 	 *
3004 	 * This #chan is used by the code rather than that calculated from the model number.
3005 	 */
3006 
3007 	instance->o_state = ONCORE_CHECK_CHAN;
3008 	cp = "state = ONCORE_CHECK_CHAN";
3009 	record_clock_stats(&(instance->peer->srcadr), cp);
3010 
3011 	instance->count3 = 1;
3012 	oncore_sendmsg(instance->ttyfd, oncore_cmd_Ba, sizeof(oncore_cmd_Ba));
3013 	oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea, sizeof(oncore_cmd_Ea));
3014 	oncore_sendmsg(instance->ttyfd, oncore_cmd_Ha, sizeof(oncore_cmd_Ha));
3015 }
3016 
3017 
3018 
3019 /* check for a GOOD Almanac, have we got one yet? */
3020 
3021 static void
3022 oncore_check_almanac(
3023 	struct instance *instance
3024 	)
3025 {
3026 	if (instance->chan == 6) {
3027 		instance->rsm.bad_almanac = instance->BEHa[64]&0x1;
3028 		instance->rsm.bad_fix	  = instance->BEHa[64]&0x52;
3029 	} else if (instance->chan == 8) {
3030 		instance->rsm.bad_almanac = instance->BEHa[72]&0x1;
3031 		instance->rsm.bad_fix	  = instance->BEHa[72]&0x52;
3032 	} else if (instance->chan == 12) {
3033 		int bits1, bits2, bits3;
3034 
3035 		bits1 = (instance->BEHa[129]>>5) & 0x7; 	/* actually Ha */
3036 		bits2 = instance->BEHa[130];
3037 		instance->rsm.bad_almanac = (bits2 & 0x80);
3038 		instance->rsm.bad_fix	  = (bits2 & 0x8) || (bits1 == 0x2);
3039 					  /* too few sat     Bad Geom	  */
3040 
3041 		bits3 = instance->BEHa[141];	/* UTC parameters */
3042 		if (!instance->count5_set && (bits3 & 0xC0)) {
3043 			instance->count5 = 2;
3044 			instance->count5_set = 1;
3045 		}
3046 #if 0
3047 {
3048 		char Msg[160];
3049 
3050 		sprintf(Msg, "ONCORE[%d]: DEBUG BITS: (%x %x), (%x %x %x),  %x %x %x %x %x\n",
3051 		instance->unit,
3052 		instance->BEHa[129], instance->BEHa[130], bits1, bits2, bits3, instance->mode == MODE_0D,
3053 		instance->mode == MODE_2D, instance->mode == MODE_3D,
3054 		instance->rsm.bad_almanac, instance->rsm.bad_fix);
3055 		record_clock_stats(&(instance->peer->srcadr), Msg);
3056 }
3057 #endif
3058 	}
3059 }
3060 
3061 
3062 
3063 /* check the antenna for changes (did it get unplugged?) */
3064 
3065 static void
3066 oncore_check_antenna(
3067 	struct instance *instance
3068 	)
3069 {
3070 	enum antenna_state antenna;		/* antenna state */
3071 
3072 	antenna = instance->ant_state;
3073 	if (instance->chan == 12)
3074 		antenna = (instance->BEHa[130] & 0x6 ) >> 1;
3075 	else
3076 		antenna = (instance->BEHa[37] & 0xc0) >> 6;  /* prob unset 6, set GT, UT unset VP */
3077 
3078 	oncore_antenna_report (instance, antenna);
3079 }
3080 
3081 
3082 
3083 /*
3084  * Check the leap second status once per day.
3085  *
3086  * Note that the ONCORE firmware for the Bj command is wrong at
3087  * least in the VP.
3088  * It starts advertising a LEAP SECOND as soon as the GPS satellite
3089  * data message (page 18, subframe 4) is updated to a date in the
3090  * future, and does not wait for the month that it will occur.
3091  * The event will usually be advertised several months in advance.
3092  * Since there is a one bit flag, there is no way to tell if it is
3093  * this month, or when...
3094  *
3095  * As such, we have the workaround below, of only checking for leap
3096  * seconds with the Bj command in June/December.
3097  *
3098  * The Gj command gives more information, and we can tell in which
3099  * month to apply the correction.
3100  *
3101  * Note that with the VP we COULD read the raw data message, and
3102  * interpret it ourselves, but since this is specific to this receiver
3103  * only, and the above workaround is adequate, we don't bother.
3104  */
3105 
3106 static void
3107 oncore_check_leap_sec(
3108 	struct instance *instance
3109 	)
3110 {
3111 	if (instance->Bj_day != instance->BEHa[5]) {	 /* do this 1/day */
3112 		instance->Bj_day = instance->BEHa[5];
3113 
3114 		if (instance->saw_Gj < 0) {	/* -1 DONT have Gj use Bj */
3115 			if ((instance->BEHa[4] == 6) || (instance->BEHa[4] == 12))
3116 				oncore_sendmsg(instance->ttyfd, oncore_cmd_Bj, sizeof(oncore_cmd_Bj));
3117 			return;
3118 		}
3119 
3120 		if (instance->saw_Gj == 0)	/* 0 is dont know if we have Gj */
3121 			instance->count4 = 1;
3122 
3123 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Gj, sizeof(oncore_cmd_Gj));
3124 		return;
3125 	}
3126 
3127 	/* Gj works for some 6/8 chan UT and the M12	  */
3128 	/* if no response from Gj in 5 sec, we try Bj	  */
3129 	/* which isnt implemented in all the GT/UT either */
3130 
3131 	if (instance->count4) { 	/* delay, waiting for Gj response */
3132 		if (instance->saw_Gj == 1)
3133 			instance->count4 = 0;
3134 		else if (instance->count4++ > 5) {	/* delay, waiting for Gj response */
3135 			instance->saw_Gj = -1;		/* didnt see it, will use Bj */
3136 			instance->count4 = 0;
3137 			if ((instance->BEHa[4] == 6) || (instance->BEHa[4] == 12))
3138 				oncore_sendmsg(instance->ttyfd, oncore_cmd_Bj, sizeof(oncore_cmd_Bj));
3139 		}
3140 	}
3141 }
3142 
3143 
3144 
3145 /* check the message checksum,
3146  *  buf points to START of message ( @@ )
3147  *  len is length WITH CR/LF.
3148  */
3149 
3150 static int
3151 oncore_checksum_ok(
3152 	u_char *buf,
3153 	int	len
3154 	)
3155 {
3156 	int	i, j;
3157 
3158 	j = 0;
3159 	for (i = 2; i < len-3; i++)
3160 		j ^= buf[i];
3161 
3162 	return(j == buf[len-3]);
3163 }
3164 
3165 
3166 
3167 static void
3168 oncore_compute_dH(
3169 	struct instance *instance
3170 	)
3171 {
3172 	int GPS, MSL;
3173 	char	Msg[160];
3174 
3175 	/* Here calculate dH = GPS - MSL for output message */
3176 	/* also set Altitude Hold mode if GT */
3177 
3178 	instance->have_dH = 1;
3179 	if (instance->chan == 12) {
3180 		GPS = buf_w32(&instance->BEHa[39]);
3181 		MSL = buf_w32(&instance->BEHa[43]);
3182 	} else {
3183 		GPS = buf_w32(&instance->BEHa[23]);
3184 		MSL = buf_w32(&instance->BEHa[27]);
3185 	}
3186 	instance->dH = GPS - MSL;
3187 	instance->dH /= 100.;
3188 
3189 	/* if MSL is not set, the calculation is meaningless */
3190 
3191 	if (MSL) {	/* not set ! */
3192 		sprintf(Msg, "dH = (GPS - MSL) = %.2fm", instance->dH);
3193 		record_clock_stats(&(instance->peer->srcadr), Msg);
3194 	}
3195 }
3196 
3197 
3198 
3199 /*
3200  * try loading Almanac from shmem (where it was copied from shmem_old
3201  */
3202 
3203 static void
3204 oncore_load_almanac(
3205 	struct instance *instance
3206 	)
3207 {
3208 	u_char	*cp, Cmd[20];
3209 	int	n;
3210 	struct timeval tv;
3211 	struct tm *tm;
3212 
3213 	if (!instance->shmem)
3214 		return;
3215 
3216 #if 1
3217 	for (cp=instance->shmem+4; (n = 256*(*(cp-3)) + *(cp-2)); cp+=(n+3)) {
3218 		if (!strncmp((char *) cp, "@@Cb", 4) &&
3219 		    oncore_checksum_ok(cp, 33) &&
3220 		    (*(cp+4) == 4 || *(cp+4) == 5)) {
3221 			write(instance->ttyfd, cp, n);
3222 #if 1
3223 			oncore_print_Cb(instance, cp);
3224 #endif
3225 		}
3226 	}
3227 #else
3228 /************DEBUG************/
3229 	for (cp=instance->shmem+4; (n = 256*(*(cp-3)) + *(cp-2)); cp+=(n+3)) {
3230 		char Msg[160];
3231 
3232 		sprintf(Msg, "See %c%c%c%c %d", *(cp), *(cp+1), *(cp+2), *(cp+3), *(cp+4));
3233 		record_clock_stats(&(instance->peer->srcadr), Msg);
3234 
3235 		if (!strncmp(cp, "@@Cb", 4)) {
3236 			oncore_print_Cb(instance, cp);
3237 			if (oncore_checksum_ok(cp, 33)) {
3238 				if (*(cp+4) == 4 || *(cp+4) == 5) {
3239 					record_clock_stats(&(instance->peer->srcadr), "GOOD SF");
3240 					write(instance->ttyfd, cp, n);
3241 				} else
3242 					record_clock_stats(&(instance->peer->srcadr), "BAD SF");
3243 			} else
3244 				record_clock_stats(&(instance->peer->srcadr), "BAD CHECKSUM");
3245 		}
3246 	}
3247 /************DEBUG************/
3248 #endif
3249 
3250 	/* Must load position and time or the Almanac doesn't do us any good */
3251 
3252 	if (!instance->posn_set) {	/* if we input a posn use it, else from SHMEM */
3253 		record_clock_stats(&(instance->peer->srcadr), "Loading Posn from SHMEM");
3254 		for (cp=instance->shmem+4; (n = 256*(*(cp-3)) + *(cp-2));  cp+=(n+3)) {
3255 			if ((instance->chan == 6  && (!strncmp((char *) cp, "@@Ba", 4) && oncore_checksum_ok(cp,  68))) ||
3256 			    (instance->chan == 8  && (!strncmp((char *) cp, "@@Ea", 4) && oncore_checksum_ok(cp,  76))) ||
3257 			    (instance->chan == 12 && (!strncmp((char *) cp, "@@Ha", 4) && oncore_checksum_ok(cp, 154)))) {
3258 				int ii, jj, kk;
3259 
3260 				instance->posn_set = 1;
3261 				ii = buf_w32(cp + 15);
3262 				jj = buf_w32(cp + 19);
3263 				kk = buf_w32(cp + 23);
3264 #if 0
3265 {
3266 char Msg[160];
3267 sprintf(Msg, "SHMEM posn = %ld (%d, %d, %d)", (long) (cp-instance->shmem), ii, jj, kk);
3268 record_clock_stats(&(instance->peer->srcadr), Msg);
3269 }
3270 #endif
3271 				if (ii != 0 || jj != 0 || kk != 0) { /* phk asked for this test */
3272 					instance->ss_lat  = ii;
3273 					instance->ss_long = jj;
3274 					instance->ss_ht   = kk;
3275 				}
3276 			}
3277 		}
3278 	}
3279 	oncore_set_posn(instance);
3280 
3281 	/* and set time to time from Computer clock */
3282 
3283 	gettimeofday(&tv, 0);
3284 	tm = gmtime((const time_t *) &tv.tv_sec);
3285 #if 1
3286 	{
3287 	char Msg[160];
3288 	sprintf(Msg, "DATE %d %d %d, %d %d %d", 1900+tm->tm_year, tm->tm_mon, tm->tm_mday,
3289 		tm->tm_hour, tm->tm_min, tm->tm_sec);
3290 	record_clock_stats(&(instance->peer->srcadr), Msg);
3291 	}
3292 #endif
3293 	if (instance->chan == 12) {
3294 		memcpy(Cmd, oncore_cmd_Gb, (size_t) sizeof(oncore_cmd_Gb));
3295 		Cmd[-2+4]  = tm->tm_mon + 1;
3296 		Cmd[-2+5]  = tm->tm_mday;
3297 		Cmd[-2+6]  = (1900+tm->tm_year)/256;
3298 		Cmd[-2+7]  = (1900+tm->tm_year)%256;
3299 		Cmd[-2+8]  = tm->tm_hour;
3300 		Cmd[-2+9]  = tm->tm_min;
3301 		Cmd[-2+10] = tm->tm_sec;
3302 		Cmd[-2+11] = 0;
3303 		Cmd[-2+12] = 0;
3304 		Cmd[-2+13] = 0;
3305 		oncore_sendmsg(instance->ttyfd, Cmd,  sizeof(oncore_cmd_Gb));
3306 	} else {
3307 		/* First set GMT offset to zero */
3308 
3309 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Ab,	sizeof(oncore_cmd_Ab));
3310 
3311 		memcpy(Cmd, oncore_cmd_Ac, (size_t) sizeof(oncore_cmd_Ac));
3312 		Cmd[-2+4] = tm->tm_mon + 1;
3313 		Cmd[-2+5] = tm->tm_mday;
3314 		Cmd[-2+6] = (1900+tm->tm_year)/256;
3315 		Cmd[-2+7] = (1900+tm->tm_year)%256;
3316 		oncore_sendmsg(instance->ttyfd, Cmd,  sizeof(oncore_cmd_Ac));
3317 
3318 		memcpy(Cmd, oncore_cmd_Aa, (size_t) sizeof(oncore_cmd_Aa));
3319 		Cmd[-2+4] = tm->tm_hour;
3320 		Cmd[-2+5] = tm->tm_min;
3321 		Cmd[-2+6] = tm->tm_sec;
3322 		oncore_sendmsg(instance->ttyfd, Cmd,  sizeof(oncore_cmd_Aa));
3323 	}
3324 
3325 	record_clock_stats(&(instance->peer->srcadr), "Setting Posn and Time after Loading Almanac");
3326 }
3327 
3328 
3329 
3330 /* Almanac data input */
3331 
3332 static void
3333 oncore_print_Cb(
3334 	struct instance *instance,
3335 	u_char *cp
3336 	)
3337 {
3338 #if 0
3339 	int	ii;
3340 	char	Msg[160];
3341 
3342 	printf("DEBUG: See: %c%c%c%c\n", *(cp), *(cp+1), *(cp+2), *(cp+3));
3343 	printf("DEBUG: Cb: [%d,%d]", *(cp+4), *(cp+5));
3344 	for(ii=0; ii<33; ii++)
3345 		printf(" %d", *(cp+ii));
3346 	printf("\n");
3347 
3348 	sprintf(Msg, "Debug: Cb: [%d,%d]", *(cp+4), *(cp+5));
3349 	record_clock_stats(&(instance->peer->srcadr), Msg);
3350 #endif
3351 }
3352 
3353 
3354 #if 0
3355 static void
3356 oncore_print_array(
3357 	u_char *cp,
3358 	int	n
3359 	)
3360 {
3361 	int	jj, i, j, nn;
3362 
3363 	nn = 0;
3364 	printf("\nTOP\n");
3365 	jj = n/16;
3366 	for (j=0; j<jj; j++) {
3367 		printf("%4d: ", nn);
3368 		nn += 16;
3369 		for (i=0; i<16; i++)
3370 			printf(" %o", *cp++);
3371 		printf("\n");
3372 	}
3373 }
3374 #endif
3375 
3376 
3377 static void
3378 oncore_print_posn(
3379 	struct instance *instance
3380 	)
3381 {
3382 	char Msg[120], ew, ns;
3383 	double xd, xm, xs, yd, ym, ys, hm, hft;
3384 	int idx, idy, is, imx, imy;
3385 	long lat, lon;
3386 
3387 	record_clock_stats(&(instance->peer->srcadr), "Posn:");
3388 	ew = 'E';
3389 	lon = instance->ss_long;
3390 	if (lon < 0) {
3391 		ew = 'W';
3392 		lon = -lon;
3393 	}
3394 
3395 	ns = 'N';
3396 	lat = instance->ss_lat;
3397 	if (lat < 0) {
3398 		ns = 'S';
3399 		lat = -lat;
3400 	}
3401 
3402 	hm = instance->ss_ht/100.;
3403 	hft= hm/0.3048;
3404 
3405 	xd = lat/3600000.;	/* lat, lon in int msec arc, ht in cm. */
3406 	yd = lon/3600000.;
3407 	sprintf(Msg, "Lat = %c %11.7fdeg,    Long = %c %11.7fdeg,    Alt = %5.2fm (%5.2fft) GPS", ns, xd, ew, yd, hm, hft);
3408 	record_clock_stats(&(instance->peer->srcadr), Msg);
3409 
3410 	idx = xd;
3411 	idy = yd;
3412 	imx = lat%3600000;
3413 	imy = lon%3600000;
3414 	xm = imx/60000.;
3415 	ym = imy/60000.;
3416 	sprintf(Msg,
3417 	    "Lat = %c %3ddeg %7.4fm,   Long = %c %3ddeg %8.5fm,  Alt = %7.2fm (%7.2fft) GPS", ns, idx, xm, ew, idy, ym, hm, hft);
3418 	record_clock_stats(&(instance->peer->srcadr), Msg);
3419 
3420 	imx = xm;
3421 	imy = ym;
3422 	is  = lat%60000;
3423 	xs  = is/1000.;
3424 	is  = lon%60000;
3425 	ys  = is/1000.;
3426 	sprintf(Msg,
3427 	    "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);
3428 	record_clock_stats(&(instance->peer->srcadr), Msg);
3429 }
3430 
3431 
3432 
3433 /*
3434  * write message to Oncore.
3435  */
3436 
3437 static void
3438 oncore_sendmsg(
3439 	int	fd,
3440 	u_char *ptr,
3441 	size_t len
3442 	)
3443 {
3444 	u_char cs = 0;
3445 
3446 #ifdef DEBUG
3447 	if (debug > 4)
3448 		printf("ONCORE: Send @@%c%c %d\n", ptr[0], ptr[1], (int) len);
3449 #endif
3450 	write(fd, "@@", (size_t) 2);
3451 	write(fd, ptr, len);
3452 	while (len--)
3453 		cs ^= *ptr++;
3454 	write(fd, &cs, (size_t) 1);
3455 	write(fd, "\r\n", (size_t) 2);
3456 }
3457 
3458 
3459 
3460 static void
3461 oncore_set_posn(
3462 	struct instance *instance
3463 	)
3464 {
3465 	int	mode;
3466 	u_char	  Cmd[20];
3467 
3468 	/* Turn OFF position hold, it needs to be off to set position (for some units),
3469 	   will get set ON in @@Ea later */
3470 
3471 	if (instance->chan == 12)
3472 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* (12) */
3473 	else {
3474 		oncore_sendmsg(instance->ttyfd, oncore_cmd_At0, sizeof(oncore_cmd_At0)); /* (6/8) */
3475 		oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); /* (6/8) */
3476 	}
3477 
3478 	mode = instance->init_type;
3479 
3480 	if (mode != 0) {	/* first set posn hold position */
3481 		memcpy(Cmd, oncore_cmd_As, (size_t) sizeof(oncore_cmd_As));	/* don't modify static variables */
3482 		w32_buf(&Cmd[-2+4],  (int) instance->ss_lat);
3483 		w32_buf(&Cmd[-2+8],  (int) instance->ss_long);
3484 		w32_buf(&Cmd[-2+12], (int) instance->ss_ht);
3485 		Cmd[-2+16] = 0;
3486 		oncore_sendmsg(instance->ttyfd, Cmd,  sizeof(oncore_cmd_As));	/* posn hold 3D posn (6/8/12) */
3487 
3488 		memcpy(Cmd, oncore_cmd_Au, (size_t) sizeof(oncore_cmd_Au));
3489 		w32_buf(&Cmd[-2+4], (int) instance->ss_ht);
3490 		Cmd[-2+8] = 0;
3491 		oncore_sendmsg(instance->ttyfd, Cmd,  sizeof(oncore_cmd_Au));	/* altitude hold (6/8/12 not UT, M12T) */
3492 
3493 		/* next set current position */
3494 
3495 		if (instance->chan == 12) {
3496 			memcpy(Cmd, oncore_cmd_Ga, (size_t) sizeof(oncore_cmd_Ga));
3497 			w32_buf(&Cmd[-2+4], (int) instance->ss_lat);
3498 			w32_buf(&Cmd[-2+8], (int) instance->ss_long);
3499 			w32_buf(&Cmd[-2+12],(int) instance->ss_ht);
3500 			Cmd[-2+16] = 0;
3501 			oncore_sendmsg(instance->ttyfd, Cmd,  sizeof(oncore_cmd_Ga));		  /* 3d posn (12) */
3502 		} else {
3503 			memcpy(Cmd, oncore_cmd_Ad, (size_t) sizeof(oncore_cmd_Ad));
3504 			w32_buf(&Cmd[-2+4], (int) instance->ss_lat);
3505 			oncore_sendmsg(instance->ttyfd, Cmd,  sizeof(oncore_cmd_Ad));	/* lat (6/8) */
3506 
3507 			memcpy(Cmd, oncore_cmd_Ae, (size_t) sizeof(oncore_cmd_Ae));
3508 			w32_buf(&Cmd[-2+4], (int) instance->ss_long);
3509 			oncore_sendmsg(instance->ttyfd, Cmd,  sizeof(oncore_cmd_Ae));	/* long (6/8) */
3510 
3511 			memcpy(Cmd, oncore_cmd_Af, (size_t) sizeof(oncore_cmd_Af));
3512 			w32_buf(&Cmd[-2+4], (int) instance->ss_ht);
3513 			Cmd[-2+8] = 0;
3514 			oncore_sendmsg(instance->ttyfd, Cmd,  sizeof(oncore_cmd_Af));	/* ht (6/8) */
3515 		}
3516 
3517 		/* Finally, turn on position hold */
3518 
3519 		if (instance->chan == 12)
3520 			oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd1,  sizeof(oncore_cmd_Gd1));
3521 		else
3522 			oncore_sendmsg(instance->ttyfd, oncore_cmd_At1,  sizeof(oncore_cmd_At1));
3523 	}
3524 }
3525 
3526 
3527 
3528 static void
3529 oncore_set_traim(
3530 	struct instance *instance
3531 	)
3532 {
3533 	char	Msg[160];
3534 
3535 	if (instance->traim_in != -1)	/* set in Input */
3536 		instance->traim = instance->traim_in;
3537 	else
3538 		instance->traim = instance->traim_ck;
3539 
3540 	sprintf(Msg, "Input   says TRAIM = %d", instance->traim_in);
3541 	record_clock_stats(&(instance->peer->srcadr), Msg);
3542 	sprintf(Msg, "Model # says TRAIM = %d", instance->traim_id);
3543 	record_clock_stats(&(instance->peer->srcadr), Msg);
3544 	sprintf(Msg, "Testing says TRAIM = %d", instance->traim_ck);
3545 	record_clock_stats(&(instance->peer->srcadr), Msg);
3546 	sprintf(Msg, "Using        TRAIM = %d", instance->traim);
3547 	record_clock_stats(&(instance->peer->srcadr), Msg);
3548 
3549 	if (instance->traim_ck == 1 && instance->traim == 0) {
3550 		/* if it should be off, and I turned it on during testing,
3551 		   then turn it off again */
3552 		if (instance->chan == 6)
3553 			oncore_sendmsg(instance->ttyfd, oncore_cmd_Bnx, sizeof(oncore_cmd_Bnx));
3554 		else if (instance->chan == 8)
3555 			oncore_sendmsg(instance->ttyfd, oncore_cmd_Enx, sizeof(oncore_cmd_Enx));
3556 		else	/* chan == 12 */
3557 			oncore_sendmsg(instance->ttyfd, oncore_cmd_Ge0, sizeof(oncore_cmd_Ge0));
3558 			oncore_sendmsg(instance->ttyfd, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0));
3559 	}
3560 }
3561 
3562 
3563 
3564 /*
3565  * if SHMEM active, every 15s, steal one 'tick' to get 2D or 3D posn.
3566  */
3567 
3568 static void
3569 oncore_shmem_get_3D(
3570 	struct instance *instance
3571 	)
3572 {
3573 	if (instance->pp->second%15 == 3) {	/* start the sequence */			/* by changing mode */
3574 		instance->shmem_reset = 1;
3575 		if (instance->chan == 12) {
3576 			if (instance->shmem_Posn == 2)
3577 				oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd2,  sizeof(oncore_cmd_Gd2));  /* 2D */
3578 			else
3579 				oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd0,  sizeof(oncore_cmd_Gd0));  /* 3D */
3580 		} else {
3581 			if (instance->saw_At) { 		/* out of 0D -> 3D mode */
3582 				oncore_sendmsg(instance->ttyfd, oncore_cmd_At0, sizeof(oncore_cmd_At0));
3583 				if (instance->shmem_Posn == 2)	/* 3D -> 2D mode */
3584 					oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1));
3585 			} else
3586 				oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0));
3587 		}
3588 	} else if (instance->shmem_reset || (instance->mode != MODE_0D)) {
3589 		instance->shmem_reset = 0;
3590 		if (instance->chan == 12)
3591 			oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd1,  sizeof(oncore_cmd_Gd1));	/* 0D */
3592 		else {
3593 			if (instance->saw_At) {
3594 				if (instance->mode == MODE_2D)	/* 2D -> 3D or 0D mode */
3595 					oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0));
3596 				oncore_sendmsg(instance->ttyfd, oncore_cmd_At1,  sizeof(oncore_cmd_At1)); /* to 0D mode */
3597 			} else
3598 				oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1,  sizeof(oncore_cmd_Av1));
3599 		}
3600 	}
3601 }
3602 
3603 
3604 
3605 /*
3606  * Here we do the Software SiteSurvey.
3607  * We have to average our own position for the Position Hold Mode
3608  *   We use Heights from the GPS ellipsoid.
3609  * We check for the END of either HW or SW SiteSurvey.
3610  */
3611 
3612 static void
3613 oncore_ss(
3614 	struct instance *instance
3615 	)
3616 {
3617 	char	*cp, Msg[160];
3618 	double	lat, lon, ht;
3619 
3620 
3621 	if (instance->site_survey == ONCORE_SS_HW) {
3622 		/*
3623 		 * Check to see if Hardware SiteSurvey has Finished.
3624 		 */
3625 
3626 		if ((instance->chan == 8  && !(instance->BEHa[37]  & 0x20)) ||
3627 		    (instance->chan == 12 && !(instance->BEHa[130] & 0x10))) {
3628 			record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode");
3629 
3630 			if (instance->chan == 12)
3631 				oncore_sendmsg(instance->ttyfd, oncore_cmd_Gax, sizeof(oncore_cmd_Gax));
3632 			else
3633 				oncore_sendmsg(instance->ttyfd, oncore_cmd_Asx, sizeof(oncore_cmd_Asx));
3634 
3635 			cp = "SSstate = ONCORE_SS_DONE";
3636 			record_clock_stats(&(instance->peer->srcadr), cp);
3637 			instance->site_survey = ONCORE_SS_DONE;
3638 		}
3639 	} else {
3640 		/*
3641 		 * Must be a Software Site Survey.
3642 		 */
3643 
3644 		if (instance->rsm.bad_fix)	/* Not if poor geometry or less than 3 sats */
3645 			return;
3646 
3647 		if (instance->mode != MODE_3D)	/* Use only 3D Fixes */
3648 			return;
3649 
3650 		instance->ss_lat  += buf_w32(&instance->BEHa[15]);
3651 		instance->ss_long += buf_w32(&instance->BEHa[19]);
3652 		instance->ss_ht   += buf_w32(&instance->BEHa[23]);  /* GPS ellipsoid */
3653 		instance->ss_count++;
3654 
3655 		if (instance->ss_count != POS_HOLD_AVERAGE)
3656 			return;
3657 
3658 		instance->ss_lat  /= POS_HOLD_AVERAGE;
3659 		instance->ss_long /= POS_HOLD_AVERAGE;
3660 		instance->ss_ht   /= POS_HOLD_AVERAGE;
3661 
3662 		sprintf(Msg, "Surveyed posn: lat %.3f (mas) long %.3f (mas) ht %.3f (cm)",
3663 			instance->ss_lat, instance->ss_long, instance->ss_ht);
3664 		record_clock_stats(&(instance->peer->srcadr), Msg);
3665 		lat = instance->ss_lat/3600000.;
3666 		lon = instance->ss_long/3600000.;
3667 		ht  = instance->ss_ht/100;
3668 		sprintf(Msg, "Surveyed posn: lat %.7f (deg) long %.7f (deg) ht %.2f (m)",
3669 			lat, lon, ht);
3670 		record_clock_stats(&(instance->peer->srcadr), Msg);
3671 
3672 		oncore_set_posn(instance);
3673 
3674 		record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode");
3675 
3676 		cp = "SSstate = ONCORE_SS_DONE";
3677 		record_clock_stats(&(instance->peer->srcadr), cp);
3678 		instance->site_survey = ONCORE_SS_DONE;
3679 	}
3680 }
3681 
3682 
3683 
3684 static int
3685 oncore_wait_almanac(
3686 	struct instance *instance
3687 	)
3688 {
3689 	if (instance->rsm.bad_almanac) {
3690 #ifdef DEBUG
3691 		if (debug)
3692 			printf("ONCORE[%d]: waiting for almanac\n", instance->unit);
3693 #endif
3694 
3695 		/*
3696 		 * If we get here (first time) then we don't have an almanac in memory.
3697 		 * Check if we have a SHMEM, and if so try to load whatever is there.
3698 		 */
3699 
3700 		if (!instance->almanac_from_shmem) {
3701 			instance->almanac_from_shmem = 1;
3702 			oncore_load_almanac(instance);
3703 		}
3704 		return(1);
3705 	} else {  /* Here we have the Almanac, we will be starting the @@Bn/@@En/@@Hn
3706 		     commands, and can finally check for TRAIM.  Again, we set a delay
3707 		     (5sec) and wait for things to settle down */
3708 
3709 		if (instance->chan == 6)
3710 			oncore_sendmsg(instance->ttyfd, oncore_cmd_Bn, sizeof(oncore_cmd_Bn));
3711 		else if (instance->chan == 8)
3712 			oncore_sendmsg(instance->ttyfd, oncore_cmd_En, sizeof(oncore_cmd_En));
3713 		else if (instance->chan == 12) {
3714 			oncore_sendmsg(instance->ttyfd, oncore_cmd_Gc, sizeof(oncore_cmd_Gc));	/* 1PPS on, continuous */
3715 			oncore_sendmsg(instance->ttyfd, oncore_cmd_Ge, sizeof(oncore_cmd_Ge));	/* TRAIM on */
3716 			oncore_sendmsg(instance->ttyfd, oncore_cmd_Hn, sizeof(oncore_cmd_Hn));	/* TRAIM status 1/s */
3717 		}
3718 		instance->traim_delay = 1;
3719 
3720 		record_clock_stats(&(instance->peer->srcadr), "Have now loaded an ALMANAC");
3721 
3722 		instance->o_state = ONCORE_RUN;
3723 		record_clock_stats(&(instance->peer->srcadr), "state = ONCORE_RUN");
3724 	}
3725 	return(0);
3726 }
3727 
3728 
3729 
3730 #else
3731 int refclock_oncore_bs;
3732 #endif /* REFCLOCK */
3733