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