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