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