]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ntp/ntpd/refclock_oncore.c
Use the stock (3.1 pre) file.
[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.
13  *      The receivers with TRAIM (VP, UT, UT+), will be more accurate than the others.
14  *      The receivers without position hold (GT, GT+) will be less accurate.
15  *
16  * Tested with:
17  *
18  *              (UT)                               (VP)
19  *   COPYRIGHT 1991-1997 MOTOROLA INC.  COPYRIGHT 1991-1996 MOTOROLA INC.
20  *   SFTW P/N #     98-P36848P          SFTW P/N # 98-P36830P
21  *   SOFTWARE VER # 2                   SOFTWARE VER # 8
22  *   SOFTWARE REV # 2                   SOFTWARE REV # 8
23  *   SOFTWARE DATE  APR 24 1998         SOFTWARE DATE  06 Aug 1996
24  *   MODEL #    R1121N1114              MODEL #    B4121P1155
25  *   HWDR P/N # 1                       HDWR P/N # _
26  *   SERIAL #   R0010A                  SERIAL #   SSG0226478
27  *   MANUFACTUR DATE 6H07               MANUFACTUR DATE 7E02
28  *                                      OPTIONS LIST    IB
29  *
30  *            (Basic)                              (M12)
31  *   COPYRIGHT 1991-1996 MOTOROLA INC.  COPYRIGHT 1991-2000 MOTOROLA INC.
32  *   SFTW P/N # 98-P36830P              SFTW P/N # 61-G10002A
33  *   SOFTWARE VER # 8                   SOFTWARE VER # 1
34  *   SOFTWARE REV # 8                   SOFTWARE REV # 3
35  *   SOFTWARE DATE  06 Aug 1996         SOFTWARE DATE  Mar 13 2000
36  *   MODEL #    B4121P1155              MODEL #    P143T12NR1
37  *   HDWR P/N # _                       HWDR P/N # 1
38  *   SERIAL #   SSG0226478              SERIAL #   P003UD
39  *   MANUFACTUR DATE 7E02               MANUFACTUR DATE 0C27
40  *   OPTIONS LIST    IB
41  *
42  * --------------------------------------------------------------------------
43  * This code uses the two devices
44  *      /dev/oncore.serial.n
45  *      /dev/oncore.pps.n
46  * which may be linked to the same device.
47  * and can read initialization data from the file
48  *      /etc/ntp.oncoreN, /etc/ntp.oncore.N, or /etc/ntp.oncore, where
49  *      n or N are the unit number, viz 127.127.30.N.
50  * --------------------------------------------------------------------------
51  * Reg.Clemens <reg@dwf.com> Sep98.
52  *  Original code written for FreeBSD.
53  *  With these mods it works on FreeBSD, SunOS, Solaris and Linux
54  *    (SunOS 4.1.3 + ppsclock)
55  *    (Solaris7 + MU4)
56  *    (RedHat 5.1 2.0.35 + PPSKit, 2.1.126 + or later).
57  *
58  *  Lat,Long,Ht, cable-delay, offset, and the ReceiverID (along with the
59  *  state machine state) are printed to CLOCKSTATS if that file is enabled
60  *  in /etc/ntp.conf.
61  *
62  * --------------------------------------------------------------------------
63  *
64  * According to the ONCORE manual (TRM0003, Rev 3.2, June 1998, page 3.13)
65  * doing an average of 10000 valid 2D and 3D fixes is what the automatic
66  * site survey mode does.  Looking at the output from the receiver
67  * it seems like it is only using 3D fixes.
68  * When we do it ourselves, take 10000 3D fixes.
69  */
70
71 #define POS_HOLD_AVERAGE        10000   /* nb, 10000s ~= 2h45m */
72
73 /*
74  * ONCORE_SHMEM_STATUS will create a mmap(2)'ed file named according to a
75  * "STATUS" line in the oncore config file, which contains the most recent
76  * copy of all types of messages we recognize.  This file can be mmap(2)'ed
77  * by monitoring and statistics programs.
78  *
79  * See separate HTML documentation for this option.
80  */
81
82 #ifdef HAVE_CONFIG_H
83 #include <config.h>
84 #endif
85
86 #if defined(REFCLOCK) && defined(CLOCK_ONCORE) && defined(HAVE_PPSAPI)
87
88 #include "ntpd.h"
89 #include "ntp_io.h"
90 #include "ntp_unixtime.h"
91 #include "ntp_refclock.h"
92 #include "ntp_stdlib.h"
93
94 #include <stdio.h>
95 #include <ctype.h>
96 #include <sys/stat.h>
97 #ifdef ONCORE_SHMEM_STATUS
98 # ifdef HAVE_SYS_MMAN_H
99 #  include <sys/mman.h>
100 #  ifndef MAP_FAILED
101 #   define MAP_FAILED ((u_char *) -1)
102 #  endif  /* not MAP_FAILED */
103 # endif /* HAVE_SYS_MMAN_H */
104 #endif /* ONCORE_SHMEM_STATUS */
105
106 #ifdef HAVE_PPSAPI
107 # ifdef HAVE_TIMEPPS_H
108 #  include <timepps.h>
109 # else
110 #  ifdef HAVE_SYS_TIMEPPS_H
111 #   include <sys/timepps.h>
112 #  endif
113 # endif
114 #endif
115
116 #ifdef HAVE_SYS_SIO_H
117 # include <sys/sio.h>
118 #endif
119
120 #ifdef HAVE_SYS_TERMIOS_H
121 # include <sys/termios.h>
122 #endif
123
124 #ifdef HAVE_SYS_PPSCLOCK_H
125 # include <sys/ppsclock.h>
126 #endif
127
128 #ifndef HAVE_STRUCT_PPSCLOCKEV
129 struct ppsclockev {
130 # ifdef HAVE_STRUCT_TIMESPEC
131         struct timespec tv;
132 # else
133         struct timeval tv;
134 # endif
135         u_int serial;
136 };
137 #endif /* not HAVE_STRUCT_PPSCLOCKEV */
138
139 enum receive_state {
140         ONCORE_NO_IDEA,
141         ONCORE_ID_SENT,
142         ONCORE_RESET_SENT,
143         ONCORE_TEST_SENT,
144         ONCORE_INIT,
145         ONCORE_ALMANAC,
146         ONCORE_RUN
147 };
148
149 enum site_survey_state {
150         ONCORE_SS_UNKNOWN,
151         ONCORE_SS_TESTING,
152         ONCORE_SS_HW,
153         ONCORE_SS_SW,
154         ONCORE_SS_DONE
155 };
156
157 /* Model Name, derived from the @@Cj message.
158  * Used to initialize some variables.
159  */
160
161 enum oncore_model {
162         ONCORE_BASIC,
163         ONCORE_PVT6,
164         ONCORE_VP,
165         ONCORE_UT,
166         ONCORE_UTPLUS,
167         ONCORE_GT,
168         ONCORE_GTPLUS,
169         ONCORE_SL,
170         ONCORE_M12,
171         ONCORE_UNKNOWN
172 };
173
174 /* the bits that describe these properties are in the same place
175  * on the VP/UT, but have moved on the M12.  As such we extract
176  * them, and use them from this struct.
177  *
178  */
179
180 struct RSM {
181         u_char  posn0D;
182         u_char  posn2D;
183         u_char  posn3D;
184         u_char  bad_almanac;
185         u_char  bad_fix;
186 };
187
188 /* It is possible to test the VP/UT each cycle (@@Ea or equivalent) to
189  * see what mode it is in.  The bits on the M12 are multiplexed with
190  * other messages, so we have to 'keep' the last known mode here.
191  */
192
193 enum posn_mode {
194         MODE_UNKNOWN,
195         MODE_0D,
196         MODE_2D,
197         MODE_3D
198 };
199
200 struct instance {
201         int     unit;           /* 127.127.30.unit */
202         struct  refclockproc *pp;
203         struct  peer *peer;
204
205         int     ttyfd;          /* TTY file descriptor */
206         int     ppsfd;          /* PPS file descriptor */
207         int     statusfd;       /* Status shm descriptor */
208 #ifdef HAVE_PPSAPI
209         pps_handle_t pps_h;
210         pps_params_t pps_p;
211 #endif
212         enum receive_state o_state;             /* Receive state */
213         enum posn_mode mode;                    /* 0D, 2D, 3D */
214         enum site_survey_state site_survey;     /* Site Survey state */
215
216         int     Bj_day;
217
218         u_long  delay;          /* ns */
219         long    offset;         /* ns */
220
221         u_char  *shmem;
222         char    *shmem_fname;
223         u_int   shmem_Cb;
224         u_int   shmem_Ba;
225         u_int   shmem_Ea;
226         u_int   shmem_Ha;
227         u_char  shmem_first;
228         u_char  shmem_reset;
229         u_char  shmem_Posn;
230
231         double  ss_lat;
232         double  ss_long;
233         double  ss_ht;
234         double  dH;
235         int     ss_count;
236         u_char  posn_set;
237
238         enum oncore_model model;
239         u_int   version;
240         u_int   revision;
241
242         u_char  chan;           /* 6 for PVT6 or BASIC, 8 for UT/VP, 12 for m12, 0 if unknown */
243         s_char  traim;          /* do we have traim? yes UT/VP, no BASIC, GT, -1 unknown, 0 no, +1 yes */
244         u_char  traim_delay;    /* seconds counter, waiting for reply */
245
246         struct  RSM rsm;        /* bits extracted from Receiver Status Msg in @@Ea */
247         u_char  printed;
248         u_char  polled;
249         int     pollcnt;
250         u_int   ev_serial;
251         int     Rcvptr;
252         u_char  Rcvbuf[500];
253         u_char  Ea[160];        /* Ba, Ea or Ha */
254         u_char  En[70];         /* Bn or En */
255         u_char  Cj[300];
256         u_char  As;
257         u_char  Ay;
258         u_char  Az;
259         u_char  have_dH;
260         u_char  init_type;
261         s_char  saw_tooth;
262         u_int   timeout;        /* count to retry Cj after Fa self-test */
263         u_char  count;          /* cycles thru Ea before starting */
264         s_char  assert;
265         u_int   saw_At;
266 };
267
268 #define rcvbuf  instance->Rcvbuf
269 #define rcvptr  instance->Rcvptr
270
271 static  void    oncore_consume       P((struct instance *));
272 static  void    oncore_poll          P((int, struct peer *));
273 static  void    oncore_read_config   P((struct instance *));
274 static  void    oncore_receive       P((struct recvbuf *));
275 static  void    oncore_sendmsg       P((int fd, u_char *, size_t));
276 static  void    oncore_shutdown      P((int, struct peer *));
277 static  int     oncore_start         P((int, struct peer *));
278 static  void    oncore_get_timestamp P((struct instance *, long, long));
279 static  void    oncore_init_shmem    P((struct instance *));
280 static  void    oncore_print_As      P((struct instance *));
281
282 static  void    oncore_msg_any     P((struct instance *, u_char *, size_t, int));
283 static  void    oncore_msg_As      P((struct instance *, u_char *, size_t));
284 static  void    oncore_msg_At      P((struct instance *, u_char *, size_t));
285 static  void    oncore_msg_Ay      P((struct instance *, u_char *, size_t));
286 static  void    oncore_msg_Az      P((struct instance *, u_char *, size_t));
287 static  void    oncore_msg_BaEaHa  P((struct instance *, u_char *, size_t));
288 static  void    oncore_msg_Bj      P((struct instance *, u_char *, size_t));
289 static  void    oncore_msg_BnEn    P((struct instance *, u_char *, size_t));
290 static  void    oncore_msg_CaFaIa  P((struct instance *, u_char *, size_t));
291 static  void    oncore_msg_Cb      P((struct instance *, u_char *, size_t));
292 static  void    oncore_msg_Cf      P((struct instance *, u_char *, size_t));
293 static  void    oncore_msg_Cj      P((struct instance *, u_char *, size_t));
294 static  void    oncore_msg_Cj_id   P((struct instance *, u_char *, size_t));
295 static  void    oncore_msg_Cj_init P((struct instance *, u_char *, size_t));
296 static  void    oncore_msg_Gj      P((struct instance *, u_char *, size_t));
297 static  void    oncore_msg_Sz      P((struct instance *, u_char *, size_t));
298
299 struct  refclock refclock_oncore = {
300         oncore_start,           /* start up driver */
301         oncore_shutdown,        /* shut down driver */
302         oncore_poll,            /* transmit poll message */
303         noentry,                /* not used */
304         noentry,                /* not used */
305         noentry,                /* not used */
306         NOFLAGS                 /* not used */
307 };
308
309 /*
310  * Understanding the next bit here is not easy unless you have a manual
311  * for the the various Oncore Models.
312  */
313
314 static struct msg_desc {
315         const char      flag[3];
316         const int       len;
317         void            (*handler) P((struct instance *, u_char *, size_t));
318         const char      *fmt;
319         int             shmem;
320 } oncore_messages[] = {
321                         /* Ea and En first since they're most common */
322         { "Ea",  76,    oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdimsdimsdsC" },
323         { "Ba",  68,    oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdsC" },
324         { "Ha", 154,    oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmaaaaoooohhhhmmmmVVvvhhddntimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddssrrccooooTTushmvvvvvvC" },
325         { "En",  69,    oncore_msg_BnEn,   "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffsffffsffffC" },
326         { "Bn",  59,    oncore_msg_BnEn,   "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffC" },
327         { "Ab",  10,    0,                 "" },
328         { "Ac",  11,    0,                 "" },
329         { "Ad",  11,    0,                 "" },
330         { "Ae",  11,    0,                 "" },
331         { "Af",  15,    0,                 "" },
332         { "As",  20,    oncore_msg_As,     "" },
333         { "At",   8,    oncore_msg_At,     "" },
334         { "Au",  12,    0,                 "" },
335         { "Av",   8,    0,                 "" },
336         { "Aw",   8,    0,                 "" },
337         { "Ay",  11,    oncore_msg_Ay,     "" },
338         { "Az",  11,    oncore_msg_Az,     "" },
339         { "AB",   8,    0,                 "" },
340         { "Bb",  92,    0,                 "" },
341         { "Bj",   8,    oncore_msg_Bj,     "" },
342         { "Ca",   9,    oncore_msg_CaFaIa, "" },
343         { "Cb",  33,    oncore_msg_Cb,     "" },
344         { "Cf",   7,    oncore_msg_Cf,     "" },
345         { "Cg",   8,    0,                 "" },
346         { "Ch",   9,    0,                 "" },
347         { "Cj", 294,    oncore_msg_Cj,     "" },
348         { "Ek",  71,    0,                 "" },
349         { "Fa",   9,    oncore_msg_CaFaIa, "" },
350         { "Gd",   8,    0,                 "" },
351         { "Gj",  21,    oncore_msg_Gj,     "" },
352         { "Ia",  10,    oncore_msg_CaFaIa, "" },
353         { "Sz",   8,    oncore_msg_Sz,     "" },
354         { {0},    7,    0,                 "" }
355 };
356
357 /*
358  * Position Set.
359  */
360 u_char oncore_cmd_Ad[] = { 'A', 'd', 0,0,0,0 };
361 u_char oncore_cmd_Ae[] = { 'A', 'e', 0,0,0,0 };
362 u_char oncore_cmd_Af[] = { 'A', 'f', 0,0,0,0, 0 };
363 u_char oncore_cmd_Ga[] = { 'G', 'a', 0,0,0,0, 0,0,0,0, 0,0,0,0, 0 };
364
365 /*
366  * Position-Hold Mode
367  *    Start automatic site survey
368  */
369 static u_char oncore_cmd_At0[] = { 'A', 't', 0 };       /* Posn Hold off */
370 static u_char oncore_cmd_At1[] = { 'A', 't', 1 };       /* Posn Hold on  */
371 static u_char oncore_cmd_At2[] = { 'A', 't', 2 };       /* Start Site Survey */
372
373 /*
374  * 0D/2D Position and Set.
375  */
376 u_char oncore_cmd_As[] = { 'A', 's', 0,0,0,0, 0,0,0,0, 0,0,0,0, 0 };
377 u_char oncore_cmd_Asx[]= { 'A', 's', 0x7f, 0xff, 0xff, 0xff,
378                                      0x7f, 0xff, 0xff, 0xff,
379                                      0x7f, 0xff, 0xff, 0xff, 0xff };
380 u_char oncore_cmd_Au[] = { 'A', 'u', 0,0,0,0,0 };
381
382 u_char oncore_cmd_Av0[] = { 'A', 'v', 0 };
383 u_char oncore_cmd_Av1[] = { 'A', 'v', 1 };
384
385 u_char oncore_cmd_Gd0[] = { 'G', 'd', 0 };      /* 3D */
386 u_char oncore_cmd_Gd1[] = { 'G', 'd', 1 };      /* 0D */
387 u_char oncore_cmd_Gd2[] = { 'G', 'd', 2 };      /* 2D */
388
389 /*
390  * Set to UTC time (not GPS).
391  */
392 u_char oncore_cmd_Aw[] = { 'A', 'w', 1 };
393
394 /*
395  * Output Almanac when it changes
396  */
397 u_char oncore_cmd_Be[] = { 'B', 'e', 1 };
398
399 /*
400  * Read back PPS Offset for Output
401  */
402 u_char oncore_cmd_Ay[]  = { 'A', 'y', 0, 0, 0, 0 };
403 u_char oncore_cmd_Ayx[] = { 'A', 'y', 0xff, 0xff, 0xff, 0xff };
404
405 /*
406  * Read back Cable Delay for Output
407  */
408 u_char oncore_cmd_Az[]  = { 'A', 'z', 0, 0, 0, 0 };
409 u_char oncore_cmd_Azx[] = { 'A', 'z', 0xff, 0xff, 0xff, 0xff };
410
411 /*
412  * Application type = static.
413  */
414 u_char oncore_cmd_AB[] = { 'A', 'B', 4 };
415
416 /*
417  * Visible Satellite Status Msg.
418  */
419 u_char oncore_cmd_Bb[] = { 'B', 'b', 1 };
420
421 /*
422  * Leap Second Pending Message
423  *    Request message once
424  */
425 u_char oncore_cmd_Bj[] = { 'B', 'j', 0 };
426 u_char oncore_cmd_Gj[] = { 'G', 'j' };
427
428 /*
429  * Set to Defaults
430  */
431 static u_char oncore_cmd_Cf[] = { 'C', 'f' };
432
433 /*
434  * Set to Position Fix mode (only needed on VP).
435  */
436 u_char oncore_cmd_Cg[] = { 'C', 'g', 1 };
437
438 /*
439  * Receiver Id
440  */
441 static u_char oncore_cmd_Cj[] = { 'C', 'j' };
442
443 /*
444  * Position/Status/Data message
445  *    Send once per second
446  */
447 static u_char oncore_cmd_Ea[]  = { 'E', 'a', 1 };
448 static u_char oncore_cmd_Ba[]  = { 'B', 'a', 1 };
449 static u_char oncore_cmd_Ha[]  = { 'H', 'a', 1 };
450 static u_char oncore_cmd_Ea0[] = { 'E', 'a', 0 };
451 static u_char oncore_cmd_Ba0[] = { 'B', 'a', 0 };
452
453 /*
454  * Position/Status Extension Msg
455  */
456 u_char oncore_cmd_Ek[] = { 'E', 'k', 0 };       /* just turn off */
457
458 /*
459  * Time Raim Setup & Status Message
460  *    Send once per second
461  *    Time-RAIM on
462  *    Alarm limit 1us
463  *    PPS on when we have the first sat
464  */
465 static u_char oncore_cmd_En[]  = { 'E', 'n', 1, 1, 0,10, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
466 static u_char oncore_cmd_En0[] = { 'E', 'n', 0, 1, 0,10, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
467 static u_char oncore_cmd_Bn[]  = { 'B', 'n', 1, 1, 0,10, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
468 static u_char oncore_cmd_Bn0[] = { 'B', 'n', 0, 1, 0,10, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
469
470 /*
471  * Self-test
472  */
473 static u_char oncore_cmd_Ca[] = { 'C', 'a' };   /*  6 Chan */
474 static u_char oncore_cmd_Fa[] = { 'F', 'a' };   /*  8 Chan */
475 static u_char oncore_cmd_Ia[] = { 'I', 'a' };   /* 12 Chan */
476
477 #define DEVICE1         "/dev/oncore.serial.%d"   /* name of serial device */
478 #define DEVICE2         "/dev/oncore.pps.%d"   /* name of pps device */
479 #define INIT_FILE       "/etc/ntp.oncore" /* optional init file */
480
481 #define SPEED           B9600           /* Oncore Binary speed (9600 bps) */
482
483 /*
484  * Assemble and disassemble 32bit signed quantities from a buffer.
485  *
486  */
487
488         /* to buffer, int w, u_char *buf */
489 #define w32_buf(buf,w)  { u_int i_tmp;                     \
490                           i_tmp = (w<0) ? (~(-w)+1) : (w); \
491                           (buf)[0] = (i_tmp >> 24) & 0xff; \
492                           (buf)[1] = (i_tmp >> 16) & 0xff; \
493                           (buf)[2] = (i_tmp >>  8) & 0xff; \
494                           (buf)[3] = (i_tmp      ) & 0xff; \
495                         }
496
497 #define w32(buf)      (((buf)[0]&0xff) << 24 | \
498                        ((buf)[1]&0xff) << 16 | \
499                        ((buf)[2]&0xff) <<  8 | \
500                        ((buf)[3]&0xff) )
501
502         /* from buffer, char *buf, result to an int */
503 #define buf_w32(buf) (((buf)[0]&0200) ? (-(~w32(buf)+1)) : w32(buf))
504
505 extern int pps_assert;
506 extern int pps_hardpps;
507
508
509
510 /*
511  * oncore_start - initialize data for processing
512  */
513
514 static int
515 oncore_start(
516         int unit,
517         struct peer *peer
518         )
519 {
520         register struct instance *instance;
521         struct refclockproc *pp;
522         int fd1, fd2, mode;
523         char device1[30], device2[30];
524         const char *cp;
525         struct stat stat1, stat2;
526
527         /* OPEN DEVICES */
528         /* opening different devices for fd1 and fd2 presents no problems */
529         /* opening the SAME device twice, seems to be OS dependent.
530                 (a) on Linux (no streams) no problem
531                 (b) on SunOS (and possibly Solaris, untested), (streams)
532                         never see the line discipline.
533            Since things ALWAYS work if we only open the device once, we check
534              to see if the two devices are in fact the same, then proceed to
535              do one open or two.
536         */
537
538         (void)sprintf(device1, DEVICE1, unit);
539         (void)sprintf(device2, DEVICE2, unit);
540
541         if (stat(device1, &stat1)) {
542                 perror("ONCORE: stat fd1");
543                 exit(1);
544         }
545
546         if (stat(device2, &stat2)) {
547                 perror("ONCORE: stat fd2");
548                 exit(1);
549         }
550
551         if ((stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino)) {
552                 /* same device here */
553                 if (!(fd1 = refclock_open(device1, SPEED, LDISC_RAW
554 #if !defined(HAVE_PPSAPI) && !defined(TIOCDCDTIMESTAMP)
555                       | LDISC_PPS
556 #endif
557                    ))) {
558                         perror("ONCORE: fd1");
559                         exit(1);
560                 }
561                 fd2 = fd1;
562         } else { /* different devices here */
563                 if (!(fd1=refclock_open(device1, SPEED, LDISC_RAW))) {
564                         perror("ONCORE: fd1");
565                         exit(1);
566                 }
567                 if ((fd2=open(device2, O_RDWR)) < 0) {
568                         perror("ONCORE: fd2");
569                         exit(1);
570                 }
571         }
572
573         /* Devices now open, create instance structure for this unit */
574
575         if (!(instance = (struct instance *) malloc(sizeof *instance))) {
576                 perror("malloc");
577                 close(fd1);
578                 return (0);
579         }
580         memset((char *) instance, 0, sizeof *instance);
581
582         /* link instance up and down */
583
584         pp = peer->procptr;
585         pp->unitptr    = (caddr_t) instance;
586         instance->pp   = pp;
587         instance->unit = unit;
588         instance->peer = peer;
589
590         /* initialize miscellaneous variables */
591
592         instance->o_state = ONCORE_NO_IDEA;
593         cp = "state = ONCORE_NO_IDEA";
594         record_clock_stats(&(instance->peer->srcadr), cp);
595
596         instance->ttyfd = fd1;
597         instance->ppsfd = fd2;
598
599         instance->Bj_day = -1;
600         instance->assert = pps_assert;
601         instance->traim = -1;
602         instance->model = ONCORE_UNKNOWN;
603         instance->mode = MODE_UNKNOWN;
604         instance->site_survey = ONCORE_SS_UNKNOWN;
605
606         peer->precision = -26;
607         peer->minpoll = 4;
608         peer->maxpoll = 4;
609         pp->clockdesc = "Motorola Oncore GPS Receiver";
610         memcpy((char *)&pp->refid, "GPS\0", (size_t) 4);
611
612         /* go read any input data in /etc/ntp.oncoreX */
613
614         oncore_read_config(instance);
615
616 #ifdef HAVE_PPSAPI
617         if (time_pps_create(fd2, &instance->pps_h) < 0) {
618                 perror("time_pps_create");
619                 return(0);
620         }
621
622         if (time_pps_getcap(instance->pps_h, &mode) < 0) {
623                 msyslog(LOG_ERR,
624                     "refclock_ioctl: time_pps_getcap failed: %m");
625                 return (0);
626         }
627
628         if (time_pps_getparams(instance->pps_h, &instance->pps_p) < 0) {
629                 msyslog(LOG_ERR,
630                     "refclock_ioctl: time_pps_getparams failed: %m");
631                 return (0);
632         }
633
634         /* nb. only turn things on, if someone else has turned something
635          *      on before we get here, leave it alone!
636          */
637
638         if (instance->assert) {         /* nb, default or ON */
639                 instance->pps_p.mode = PPS_CAPTUREASSERT | PPS_OFFSETASSERT;
640                 instance->pps_p.assert_offset.tv_sec = 0;
641                 instance->pps_p.assert_offset.tv_nsec = 0;
642         } else {
643                 instance->pps_p.mode = PPS_CAPTURECLEAR  | PPS_OFFSETCLEAR;
644                 instance->pps_p.clear_offset.tv_sec = 0;
645                 instance->pps_p.clear_offset.tv_nsec = 0;
646         }
647         instance->pps_p.mode |= PPS_TSFMT_TSPEC;
648         instance->pps_p.mode &= mode;           /* only set what is legal */
649
650         if (time_pps_setparams(instance->pps_h, &instance->pps_p) < 0) {
651                 perror("time_pps_setparams");
652                 exit(1);
653         }
654
655         if (pps_device) {
656                 if (stat(pps_device, &stat1)) {
657                         perror("ONCORE: stat pps_device");
658                         return(0);
659                 }
660
661                 /* must have hardpps ON, and fd2 must be the same device as on the pps line */
662
663                 if (pps_hardpps && ((stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino))) {
664                         int     i;
665
666                         if (instance->assert)
667                                 i = PPS_CAPTUREASSERT;
668                         else
669                                 i = PPS_CAPTURECLEAR;
670
671                         if (i&mode) {
672                                 if (time_pps_kcbind(instance->pps_h, PPS_KC_HARDPPS, i,
673                                     PPS_TSFMT_TSPEC) < 0) {
674                                         msyslog(LOG_ERR,
675                                             "refclock_ioctl: time_pps_kcbind failed: %m");
676                                         return (0);
677                                 }
678                                 pps_enable = 1;
679                         }
680                 }
681         }
682 #endif
683
684         pp->io.clock_recv = oncore_receive;
685         pp->io.srcclock = (caddr_t)peer;
686         pp->io.datalen = 0;
687         pp->io.fd = fd1;
688         if (!io_addclock(&pp->io)) {
689                 perror("io_addclock");
690                 (void) close(fd1);
691                 free(instance);
692                 return (0);
693         }
694
695         /*
696          * This will return the Model Number of the Oncore receiver.
697          */
698
699         oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
700         instance->o_state = ONCORE_ID_SENT;
701         cp = "state = ONCORE_ID SENT";
702         record_clock_stats(&(instance->peer->srcadr), cp);
703         instance->timeout = 4;
704
705         instance->pollcnt = 2;
706         return (1);
707 }
708
709
710
711 /*
712  * Read Input file if it exists.
713  */
714
715 static void
716 oncore_read_config(
717         struct instance *instance
718         )
719 {
720 /*
721  * First we try to open the configuration file
722  *    /etc/oncoreN
723  * where N is the unit number viz 127.127.30.N.
724  * If we don't find it we try
725  *    /etc/ntp.oncore.N
726  * and then
727  *    /etc/ntp.oncore
728  *
729  * If we don't find any then we don't have the cable delay or PPS offset
730  * and we choose MODE (4) below.
731  *
732  * Five Choices for MODE
733  *    (0) ONCORE is preinitialized, don't do anything to change it.
734  *          nb, DON'T set 0D mode, DON'T set Delay, position...
735  *    (1) NO RESET, Read Position, delays from data file, lock it in, go to 0D mode.
736  *    (2) NO RESET, Read Delays from data file, do SITE SURVEY to get position,
737  *                  lock this in, go to 0D mode.
738  *    (3) HARD RESET, Read Position, delays from data file, lock it in, go to 0D mode.
739  *    (4) HARD RESET, Read Delays from data file, do SITE SURVEY to get position,
740  *                  lock this in, go to 0D mode.
741  *     NB. If a POSITION is specified in the config file with mode=(2,4) [SITE SURVEY]
742  *         then this position is set as the INITIAL position of the ONCORE.
743  *         This can reduce the time to first fix.
744  * -------------------------------------------------------------------------------
745  * Note that an Oncore UT without a battery backup retains NO information if it is
746  *   power cycled, with a Battery Backup it remembers the almanac, etc.
747  * For an Oncore VP, there is an eeprom that will contain this data, along with the
748  *   option of Battery Backup.
749  * So a UT without Battery Backup is equivalent to doing a HARD RESET on each
750  *   power cycle, since there is nowhere to store the data.
751  * -------------------------------------------------------------------------------
752  *
753  * If we open one or the other of the files, we read it looking for
754  *   MODE, LAT, LON, (HT, HTGPS, HTMSL), DELAY, OFFSET, ASSERT, CLEAR, STATUS,
755  *   POSN3D, POSN2D, CHAN, TRAIM
756  * then initialize using method MODE.  For Mode = (1,3) all of (LAT, LON, HT) must
757  *   be present or mode reverts to (2,4).
758  *
759  * Read input file.
760  *
761  *      # is comment to end of line
762  *      = allowed between 1st and 2nd fields.
763  *
764  *      Expect to see one line with 'MODE' as first field, followed by an integer
765  *         in the range 0-4 (default = 4).
766  *
767  *      Expect to see two lines with 'LONG', 'LAT' followed by 1-3 fields.
768  *      All numbers are floating point.
769  *              DDD.ddd
770  *              DDD  MMM.mmm
771  *              DDD  MMM  SSS.sss
772  *
773  *      Expect to see one line with 'HT' as first field,
774  *         followed by 1-2 fields.  First is a number, the second is 'FT' or 'M'
775  *         for feet or meters.  HT is the height above the GPS ellipsoid.
776  *         If the reciever reports height in both GPS and MSL, then we will report
777  *         the difference GPS-MSL on the clockstats file.
778  *
779  *      There is an optional line, starting with DELAY, followed
780  *         by 1 or two fields.  The first is a number (a time) the second is
781  *         'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds.
782  *          DELAY  is cable delay, typically a few tens of ns.
783  *
784  *      There is an optional line, starting with OFFSET, followed
785  *         by 1 or two fields.  The first is a number (a time) the second is
786  *         'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds.
787  *         OFFSET is the offset of the PPS pulse from 0. (only fully implemented
788  *              with the PPSAPI, we need to be able to tell the Kernel about this
789  *              offset if the Kernel PLL is in use, but can only do this presently
790  *              when using the PPSAPI interface.  If not using the Kernel PLL,
791  *              then there is no problem.
792  *
793  *      There is an optional line, with either ASSERT or CLEAR on it, which
794  *         determine which transition of the PPS signal is used for timing by the
795  *         PPSAPI.  If neither is present, then ASSERT is assumed.
796  *
797  *      There are three options that have to do with using the shared memory opition.
798  *         First, to enable the option there must be an ASSERT line with a file name.
799  *         The file name is the file associated with the shared memory.
800  *
801  *      In the shared memory there are three 'records' containing the @@Ea (or equivalent)
802  *         data, and this contains the position data.  There will always be data in the
803  *         record cooresponding to the '0D' @@Ea record, and the user has a choice of
804  *         filling the '3D' @@Ea record by specifying POSN3D, or the '2D' record by
805  *         specifying POSN2D.  In either case the '2D' or '3D' record is filled once
806  *         every 15s.
807  *
808  *      Two additional variables that can be set are CHAN and TRAIM.  These should be
809  *         set correctly by the code examining the @@Cj record, but we bring them out here
810  *         to allow the user to override either the # of channels, or the existance of TRAIM.
811  *         CHAN expects to be followed by in integer: 6, 8, or 12. TRAIM expects to be
812  *         followed by YES or NO.
813  *
814  * So acceptable input would be
815  *      # these are my coordinates (RWC)
816  *      LON  -106 34.610
817  *      LAT    35 08.999
818  *      HT      1589    # could equally well say HT 5215 FT
819  *      DELAY  60 ns
820  */
821
822         FILE    *fd;
823         char    *cp, *cc, *ca, line[100], units[2], device[20], Msg[160];
824         int     i, sign, lat_flg, long_flg, ht_flg, mode;
825         double  f1, f2, f3;
826
827         sprintf(device, "%s%d", INIT_FILE, instance->unit);             /* try "ntp.oncore0" first */
828         if ((fd=fopen(device, "r")) == NULL) {                          /*   it was in the original documentation */
829                 sprintf(device, "%s.%d", INIT_FILE, instance->unit);    /* then try "ntp.oncore.0 */
830                 if ((fd=fopen(device, "r")) == NULL) {
831                         if ((fd=fopen(INIT_FILE, "r")) == NULL) {       /* and finally "ntp.oncore" */
832                                 instance->init_type = 4;
833                                 return;
834                         }
835                 }
836         }
837
838         mode = 0;
839         lat_flg = long_flg = ht_flg = 0;
840         while (fgets(line, 100, fd)) {
841
842                 /* Remove comments */
843                 if ((cp = strchr(line, '#')))
844                         *cp = '\0';
845
846                 /* Remove trailing space */
847                 for (i = strlen(line);
848                      i > 0 && isascii((int)line[i - 1]) && isspace((int)line[i - 1]);
849                         )
850                         line[--i] = '\0';
851
852                 /* Remove leading space */
853                 for (cc = line; *cc && isascii((int)*cc) && isspace((int)*cc); cc++)
854                         continue;
855
856                 /* Stop if nothing left */
857                 if (!*cc)
858                         continue;
859
860                 /* Uppercase the command and find the arg */
861                 for (ca = cc; *ca; ca++) {
862                         if (isascii((int)*ca)) {
863                                 if (islower((int)*ca)) {
864                                         *ca = toupper(*ca);
865                                 } else if (isspace((int)*ca) || (*ca == '='))
866                                         break;
867                         }
868                 }
869
870                 /* Remove space (and possible =) leading the arg */
871                 for (; *ca && isascii((int)*ca) && (isspace((int)*ca) || (*ca == '=')); ca++)
872                         continue;
873
874                 /*
875                  * move call to oncore_shmem_init() from here to after
876                  * we have determined Oncore Model, so we can ignore
877                  * request if model doesnt 'support' it
878                  */
879
880                 if (!strncmp(cc, "STATUS", (size_t) 6) || !strncmp(cc, "SHMEM", (size_t) 5)) {
881                         i = strlen(ca);
882                         instance->shmem_fname = (char *) malloc((unsigned) (i+1));
883                         strcpy(instance->shmem_fname, ca);
884                         continue;
885                 }
886
887                 /* Uppercase argument as well */
888                 for (cp = ca; *cp; cp++)
889                         if (isascii((int)*cp) && islower((int)*cp))
890                                 *cp = toupper(*cp);
891
892                 if (!strncmp(cc, "LAT", (size_t) 3)) {
893                         f1 = f2 = f3 = 0;
894                         sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3);
895                         sign = 1;
896                         if (f1 < 0) {
897                                 f1 = -f1;
898                                 sign = -1;
899                         }
900                         instance->ss_lat = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/
901                         lat_flg++;
902                 } else if (!strncmp(cc, "LON", (size_t) 3)) {
903                         f1 = f2 = f3 = 0;
904                         sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3);
905                         sign = 1;
906                         if (f1 < 0) {
907                                 f1 = -f1;
908                                 sign = -1;
909                         }
910                         instance->ss_long = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/
911                         long_flg++;
912                 } else if (!strncmp(cc, "HT", (size_t) 2)) {
913                         f1 = 0;
914                         units[0] = '\0';
915                         sscanf(ca, "%lf %1s", &f1, units);
916                         if (units[0] == 'F')
917                                 f1 = 0.3048 * f1;
918                         instance->ss_ht = 100 * f1;    /* cm */
919                         ht_flg++;
920                 } else if (!strncmp(cc, "DELAY", (size_t) 5)) {
921                         f1 = 0;
922                         units[0] = '\0';
923                         sscanf(ca, "%lf %1s", &f1, units);
924                         if (units[0] == 'N')
925                                 ;
926                         else if (units[0] == 'U')
927                                 f1 = 1000 * f1;
928                         else if (units[0] == 'M')
929                                 f1 = 1000000 * f1;
930                         else
931                                 f1 = 1000000000 * f1;
932                         if (f1 < 0 || f1 > 1.e9)
933                                 f1 = 0;
934                         if (f1 < 0 || f1 > 999999) {
935                                 sprintf(Msg, "PPS Cable delay of %fns out of Range, ignored", f1);
936                                 record_clock_stats(&(instance->peer->srcadr), Msg);
937                         } else
938                                 instance->delay = f1;           /* delay in ns */
939                 } else if (!strncmp(cc, "OFFSET", (size_t) 6)) {
940                         f1 = 0;
941                         units[0] = '\0';
942                         sscanf(ca, "%lf %1s", &f1, units);
943                         if (units[0] == 'N')
944                                 ;
945                         else if (units[0] == 'U')
946                                 f1 = 1000 * f1;
947                         else if (units[0] == 'M')
948                                 f1 = 1000000 * f1;
949                         else
950                                 f1 = 1000000000 * f1;
951                         if (f1 < 0 || f1 > 1.e9)
952                                 f1 = 0;
953                         if (f1 < 0 || f1 > 999999999.) {
954                                 sprintf(Msg, "PPS Offset of %fns out of Range, ignored", f1);
955                                 record_clock_stats(&(instance->peer->srcadr), Msg);
956                         } else
957                                 instance->offset = f1;          /* offset in ns */
958                 } else if (!strncmp(cc, "MODE", (size_t) 4)) {
959                         sscanf(ca, "%d", &mode);
960                         if (mode < 0 || mode > 4)
961                                 mode = 4;
962                 } else if (!strncmp(cc, "ASSERT", (size_t) 6)) {
963                         instance->assert = 1;
964                 } else if (!strncmp(cc, "CLEAR", (size_t) 5)) {
965                         instance->assert = 0;
966                 } else if (!strncmp(cc, "POSN2D", (size_t) 6)) {
967                         instance->shmem_Posn = 2;
968                 } else if (!strncmp(cc, "POSN3D", (size_t) 6)) {
969                         instance->shmem_Posn = 3;
970                 } else if (!strncmp(cc, "CHAN", (size_t) 4)) {
971                         sscanf(ca, "%d", &i);
972                         if ((i == 6) || (i == 8) || (i == 12))
973                                 instance->chan = i;
974                 } else if (!strncmp(cc, "TRAIM", (size_t) 5)) {
975                         instance->traim = 1;                            /* so TRAIM alone is YES */
976                         if (!strcmp(ca, "NO") || !strcmp(ca, "OFF"))    /* Yes/No, On/Off */
977                                 instance->traim = 0;
978                 }
979         }
980         fclose(fd);
981
982         /*
983          *    OK, have read all of data file, and extracted the good stuff.
984          *    If lat/long/ht specified they ALL must be specified for mode = (1,3).
985          */
986
987         instance->posn_set = 1;
988         if ((lat_flg || long_flg || ht_flg) && !(lat_flg * long_flg * ht_flg)) {
989                 printf("ONCORE: incomplete data on %s\n", INIT_FILE);
990                 instance->posn_set = 0;
991                 if (mode == 1 || mode == 3) {
992                         sprintf(Msg, "Input Mode = %d, but no/incomplete position, mode set to %d", mode, mode+1);
993                         record_clock_stats(&(instance->peer->srcadr), Msg);
994                         mode++;
995                 }
996         }
997         instance->init_type = mode;
998
999         sprintf(Msg, "Input mode = %d", mode);
1000         record_clock_stats(&(instance->peer->srcadr), Msg);
1001 }
1002
1003
1004
1005 static void
1006 oncore_init_shmem(
1007         struct instance *instance
1008         )
1009 {
1010 #ifdef ONCORE_SHMEM_STATUS
1011         int i, l, n;
1012         char *buf;
1013         struct msg_desc *mp;
1014         size_t oncore_shmem_length;
1015
1016         if (instance->shmem_first)
1017                 return;
1018
1019         instance->shmem_first++;
1020
1021         if ((instance->statusfd = open(instance->shmem_fname, O_RDWR|O_CREAT|O_TRUNC, 0644)) < 0) {
1022                 perror(instance->shmem_fname);
1023                 return;
1024         }
1025
1026         n = 1;
1027         for (mp = oncore_messages; mp->flag[0]; mp++) {
1028                 mp->shmem = n;
1029                 /* Allocate space for multiplexed almanac, and 0D/2D/3D @@Ea records */
1030                 if (!strcmp(mp->flag, "Cb")) {
1031                         instance->shmem_Cb = n;
1032                         n += (mp->len + 3) * 34;
1033                 }
1034                 if (!strcmp(mp->flag, "Ba")) {
1035                         instance->shmem_Ba = n;
1036                         n += (mp->len + 3) * 3;
1037                 }
1038                 if (!strcmp(mp->flag, "Ea")) {
1039                         instance->shmem_Ea = n;
1040                         n += (mp->len + 3) * 3;
1041                 }
1042                 if (!strcmp(mp->flag, "Ha")) {
1043                         instance->shmem_Ha = n;
1044                         n += (mp->len + 3) * 3;
1045                 }
1046                 n += (mp->len + 3);
1047         }
1048         oncore_shmem_length = n + 2;
1049         fprintf(stderr, "ONCORE: SHMEM length: %d bytes\n", (int) oncore_shmem_length);
1050
1051         buf = malloc(oncore_shmem_length);
1052         if (buf == NULL) {
1053                 perror("malloc");
1054                 return;
1055         }
1056         memset(buf, 0, sizeof(buf));
1057         i = write(instance->statusfd, buf, oncore_shmem_length);
1058         if (i != oncore_shmem_length) {
1059                 perror(instance->shmem_fname);
1060                 return;
1061         }
1062         free(buf);
1063         instance->shmem = (u_char *) mmap(0, oncore_shmem_length,
1064             PROT_READ | PROT_WRITE,
1065 #ifdef MAP_HASSEMAPHORE
1066                                MAP_HASSEMAPHORE |
1067 #endif
1068                                MAP_SHARED,
1069             instance->statusfd, (off_t)0);
1070         if (instance->shmem == (u_char *)MAP_FAILED) {
1071                 instance->shmem = 0;
1072                 close (instance->statusfd);
1073                 return;
1074         }
1075         for (mp = oncore_messages; mp->flag[0]; mp++) {
1076                 l = mp->shmem;
1077                 instance->shmem[l + 0] = mp->len >> 8;
1078                 instance->shmem[l + 1] = mp->len & 0xff;
1079                 instance->shmem[l + 2] = 0;
1080                 instance->shmem[l + 3] = '@';
1081                 instance->shmem[l + 4] = '@';
1082                 instance->shmem[l + 5] = mp->flag[0];
1083                 instance->shmem[l + 6] = mp->flag[1];
1084                 if (!strcmp(mp->flag, "Cb") || !strcmp(mp->flag, "Ba") || !strcmp(mp->flag, "Ea") || !strcmp(mp->flag, "Ha")) {
1085                         if (!strcmp(mp->flag, "Cb"))
1086                                 n = 35;
1087                         else
1088                                 n = 4;
1089                         for (i = 1; i < n; i++) {
1090                                 instance->shmem[l + i * (mp->len+3) + 0] = mp->len >> 8;
1091                                 instance->shmem[l + i * (mp->len+3) + 1] = mp->len & 0xff;
1092                                 instance->shmem[l + i * (mp->len+3) + 2] = 0;
1093                                 instance->shmem[l + i * (mp->len+3) + 3] = '@';
1094                                 instance->shmem[l + i * (mp->len+3) + 4] = '@';
1095                                 instance->shmem[l + i * (mp->len+3) + 5] = mp->flag[0];
1096                                 instance->shmem[l + i * (mp->len+3) + 6] = mp->flag[1];
1097                         }
1098                 }
1099         }
1100 #endif /* ONCORE_SHMEM_STATUS */
1101 }
1102
1103
1104
1105 /*
1106  * oncore_shutdown - shut down the clock
1107  */
1108
1109 static void
1110 oncore_shutdown(
1111         int unit,
1112         struct peer *peer
1113         )
1114 {
1115         register struct instance *instance;
1116         struct refclockproc *pp;
1117
1118         pp = peer->procptr;
1119         instance = (struct instance *) pp->unitptr;
1120
1121         io_closeclock(&pp->io);
1122
1123         free(instance);
1124 }
1125
1126
1127
1128 /*
1129  * oncore_poll - called by the transmit procedure
1130  */
1131
1132 static void
1133 oncore_poll(
1134         int unit,
1135         struct peer *peer
1136         )
1137 {
1138         struct instance *instance;
1139
1140         instance = (struct instance *) peer->procptr->unitptr;
1141         if (instance->timeout) {
1142                 char    *cp;
1143
1144                 instance->timeout--;
1145                 if (instance->timeout == 0) {
1146                         cp = "Oncore: No response from @@Cj, shutting down driver";
1147                         record_clock_stats(&(instance->peer->srcadr), cp);
1148                         oncore_shutdown(unit, peer);
1149                 } else {
1150                         oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
1151                         cp = "Oncore: Resend @@Cj";
1152                         record_clock_stats(&(instance->peer->srcadr), cp);
1153                 }
1154                 return;
1155         }
1156
1157         if (!instance->pollcnt)
1158                 refclock_report(peer, CEVNT_TIMEOUT);
1159         else
1160                 instance->pollcnt--;
1161         peer->procptr->polls++;
1162         instance->polled = 1;
1163 }
1164
1165
1166
1167 /*
1168  * move data from NTP to buffer (toss in unlikely case it wont fit)
1169  */
1170
1171 static void
1172 oncore_receive(
1173         struct recvbuf *rbufp
1174         )
1175 {
1176         size_t i;
1177         u_char *p;
1178         struct peer *peer;
1179         struct instance *instance;
1180
1181         peer = (struct peer *)rbufp->recv_srcclock;
1182         instance = (struct instance *) peer->procptr->unitptr;
1183         p = (u_char *) &rbufp->recv_space;
1184
1185 #if 0
1186         if (debug > 4) {
1187                 int i;
1188                 printf("ONCORE: >>>");
1189                 for(i=0; i<rbufp->recv_length; i++)
1190                         printf("%02x ", p[i]);
1191                 printf("\n");
1192                 printf("ONCORE: >>>");
1193                 for(i=0; i<rbufp->recv_length; i++)
1194                         printf("%03o ", p[i]);
1195                 printf("\n");
1196         }
1197 #endif
1198
1199         i = rbufp->recv_length;
1200         if (rcvbuf+rcvptr+i > &rcvbuf[sizeof rcvbuf])
1201                 i = sizeof(rcvbuf) - rcvptr;    /* and some char will be lost */
1202         memcpy(rcvbuf+rcvptr, p, i);
1203         rcvptr += i;
1204         oncore_consume(instance);
1205 }
1206
1207
1208
1209 /*
1210  * Deal with any complete messages
1211  */
1212
1213 static void
1214 oncore_consume(
1215         struct instance *instance
1216         )
1217 {
1218         int i, j, m;
1219         unsigned l;
1220
1221         while (rcvptr >= 7) {
1222                 if (rcvbuf[0] != '@' || rcvbuf[1] != '@') {
1223                         /* We're not in sync, lets try to get there */
1224                         for (i=1; i < rcvptr-1; i++)
1225                                 if (rcvbuf[i] == '@' && rcvbuf[i+1] == '@')
1226                                         break;
1227                         if (debug > 4)
1228                                 printf("ONCORE[%d]: >>> skipping %d chars\n", instance->unit, i);
1229                         if (i != rcvptr)
1230                                 memcpy(rcvbuf, rcvbuf+i, (size_t)(rcvptr-i));
1231                         rcvptr -= i;
1232                         continue;
1233                 }
1234
1235                 /* Ok, we have a header now */
1236                 l = sizeof(oncore_messages)/sizeof(oncore_messages[0]) -1;
1237                 for(m=0; m<l; m++)
1238                         if (!strncmp(oncore_messages[m].flag, (char *)(rcvbuf+2), (size_t) 2))
1239                                 break;
1240                 if (m == l) {
1241                         if (debug > 4)
1242                                 printf("ONCORE[%d]: >>> Unknown MSG, skipping 4 (%c%c)\n", instance->unit, rcvbuf[2], rcvbuf[3]);
1243                         memcpy(rcvbuf, rcvbuf+4, (size_t) 4);
1244                         rcvptr -= 4;
1245                         continue;
1246                 }
1247
1248                 l = oncore_messages[m].len;
1249 #if 0
1250                 if (debug > 3)
1251                         printf("ONCORE[%d]: GOT: %c%c  %d of %d entry %d\n", instance->unit, rcvbuf[2], rcvbuf[3], rcvptr, l, m);
1252 #endif
1253                 /* Got the entire message ? */
1254
1255                 if (rcvptr < l)
1256                         return;
1257
1258                 /* are we at the end of message? should be <Cksum><CR><LF> */
1259
1260                 if (rcvbuf[l-2] != '\r' || rcvbuf[l-1] != '\n') {
1261                         if (debug)
1262                                 printf("ONCORE[%d]: NO <CR><LF> at end of message\n", instance->unit);
1263                 } else {        /* check the CheckSum */
1264                         j = 0;
1265                         for (i = 2; i < l-3; i++)
1266                                 j ^= rcvbuf[i];
1267                         if (j == rcvbuf[l-3]) {
1268                                 if (instance->shmem != NULL) {
1269                                         instance->shmem[oncore_messages[m].shmem + 2]++;
1270                                         memcpy(instance->shmem + oncore_messages[m].shmem + 3,
1271                                             rcvbuf, (size_t) l);
1272                                 }
1273                                 oncore_msg_any(instance, rcvbuf, (size_t) (l-3), m);
1274                                 if (oncore_messages[m].handler)
1275                                         oncore_messages[m].handler(instance, rcvbuf, (size_t) (l-3));
1276                         } else if (debug) {
1277                                 printf("ONCORE[%d]: Checksum mismatch! calc %o is %o\n", instance->unit, j, rcvbuf[l-3]);
1278                                 printf("ONCORE[%d]: @@%c%c ", instance->unit, rcvbuf[2], rcvbuf[3]);
1279                                 for (i=4; i<l; i++)
1280                                         printf("%03o ", rcvbuf[i]);
1281                                 printf("\n");
1282                         }
1283                 }
1284
1285                 if (l != rcvptr)
1286                         memcpy(rcvbuf, rcvbuf+l, (size_t) (rcvptr-l));
1287                 rcvptr -= l;
1288         }
1289 }
1290
1291
1292
1293 /*
1294  * write message to Oncore.
1295  */
1296
1297 static void
1298 oncore_sendmsg(
1299         int     fd,
1300         u_char *ptr,
1301         size_t len
1302         )
1303 {
1304         u_char cs = 0;
1305
1306         printf("ONCORE: Send @@%c%c %d\n", ptr[0], ptr[1], (int) len);
1307         write(fd, "@@", (size_t) 2);
1308         write(fd, ptr, len);
1309         while (len--)
1310                 cs ^= *ptr++;
1311         write(fd, &cs, (size_t) 1);
1312         write(fd, "\r\n", (size_t) 2);
1313 }
1314
1315
1316
1317 /*
1318  * print Oncore response message.
1319  */
1320
1321 static void
1322 oncore_msg_any(
1323         struct instance *instance,
1324         u_char *buf,
1325         size_t len,
1326         int idx
1327         )
1328 {
1329         int i;
1330         const char *fmt = oncore_messages[idx].fmt;
1331         const char *p;
1332 #ifdef HAVE_GETCLOCK
1333         struct timespec ts;
1334 #endif
1335         struct timeval tv;
1336
1337         if (debug > 3) {
1338 #ifdef HAVE_GETCLOCK
1339                 (void) getclock(TIMEOFDAY, &ts); 
1340                 tv.tv_sec = ts.tv_sec; 
1341                 tv.tv_usec = ts.tv_nsec / 1000; 
1342 #else
1343                 GETTIMEOFDAY(&tv, 0);
1344 #endif
1345                 printf("ONCORE[%d]: %ld.%06ld\n", instance->unit, (long) tv.tv_sec, (long) tv.tv_usec);
1346
1347                 if (!*fmt) {
1348                         printf(">>@@%c%c ", buf[2], buf[3]);
1349                         for(i=2; i < len && i < 2400 ; i++)
1350                                 printf("%02x", buf[i]);
1351                         printf("\n");
1352                         return;
1353                 } else {
1354                         printf("##");
1355                         for (p = fmt; *p; p++) {
1356                                 putchar(*p);
1357                                 putchar('_');
1358                         }
1359                         printf("\n%c%c", buf[2], buf[3]);
1360                         i = 4;
1361                         for (p = fmt; *p; p++) {
1362                                 printf("%02x", buf[i++]);
1363                         }
1364                         printf("\n");
1365                 }
1366         }
1367 }
1368
1369
1370
1371 /*
1372  * Demultiplex the almanac into shmem
1373  */
1374
1375 static void
1376 oncore_msg_Cb(
1377         struct instance *instance,
1378         u_char *buf,
1379         size_t len
1380         )
1381 {
1382         int i;
1383
1384         if (instance->shmem == NULL)
1385                 return;
1386
1387         if (buf[4] == 5)
1388                 i = buf[5];
1389         else if (buf[4] == 4 && buf[5] <= 5)
1390                 i = buf[5] + 24;
1391         else if (buf[4] == 4 && buf[5] <= 10)
1392                 i = buf[5] + 23;
1393         else
1394                 i = 34;
1395         i *= 36;
1396         instance->shmem[instance->shmem_Cb + i + 2]++;
1397         memcpy(instance->shmem + instance->shmem_Cb + i + 3, buf, (size_t) (len + 3));
1398 }
1399
1400
1401
1402 /*
1403  * We do an @@Cj twice in the initialization sequence.
1404  * o Once at the very beginning to get the Model number so we know what commands
1405  *   we can issue,
1406  * o And once later after we have done a reset and test, (which may hang),
1407  *   as we are about to initialize the Oncore and start it running.
1408  * o We have one routine below for each case.
1409  */
1410
1411
1412 /*
1413  * Determine the Type from the Model #, this determines #chan and if TRAIM is
1414  *   available.  We use ONLY the #chans, and determint TRAIM by trying it.
1415  */
1416
1417 static void
1418 oncore_msg_Cj(
1419         struct instance *instance,
1420         u_char *buf,
1421         size_t len
1422         )
1423 {
1424         memcpy(instance->Cj, buf, len);
1425
1426         instance->timeout = 0;
1427         if (instance->o_state == ONCORE_ID_SENT)
1428                 oncore_msg_Cj_id(instance, buf, len);
1429         else if (instance->o_state == ONCORE_INIT)
1430                 oncore_msg_Cj_init(instance, buf, len);
1431 }
1432
1433
1434
1435 /* The information on determing a Oncore 'Model', viz VP, UT, etc, from
1436  *      the Model Number comes from "Richard M. Hambly" <rick@cnssys.com>
1437  *      and from Motorola.  Until recently Rick was the only source of
1438  *      this information as Motorola didnt give the information out.
1439  */
1440
1441 static void
1442 oncore_msg_Cj_id(
1443         struct instance *instance,
1444         u_char *buf,
1445         size_t len
1446         )
1447 {
1448         char *cp, *cp1, *cp2, Model[21], Msg[160];
1449         int     mode;
1450
1451         /* Write Receiver ID message to clockstats file */
1452
1453         instance->Cj[294] = '\0';
1454         for (cp=(char *)instance->Cj; cp< (char *) &instance->Cj[294]; ) {
1455                 cp1 = strchr(cp, '\r');
1456                 if (!cp1)
1457                         cp1 = (char *)&instance->Cj[294];
1458                 *cp1 = '\0';
1459                 record_clock_stats(&(instance->peer->srcadr), cp);
1460                 *cp1 = '\r';
1461                 cp = cp1+2;
1462         }
1463
1464         /* next, the Firmware Version and Revision numbers */
1465
1466         instance->version  = atoi(&instance->Cj[83]);
1467         instance->revision = atoi(&instance->Cj[111]);
1468
1469         /* from model number decide which Oncore this is,
1470                 and then the number of channels */
1471
1472         for (cp=&instance->Cj[160]; *cp == ' '; cp++)   /* start right after 'Model #' */
1473                 ;
1474         cp1 = cp;
1475         cp2 = Model;
1476         for (; !isspace((int)*cp) && cp-cp1 < 20; cp++, cp2++)
1477                 *cp2 = *cp;
1478         *cp2 = '\0';
1479
1480         cp = 0;
1481         if (!strncmp(Model, "PVT6", (size_t) 4)) {
1482                 cp = "PVT6";
1483                 instance->model = ONCORE_PVT6;
1484         } else if (Model[0] == 'A') {
1485                 cp = "Basic";
1486                 instance->model = ONCORE_BASIC;
1487         } else if (Model[0] == 'B' || !strncmp(Model, "T8", (size_t) 2)) {
1488                 cp = "VP";
1489                 instance->model = ONCORE_VP;
1490         } else if (!strncmp(Model, "P1", (size_t) 2)) {
1491                 cp = "M12";
1492                 instance->model = ONCORE_M12;
1493         } else if (Model[0] == 'R') {
1494                 if (Model[5] == 'N') {
1495                         cp = "GT";
1496                         instance->model = ONCORE_GT;
1497                 } else if ((Model[1] == '3' || Model[1] == '4') && Model[5] == 'G') {
1498                         cp = "GT+";
1499                         instance->model = ONCORE_GTPLUS;
1500                 } else if ((Model[1] == '5' && Model[5] == 'U') || (Model[1] == '1' && Model[5] == 'A')) {
1501                                 cp = "UT";
1502                                 instance->model = ONCORE_UT;
1503                 } else if (Model[1] == '5' && Model[5] == 'G') {
1504                         cp = "UT+";
1505                         instance->model = ONCORE_UTPLUS;
1506                 } else if (Model[1] == '6' && Model[5] == 'G') {
1507                         cp = "SL";
1508                         instance->model = ONCORE_SL;
1509                 } else {
1510                         cp = "Unknown";
1511                         instance->model = ONCORE_UNKNOWN;
1512                 }
1513         } else  {
1514                 cp = "Unknown";
1515                 instance->model = ONCORE_UNKNOWN;
1516         }
1517
1518         sprintf(Msg, "This looks like an Oncore %s with version %d.%d firmware.", cp, instance->version, instance->revision);
1519         record_clock_stats(&(instance->peer->srcadr), Msg);
1520
1521         if (instance->chan == 0) {      /* dont reset if set in input data */
1522                 instance->chan = 8;     /* default */
1523                 if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6)
1524                         instance->chan = 6;
1525                 else if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || instance->model == ONCORE_UTPLUS)
1526                         instance->chan = 8;
1527                 else if (instance->model == ONCORE_M12)
1528                         instance->chan = 12;
1529         }
1530
1531         if (instance->traim == -1) {    /* dont reset if set in input data */
1532                 instance->traim = 0;    /* default */
1533                 if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6)
1534                         instance->traim = 0;
1535                 else if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || instance->model == ONCORE_UTPLUS)
1536                         instance->traim = 1;
1537                 else if (instance->model == ONCORE_M12)
1538                         instance->traim = 0;
1539         }
1540
1541         sprintf(Msg, "Channels = %d, TRAIM = %s", instance->chan,
1542                 ((instance->traim < 0) ? "UNKNOWN" : ((instance->traim > 0) ? "ON" : "OFF")));
1543         record_clock_stats(&(instance->peer->srcadr), Msg);
1544
1545         /* The M12 with 1.3 Firmware, looses track of all Satellites and has to
1546          * start again if we go from 0D -> 3D, then looses them again when we
1547          * go from 3D -> 0D.  We do this to get a @@Ea message for SHMEM.
1548          * For NOW we have SHMEM turned off for the M12, v1.3
1549          */
1550
1551 /*BAD M12*/ if (instance->model == ONCORE_M12 && instance->version == 1 && instance->revision <= 3) {
1552                 instance->shmem_fname = 0;
1553                 cp = "*** SHMEM turned off for ONCORE M12 ***";
1554                 record_clock_stats(&(instance->peer->srcadr), cp);
1555         }
1556
1557         /*
1558          * we now know model number and have zeroed
1559          * instance->shmem_fname if SHMEM is not supported
1560          */
1561
1562         if (instance->shmem_fname);
1563                 oncore_init_shmem(instance);
1564
1565         if (instance->shmem)
1566                 cp = "SHMEM is available";
1567         else
1568                 cp = "SHMEM is NOT available";
1569         record_clock_stats(&(instance->peer->srcadr), cp);
1570
1571 #ifdef HAVE_PPSAPI
1572         if (instance->assert)
1573                 cp = "Timing on Assert.";
1574         else
1575                 cp = "Timing on Clear.";
1576         record_clock_stats(&(instance->peer->srcadr), cp);
1577 #endif
1578
1579         mode = instance->init_type;
1580         if (mode == 3 || mode == 4) {   /* Cf will call Fa */
1581                 oncore_sendmsg(instance->ttyfd, oncore_cmd_Cf, sizeof(oncore_cmd_Cf));
1582                 instance->o_state = ONCORE_RESET_SENT;
1583                 cp = "state = ONCORE_RESET_SENT";
1584                 record_clock_stats(&(instance->peer->srcadr), cp);
1585         } else {
1586                 if (instance->chan == 6)
1587                         oncore_sendmsg(instance->ttyfd, oncore_cmd_Ca, sizeof(oncore_cmd_Ca));
1588                 else if (instance->chan == 8)
1589                         oncore_sendmsg(instance->ttyfd, oncore_cmd_Fa, sizeof(oncore_cmd_Fa));
1590                 else if (instance->chan == 12)
1591                         oncore_sendmsg(instance->ttyfd, oncore_cmd_Ia, sizeof(oncore_cmd_Ia));
1592
1593                 instance->o_state = ONCORE_TEST_SENT;
1594                 cp = "state = ONCORE_TEST_SENT";
1595                 record_clock_stats(&(instance->peer->srcadr), cp);
1596                 instance->timeout = 4;
1597         }
1598 }
1599
1600
1601
1602 static void
1603 oncore_msg_Cj_init(
1604         struct instance *instance,
1605         u_char *buf,
1606         size_t len
1607         )
1608 {
1609         char *cp, Cmd[20], Msg[160];
1610         int     mode;
1611
1612         /* OK, know type of Oncore, have possibly reset, and have tested.
1613          * If we have or don't have TRAIM and position hold may still be unknown.
1614          * Now initialize.
1615          */
1616
1617         oncore_sendmsg(instance->ttyfd, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Set Posn Fix mode (not Idle (VP)) */
1618         oncore_sendmsg(instance->ttyfd, oncore_cmd_Bb, sizeof(oncore_cmd_Bb)); /* turn on for shmem */
1619         oncore_sendmsg(instance->ttyfd, oncore_cmd_Ek, sizeof(oncore_cmd_Ek)); /* turn off */
1620         oncore_sendmsg(instance->ttyfd, oncore_cmd_Aw, sizeof(oncore_cmd_Aw)); /* UTC time */
1621         oncore_sendmsg(instance->ttyfd, oncore_cmd_AB, sizeof(oncore_cmd_AB)); /* Appl type static */
1622         oncore_sendmsg(instance->ttyfd, oncore_cmd_Be, sizeof(oncore_cmd_Be)); /* Tell us the Almanac for shmem */
1623
1624         /* Turn OFF position hold, it needs to be off to set position (for some units),
1625            will get set ON in @@Ea later */
1626
1627         if (instance->chan == 12)
1628                 oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0));
1629         else {
1630                 oncore_sendmsg(instance->ttyfd, oncore_cmd_At0, sizeof(oncore_cmd_At0));
1631                 oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0));
1632         }
1633
1634         mode = instance->init_type;
1635         if (debug) {
1636                 printf("ONCORE[%d]: INIT mode = %d\n", instance->unit, mode);
1637                 printf("ONCORE[%d]: chan = %d\n", instance->unit, instance->chan);
1638         }
1639
1640         /* If there is Position input in the Config file
1641          * and mode = (1,3) set it as posn hold posn, goto 0D mode.
1642          *  or mode = (2,4) set it as INITIAL position, and do Site Survey.
1643          */
1644
1645
1646         if (instance->posn_set) {
1647                 switch (mode) { /* if we have a position, put it in as posn and posn-hold posn */
1648                 case 0:
1649                         break;
1650                 case 1:
1651                 case 2:
1652                 case 3:
1653                 case 4:
1654                         memcpy(Cmd, oncore_cmd_As, sizeof(oncore_cmd_As));      /* dont modify static variables */
1655                         w32_buf(&Cmd[2],  (int) instance->ss_lat);
1656                         w32_buf(&Cmd[6],  (int) instance->ss_long);
1657                         w32_buf(&Cmd[10], (int) instance->ss_ht);
1658                         Cmd[14] = 0;
1659                         oncore_sendmsg(instance->ttyfd, Cmd,  sizeof(oncore_cmd_As));
1660
1661                         memcpy(Cmd, oncore_cmd_Au, sizeof(oncore_cmd_Au));
1662                         w32_buf(&Cmd[2], (int) instance->ss_ht);
1663                         Cmd[6] = 0;
1664                         oncore_sendmsg(instance->ttyfd, Cmd,  sizeof(oncore_cmd_Au));
1665
1666                         if (instance->chan == 12) {
1667                                 memcpy(Cmd, oncore_cmd_Ga, sizeof(oncore_cmd_Ga));
1668                                 w32_buf(&Cmd[2], (int) instance->ss_lat);
1669                                 w32_buf(&Cmd[6], (int) instance->ss_long);
1670                                 w32_buf(&Cmd[10], (int) instance->ss_ht);
1671                                 Cmd[14] = 0;
1672                                 oncore_sendmsg(instance->ttyfd, Cmd,  sizeof(oncore_cmd_Ga));
1673                                 oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd1,  sizeof(oncore_cmd_Gd1));
1674                         } else {
1675                                 memcpy(Cmd, oncore_cmd_Ad, sizeof(oncore_cmd_Ad));
1676                                 w32_buf(&Cmd[2], (int) instance->ss_lat);
1677                                 oncore_sendmsg(instance->ttyfd, Cmd,  sizeof(oncore_cmd_Ad));
1678
1679                                 memcpy(Cmd, oncore_cmd_Ae, sizeof(oncore_cmd_Ae));
1680                                 w32_buf(&Cmd[2], (int) instance->ss_long);
1681                                 oncore_sendmsg(instance->ttyfd, Cmd,  sizeof(oncore_cmd_Ae));
1682
1683                                 memcpy(Cmd, oncore_cmd_Af, sizeof(oncore_cmd_Af));
1684                                 w32_buf(&Cmd[2], (int) instance->ss_ht);
1685                                 Cmd[6] = 0;
1686                                 oncore_sendmsg(instance->ttyfd, Cmd,  sizeof(oncore_cmd_Af));
1687                                 oncore_sendmsg(instance->ttyfd, oncore_cmd_At1,  sizeof(oncore_cmd_At1));
1688                         }
1689                         break;
1690                 }
1691         }
1692
1693
1694         switch (mode) {
1695         case 0: /* NO initialization, don't change anything */
1696                 instance->site_survey = ONCORE_SS_DONE;
1697                 break;
1698
1699         case 1:
1700         case 3: /* Use given Position */
1701                 instance->site_survey = ONCORE_SS_DONE;
1702                 break;
1703
1704         case 2:
1705         case 4: /* Site Survey */
1706                 if (instance->chan == 12) {     /* no 12chan site survey command */
1707                         instance->site_survey = ONCORE_SS_SW;
1708                         sprintf(Msg, "Initiating software 3D site survey (%d samples)", POS_HOLD_AVERAGE);
1709                         record_clock_stats(&(instance->peer->srcadr), Msg);
1710                 } else {
1711                         instance->site_survey = ONCORE_SS_TESTING;
1712                         oncore_sendmsg(instance->ttyfd, oncore_cmd_At2,  sizeof(oncore_cmd_At2));
1713                 }
1714                 break;
1715         }
1716
1717         if (mode != 0) {
1718                         /* cable delay in ns */
1719                 memcpy(Cmd, oncore_cmd_Az, sizeof(oncore_cmd_Az));
1720                 w32_buf(&Cmd[2], instance->delay);
1721                 oncore_sendmsg(instance->ttyfd, Cmd,  sizeof(oncore_cmd_Az));
1722
1723                         /* PPS offset in ns */
1724                 if (instance->offset) {
1725                         if (instance->model == ONCORE_VP || instance->model == ONCORE_UT ||
1726                            instance->model == ONCORE_UTPLUS) {
1727                                 memcpy(Cmd, oncore_cmd_Ay, sizeof(oncore_cmd_Ay));
1728                                 w32_buf(&Cmd[2], instance->offset);
1729                                 oncore_sendmsg(instance->ttyfd, Cmd,  sizeof(oncore_cmd_Ay));
1730                         } else {
1731                                 cp = "Can only set PPS OFFSET for VP/UT/UT+, offset ignored";
1732                                 record_clock_stats(&(instance->peer->srcadr), cp);
1733                                 instance->offset = 0;
1734                         }
1735                 }
1736         }
1737
1738         /* 6, 8 12 chan - Position/Status/Data Output Message, 1/s */
1739         /* now we're really running */
1740
1741         if (instance->chan == 6) { /* kill 8 chan commands, possibly testing VP in 6chan mode */
1742                 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ba,  sizeof(oncore_cmd_Ba));
1743                 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea0, sizeof(oncore_cmd_Ea0));
1744                 oncore_sendmsg(instance->ttyfd, oncore_cmd_En0, sizeof(oncore_cmd_En0));
1745         } else if (instance->chan == 8) {  /* kill 6chan commands */
1746                 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea,  sizeof(oncore_cmd_Ea));
1747                 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ba0, sizeof(oncore_cmd_Ba0));
1748                 oncore_sendmsg(instance->ttyfd, oncore_cmd_Bn0, sizeof(oncore_cmd_Bn0));
1749         } else if (instance->chan == 12)
1750                 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ha, sizeof(oncore_cmd_Ha));
1751
1752         instance->count = 1;
1753         instance->o_state = ONCORE_ALMANAC;
1754         cp = "state = ONCORE_ALMANAC";
1755         record_clock_stats(&(instance->peer->srcadr), cp);
1756 }
1757
1758
1759
1760 /*
1761  * Set to Factory Defaults (Reasonable for UT w/ no Battery Backup
1762  *      not so for VP (eeprom) or any unit with a battery
1763  */
1764
1765 static void
1766 oncore_msg_Cf(
1767         struct instance *instance,
1768         u_char *buf,
1769         size_t len
1770         )
1771 {
1772         const char *cp;
1773
1774         if (instance->o_state == ONCORE_RESET_SENT) {
1775                 if (instance->chan == 6)
1776                         oncore_sendmsg(instance->ttyfd, oncore_cmd_Ca, sizeof(oncore_cmd_Ca));
1777                 else if (instance->chan == 8)
1778                         oncore_sendmsg(instance->ttyfd, oncore_cmd_Fa, sizeof(oncore_cmd_Fa));
1779                 else if (instance->chan == 12)
1780                         oncore_sendmsg(instance->ttyfd, oncore_cmd_Ia, sizeof(oncore_cmd_Ia));
1781
1782                 instance->o_state = ONCORE_TEST_SENT;
1783                 cp = "state = ONCORE_TEST_SENT";
1784                 record_clock_stats(&(instance->peer->srcadr), cp);
1785         }
1786 }
1787
1788
1789
1790 /* Here for @@Ca, @@Fa and @@Ia messages */
1791
1792 /* There are good reasons NOT to do a @@Ca or @@Fa command with the ONCORE.
1793  * Doing it, it was found that under some circumstances the following
1794  * command would fail if issued immediately after the return from the
1795  * @@Fa, but a 2sec delay seemed to fix things.  Since simply calling
1796  * sleep(2) is wastefull, and may cause trouble for some OS's, repeating
1797  * itimer, we set a flag, and test it at the next POLL.  If it hasnt
1798  * been cleared, we reissue the @@Cj that is issued below.
1799  * Note that we do a @@Cj at the beginning, and again here.
1800  * The first is to get the info, the 2nd is just used as a safe command
1801  * after the @@Fa for all Oncores (and it was in this posn in the
1802  * original code).
1803  */
1804
1805 static void
1806 oncore_msg_CaFaIa(
1807         struct instance *instance,
1808         u_char *buf,
1809         size_t len
1810         )
1811 {
1812         char *cp;
1813
1814         if (instance->o_state == ONCORE_TEST_SENT) {
1815                 int     antenna;
1816
1817                 instance->timeout = 0;
1818
1819                 if (debug > 2) {
1820                         if (buf[2] == 'I')
1821                                 printf("ONCORE[%d]: >>@@%ca %x %x %x\n", instance->unit, buf[2], buf[4], buf[5], buf[6]);
1822                         else
1823                                 printf("ONCORE[%d]: >>@@%ca %x %x\n", instance->unit, buf[2], buf[4], buf[5]);
1824                 }
1825
1826                 antenna = buf[4] & 0xc0;
1827                 antenna >>= 6;
1828                 buf[4] &= ~0xc0;
1829
1830                 if (buf[4] || buf[5] || ((buf[2] == 'I') && buf[6])) {
1831                         cp = "ONCORE: Self Test Failed, shutting down driver";
1832                         record_clock_stats(&(instance->peer->srcadr), cp);
1833                         oncore_shutdown(instance->unit, instance->peer);
1834                         return;
1835                 }
1836                 if (antenna) {
1837                         char *cp1, Msg[160];
1838
1839                         cp1 = (antenna == 0x1) ? "(Over Current)" :
1840                                 ((antenna == 0x2) ? "(Under Current)" : "(No Voltage)");
1841
1842                         cp = "ONCORE: Self Test, NonFatal Antenna Problems ";
1843                         strcpy(Msg, cp);
1844                         strcat(Msg, cp1);
1845                         record_clock_stats(&(instance->peer->srcadr), Msg);
1846                 }
1847
1848                 oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
1849                 instance->o_state = ONCORE_INIT;
1850                 cp = "state = ONCORE_INIT";
1851                 record_clock_stats(&(instance->peer->srcadr), cp);
1852         }
1853 }
1854
1855
1856
1857 /* Ba, Ea and Ha come here */
1858
1859 static void
1860 oncore_msg_BaEaHa(
1861         struct instance *instance,
1862         u_char *buf,
1863         size_t len
1864         )
1865 {
1866         const char      *cp;
1867         char            Msg[160], Cmd[20];
1868         u_char          *vp;    /* pointer to start of shared mem for Ba/Ea/Ha */
1869         size_t          Len;
1870
1871         /* At the beginning of Ea here there are various 'timers'.
1872          * We enter Ea 1/sec, and since the upper levels of NTP have usurped
1873          * the use of timers, we use the 1/sec entry to Ea to do things that
1874          * we would normally do with timers...
1875          */
1876
1877         if (instance->count) {
1878                 if (instance->count++ < 5)      /* make sure results are stable, using position */
1879                         return;
1880                 instance->count = 0;
1881         }
1882
1883         if (instance->o_state != ONCORE_ALMANAC && instance->o_state != ONCORE_RUN)
1884                 return;
1885
1886         Len = len+3;            /* message length @@ -> CR,LF */
1887         memcpy(instance->Ea, buf, Len);         /* Ba, Ea or Ha */
1888
1889         if (buf[2] == 'B') {                    /* 6chan */
1890                 if (instance->Ea[64]&0x8)
1891                         instance->mode = MODE_0D;
1892                 else if (instance->Ea[64]&0x10)
1893                         instance->mode = MODE_2D;
1894                 else if (instance->Ea[64]&0x20)
1895                         instance->mode = MODE_3D;
1896         } else if (buf[2] == 'E') {             /* 8chan */
1897                 if (instance->Ea[72]&0x8)
1898                         instance->mode = MODE_0D;
1899                 else if (instance->Ea[72]&0x10)
1900                         instance->mode = MODE_2D;
1901                 else if (instance->Ea[72]&0x20)
1902                         instance->mode = MODE_3D;
1903         } else if (buf[2] == 'H') {             /* 12chan */
1904                 int bits;
1905
1906                 bits = (instance->Ea[129]>>5) & 0x7;        /* actually Ha */
1907                 if (bits == 0x4)
1908                         instance->mode = MODE_0D;
1909                 else if (bits == 0x6)
1910                         instance->mode = MODE_2D;
1911                 else if (bits == 0x7)
1912                         instance->mode = MODE_3D;
1913         }
1914
1915         vp = (u_char) 0;        /* just to keep compiler happy */
1916         if (instance->chan == 6) {
1917                 instance->rsm.bad_almanac = instance->Ea[64]&0x1;
1918                 instance->rsm.bad_fix     = instance->Ea[64]&0x52;
1919                 vp = &instance->shmem[instance->shmem_Ba];
1920         } else if (instance->chan == 8) {
1921                 instance->rsm.bad_almanac = instance->Ea[72]&0x1;
1922                 instance->rsm.bad_fix     = instance->Ea[72]&0x52;
1923                 vp = &instance->shmem[instance->shmem_Ea];
1924         } else if (instance->chan == 12) {
1925                 int bits1, bits2;
1926
1927                 bits1 = (instance->Ea[129]>>5) & 0x7;        /* actually Ha */
1928                 bits2 = instance->Ea[130];
1929                 instance->rsm.bad_almanac = (bits2 & 0x80);
1930                 instance->rsm.bad_fix     = (bits2 & 0x8) || (bits1 == 0x2);
1931                                           /* too few sat     Bad Geom     */
1932                 vp = &instance->shmem[instance->shmem_Ha];
1933 #if 0
1934 fprintf(stderr, "ONCORE: DEBUG BITS: (%x %x), (%x %x),  %x %x %x %x %x\n",
1935                 instance->Ea[129], instance->Ea[130], bits1, bits2, instance->mode == MODE_0D, instance->mode == MODE_2D,
1936                 instance->mode == MODE_3D, instance->rsm.bad_almanac, instance->rsm.bad_fix);
1937 #endif
1938         }
1939
1940         /* Here calculate dH = GPS - MSL for output message */
1941         /* also set Altitude Hold mode if GT */
1942
1943         if (!instance->have_dH) {
1944                 int     GPS, MSL;
1945
1946                 instance->have_dH++;
1947                 if (instance->chan == 12) {
1948                         GPS = buf_w32(&instance->Ea[39]);
1949                         MSL = buf_w32(&instance->Ea[43]);
1950                 } else {
1951                         GPS = buf_w32(&instance->Ea[23]);
1952                         MSL = buf_w32(&instance->Ea[27]);
1953                 }
1954                 instance->dH = GPS - MSL;
1955                 instance->dH /= 100.;
1956
1957                 if (MSL) {      /* not set ! */
1958                         sprintf(Msg, "dH = (GPS - MSL) = %.2fm", instance->dH);
1959                         record_clock_stats(&(instance->peer->srcadr), Msg);
1960                 }
1961
1962                 /* stuck in here as it only gets done once */
1963
1964                 if (instance->chan != 12 && !instance->saw_At) {
1965                         cp = "Not Good, no @@At command, must be a GT/GT+";
1966                         record_clock_stats(&(instance->peer->srcadr), cp);
1967                         oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1));
1968                 }
1969         }
1970
1971         /*
1972          * For instance->site_survey to be ONCORE_SS_TESTING, this must be the first
1973          * time thru @@Ea.  There are two choices
1974          *   (a) We did not get a response to the @@At0 or @@At2 commands,
1975          *         must be a GT/GT+/SL with no position hold mode.
1976          *   (b) Saw the @@At0, @@At2 commands, but @@At2 failed,
1977          *         must be a VP or older UT which doesnt have Site Survey mode.
1978          *         We will have to do it ourselves.
1979          */
1980
1981         if (instance->site_survey == ONCORE_SS_TESTING) {       /* first time thru Ea */
1982                 sprintf(Msg, "Initiating software 3D site survey (%d samples)",
1983                                 POS_HOLD_AVERAGE);
1984                 record_clock_stats(&(instance->peer->srcadr), Msg);
1985                 instance->site_survey = ONCORE_SS_SW;
1986
1987                 instance->ss_lat = instance->ss_long = instance->ss_ht = 0;
1988                 oncore_sendmsg(instance->ttyfd, oncore_cmd_At0, sizeof(oncore_cmd_At0)); /* disable */
1989         }
1990
1991         if (instance->shmem) {
1992                 int     i;
1993
1994                 i = 0;
1995                 if (instance->mode == MODE_0D)         /* 0D, Position Hold */
1996                         i = 1;
1997                 else if (instance->mode == MODE_2D)    /* 2D, Altitude Hold */
1998                         i = 2;
1999                 else if (instance->mode == MODE_3D)    /* 3D fix */
2000                         i = 3;
2001                 if (i) {
2002                         i *= (Len+3);
2003                         vp[i + 2]++;
2004                         memcpy(&vp[i+3], buf, Len);
2005                 }
2006         }
2007
2008         /* Almanac mode, waiting for Almanac, cant do anything till we have it */
2009         /* When we have an almanac, start the En/Bn messages */
2010
2011         if (instance->o_state == ONCORE_ALMANAC) {
2012                 if (instance->rsm.bad_almanac) {
2013                         if (debug)
2014                                 printf("ONCORE: waiting for almanac\n");
2015                         return;
2016                 } else {  /* Here we have almanac.
2017                              Start TRAIM (@@En/@@Bn) dependant on TRAIM flag.
2018                              If flag == -1, then we dont know if this unit supports
2019                              traim, and we issue the command and then wait up to
2020                              5sec to see if we get a reply */
2021
2022                         if (instance->traim != 0) {     /* either yes or unknown */
2023                                 if (instance->chan == 6)
2024                                         oncore_sendmsg(instance->ttyfd, oncore_cmd_Bn, sizeof(oncore_cmd_Bn));
2025                                 else if (instance->chan == 8)
2026                                         oncore_sendmsg(instance->ttyfd, oncore_cmd_En, sizeof(oncore_cmd_En));
2027
2028                                 if (instance->traim == -1)
2029                                         instance->traim_delay = 1;
2030                         }
2031                         instance->o_state = ONCORE_RUN;
2032                         cp = "state = ONCORE_RUN";
2033                         record_clock_stats(&(instance->peer->srcadr), cp);
2034                 }
2035         }
2036
2037         /*
2038          * check if timer active
2039          * if it hasnt been cleared, then @@En/@@Bn did not respond
2040          */
2041
2042         if (instance->traim_delay) {
2043                 if (instance->traim_delay++ > 5) {
2044                         instance->traim = 0;
2045                         instance->traim_delay = 0;
2046                         cp = "ONCORE: Did not detect TRAIM response, TRAIM = OFF";
2047                         record_clock_stats(&(instance->peer->srcadr), cp);
2048                 }
2049         }
2050
2051         /*
2052          * must be ONCORE_RUN if we are here.
2053          */
2054
2055         instance->pp->year = buf[6]*256+buf[7];
2056         instance->pp->day = ymd2yd(buf[6]*256+buf[7], buf[4], buf[5]);
2057         instance->pp->hour = buf[8];
2058         instance->pp->minute = buf[9];
2059         instance->pp->second = buf[10];
2060
2061         /*
2062          * Check to see if Hardware SiteSurvey has Finished.
2063          */
2064
2065         if ((instance->site_survey == ONCORE_SS_HW) && !(instance->Ea[37] & 0x20)) {
2066                 record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode");
2067                 instance->site_survey = ONCORE_SS_DONE;
2068         }
2069
2070         if (!instance->printed && instance->site_survey == ONCORE_SS_DONE) {
2071                 instance->printed = 1;
2072                         /* Read back Position Hold Params (cant for GT) */
2073                 if (instance->saw_At)
2074                         oncore_sendmsg(instance->ttyfd, oncore_cmd_Asx,  sizeof(oncore_cmd_Asx));
2075                 else
2076                         oncore_print_As(instance);
2077
2078                         /* Read back PPS Offset for Output */
2079                         /* Nb. This will fail silently for early UT (no plus) and M12 models */
2080                 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ayx,  sizeof(oncore_cmd_Ayx));
2081
2082                         /* Read back Cable Delay for Output */
2083                 oncore_sendmsg(instance->ttyfd, oncore_cmd_Azx,  sizeof(oncore_cmd_Azx));
2084         }
2085
2086         /*
2087          * Check the leap second status once per day.
2088          */
2089
2090         if (instance->Bj_day != buf[5]) {     /* do this 1/day */
2091                 instance->Bj_day = buf[5];
2092
2093                 if (instance->chan == 12)
2094                         oncore_sendmsg(instance->ttyfd, oncore_cmd_Gj, sizeof(oncore_cmd_Gj));
2095                 else {
2096                         /*
2097                          * The following additional check, checking for June/December, is a
2098                          * workaround for incorrect ONCORE firmware.  The oncore starts
2099                          * reporting the leap second when the GPS satellite data message
2100                          * (page 18, subframe 4) is updated to a date in the future, which
2101                          * can be several months before the leap second.  WWV and other
2102                          * services seem to wait until the month of the event to turn
2103                          * on their indicators (which is usually a single bit).
2104                          */
2105
2106                         if ((buf[4] == 6) || (buf[4] == 12))
2107                                 oncore_sendmsg(instance->ttyfd, oncore_cmd_Bj, sizeof(oncore_cmd_Bj));
2108                 }
2109         }
2110
2111         /*
2112          * if SHMEM active, every 15s, steal one 'tick' to get 2D or 3D posn.
2113          */
2114
2115         if (instance->shmem && instance->shmem_Posn && (instance->site_survey == ONCORE_SS_DONE)) {     /* dont screw up the SS by changing mode */
2116                 if (instance->pp->second%15 == 3) {     /* start the sequence */
2117                         instance->shmem_reset = 1;
2118                         if (instance->chan == 12) {
2119                                 if (instance->shmem_Posn == 2)
2120                                         oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd2,  sizeof(oncore_cmd_Gd2));  /* 2D */
2121                                 else
2122                                         oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd0,  sizeof(oncore_cmd_Gd0));  /* 3D */
2123                         } else {
2124                                 if (instance->saw_At) {
2125                                         oncore_sendmsg(instance->ttyfd, oncore_cmd_At0, sizeof(oncore_cmd_At0)); /* out of 0D to 3D mode */
2126                                         if (instance->shmem_Posn == 2)
2127                                                 oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1));   /* 3D to 2D mode */
2128                                 } else
2129                                         oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0));
2130                         }
2131                 } else if (instance->shmem_reset || (instance->mode != MODE_0D)) {
2132                         instance->shmem_reset = 0;
2133                         if (instance->chan == 12)
2134                                 oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd1,  sizeof(oncore_cmd_Gd1));       /* 0D */
2135                         else {
2136                                 if (instance->saw_At) {
2137                                         if (instance->mode == MODE_2D)
2138                                                 oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); /* 2D -> 3D or 0D */
2139                                         oncore_sendmsg(instance->ttyfd, oncore_cmd_At1,  sizeof(oncore_cmd_At1));        /* to 0D mode */
2140                                 } else
2141                                         oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1,  sizeof(oncore_cmd_Av1));
2142                         }
2143                 }
2144         }
2145
2146         if (instance->traim == 0)       /* NO traim, go get tick */
2147                 oncore_get_timestamp(instance, instance->offset, instance->offset);
2148
2149         if (instance->site_survey != ONCORE_SS_SW)
2150                 return;
2151
2152         /*
2153          * We have to average our own position for the Position Hold Mode
2154          *   We use Heights from the GPS ellipsoid.
2155          */
2156
2157         if (instance->rsm.bad_fix)      /* Not if poor geometry or less than 3 sats */
2158                 return;
2159
2160         if (instance->mode != MODE_3D)  /* Only 3D Fix */
2161                 return;
2162
2163         instance->ss_lat  += buf_w32(&instance->Ea[15]);
2164         instance->ss_long += buf_w32(&instance->Ea[19]);
2165         instance->ss_ht   += buf_w32(&instance->Ea[23]);  /* GPS ellipsoid */
2166         instance->ss_count++;
2167
2168         if (instance->ss_count != POS_HOLD_AVERAGE)
2169                 return;
2170
2171         instance->ss_lat  /= POS_HOLD_AVERAGE;
2172         instance->ss_long /= POS_HOLD_AVERAGE;
2173         instance->ss_ht   /= POS_HOLD_AVERAGE;
2174
2175         sprintf(Msg, "Surveyed posn:  lat %.3f long %.3f ht %.3f",
2176                         instance->ss_lat, instance->ss_long, instance->ss_ht);
2177         record_clock_stats(&(instance->peer->srcadr), Msg);
2178
2179         /* set newly determined position as 3D Position hold position */
2180
2181         memcpy(Cmd, oncore_cmd_As, sizeof(oncore_cmd_As));
2182         w32_buf(&Cmd[2],  (int) instance->ss_lat);
2183         w32_buf(&Cmd[6],  (int) instance->ss_long);
2184         w32_buf(&Cmd[10], (int) instance->ss_ht);
2185         Cmd[14] = 0;
2186         oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_As));
2187
2188         /* set height seperately for 2D */
2189
2190         memcpy(Cmd, oncore_cmd_Au, sizeof(oncore_cmd_Au));
2191         w32_buf(&Cmd[2], (int) instance->ss_ht);
2192         Cmd[6] = 0;
2193         oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Au));
2194
2195         /* and set Position Hold */
2196
2197         if (instance->chan == 12)
2198                 oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd1, sizeof(oncore_cmd_Gd1));
2199         else {
2200                 if (instance->saw_At)
2201                         oncore_sendmsg(instance->ttyfd, oncore_cmd_At1, sizeof(oncore_cmd_At1));
2202                 else
2203                         oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1));
2204         }
2205
2206         record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode");
2207         instance->site_survey = ONCORE_SS_DONE;
2208 }
2209
2210
2211
2212 static void
2213 oncore_msg_BnEn(
2214         struct instance *instance,
2215         u_char *buf,
2216         size_t len
2217         )
2218 {
2219         long    dt1, dt2;
2220         char    *cp;
2221
2222         if (instance->o_state != ONCORE_RUN)
2223                 return;
2224
2225         if (instance->traim_delay) {     /* flag that @@En/@@Bn returned */
2226                         instance->traim = 1;
2227                         instance->traim_delay = 0;
2228                         cp = "ONCORE: Detected TRAIM, TRAIM = ON";
2229                         record_clock_stats(&(instance->peer->srcadr), cp);
2230         }
2231
2232         memcpy(instance->En, buf, len);         /* En or Bn */
2233
2234         /* If Time RAIM doesn't like it, don't trust it */
2235
2236         if (instance->En[21])
2237                 return;
2238
2239         dt1 = instance->saw_tooth + instance->offset;    /* dt this time step */
2240         instance->saw_tooth = (s_char) instance->En[25]; /* update for next time */
2241         dt2 = instance->saw_tooth + instance->offset;    /* dt next time step */
2242
2243         oncore_get_timestamp(instance, dt1, dt2);
2244 }
2245
2246
2247
2248 static void
2249 oncore_get_timestamp(
2250         struct instance *instance,
2251         long dt1,       /* tick offset THIS time step */
2252         long dt2        /* tick offset NEXT time step */
2253         )
2254 {
2255         int     Rsm;
2256         u_long  i, j;
2257         l_fp ts, ts_tmp;
2258         double dmy;
2259 #ifdef HAVE_STRUCT_TIMESPEC
2260         struct timespec *tsp = 0;
2261 #else
2262         struct timeval  *tsp = 0;
2263 #endif
2264 #ifdef HAVE_PPSAPI
2265         int     current_mode;
2266         pps_params_t current_params;
2267         struct timespec timeout;
2268         pps_info_t pps_i;
2269 #else  /* ! HAVE_PPSAPI */
2270 #ifdef HAVE_CIOGETEV
2271         struct ppsclockev ev;
2272         int r = CIOGETEV;
2273 #endif
2274 #ifdef HAVE_TIOCGPPSEV
2275         struct ppsclockev ev;
2276         int r = TIOCGPPSEV;
2277 #endif
2278 #if     TIOCDCDTIMESTAMP
2279         struct timeval  tv;
2280 #endif
2281 #endif  /* ! HAVE_PPS_API */
2282
2283         if ((instance->site_survey == ONCORE_SS_DONE) && (instance->mode != MODE_0D))
2284                 return;
2285
2286         /* Don't do anything without an almanac to define the GPS->UTC delta */
2287
2288         if (instance->rsm.bad_almanac)
2289                 return;
2290
2291 #ifdef HAVE_PPSAPI
2292         j = instance->ev_serial;
2293         timeout.tv_sec = 0;
2294         timeout.tv_nsec = 0;
2295         if (time_pps_fetch(instance->pps_h, PPS_TSFMT_TSPEC, &pps_i,
2296             &timeout) < 0) {
2297                 printf("ONCORE: time_pps_fetch failed\n");
2298                 return;
2299         }
2300
2301         if (instance->assert) {
2302                 tsp = &pps_i.assert_timestamp;
2303
2304                 if (debug > 2) {
2305                         i = (u_long) pps_i.assert_sequence;
2306 #ifdef HAVE_STRUCT_TIMESPEC
2307                         printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%09ld\n",
2308                             instance->unit, i, j,
2309                             (long)tsp->tv_sec, (long)tsp->tv_nsec);
2310 #else
2311                         printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%06ld\n",
2312                             instance->unit, i, j,
2313                             (long)tsp->tv_sec, (long)tsp->tv_usec);
2314 #endif
2315                 }
2316
2317                 if (pps_i.assert_sequence == j) {
2318                         printf("ONCORE: oncore_get_timestamp, error serial pps\n");
2319                         return;
2320                 }
2321                 instance->ev_serial = pps_i.assert_sequence;
2322         } else {
2323                 tsp = &pps_i.clear_timestamp;
2324
2325                 if (debug > 2) {
2326                         i = (u_long) pps_i.clear_sequence;
2327 #ifdef HAVE_STRUCT_TIMESPEC
2328                         printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%09ld\n",
2329                             instance->unit, i, j, (long)tsp->tv_sec, (long)tsp->tv_nsec);
2330 #else
2331                         printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%06ld\n",
2332                             instance->unit, i, j, (long)tsp->tv_sec, (long)tsp->tv_usec);
2333 #endif
2334                 }
2335
2336                 if (pps_i.clear_sequence == j) {
2337                         printf("ONCORE: oncore_get_timestamp, error serial pps\n");
2338                         return;
2339                 }
2340                 instance->ev_serial = pps_i.clear_sequence;
2341         }
2342
2343         /* convert timespec -> ntp l_fp */
2344
2345         dmy = tsp->tv_nsec;
2346         dmy /= 1e9;
2347         ts.l_uf =  dmy * 4294967296.0;
2348         ts.l_ui = tsp->tv_sec;
2349 #if 0
2350      alternate code for previous 4 lines is
2351         dmy = 1.0e-9*tsp->tv_nsec;      /* fractional part */
2352         DTOLFP(dmy, &ts);
2353         dmy = tsp->tv_sec;              /* integer part */
2354         DTOLFP(dmy, &ts_tmp);
2355         L_ADD(&ts, &ts_tmp);
2356      or more simply
2357         dmy = 1.0e-9*tsp->tv_nsec;      /* fractional part */
2358         DTOLFP(dmy, &ts);
2359         ts.l_ui = tsp->tv_sec;
2360 #endif  /* 0 */
2361 #else
2362 # if defined(HAVE_TIOCGPPSEV) || defined(HAVE_CIOGETEV)
2363         j = instance->ev_serial;
2364         if (ioctl(instance->ppsfd, r, (caddr_t) &ev) < 0) {
2365                 perror("ONCORE: IOCTL:");
2366                 return;
2367         }
2368
2369         tsp = &ev.tv;
2370
2371         if (debug > 2)
2372 #ifdef HAVE_STRUCT_TIMESPEC
2373                 printf("ONCORE: serial/j (%d, %d) %ld.%09ld\n",
2374                         ev.serial, j, tsp->tv_sec, tsp->tv_nsec);
2375 #else
2376                 printf("ONCORE: serial/j (%d, %d) %ld.%06ld\n",
2377                         ev.serial, j, tsp->tv_sec, tsp->tv_usec);
2378 #endif
2379
2380         if (ev.serial == j) {
2381                 printf("ONCORE: oncore_get_timestamp, error serial pps\n");
2382                 return;
2383         }
2384         instance->ev_serial = ev.serial;
2385
2386         /* convert timeval -> ntp l_fp */
2387
2388         TVTOTS(tsp, &ts);
2389 # else
2390 #  if defined(TIOCDCDTIMESTAMP)
2391         if(ioctl(instance->ppsfd, TIOCDCDTIMESTAMP, &tv) < 0) {
2392                 perror("ONCORE: ioctl(TIOCDCDTIMESTAMP)");
2393                 return;
2394         }
2395         tsp = &tv;
2396         TVTOTS(tsp, &ts);
2397 #  else
2398 #error "Cannot compile -- no PPS mechanism configured!"
2399 #  endif
2400 # endif
2401 #endif
2402         /* now have timestamp in ts */
2403         /* add in saw_tooth and offset, these will be ZERO if no TRAIM */
2404
2405         /* saw_tooth not really necessary if using TIMEVAL */
2406         /* since its only precise to us, but do it anyway. */
2407
2408         /* offset in ns, and is positive (late), we subtract */
2409         /* to put the PPS time transition back where it belongs */
2410
2411 #ifdef HAVE_PPSAPI
2412         /* must hand the offset for the NEXT sec off to the Kernel to do */
2413         /* the addition, so that the Kernel PLL sees the offset too */
2414
2415         if (instance->assert)
2416                 instance->pps_p.assert_offset.tv_nsec = -dt2;
2417         else
2418                 instance->pps_p.clear_offset.tv_nsec  = -dt2;
2419
2420         /* The following code is necessary, and not just a time_pps_setparams,
2421          * using the saved instance->pps_p, since some other process on the
2422          * machine may have diddled with the mode bits (say adding something
2423          * that it needs).  We take what is there and ADD what we need.
2424          * [[ The results from the time_pps_getcap is unlikely to change so
2425          *    we could probably just save it, but I choose to do the call ]]
2426          * Unfortunately, there is only ONE set of mode bits in the kernel per
2427          * interface, and not one set for each open handle.
2428          *
2429          * There is still a race condition here where we might mess up someone
2430          * elses mode, but if he is being careful too, he should survive.
2431          */
2432
2433         if (time_pps_getcap(instance->pps_h, &current_mode) < 0) {
2434                 msyslog(LOG_ERR,
2435                     "refclock_ioctl: time_pps_getcap failed: %m");
2436                 return;
2437         }
2438
2439         if (time_pps_getparams(instance->pps_h, &current_params) < 0) {
2440                 msyslog(LOG_ERR,
2441                     "refclock_ioctl: time_pps_getparams failed: %m");
2442                 return;
2443         }
2444
2445                 /* or current and mine */
2446         current_params.mode |= instance->pps_p.mode;
2447                 /* but only set whats legal */
2448         current_params.mode &= current_mode;
2449
2450         current_params.assert_offset.tv_sec = 0;
2451         current_params.assert_offset.tv_nsec = -dt2;
2452         current_params.clear_offset.tv_sec = 0;
2453         current_params.clear_offset.tv_nsec = -dt2;
2454
2455         if (time_pps_setparams(instance->pps_h, &current_params))
2456                 perror("time_pps_setparams");
2457 #else
2458         /* if not PPSAPI, no way to inform kernel of OFFSET, just add the */
2459         /* offset for THIS second */
2460
2461         dmy = -1.0e-9*dt1;
2462         DTOLFP(dmy, &ts_tmp);
2463         L_ADD(&ts, &ts_tmp);
2464 #endif
2465         /* have time from UNIX origin, convert to NTP origin. */
2466
2467         ts.l_ui += JAN_1970;
2468         instance->pp->lastrec = ts;
2469         instance->pp->msec = 0;
2470
2471         ts_tmp = ts;
2472         ts_tmp.l_ui = 0;        /* zero integer part */
2473         LFPTOD(&ts_tmp, dmy);   /* convert fractional part to a double */
2474         j = 1.0e9*dmy;          /* then to integer ns */
2475
2476         Rsm = 0;
2477         if (instance->chan == 6)
2478                 Rsm = instance->Ea[64];
2479         else if (instance->chan == 8)
2480                 Rsm = instance->Ea[72];
2481         else if (instance->chan == 12)
2482                 Rsm = ((instance->Ea[129]<<8) | instance->Ea[130]);
2483
2484         if (instance->chan == 6 || instance->chan == 8) {
2485                 sprintf(instance->pp->a_lastcode,       /* MAX length 128, currently at 117 */
2486                     "%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",
2487                     ts.l_ui, j,
2488                     instance->pp->year, instance->pp->day,
2489                     instance->pp->hour, instance->pp->minute, instance->pp->second,
2490                     (long) tsp->tv_sec % 60,
2491                     Rsm, 0.1*(256*instance->Ea[35]+instance->Ea[36]),
2492                     /*rsat      dop */
2493                     instance->Ea[38], instance->Ea[39], instance->En[21],
2494                     /*  nsat visible,     nsat tracked,     traim */
2495                     instance->En[23]*256+instance->En[24], (s_char) instance->En[25],
2496                     /* sigma                               neg-sawtooth */
2497           /*sat*/   instance->Ea[41], instance->Ea[45], instance->Ea[49], instance->Ea[53],
2498                     instance->Ea[57], instance->Ea[61], instance->Ea[65], instance->Ea[69]
2499                     );                                  /* will be 0 for 6 chan */
2500         } else if (instance->chan == 12) {
2501                 sprintf(instance->pp->a_lastcode,
2502                     "%u.%09lu %d %d %2d %2d %2d %2ld rstat %02x dop %4.1f nsat %2d,%d sat %d%d%d%d%d%d%d%d%d%d%d%d",
2503                     ts.l_ui, j,
2504                     instance->pp->year, instance->pp->day,
2505                     instance->pp->hour, instance->pp->minute, instance->pp->second,
2506                     (long) tsp->tv_sec % 60,
2507                     Rsm, 0.1*(256*instance->Ea[53]+instance->Ea[54]),
2508                     /*rsat      dop */
2509                     instance->Ea[55], instance->Ea[56],
2510                     /*  nsat visible,     nsat tracked  */
2511           /*sat*/   instance->Ea[58], instance->Ea[64], instance->Ea[70], instance->Ea[76],
2512                     instance->Ea[82], instance->Ea[88], instance->Ea[94], instance->Ea[100],
2513                     instance->Ea[106], instance->Ea[112], instance->Ea[118], instance->Ea[124]
2514                     );
2515         }
2516
2517         if (debug > 2) {
2518                 int n;
2519                 n = strlen(instance->pp->a_lastcode);
2520                 printf("ONCORE[%d]: len = %d %s\n", instance->unit, n, instance->pp->a_lastcode);
2521         }
2522
2523         if (!refclock_process(instance->pp)) {
2524                 refclock_report(instance->peer, CEVNT_BADTIME);
2525                 return;
2526         }
2527
2528         record_clock_stats(&(instance->peer->srcadr), instance->pp->a_lastcode);
2529         instance->pollcnt = 2;
2530
2531         if (instance->polled) {
2532                 instance->polled = 0;
2533 /*
2534                 instance->pp->dispersion = instance->pp->skew = 0;
2535 */
2536                 refclock_receive(instance->peer);
2537         }
2538 }
2539
2540
2541
2542 /*
2543  * Try to use Oncore UT+ Auto Survey Feature
2544  *      If its not there (VP), set flag to do it ourselves.
2545  */
2546
2547 static void
2548 oncore_msg_At(
2549         struct instance *instance,
2550         u_char *buf,
2551         size_t len
2552         )
2553 {
2554         instance->saw_At = 1;
2555         if (instance->site_survey == ONCORE_SS_TESTING) {
2556                 if (buf[4] == 2) {
2557                         record_clock_stats(&(instance->peer->srcadr),
2558                                         "Initiating hardware 3D site survey");
2559                         instance->site_survey = ONCORE_SS_HW;
2560                 }
2561         }
2562 }
2563
2564
2565
2566 /* get leap-second warning message */
2567
2568 /*
2569  * @@Bj does NOT behave as documented in current Oncore firmware.
2570  * It turns on the LEAP indicator when the data is set, and does not,
2571  * as documented, wait until the beginning of the month when the
2572  * leap second will occur.
2573  * Until this firmware bug is fixed, @@Bj is only called in June/December.
2574  */
2575
2576 static void
2577 oncore_msg_Bj(
2578         struct instance *instance,
2579         u_char *buf,
2580         size_t len
2581         )
2582 {
2583         const char      *cp;
2584
2585         switch(buf[4]) {
2586         case 1:
2587                 instance->peer->leap = LEAP_ADDSECOND;
2588                 cp = "Set peer.leap to LEAP_ADDSECOND";
2589                 break;
2590         case 2:
2591                 instance->peer->leap = LEAP_DELSECOND;
2592                 cp = "Set peer.leap to LEAP_DELSECOND";
2593                 break;
2594         case 0:
2595         default:
2596                 instance->peer->leap = LEAP_NOWARNING;
2597                 cp = "Set peer.leap to LEAP_NOWARNING";
2598                 break;
2599         }
2600         record_clock_stats(&(instance->peer->srcadr), cp);
2601 }
2602
2603 /* Leap Second for M12, gives all info from satellite message */
2604
2605 static void
2606 oncore_msg_Gj(
2607         struct instance *instance,
2608         u_char *buf,
2609         size_t len
2610         )
2611 {
2612         int dt;
2613         char Msg[160], *cp;
2614         static char *Month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jly",
2615                 "Aug", "Sep", "Oct", "Nov", "Dec" };
2616
2617         /* print the message to verify whats there */
2618
2619         dt = buf[5] - buf[4];
2620
2621 #if 1
2622         sprintf(Msg, "ONCORE[%d]: Leap Sec Msg: %d %d %d %d %d %d %d %d %d %d",
2623                         instance->unit,
2624                         buf[4], buf[5], 256*buf[6]+buf[7], buf[8], buf[9], buf[10],
2625                         (buf[14]+256*(buf[13]+256*(buf[12]+256*buf[11]))),
2626                         buf[15], buf[16], buf[17]);
2627         record_clock_stats(&(instance->peer->srcadr), Msg);
2628 #endif
2629         if (dt) {
2630                 sprintf(Msg, "ONCORE[%d]: Leap second (%d) scheduled for %d%s%d at %d:%d:%d",
2631                         instance->unit,
2632                         dt, buf[9], Month[buf[8]], 256*buf[6]+buf[7],
2633                         buf[15], buf[16], buf[17]);
2634                 record_clock_stats(&(instance->peer->srcadr), Msg);
2635         }
2636
2637         /* Only raise warning within a month of the leap second */
2638
2639         instance->peer->leap = LEAP_NOWARNING;
2640         cp = "Set peer.leap to LEAP_NOWARNING";
2641
2642         if (buf[6] == instance->Ea[6] && buf[7] == instance->Ea[7] && /* year */
2643             buf[8] == instance->Ea[4]) {        /* month */
2644                 if (dt) {
2645                         if (dt < 0) {
2646                                 instance->peer->leap = LEAP_DELSECOND;
2647                                 cp = "Set peer.leap to LEAP_DELSECOND";
2648                         } else {
2649                                 instance->peer->leap = LEAP_ADDSECOND;
2650                                 cp = "Set peer.leap to LEAP_ADDSECOND";
2651                         }
2652                 }
2653         }
2654         record_clock_stats(&(instance->peer->srcadr), cp);
2655 }
2656
2657
2658
2659 /*
2660  * get Position hold position
2661  */
2662
2663 static void
2664 oncore_msg_As(
2665         struct instance *instance,
2666         u_char *buf,
2667         size_t len
2668         )
2669 {
2670         if (!instance->printed || instance->As)
2671                 return;
2672
2673         instance->As = 1;
2674
2675         instance->ss_lat  = buf_w32(&buf[4]);
2676         instance->ss_long = buf_w32(&buf[8]);
2677         instance->ss_ht   = buf_w32(&buf[12]);
2678
2679         /* Print out Position */
2680         oncore_print_As(instance);
2681 }
2682
2683
2684
2685 static void
2686 oncore_print_As(
2687         struct instance *instance
2688         )
2689 {
2690         char Msg[120], ew, ns;
2691         double xd, xm, xs, yd, ym, ys, hm, hft;
2692         int idx, idy, is, imx, imy;
2693         long lat, lon;
2694
2695         record_clock_stats(&(instance->peer->srcadr), "Posn:");
2696         ew = 'E';
2697         lon = instance->ss_long;
2698         if (lon < 0) {
2699                 ew = 'W';
2700                 lon = -lon;
2701         }
2702
2703         ns = 'N';
2704         lat = instance->ss_lat;
2705         if (lat < 0) {
2706                 ns = 'S';
2707                 lat = -lat;
2708         }
2709
2710         hm = instance->ss_ht/100.;
2711         hft= hm/0.3048;
2712
2713         xd = lat/3600000.;      /* lat, lon in int msec arc, ht in cm. */
2714         yd = lon/3600000.;
2715         sprintf(Msg, "Lat = %c %11.7fdeg,    Long = %c %11.7fdeg,    Alt = %5.2fm (%5.2fft) GPS", ns, xd, ew, yd, hm, hft);
2716         record_clock_stats(&(instance->peer->srcadr), Msg);
2717
2718         idx = xd;
2719         idy = yd;
2720         imx = lat%3600000;
2721         imy = lon%3600000;
2722         xm = imx/60000.;
2723         ym = imy/60000.;
2724         sprintf(Msg, "Lat = %c %3ddeg %7.4fm,   Long = %c %3ddeg %8.5fm,  Alt = %7.2fm (%7.2fft) GPS", ns, idx, xm, ew, idy, ym, hm, hft);
2725         record_clock_stats(&(instance->peer->srcadr), Msg);
2726
2727         imx = xm;
2728         imy = ym;
2729         is  = lat%60000;
2730         xs  = is/1000.;
2731         is  = lon%60000;
2732         ys  = is/1000.;
2733         sprintf(Msg, "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);
2734         record_clock_stats(&(instance->peer->srcadr), Msg);
2735 }
2736
2737
2738
2739 /*
2740  * get PPS Offset
2741  * Nb. @@Ay is not supported for early UT (no plus) model
2742  */
2743
2744 static void
2745 oncore_msg_Ay(
2746         struct instance *instance,
2747         u_char *buf,
2748         size_t len
2749         )
2750 {
2751         char Msg[120];
2752
2753         if (!instance->printed || instance->Ay)
2754                 return;
2755
2756         instance->Ay = 1;
2757
2758         instance->offset = buf_w32(&buf[4]);
2759
2760         sprintf(Msg, "PPS Offset  is set to %ld ns", instance->offset);
2761         record_clock_stats(&(instance->peer->srcadr), Msg);
2762 }
2763
2764
2765
2766 /*
2767  * get Cable Delay
2768  */
2769
2770 static void
2771 oncore_msg_Az(
2772         struct instance *instance,
2773         u_char *buf,
2774         size_t len
2775         )
2776 {
2777         char Msg[120];
2778
2779         if (!instance->printed || instance->Az)
2780                 return;
2781
2782         instance->Az = 1;
2783
2784         instance->delay = buf_w32(&buf[4]);
2785
2786         sprintf(Msg, "Cable delay is set to %ld ns", instance->delay);
2787         record_clock_stats(&(instance->peer->srcadr), Msg);
2788 }
2789
2790 static void
2791 oncore_msg_Sz(
2792         struct instance *instance,
2793         u_char *buf,
2794         size_t len
2795         )
2796 {
2797         const char *cp;
2798
2799         cp = "Oncore: System Failure at Power On";
2800         if (instance && instance->peer) {
2801                 record_clock_stats(&(instance->peer->srcadr), cp);
2802                 oncore_shutdown(instance->unit, instance->peer);
2803         }
2804 }
2805
2806 #else
2807 int refclock_oncore_bs;
2808 #endif /* REFCLOCK */