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