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