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