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