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