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