File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / ntpd / refclock_oncore.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:08:38 2012 UTC (12 years, 1 month ago) by misho
Branches: ntp, MAIN
CVS tags: v4_2_6p5p0, v4_2_6p5, HEAD
ntp 4.2.6p5

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>