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