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