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