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