]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ntp/ntpd/refclock_oncore.c
This commit was generated by cvs2svn to compensate for changes in r58310,
[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  *
13  * Tested with:
14  *
15  *              (UT)                               (VP)
16  *   COPYRIGHT 1991-1997 MOTOROLA INC.  COPYRIGHT 1991-1996 MOTOROLA INC.
17  *   SFTW P/N #     98-P36848P          SFTW P/N # 98-P36830P
18  *   SOFTWARE VER # 2                   SOFTWARE VER # 8
19  *   SOFTWARE REV # 2                   SOFTWARE REV # 8
20  *   SOFTWARE DATE  APR 24 1998         SOFTWARE DATE  06 Aug 1996
21  *   MODEL #    R1121N1114              MODEL #    B4121P1155
22  *   HWDR P/N # 1                       HDWR P/N # _
23  *   SERIAL #   R0010A                  SERIAL #   SSG0226478
24  *   MANUFACTUR DATE 6H07               MANUFACTUR DATE 7E02
25  *                                      OPTIONS LIST    IB
26  *
27  * --------------------------------------------------------------------------
28  * This code uses the two devices
29  *      /dev/oncore.serial.n
30  *      /dev/oncore.pps.n
31  * which may be linked to the same device.
32  * and can read initialization data from the file
33  *      /etc/ntp.oncoreN (where n and N are the unit number, viz 127.127.30.N)
34  *  or  /etc/ntp.oncore
35  * --------------------------------------------------------------------------
36  * Reg.Clemens <reg@dwf.com> Sep98.
37  *  Original code written for FreeBSD.
38  *  With these mods it works on SunOS, Solaris (untested) and Linux
39  *    (RedHat 5.1 2.0.35 + PPSKit, 2.1.126 + changes).
40  *
41  *  Lat,Long,Ht, cable-delay, offset, and the ReceiverID (along with the
42  *  state machine state) are printed to CLOCKSTATS if that file is enabled
43  *  in /etc/ntp.conf.
44  *
45  * --------------------------------------------------------------------------
46  */
47
48 /*
49  * According to the ONCORE manual (TRM0003, Rev 3.2, June 1998, page 3.13)
50  * doing an average of 10000 valid 2D and 3D fixes is what the automatic
51  * site survey mode does.  Looking at the output from the receiver
52  * it seems like it is only using 3D fixes.
53  * When we do it ourselves, take 10000 3D fixes.
54  */
55
56 #define POS_HOLD_AVERAGE        10000   /* nb, 10000s ~= 2h45m */
57
58 /*
59  * ONCORE_SHMEM_STATUS will create a mmap(2)'ed file named according to a
60  * "STATUS" line in the oncore config file, which contains the most recent
61  * copy of all types of messages we recognize.  This file can be mmap(2)'ed
62  * by monitoring and statistics programs.
63  */
64
65 #ifdef HAVE_CONFIG_H
66 #include <config.h>
67 #endif
68
69 #if defined(REFCLOCK) && defined(CLOCK_ONCORE)
70
71 #include <stdio.h>
72 #include <ctype.h>
73 #include <sys/types.h>
74 #include <sys/time.h>
75 #include <sys/stat.h>
76 #ifdef ONCORE_SHMEM_STATUS
77 # ifdef HAVE_SYS_MMAN_H
78 #  include <sys/mman.h>
79 #  ifndef MAP_FAILED
80 #   define MAP_FAILED ((u_char *) -1)
81 #  endif  /* not MAP_FAILED */
82 # endif /* HAVE_SYS_MMAN_H */
83 #endif /* ONCORE_SHMEM_STATUS */
84
85 #ifdef HAVE_PPSAPI
86 #  ifdef HAVE_TIMEPPS_H
87 #    include <timepps.h>
88 # else
89 #  ifdef HAVE_SYS_TIMEPPS_H
90 #    include <sys/timepps.h>
91 #  endif
92 # endif
93 #endif
94
95 #ifdef HAVE_SYS_SIO_H
96 # include <sys/sio.h>
97 #endif
98
99 #include "ntpd.h"
100 #include "ntp_io.h"
101 #include "ntp_unixtime.h"
102 #include "ntp_refclock.h"
103 #include "ntp_stdlib.h"
104
105 #ifdef HAVE_SYS_TERMIOS_H
106 #include <sys/termios.h>
107 #endif
108
109 #ifdef HAVE_SYS_PPSCLOCK_H
110 # include <sys/ppsclock.h>
111 #endif
112
113 #ifndef HAVE_STRUCT_PPSCLOCKEV
114 struct ppsclockev {
115 # ifdef HAVE_TIMESPEC
116         struct timespec tv;
117 # else
118         struct timeval tv;
119 # endif
120         u_int serial;
121 };
122 #endif /* not HAVE_STRUCT_PPSCLOCKEV */
123
124 enum receive_state {
125         ONCORE_NO_IDEA,
126         ONCORE_RESET_SENT,
127         ONCORE_TEST_SENT,
128         ONCORE_ID_SENT,
129         ONCORE_ALMANAC,
130         ONCORE_RUN
131 };
132
133 enum site_survey_state {
134         ONCORE_SS_UNKNOWN,
135         ONCORE_SS_HW,
136         ONCORE_SS_SW,
137         ONCORE_SS_DONE
138 };
139
140 struct instance {
141         int     unit;           /* 127.127.30.unit */
142         int     ttyfd;          /* TTY file descriptor */
143         int     ppsfd;          /* PPS file descriptor */
144         int     statusfd;       /* Status shm descriptor */
145         u_char  *shmem;
146 #ifdef HAVE_PPSAPI
147         pps_handle_t pps_h;
148         pps_params_t pps_p;
149 #endif
150         enum receive_state o_state;             /* Receive state */
151
152         enum site_survey_state site_survey;     /* Site Survey state */
153
154         struct  refclockproc *pp;
155         struct  peer *peer;
156
157         int     Bj_day;
158
159         long    delay;          /* ns */
160         long    offset;         /* ns */
161
162         double  ss_lat;
163         double  ss_long;
164         double  ss_ht;
165         int     ss_count;
166         u_char  ss_ht_type;
167         u_char  posn_set;
168
169         u_char  printed;
170         u_char  polled;
171         int     pollcnt;
172         u_int   ev_serial;
173         int     Rcvptr;
174         u_char  Rcvbuf[500];
175         u_char  Ea[77];
176         u_char  En[70];
177         u_char  Cj[300];
178         u_char  As;
179         u_char  Ay;
180         u_char  Az;
181         u_char  init_type;
182         s_char  saw_tooth;
183         u_char  timeout;        /* flag to retry Cj after Fa reset */
184         s_char  assert;
185 };
186
187 #define rcvbuf  instance->Rcvbuf
188 #define rcvptr  instance->Rcvptr
189
190 static  void    oncore_consume    P((struct instance *));
191 static  void    oncore_poll       P((int, struct peer *));
192 static  void    oncore_read_config      P((struct instance *));
193 static  void    oncore_receive    P((struct recvbuf *));
194 static  void    oncore_sendmsg    P((int fd, u_char *, u_int));
195 static  void    oncore_shutdown   P((int, struct peer *));
196 static  int     oncore_start      P((int, struct peer *));
197
198 static  void    oncore_msg_any  P((struct instance *, u_char *, u_int, int));
199 static  void    oncore_msg_As   P((struct instance *, u_char *, u_int));
200 static  void    oncore_msg_At   P((struct instance *, u_char *, u_int));
201 static  void    oncore_msg_Ay   P((struct instance *, u_char *, u_int));
202 static  void    oncore_msg_Az   P((struct instance *, u_char *, u_int));
203 static  void    oncore_msg_Bj   P((struct instance *, u_char *, u_int));
204 static  void    oncore_msg_Cb   P((struct instance *, u_char *, u_int));
205 static  void    oncore_msg_Cf   P((struct instance *, u_char *, u_int));
206 static  void    oncore_msg_Cj   P((struct instance *, u_char *, u_int));
207 static  void    oncore_msg_Ea   P((struct instance *, u_char *, u_int));
208 static  void    oncore_msg_En   P((struct instance *, u_char *, u_int));
209 static  void    oncore_msg_Fa   P((struct instance *, u_char *, u_int));
210
211 struct  refclock refclock_oncore = {
212         oncore_start,           /* start up driver */
213         oncore_shutdown,        /* shut down driver */
214         oncore_poll,            /* transmit poll message */
215         noentry,                /* not used */
216         noentry,                /* not used */
217         noentry,                /* not used */
218         NOFLAGS                 /* not used */
219 };
220
221 /*
222  * Understanding the next bit here is not easy unless you have a manual
223  * for the the UT or VP Oncore.
224  */
225
226 static struct msg_desc {
227         const char      flag[3];
228         const int       len;
229         void            (*handler) P((struct instance *, u_char *, u_int));
230         const char      *fmt;
231         int             shmem;
232 } oncore_messages[] = {
233         /* Ea and En first since they're most common */
234         { "Ea",  76,    oncore_msg_Ea,  "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdimsdimsdsC" },
235         { "En",  69,    oncore_msg_En,  "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffsffffsffffC" },
236         { "Ab",  10,    0,              "" },
237         { "Ac",  11,    0,              "" },
238         { "Ad",  11,    0,              "" },
239         { "Ae",  11,    0,              "" },
240         { "Af",  15,    0,              "" },
241         { "As",  20,    oncore_msg_As,  "" },
242         { "At",   8,    oncore_msg_At,  "" },
243         { "Aw",   8,    0,              "" },
244         { "Ay",  11,    oncore_msg_Ay,  "" },
245         { "Az",  11,    oncore_msg_Az,  "" },
246         { "AB",   8,    0,              "" },
247         { "Bb",  92,    0,              "" },
248         { "Bj",   8,    oncore_msg_Bj,  "" },
249         { "Cb",  33,    oncore_msg_Cb,  "" },
250         { "Cf",   7,    oncore_msg_Cf,  "" },
251         { "Cg",   8,    0,              "" },
252         { "Ch",   9,    0,              "" },
253         { "Cj", 294,    oncore_msg_Cj,  "" },
254         { "Ek",  71,    0,              "" },
255         { "Fa",   9,    oncore_msg_Fa,  "" },
256         { "Sz",   8,    0,              "" },
257         { {0},    7,    0, ""}
258 };
259
260 static unsigned int oncore_shmem_Cb;
261
262 /*
263  * Position Set.
264  */
265 u_char oncore_cmd_Ad[] = { 'A', 'd', 0,0,0,0 };
266 u_char oncore_cmd_Ae[] = { 'A', 'e', 0,0,0,0 };
267 u_char oncore_cmd_Af[] = { 'A', 'f', 0,0,0,0, 0 };
268
269 /*
270  * Position-Hold Mode
271  *    Start automatic site survey
272  */
273 static u_char oncore_cmd_At[] = { 'A', 't', 2 };
274
275 /*
276  * Position-Hold Position
277  */
278 u_char oncore_cmd_As[] = { 'A', 's', 0,0,0,0, 0,0,0,0, 0,0,0,0, 0 };
279 u_char oncore_cmd_Asx[]= { 'A', 's', 0x7f, 0xff, 0xff, 0xff,
280                                      0x7f, 0xff, 0xff, 0xff,
281                                      0x7f, 0xff, 0xff, 0xff, 0xff };
282
283 /*
284  * Set to UTC time (not GPS).
285  */
286 u_char oncore_cmd_Aw[] = { 'A', 'w', 1 };
287
288 /*
289  * Output Almanac when it changes
290  */
291 u_char oncore_cmd_Be[] = { 'B', 'e', 1 };
292
293 /*
294  * Read back PPS Offset for Output
295  */
296 u_char oncore_cmd_Ay[]  = { 'A', 'y', 0, 0, 0, 0 };
297 u_char oncore_cmd_Ayx[] = { 'A', 'y', 0xff, 0xff, 0xff, 0xff };
298
299 /*
300  * Read back Cable Delay for Output
301  */
302 u_char oncore_cmd_Az[]  = { 'A', 'z', 0, 0, 0, 0 };
303 u_char oncore_cmd_Azx[] = { 'A', 'z', 0xff, 0xff, 0xff, 0xff };
304
305 /*
306  * Application type = static.
307  */
308 u_char oncore_cmd_AB[] = { 'A', 'B', 4 };
309
310 /*
311  * Visible Satellite Status Msg.
312  */
313 u_char oncore_cmd_Bb[] = { 'B', 'b', 1 };
314
315 /*
316  * Leap Second Pending Message
317  *    Request message once
318  */
319 u_char oncore_cmd_Bj[] = { 'B', 'j', 0 };
320
321 /*
322  * Set to Defaults
323  */
324 static u_char oncore_cmd_Cf[] = { 'C', 'f' };
325
326 /*
327  * Set to Position Fix mode (only needed on VP).
328  */
329 u_char oncore_cmd_Cg[] = { 'C', 'g', 1 };
330
331 /*
332  * Receiver Id
333  */
334 static u_char oncore_cmd_Cj[] = { 'C', 'j' };
335
336 /*
337  * Position/Status/Data message
338  *    Send once per second
339  */
340 static u_char oncore_cmd_Ea[] = { 'E', 'a', 1 };
341
342 /*
343  * Position/Status Extension Msg
344  */
345 u_char oncore_cmd_Ek[] = { 'E', 'k', 0 };       /* just turn off */
346
347 /*
348  * Time Raim Setup & Status Message
349  *    Send once per second
350  *    Time-RAIM on
351  *    Alarm limit 1us
352  *    PPS on when we have the first sat
353  */
354 static u_char oncore_cmd_En[] = { 'E', 'n', 1, 1, 0,10, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
355
356 /*
357  * Self-test
358  */
359 static u_char oncore_cmd_Fa[] = { 'F', 'a' };
360
361 #define DEVICE1         "/dev/oncore.serial.%d"   /* name of serial device */
362 #define DEVICE2         "/dev/oncore.pps.%d"   /* name of pps device */
363 #define INIT_FILE       "/etc/ntp.oncore" /* optional init file */
364
365 #define SPEED           B9600           /* Oncore Binary speed (9600 bps) */
366
367 /*
368  * Assemble and disassemble 32bit signed quantities from a buffer.
369  *
370  */
371
372         /* to buffer, int w, u_char *buf */
373 #define w32_buf(buf,w)  { unsigned int i_tmp;              \
374                           i_tmp = (w<0) ? (~(-w)+1) : (w); \
375                           (buf)[0] = (i_tmp >> 24) & 0xff; \
376                           (buf)[1] = (i_tmp >> 16) & 0xff; \
377                           (buf)[2] = (i_tmp >>  8) & 0xff; \
378                           (buf)[3] = (i_tmp      ) & 0xff; \
379                         }
380
381 #define w32(buf)      (((buf)[0]&0xff) << 24 | \
382                        ((buf)[1]&0xff) << 16 | \
383                        ((buf)[2]&0xff) <<  8 | \
384                        ((buf)[3]&0xff) )
385
386         /* from buffer, char *buf, result to an int */
387 #define buf_w32(buf) (((buf)[0]&0200) ? (-(~w32(buf)+1)) : w32(buf))
388
389 extern int pps_assert;
390 extern int pps_hardpps;
391
392
393 /*
394  * oncore_start - initialize data for processing
395  */
396 static int
397 oncore_start(
398         int unit,
399         struct peer *peer
400         )
401 {
402         register struct instance *instance;
403         struct refclockproc *pp;
404         int fd1, fd2, mode;
405         char device1[30], device2[30];
406         const char *cp;
407         struct stat stat1, stat2;
408
409         /* OPEN DEVICES */
410         /* opening different devices for fd1 and fd2 presents no problems */
411         /* opening the SAME device twice, seems to be OS dependent.
412                 (a) on Linux (no streams) no problem
413                 (b) on SunOS (and possibly Solaris, untested), (streams)
414                         never see the line discipline.
415            Since things ALWAYS work if we only open the device once, we check
416              to see if the two devices are in fact the same, then proceed to
417              do one open or two.
418         */
419
420         (void)sprintf(device1, DEVICE1, unit);
421         (void)sprintf(device2, DEVICE2, unit);
422
423         if (stat(device1, &stat1)) {
424                 perror("ONCORE: stat fd1");
425                 exit(1);
426         }
427
428         if (stat(device2, &stat2)) {
429                 perror("ONCORE: stat fd2");
430                 exit(1);
431         }
432
433         if ((stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino)) {
434                 /* same device here */
435                 if (!(fd1 = refclock_open(device1, SPEED, LDISC_RAW
436 #if !defined(HAVE_PPSAPI) && !defined(TIOCDCDTIMESTAMP)
437                       | LDISC_PPS
438 #endif
439                    ))) {
440                         perror("ONCORE: fd1");
441                         exit(1);
442                 }
443                 fd2 = fd1;
444         } else { /* different devices here */
445                 if (!(fd1=refclock_open(device1, SPEED, LDISC_RAW))) {
446                         perror("ONCORE: fd1");
447                         exit(1);
448                 }
449                 if ((fd2=open(device2, O_RDWR)) < 0) {
450                         perror("ONCORE: fd2");
451                         exit(1);
452                 }
453         }
454
455         /* Devices now open, initialize instance structure */
456
457         if (!(instance = (struct instance *)emalloc(sizeof *instance))) {
458                 perror("malloc");
459                 close(fd1);
460                 return (0);
461         }
462         memset((char *) instance, 0, sizeof *instance);
463         pp = peer->procptr;
464         pp->unitptr = (caddr_t)instance;
465         instance->unit  = unit;
466         instance->ttyfd = fd1;
467         instance->ppsfd = fd2;
468
469         instance->Bj_day = -1;
470         instance->assert = pps_assert;
471
472         /* go read any input data in /etc/ntp.oncoreX */
473
474         oncore_read_config(instance);
475
476 #ifdef HAVE_PPSAPI
477         if (time_pps_create(fd2, &instance->pps_h) < 0) {
478                 perror("time_pps_create");
479                 return(0);
480         }
481
482         if (time_pps_getcap(instance->pps_h, &mode) < 0) {
483                 msyslog(LOG_ERR,
484                     "refclock_ioctl: time_pps_getcap failed: %m");
485                 return (0);
486         }
487
488         if (time_pps_getparams(instance->pps_h, &instance->pps_p) < 0) {
489                 msyslog(LOG_ERR,
490                     "refclock_ioctl: time_pps_getparams failed: %m");
491                 return (0);
492         }
493
494         /* nb. only turn things on, if someone else has turned something
495          *      on before we get here, leave it alone!
496          */
497
498         if (instance->assert) {         /* nb, default or ON */
499                 instance->pps_p.mode = PPS_CAPTUREASSERT | PPS_OFFSETASSERT;
500                 instance->pps_p.assert_offset.tv_sec = 0;
501                 instance->pps_p.assert_offset.tv_nsec = 0;
502         } else {
503                 instance->pps_p.mode = PPS_CAPTURECLEAR  | PPS_OFFSETCLEAR;
504                 instance->pps_p.clear_offset.tv_sec = 0;
505                 instance->pps_p.clear_offset.tv_nsec = 0;
506         }
507         instance->pps_p.mode |= PPS_TSFMT_TSPEC;
508         instance->pps_p.mode &= mode;           /* only do it if it is legal */
509
510         if (time_pps_setparams(instance->pps_h, &instance->pps_p) < 0) {
511                 perror("time_pps_setparams");
512                 exit(1);
513         }
514
515         if (pps_device) {
516                 if (stat(pps_device, &stat1)) {
517                         perror("ONCORE: stat pps_device");
518                         return(0);
519                 }
520         
521                 /* must have hardpps ON, and fd2 must be the same device as on the pps line */
522         
523                 if (pps_hardpps && ((stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino))) {
524                         int     i;
525         
526                         if (instance->assert)
527                                 i = PPS_CAPTUREASSERT;
528                         else
529                                 i = PPS_CAPTURECLEAR;
530         
531                         if (i&mode) {
532                                 if (time_pps_kcbind(instance->pps_h, PPS_KC_HARDPPS, i,
533                                     PPS_TSFMT_TSPEC) < 0) {
534                                         msyslog(LOG_ERR,
535                                             "refclock_ioctl: time_pps_kcbind failed: %m");
536                                         return (0);
537                                 }
538                         }
539                 }
540         }
541 #endif
542
543         instance->pp = pp;
544         instance->peer = peer;
545         instance->o_state = ONCORE_NO_IDEA;
546         cp = "state = ONCORE_NO_IDEA";
547         record_clock_stats(&(instance->peer->srcadr), cp);
548
549         /*
550          * Initialize miscellaneous variables
551          */
552
553         peer->precision = -26;
554         peer->minpoll = 4;
555         peer->maxpoll = 4;
556         pp->clockdesc = "Motorola UT/VP Oncore GPS Receiver";
557         memcpy((char *)&pp->refid, "GPS\0", 4);
558
559         pp->io.clock_recv = oncore_receive;
560         pp->io.srcclock = (caddr_t)peer;
561         pp->io.datalen = 0;
562         pp->io.fd = fd1;
563         if (!io_addclock(&pp->io)) {
564                 perror("io_addclock");
565                 (void) close(fd1);
566                 free(instance);
567                 return (0);
568         }
569         pp->unitptr = (caddr_t)instance;
570
571         /*
572          * This will start the Oncore receiver.
573          * We send info from config to Oncore later.
574          */
575
576         instance->timeout = 1;
577         mode = instance->init_type;
578         if (mode == 3 || mode == 4) {
579                 oncore_sendmsg(instance->ttyfd, oncore_cmd_Cf, sizeof oncore_cmd_Cf);
580                 instance->o_state = ONCORE_RESET_SENT;
581                 cp = "state = ONCORE_RESET_SENT";
582                 record_clock_stats(&(instance->peer->srcadr), cp);
583         } else {
584                 oncore_sendmsg(instance->ttyfd, oncore_cmd_Fa, sizeof oncore_cmd_Fa);
585                 instance->o_state = ONCORE_TEST_SENT;
586                 cp = "state = ONCORE_TEST_SENT";
587                 record_clock_stats(&(instance->peer->srcadr), cp);
588         }
589
590         instance->pollcnt = 2;
591         return (1);
592 }
593
594
595
596 static void
597 oncore_init_shmem(struct instance *instance, char *filename)
598 {
599 #ifdef ONCORE_SHMEM_STATUS
600         int i, l, n;
601         char *buf;
602         struct msg_desc *mp;
603         static unsigned int oncore_shmem_length;
604
605         if (oncore_messages[0].shmem == 0) {
606                 n = 1;
607                 for (mp = oncore_messages; mp->flag[0]; mp++) {
608                         mp->shmem = n;
609                         /* Allocate space for multiplexed almanac */
610                         if (!strcmp(mp->flag, "Cb")) {
611                                 oncore_shmem_Cb = n;
612                                 n += (mp->len + 2) * 34;
613                         }
614                         n += mp->len + 2;
615                 }
616                 oncore_shmem_length = n + 2;
617                 fprintf(stderr, "ONCORE: SHMEM length: %d bytes\n", oncore_shmem_length);
618         }
619         instance->statusfd = open(filename, O_RDWR|O_CREAT|O_TRUNC, 0644);
620         if (instance->statusfd < 0) {
621                 perror(filename);
622                 exit(4);
623         }
624         buf = malloc(oncore_shmem_length);
625         if (buf == NULL) {
626                 perror("malloc");
627                 exit(4);
628         }
629         memset(buf, 0, sizeof(buf));
630         i = write(instance->statusfd, buf, oncore_shmem_length);
631         if (i != oncore_shmem_length) {
632                 perror(filename);
633                 exit(4);
634         }
635         free(buf);
636         instance->shmem = (u_char *) mmap(0, oncore_shmem_length, 
637             PROT_READ | PROT_WRITE,
638 #ifdef MAP_HASSEMAPHORE
639                                MAP_HASSEMAPHORE |
640 #endif
641                                MAP_SHARED,
642             instance->statusfd, (off_t)0);
643         if (instance->shmem == MAP_FAILED) {
644                 instance->shmem = 0;
645                 close (instance->statusfd);
646                 exit(4);
647         }
648         for (mp = oncore_messages; mp->flag[0]; mp++) {
649                 l = mp->shmem;
650                 instance->shmem[l + 0] = mp->len >> 8;
651                 instance->shmem[l + 1] = mp->len & 0xff;
652                 instance->shmem[l + 2] = '@';
653                 instance->shmem[l + 3] = '@';
654                 instance->shmem[l + 4] = mp->flag[0];
655                 instance->shmem[l + 5] = mp->flag[1];
656                 if (!strcmp(mp->flag, "Cb")) {
657                         for (i = 1; i < 35; i++) {
658                                 instance->shmem[l + i * 35 + 0] = mp->len >> 8;
659                                 instance->shmem[l + i * 35 + 1] = mp->len & 0xff;
660                                 instance->shmem[l + i * 35 + 2] = '@';
661                                 instance->shmem[l + i * 35 + 3] = '@';
662                                 instance->shmem[l + i * 35 + 4] = mp->flag[0];
663                                 instance->shmem[l + i * 35 + 5] = mp->flag[1];
664                         }
665                 }
666         }
667 #endif /* ONCORE_SHMEM_STATUS */
668
669
670 /*
671  * Read Input file if it exists.
672  */
673 static void
674 oncore_read_config(
675         struct instance *instance
676         )
677 {
678 /*
679  * First we try to open the configuration file /etc/ntp.oncoreN, where
680  * N is the unit number viz 127.127.30.N.
681  * If we don't find it, then we try the file /etc/ntp.oncore.
682  *
683  * If we find NEITHER then we don't have the cable delay or PPS offset
684  * and we choose MODE (4) below.
685  *
686  * Five Choices for MODE
687  *    (0) ONCORE is preinitialized, don't do anything to change it.
688  *          nb, DON'T set 0D mode, DON'T set Delay, position...
689  *    (1) NO RESET, Read Position, delays from data file, lock it in, go to 0D mode.
690  *    (2) NO RESET, Read Delays from data file, do SITE SURVEY to get position,
691  *                  lock this in, go to 0D mode.
692  *    (3) HARD RESET, Read Position, delays from data file, lock it in, go to 0D mode.
693  *    (4) HARD RESET, Read Delays from data file, do SITE SURVEY to get position,
694  *                  lock this in, go to 0D mode.
695  *     NB. If a POSITION is specified in the config file with mode=(2,4) [SITE SURVEY]
696  *         then this position is set as the INITIAL position of the ONCORE.
697  *         This can reduce the time to first fix.
698  * -------------------------------------------------------------------------------
699  * Note that an Oncore UT without a battery backup retains NO information if it is
700  *   power cycled, with a Battery Backup it remembers the almanac, etc.
701  * For an Oncore VP, there is an eeprom that will contain this data, along with the
702  *   option of Battery Backup.
703  * So a UT without Battery Backup is equivalent to doing a HARD RESET on each
704  *   power cycle, since there is nowhere to store the data.
705  * -------------------------------------------------------------------------------
706  *
707  * If we open one or the other of the files, we read it looking for
708  *   MODE, LAT, LON, (HT, HTGPS, HTMSL), DELAY, OFFSET
709  * then initialize using method MODE.  For Mode = (1,3) all of (LAT, LON, HT) must
710  *   be present or mode reverts to (2,4).
711  *
712  * Read input file.
713  *
714  *      # is comment to end of line
715  *      = allowed between 1st and 2nd fields.
716  *
717  *      Expect to see one line with 'MODE' as first field, followed by an integer
718  *         in the range 0-4 (default = 4).
719  *
720  *      Expect to see two lines with 'LONG', 'LAT' followed by 1-3 fields.
721  *      All numbers are floating point.
722  *              DDD.ddd
723  *              DDD  MMM.mmm
724  *              DDD  MMM  SSS.sss
725  *
726  *      Expect to see one line with 'HT' (or 'HTMSL' or 'HTGPS') as first field.
727  *         followed by 1-2 fields.  First is a number, the second is 'FT' or 'M'.
728  *         for feet or meters.  HT is the same as HTGPS.
729  *           HTMSL = HT above mean_sea_level,
730  *           HTGPS = HT above GPS ellipse.
731  *
732  *      There are two optional lines, starting with DELAY and OFFSET, followed
733  *         by 1 or two fields.  The first is a number (a time) the second is
734  *         'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds.
735  *           DELAY  is cable delay, typically a few tens of ns.
736  *           OFFSET is the offset of the PPS pulse from 0. (only fully implemented
737  *              with the PPSAPI, we need to be able to tell the Kernel about this
738  *              offset if the Kernel PLL is in use, but can only do this presently
739  *              when using the PPSAPI interface.  If not using the Kernel PLL,
740  *              then there is no problem.
741  *
742  *      There is another optional line, with either ASSERT or CLEAR on it, which
743  *         determine which transition of the PPS signal is used for timing by the
744  *         PPSAPI.  If neither is present, then ASSERT is assumed.
745  *
746  * So acceptable input would be
747  *      # these are my coordinates (RWC)
748  *      LON  -106 34.610
749  *      LAT    35 08.999
750  *      HT      1589    # could equally well say HT 5215 FT
751  *      DELAY  60 ns
752  */
753
754         FILE    *fd;
755         char    *cp, *cc, *ca, line[100], units[2], device[20];
756         int     i, sign, lat_flg, long_flg, ht_flg, mode;
757         double  f1, f2, f3;
758
759         sprintf(device, "%s%d", INIT_FILE, instance->unit);
760         if ((fd=fopen(device, "r")) == NULL)
761                 if ((fd=fopen(INIT_FILE, "r")) == NULL) {
762                         instance->init_type = 4;
763                         return;
764                 }
765
766         mode = 0;
767         lat_flg = long_flg = ht_flg = 0;
768         while (fgets(line, 100, fd)) {
769
770                 /* Remove comments */
771                 if ((cp = strchr(line, '#')))
772                         *cp = '\0';
773                 
774                 /* Remove trailing space */
775                 for (i = strlen(line);
776                      i > 0 && isascii((int)line[i - 1]) && isspace((int)line[i - 1]);
777                         )
778                         line[--i] = '\0';
779
780                 /* Remove leading space */
781                 for (cc = line; *cc && isascii((int)*cc) && isspace((int)*cc); cc++)
782                         continue;
783
784                 /* Stop if nothing left */
785                 if (!*cc)
786                         continue;
787
788                 /* Lowercase the command and find the arg */
789                 for (ca = cc; *ca; ca++) {
790                         if (isascii((int)*ca) && islower((int)*ca)) {
791                                 *ca = toupper(*ca);
792                         } else if (isascii((int)*ca) && isspace((int)*ca)) {
793                                 break;
794                         } else if (*ca == '=') {
795                                 *ca = ' ';
796                                 break;
797                         }
798                 }
799                 
800                 /* Remove space leading the arg */
801                 for (; *ca && isascii((int)*ca) && isspace((int)*ca); ca++)
802                         continue;
803
804                 if (!strncmp(cc, "STATUS", 6)) {
805                         oncore_init_shmem(instance, ca);
806                         continue;
807                 }
808
809                 /* Uppercase argument as well */
810                 for (cp = ca; *cp; cp++)
811                         if (isascii((int)*cp) && islower((int)*cp))
812                                 *cp = toupper(*cp);
813
814                 if (!strncmp(cc, "LAT", 3)) {
815                         f1 = f2 = f3 = 0;
816                         sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3);
817                         sign = 1;
818                         if (f1 < 0) {
819                                 f1 = -f1;
820                                 sign = -1;
821                         }
822                         instance->ss_lat = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/
823                         lat_flg++;
824                 } else if (!strncmp(cc, "LON", 3)) {
825                         f1 = f2 = f3 = 0;
826                         sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3);
827                         sign = 1;
828                         if (f1 < 0) {
829                                 f1 = -f1;
830                                 sign = -1;
831                         }
832                         instance->ss_long = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/
833                         long_flg++;
834                 } else if (!strncmp(cc, "HT", 2)) {
835                         if (!strncmp(cc, "HTGPS", 5)) 
836                                 instance->ss_ht_type = 0;
837                         else if (!strncmp(cc, "HTMSL", 5))
838                                 instance->ss_ht_type = 1;
839                         else 
840                                 instance->ss_ht_type = 0;
841                         f1 = 0;
842                         units[0] = '\0';
843                         sscanf(ca, "%lf %1s", &f1, units);
844                         if (units[0] == 'F')
845                                 f1 = 0.3048 * f1;
846                         instance->ss_ht = 100 * f1;    /* cm */
847                         ht_flg++;
848                 } else if (!strncmp(cc, "DELAY", 5)) {
849                         f1 = 0;
850                         units[0] = '\0';
851                         sscanf(ca, "%lf %1s", &f1, units);
852                         if (units[0] == 'N')
853                                 ;
854                         else if (units[0] == 'U')
855                                 f1 = 1000 * f1;
856                         else if (units[0] == 'M')
857                                 f1 = 1000000 * f1;
858                         else
859                                 f1 = 1000000000 * f1;
860                         if (f1 < 0 || f1 > 1.e9)
861                                 f1 = 0;
862                         instance->delay = f1;           /* delay in ns */
863                 } else if (!strncmp(cc, "OFFSET", 6)) {
864                         f1 = 0;
865                         units[0] = '\0';
866                         sscanf(ca, "%lf %1s", &f1, units);
867                         if (units[0] == 'N')
868                                 ;
869                         else if (units[0] == 'U')
870                                 f1 = 1000 * f1;
871                         else if (units[0] == 'M')
872                                 f1 = 1000000 * f1;
873                         else
874                                 f1 = 1000000000 * f1;
875                         if (f1 < 0 || f1 > 1.e9)
876                                 f1 = 0;
877                         instance->offset = f1;          /* offset in ns */
878                 } else if (!strncmp(cc, "MODE", 4)) {
879                         sscanf(ca, "%d", &mode);
880                         if (mode < 0 || mode > 4)
881                                 mode = 4;
882                         instance->init_type = mode;
883                 } else if (!strncmp(cc, "ASSERT", 6)) {
884                         instance->assert = 1;
885                 } else if (!strncmp(cc, "CLEAR", 5)) {
886                         instance->assert = 0;
887                 }
888         }
889         fclose(fd);
890
891         /*
892          *    OK, have read all of data file, and extracted the good stuff.
893          *    If lat/long/ht specified they ALL must be specified for mode = (1,3).
894          */
895
896         instance->posn_set = 1;
897         if ((lat_flg || long_flg || ht_flg) && !(lat_flg * long_flg * ht_flg)) {
898                 printf("ONCORE: incomplete data on %s\n", INIT_FILE);
899                 instance->posn_set = 0;
900                 if (mode == 1 || mode == 3)
901                         instance->init_type++;
902         }
903 }
904
905
906
907 /*
908  * oncore_shutdown - shut down the clock
909  */
910 static void
911 oncore_shutdown(
912         int unit,
913         struct peer *peer
914         )
915 {
916         register struct instance *instance;
917         struct refclockproc *pp;
918
919         pp = peer->procptr;
920         instance = (struct instance *) pp->unitptr;
921         free(instance);
922 }
923
924
925
926 /*
927  * oncore_poll - called by the transmit procedure
928  */
929 static void
930 oncore_poll(
931         int unit,
932         struct peer *peer
933         )
934 {
935         struct instance *instance;
936
937         instance = (struct instance *) peer->procptr->unitptr;
938         if (instance->timeout) {
939                 char    *cp;
940
941                 oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof oncore_cmd_Cj);
942                 instance->o_state = ONCORE_ID_SENT;
943                 cp = "state = ONCORE_ID_SENT";
944                 record_clock_stats(&(instance->peer->srcadr), cp);
945                 return;
946         }
947
948         if (!instance->pollcnt)
949                 refclock_report(peer, CEVNT_TIMEOUT);
950         else
951                 instance->pollcnt--;
952         peer->procptr->polls++;
953         instance->polled = 1;
954 }
955
956
957
958 /*
959  * move dta from NTP to buffer (toss in unlikely case it wont fit)
960  */
961 static void
962 oncore_receive(
963         struct recvbuf *rbufp
964         )
965 {
966         u_int   i;
967         u_char *p;
968         struct peer *peer;
969         struct instance *instance;
970
971         peer = (struct peer *)rbufp->recv_srcclock;
972         instance = (struct instance *) peer->procptr->unitptr;
973         p = (u_char *) &rbufp->recv_space;
974
975 #if 0
976         if (debug > 4) {
977                 int i;
978                 printf("ONCORE: >>>");
979                 for(i=0; i<rbufp->recv_length; i++)
980                         printf("%02x ", p[i]);
981                 printf("\n");
982                 printf("ONCORE: >>>");
983                 for(i=0; i<rbufp->recv_length; i++)
984                         printf("%03o ", p[i]);
985                 printf("\n");
986         }
987 #endif
988
989         i = rbufp->recv_length;
990         if (rcvbuf+rcvptr+i > &rcvbuf[sizeof rcvbuf])
991                 i = sizeof(rcvbuf) - rcvptr;    /* and some char will be lost */
992         memcpy(rcvbuf+rcvptr, p, i);
993         rcvptr += i;
994         oncore_consume(instance);
995 }
996
997
998
999 /*
1000  * Deal with any complete messages
1001  */
1002 static void
1003 oncore_consume(
1004         struct instance *instance
1005         )
1006 {
1007         int i, j, m;
1008         unsigned l;
1009
1010         while (rcvptr >= 7) {
1011                 if (rcvbuf[0] != '@' || rcvbuf[1] != '@') {
1012                         /* We're not in sync, lets try to get there */
1013                         for (i=1; i < rcvptr-1; i++)
1014                                 if (rcvbuf[i] == '@' && rcvbuf[i+1] == '@')
1015                                         break;
1016                         if (debug > 4)
1017                                 printf("ONCORE: >>> skipping %d chars\n", i);
1018                         if (i != rcvptr)
1019                                 memcpy(rcvbuf, rcvbuf+i, (unsigned)(rcvptr-i));
1020                         rcvptr -= i;
1021                 }
1022
1023                 /* Ok, we have a header now */
1024                 l = sizeof(oncore_messages)/sizeof(oncore_messages[0]) -1;
1025                 for(m=0; m<l; m++)
1026                         if (!strncmp(oncore_messages[m].flag, (char *)(rcvbuf+2), 2))
1027                                 break;
1028                 l = oncore_messages[m].len;
1029 #if 0
1030                 if (debug > 3)
1031                         printf("ONCORE: GOT: %c%c  %d of %d entry %d\n", rcvbuf[2], rcvbuf[3], rcvptr, l, m);
1032 #endif
1033                 /* Got the entire message ? */
1034
1035                 if (rcvptr < l)
1036                         return;
1037
1038                 /* Check the checksum */
1039
1040                 j = 0;
1041                 for (i = 2; i < l-3; i++)
1042                         j ^= rcvbuf[i];
1043                 if (j == rcvbuf[l-3]) {
1044                         if (instance->shmem != NULL) 
1045                                 memcpy(instance->shmem + oncore_messages[m].shmem + 2,
1046                                     rcvbuf, l);
1047                         oncore_msg_any(instance, rcvbuf, (unsigned) (l-3), m);
1048                         if (oncore_messages[m].handler)
1049                                 oncore_messages[m].handler(instance, rcvbuf, (unsigned) (l-3));
1050                 } else if (debug) {
1051                         printf("ONCORE: Checksum mismatch! calc %o is %o\n", j, rcvbuf[l-3]);
1052                         printf("ONCORE: @@%c%c ", rcvbuf[2], rcvbuf[3]);
1053                         for (i=4; i<l; i++)
1054                                 printf("%03o ", rcvbuf[i]);
1055                         printf("\n");
1056                 }
1057
1058                 if (l != rcvptr)
1059                         memcpy(rcvbuf, rcvbuf+l, (unsigned) (rcvptr-l));
1060                 rcvptr -= l;
1061         }
1062 }
1063
1064
1065
1066 /*
1067  * write message to Oncore.
1068  */
1069 static void
1070 oncore_sendmsg(
1071         int     fd,
1072         u_char *ptr,
1073         u_int len
1074         )
1075 {
1076         u_char cs = 0;
1077
1078         printf("ONCORE: Send @@%c%c %d\n", ptr[0], ptr[1], len);
1079         write(fd, "@@", 2);
1080         write(fd, ptr, len);
1081         while (len--)
1082                 cs ^= *ptr++;
1083         write(fd, &cs, 1);
1084         write(fd, "\r\n", 2);
1085 }
1086
1087
1088
1089 static void
1090 oncore_msg_any(
1091         struct instance *instance,
1092         u_char *buf,
1093         u_int len,
1094         int idx
1095         )
1096 {
1097         int i;
1098         const char *fmt = oncore_messages[idx].fmt;
1099         const char *p;
1100         struct timeval tv;
1101
1102         if (debug > 3) {
1103                 GETTIMEOFDAY(&tv, 0);
1104                 printf("ONCORE: %ld.%06ld\n", (long) tv.tv_sec, (long) tv.tv_usec);
1105
1106                 if (!*fmt) {
1107                         printf(">>@@%c%c ", buf[2], buf[3]);
1108                         for(i=2; i < len && i < 2400 ; i++)
1109                                 printf("%02x", buf[i]);
1110                         printf("\n");
1111                         return;
1112                 } else {
1113                         printf("##");
1114                         for (p = fmt; *p; p++) {
1115                                 putchar(*p);
1116                                 putchar('_');
1117                         }
1118                         printf("\n%c%c", buf[2], buf[3]);
1119                         i = 4;
1120                         for (p = fmt; *p; p++) {
1121                                 printf("%02x", buf[i++]);
1122                         }
1123                         printf("\n");
1124                 }
1125         }
1126 }
1127
1128
1129
1130 /*
1131  * Demultiplex the almanac into shmem
1132  */
1133 static void
1134 oncore_msg_Cb(
1135         struct instance *instance,
1136         u_char *buf,
1137         u_int len
1138         )
1139 {
1140         int i;
1141
1142         if (instance->shmem == NULL)
1143                 return;
1144
1145         if (buf[4] == 5) 
1146                 i = buf[5];
1147         else if (buf[4] == 4 && buf[5] <= 5)
1148                 i = buf[5] + 24;
1149         else if (buf[4] == 4 && buf[5] <= 10)
1150                 i = buf[5] + 23;
1151         else
1152                 i = 34;
1153         i *= 35;
1154         memcpy(instance->shmem + oncore_shmem_Cb + i + 2, buf, len + 3);
1155 }
1156
1157 /*
1158  * Set to Factory Defaults (Reasonable for UT w/ no Battery Backup
1159  *      not so for VP (eeprom) or UT with battery
1160  */
1161 static void
1162 oncore_msg_Cf(
1163         struct instance *instance,
1164         u_char *buf,
1165         u_int len
1166         )
1167 {
1168         const char *cp;
1169
1170         if (instance->o_state == ONCORE_RESET_SENT) {
1171                 oncore_sendmsg(instance->ttyfd, oncore_cmd_Fa, sizeof oncore_cmd_Fa);
1172                 instance->o_state = ONCORE_TEST_SENT;
1173                 cp = "state = ONCORE_TEST_SENT";
1174                 record_clock_stats(&(instance->peer->srcadr), cp);
1175         }
1176 }
1177
1178
1179
1180 /* there are good reasons NOT to do a @@Fa command with the ONCORE.
1181  * Doing it, it was found that under some circumstances the following
1182  * command would fail if issued immediately after the return from the
1183  * @@Fa, but a 2sec delay seemed to fix things.  Since simply calling
1184  * sleep(2) is wastefull, and may cause trouble for some OS's, repeating
1185  * itimer, we set a flag, and test it at the next POLL.  If it hasnt
1186  * been cleared, we reissue the @@Ca that is issued below.
1187  */
1188
1189 static void
1190 oncore_msg_Fa(
1191         struct instance *instance,
1192         u_char *buf,
1193         u_int len
1194         )
1195 {
1196         const char *cp;
1197
1198         if (instance->o_state == ONCORE_TEST_SENT) {
1199                 if (debug > 2)
1200                         printf("ONCORE: >>@@Fa %x %x\n", buf[4], buf[5]);
1201                 if (buf[4] || buf[5]) {
1202                         printf("ONCORE: SELF TEST FAILED\n");
1203                         exit(1);
1204                 }
1205
1206                 oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof oncore_cmd_Cj);
1207                 instance->o_state = ONCORE_ID_SENT;
1208                 cp = "state = ONCORE_ID_SENT";
1209                 record_clock_stats(&(instance->peer->srcadr), cp);
1210         }
1211 }
1212
1213
1214
1215 /*
1216  * preliminaries out of the way, this is the REAL start of initialization
1217  */
1218 static void
1219 oncore_msg_Cj(
1220         struct instance *instance,
1221         u_char *buf,
1222         u_int len
1223         )
1224 {
1225         char *cp, *cp1;
1226         int     mode;
1227
1228         instance->timeout = 0;
1229         if (instance->o_state != ONCORE_ID_SENT)
1230                 return;
1231
1232         memcpy(instance->Cj, buf, len);
1233
1234         /* Write Receiver ID to clockstats file */
1235
1236         instance->Cj[294] = '\0';
1237         for (cp=(char *)instance->Cj; cp< (char *) &instance->Cj[294]; ) {
1238                 cp1 = strchr(cp, '\r');
1239                 if (!cp1)
1240                         cp1 = (char *)&instance->Cj[294];
1241                 *cp1 = '\0';
1242                 record_clock_stats(&(instance->peer->srcadr), cp);
1243                 *cp1 = '\r';
1244                 cp = cp1+2;
1245         }
1246 #ifdef HAVE_PPSAPI
1247         if (instance->assert)
1248                 cp = "Timing on Assert.";
1249         else
1250                 cp = "Timing on Clear.";
1251         record_clock_stats(&(instance->peer->srcadr), cp);
1252 #endif
1253
1254         oncore_sendmsg(instance->ttyfd, oncore_cmd_Cg, sizeof oncore_cmd_Cg); /* Set Posn Fix mode (not Idle (VP)) */
1255         oncore_sendmsg(instance->ttyfd, oncore_cmd_Bb, sizeof oncore_cmd_Bb); /* turn off */
1256         oncore_sendmsg(instance->ttyfd, oncore_cmd_Ek, sizeof oncore_cmd_Ek); /* turn off */
1257         oncore_sendmsg(instance->ttyfd, oncore_cmd_Aw, sizeof oncore_cmd_Aw); /* UTC time */
1258         oncore_sendmsg(instance->ttyfd, oncore_cmd_AB, sizeof oncore_cmd_AB); /* Appl type static */
1259         oncore_sendmsg(instance->ttyfd, oncore_cmd_Be, sizeof oncore_cmd_Be); /* Tell us the Almanac */
1260
1261         mode = instance->init_type;
1262         if (debug)
1263                 printf("ONCORE: INIT mode = %d\n", mode);
1264
1265         /* If there is Position input in the Config file
1266          * and mode = (1,3) set it as posn hold posn, goto 0D mode.
1267          *  or mode = (2,4) set it as INITIAL position, and Site Survey.
1268          */
1269
1270         switch (mode) {
1271         case 0: /* NO initialization, don't change anything */
1272                 instance->site_survey = ONCORE_SS_DONE;
1273                 break;
1274
1275         case 1:
1276         case 3:
1277                 w32_buf(&oncore_cmd_As[2],  (int) instance->ss_lat);
1278                 w32_buf(&oncore_cmd_As[6],  (int) instance->ss_long);
1279                 w32_buf(&oncore_cmd_As[10], (int) instance->ss_ht);
1280                 oncore_cmd_As[14] = instance->ss_ht_type;
1281                 oncore_sendmsg(instance->ttyfd, oncore_cmd_As,  sizeof oncore_cmd_As);
1282
1283                 instance->site_survey = ONCORE_SS_DONE;
1284                 oncore_cmd_At[2] = 1;
1285                 oncore_sendmsg(instance->ttyfd, oncore_cmd_At,  sizeof oncore_cmd_At);
1286                 record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode");
1287                 break;
1288
1289         case 2:
1290         case 4:
1291                 if (instance->posn_set) {
1292                         w32_buf(&oncore_cmd_Ad[2], (int) instance->ss_lat);
1293                         w32_buf(&oncore_cmd_Ae[2], (int) instance->ss_long);
1294                         w32_buf(&oncore_cmd_Af[2], (int) instance->ss_ht);
1295                         oncore_cmd_Af[6] = instance->ss_ht_type;
1296                         oncore_sendmsg(instance->ttyfd, oncore_cmd_Ad,  sizeof oncore_cmd_Ad);
1297                         oncore_sendmsg(instance->ttyfd, oncore_cmd_Ae,  sizeof oncore_cmd_Ae);
1298                         oncore_sendmsg(instance->ttyfd, oncore_cmd_Af,  sizeof oncore_cmd_Af);
1299                 }
1300                 instance->site_survey = ONCORE_SS_UNKNOWN;
1301                 oncore_cmd_At[2] = 2;
1302                 oncore_sendmsg(instance->ttyfd, oncore_cmd_At,  sizeof oncore_cmd_At);
1303                 break;
1304         }
1305
1306         if (mode != 0) {
1307                         /* cable delay in ns */
1308                 w32_buf(&oncore_cmd_Az[2], instance->delay);
1309                 oncore_sendmsg(instance->ttyfd, oncore_cmd_Az,  sizeof oncore_cmd_Az);
1310
1311                         /* PPS offset in ns */
1312                 w32_buf(&oncore_cmd_Ay[2], instance->offset);
1313                 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ay,  sizeof oncore_cmd_Ay);
1314         }
1315
1316         /* 8chan - Position/Status/Data Output Message, 1/s */
1317
1318         oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea,  sizeof oncore_cmd_Ea);
1319
1320         instance->o_state = ONCORE_ALMANAC;
1321         cp = "state = ONCORE_ALMANAC";
1322         record_clock_stats(&(instance->peer->srcadr), cp);
1323 }
1324
1325
1326
1327 static void
1328 oncore_msg_Ea(
1329         struct instance *instance,
1330         u_char *buf,
1331         u_int len
1332         )
1333 {
1334         const char      *cp;
1335         char            Msg[160];
1336
1337         if (instance->o_state != ONCORE_ALMANAC && instance->o_state != ONCORE_RUN)
1338                 return;
1339
1340         memcpy(instance->Ea, buf, len);
1341
1342         /* When we have an almanac, start the En messages */
1343
1344         if (instance->o_state == ONCORE_ALMANAC) {
1345                 if ((instance->Ea[72] & 1)) {
1346                         if (debug)
1347                                 printf("ONCORE: waiting for almanac\n");
1348                         return;
1349                 } else {
1350                         oncore_sendmsg(instance->ttyfd, oncore_cmd_En, sizeof oncore_cmd_En);
1351                         instance->o_state = ONCORE_RUN;
1352                         cp = "state = ONCORE_RUN";
1353                         record_clock_stats(&(instance->peer->srcadr), cp);
1354                 }
1355         }
1356
1357         /* must be ONCORE_RUN if we are here */
1358         /* First check if Hardware SiteSurvey has Finished */
1359
1360         if ((instance->site_survey == ONCORE_SS_HW) && !(instance->Ea[37] & 0x20)) {
1361                 instance->site_survey = ONCORE_SS_DONE;
1362                 record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode");
1363         }
1364
1365         if (!instance->printed && instance->site_survey == ONCORE_SS_DONE) {    /* will print to clockstat when all */
1366                 instance->printed = 1;                                          /* three messages respond */
1367                         /* Read back Position Hold Params */
1368                 oncore_sendmsg(instance->ttyfd, oncore_cmd_Asx,  sizeof oncore_cmd_Asx);
1369                         /* Read back PPS Offset for Output */
1370                         /* Nb. This will fail silently for early UT (no plus) model */
1371                 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ayx,  sizeof oncore_cmd_Ayx);
1372                         /* Read back Cable Delay for Output */
1373                 oncore_sendmsg(instance->ttyfd, oncore_cmd_Azx,  sizeof oncore_cmd_Azx);
1374         }
1375
1376         /* Check the leap second status once per day */
1377
1378         /*
1379          * The following additional check, checking for June/December, is a
1380          * workaround for incorrect ONCORE firmware.  The oncore starts
1381          * reporting the leap second when the GPS satellite data message
1382          * (page 18, subframe 4) is updated to a date in the future, which
1383          * which can be several months before the leap second.  WWV and other
1384          * services seem to wait until the month of the event to turn
1385          * on their indicators (which are usually a single bit).
1386          */
1387
1388         if ((buf[4] == 6) || (buf[4] == 12)) {
1389                 if (instance->Bj_day != buf[5]) {     /* do this 1/day */
1390                         instance->Bj_day = buf[5];
1391                         oncore_sendmsg(instance->ttyfd, oncore_cmd_Bj, sizeof oncore_cmd_Bj);
1392                 }
1393         }
1394         instance->pp->year = buf[6]*256+buf[7];
1395         instance->pp->day = ymd2yd(buf[6]*256+buf[7], buf[4], buf[5]);
1396         instance->pp->hour = buf[8];
1397         instance->pp->minute = buf[9];
1398         instance->pp->second = buf[10];
1399
1400         if (instance->site_survey != ONCORE_SS_SW)
1401                 return;
1402
1403         /*
1404          * We have to average our own position for the Position Hold Mode
1405          */
1406
1407         /* We only take PDOP/3D fixes */
1408
1409         if (instance->Ea[37] & 1)
1410                 return;
1411
1412         /* Not if poor geometry or less than 3 sats */
1413
1414         if (instance->Ea[72] & 0x52)
1415                 return;
1416
1417         /* Only 3D fix */
1418
1419         if (!(instance->Ea[72] & 0x20))
1420                 return;
1421
1422         instance->ss_lat  += buf_w32(&instance->Ea[15]);
1423         instance->ss_long += buf_w32(&instance->Ea[19]);
1424         instance->ss_ht   += buf_w32(&instance->Ea[23]);  /* GPS ellipse */
1425         instance->ss_count++;
1426
1427         if (instance->ss_count != POS_HOLD_AVERAGE)
1428                 return;
1429
1430         instance->ss_lat  /= POS_HOLD_AVERAGE;
1431         instance->ss_long /= POS_HOLD_AVERAGE;
1432         instance->ss_ht   /= POS_HOLD_AVERAGE;
1433
1434         sprintf(Msg, "Surveyed posn:  lat %.3f long %.3f ht %.3f",
1435                         instance->ss_lat, instance->ss_long, instance->ss_ht);
1436         record_clock_stats(&(instance->peer->srcadr), Msg);
1437
1438         w32_buf(&oncore_cmd_As[2],  (int) instance->ss_lat);
1439         w32_buf(&oncore_cmd_As[6],  (int) instance->ss_long);
1440         w32_buf(&oncore_cmd_As[10], (int) instance->ss_ht);
1441         oncore_cmd_As[14] = 0;
1442         oncore_sendmsg(instance->ttyfd, oncore_cmd_As, sizeof oncore_cmd_As);
1443
1444         oncore_cmd_At[2] = 1;
1445         oncore_sendmsg(instance->ttyfd, oncore_cmd_At, sizeof oncore_cmd_At);
1446         record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode");
1447         instance->site_survey = ONCORE_SS_DONE;
1448 }
1449
1450
1451
1452 static void
1453 oncore_msg_En(
1454         struct instance *instance,
1455         u_char *buf,
1456         u_int len
1457         )
1458 {
1459         int     j;
1460         l_fp ts, ts_tmp;
1461         double dmy;
1462 #ifdef HAVE_TIMESPEC
1463         struct timespec *tsp = 0;
1464 #else
1465         struct timeval  *tsp = 0;
1466 #endif
1467 #ifdef HAVE_PPSAPI
1468         struct timespec timeout;
1469         pps_info_t pps_i;
1470 #else  /* ! HAVE_PPSAPI */
1471 #ifdef HAVE_CIOGETEV
1472         struct ppsclockev ev;
1473         int r = CIOGETEV;
1474 #endif
1475 #ifdef HAVE_TIOCGPPSEV
1476         struct ppsclockev ev;
1477         int r = TIOCGPPSEV;
1478 #endif
1479 #if     TIOCDCDTIMESTAMP
1480         struct timeval  tv;
1481 #endif
1482 #endif  /* ! HAVE_PPS_API */
1483
1484         if (instance->o_state != ONCORE_RUN)
1485                 return;
1486
1487         memcpy(instance->En, buf, len);
1488
1489         /* Don't do anything without an almanac to define the GPS->UTC delta */
1490
1491         if (instance->Ea[72] & 1)
1492                 return;
1493
1494         /* If Time RAIM doesn't like it, don't trust it */
1495
1496         if (instance->En[21])
1497                 return;
1498
1499 #ifdef HAVE_PPSAPI
1500         j = instance->ev_serial;
1501         timeout.tv_sec = 0;
1502         timeout.tv_nsec = 0;
1503         if (time_pps_fetch(instance->pps_h, PPS_TSFMT_TSPEC, &pps_i,
1504             &timeout) < 0) {
1505                 printf("ONCORE: time_pps_fetch failed\n");
1506                 return;
1507         }
1508
1509         if (instance->assert) {
1510                 tsp = &pps_i.assert_timestamp;
1511
1512                 if (debug > 2)
1513                         printf("ONCORE: serial/j (%d, %d) %ld.%09ld\n",
1514                             pps_i.assert_sequence, j, tsp->tv_sec, tsp->tv_nsec);
1515
1516                 if (pps_i.assert_sequence == j) {
1517                         printf("ONCORE: oncore_msg_En, error serial pps\n");
1518                         return;
1519                 }
1520                 instance->ev_serial = pps_i.assert_sequence;
1521         } else {
1522                 tsp = &pps_i.clear_timestamp;
1523
1524                 if (debug > 2)
1525                         printf("ONCORE: serial/j (%d, %d) %ld.%09ld\n",
1526                             pps_i.clear_sequence, j, tsp->tv_sec, tsp->tv_nsec);
1527
1528                 if (pps_i.clear_sequence == j) {
1529                         printf("ONCORE: oncore_msg_En, error serial pps\n");
1530                         return;
1531                 }
1532                 instance->ev_serial = pps_i.clear_sequence;
1533         }
1534
1535         /* convert timespec -> ntp l_fp */
1536
1537         dmy = tsp->tv_nsec;
1538         dmy /= 1e9;
1539         ts.l_uf =  dmy * 4294967296.0;
1540         ts.l_ui = tsp->tv_sec;
1541 #if 0
1542      alternate code for previous 4 lines is
1543         dmy = 1.0e-9*tsp->tv_nsec;      /* fractional part */
1544         DTOLFP(dmy, &ts);
1545         dmy = tsp->tv_sec;              /* integer part */
1546         DTOLFP(dmy, &ts_tmp);
1547         L_ADD(&ts, &ts_tmp);
1548      or more simply
1549         dmy = 1.0e-9*tsp->tv_nsec;      /* fractional part */
1550         DTOLFP(dmy, &ts);
1551         ts.l_ui = tsp->tv_sec;
1552 #endif  /* 0 */
1553 #else
1554 # if defined(HAVE_TIOCGPPSEV) || defined(HAVE_CIOGETEV)
1555         j = instance->ev_serial;
1556         if (ioctl(instance->ppsfd, r, (caddr_t) &ev) < 0) {
1557                 perror("ONCORE: IOCTL:");
1558                 return;
1559         }
1560
1561         tsp = &ev.tv;
1562
1563         if (debug > 2)
1564                 printf("ONCORE: serial/j (%d, %d) %ld.%06ld\n",
1565                         ev.serial, j, tsp->tv_sec, tsp->tv_usec);
1566
1567         if (ev.serial == j) {
1568                 printf("ONCORE: oncore_msg_En, error serial pps\n");
1569                 return;
1570         }
1571         instance->ev_serial = ev.serial;
1572
1573         /* convert timeval -> ntp l_fp */
1574
1575         TVTOTS(tsp, &ts);
1576 # else
1577 #  if defined(TIOCDCDTIMESTAMP)
1578         if(ioctl(instance->ppsfd, TIOCDCDTIMESTAMP, &tv) < 0) {
1579                 perror("ONCORE: ioctl(TIOCDCDTIMESTAMP)");
1580                 return;
1581         }
1582         tsp = &tv;
1583         TVTOTS(tsp, &ts);
1584 #  else
1585 #error "Cannot compile -- no PPS mechanism configured!"
1586 #  endif
1587 # endif
1588 #endif
1589         /* now have timestamp in ts */
1590         /* add in saw_tooth and offset */
1591
1592         /* saw_tooth not really necessary if using TIMEVAL */
1593         /* since its only precise to us, but do it anyway. */
1594
1595         /* offset in ns, and is positive (late), we subtract */
1596         /* to put the PPS time transition back where it belongs */
1597
1598         j  = instance->saw_tooth + instance->offset;
1599         instance->saw_tooth = (s_char) buf[25]; /* update for next time */
1600 #ifdef HAVE_PPSAPI
1601         /* must hand this offset off to the Kernel to do the addition */
1602         /* so that the Kernel PLL sees the offset too */
1603
1604         if (instance->assert) {
1605                 instance->pps_p.assert_offset.tv_nsec =
1606                          -(instance->saw_tooth + instance->offset);
1607         } else {
1608                 instance->pps_p.clear_offset.tv_nsec =
1609                          -(instance->saw_tooth + instance->offset);
1610         }
1611
1612         if (time_pps_setparams(instance->pps_h, &instance->pps_p))
1613                 perror("time_pps_setparams");
1614 #else
1615         /* if not PPSAPI, no way to inform kernel of OFFSET, just do it */
1616
1617         dmy = -1.0e-9*j;
1618         DTOLFP(dmy, &ts_tmp);
1619         L_ADD(&ts, &ts_tmp);
1620 #endif
1621         /* have time from UNIX origin, convert to NTP origin. */
1622
1623         ts.l_ui += JAN_1970;
1624         instance->pp->lastrec = ts;
1625         instance->pp->msec = 0;
1626
1627         ts_tmp = ts;
1628         ts_tmp.l_ui = 0;        /* zero integer part */
1629         LFPTOD(&ts_tmp, dmy);   /* convert fractional part to a double */
1630         j = 1.0e9*dmy;          /* then to integer ns */
1631         sprintf(instance->pp->a_lastcode,
1632             "%u.%09u %d %d %2d %2d %2d %2ld rstat %02x dop %d nsat %2d,%d raim %d sigma %d neg-sawtooth %3d sat %d%d%d%d%d%d%d%d",
1633             ts.l_ui, j,
1634             instance->pp->year, instance->pp->day,
1635             instance->pp->hour, instance->pp->minute, instance->pp->second,
1636             (long) tsp->tv_sec % 60,
1637
1638             instance->Ea[72], instance->Ea[37], instance->Ea[38], instance->Ea[39], instance->En[21],
1639             /*rstat           dop               nsat visible,     nsat tracked,     raim */
1640             instance->En[23]*256+instance->En[24], (s_char) buf[25],
1641             /* sigma                               neg-sawtooth */
1642   /*sat*/   instance->Ea[41], instance->Ea[45], instance->Ea[49], instance->Ea[53],
1643             instance->Ea[57], instance->Ea[61], instance->Ea[65], instance->Ea[69]
1644             );
1645
1646         if (debug > 2) {
1647                 int i;
1648                 i = strlen(instance->pp->a_lastcode);
1649                 printf("ONCORE: len = %d %s\n", i, instance->pp->a_lastcode);
1650         }
1651
1652         if (!refclock_process(instance->pp)) {
1653                 refclock_report(instance->peer, CEVNT_BADTIME);
1654                 return;
1655         }
1656
1657         record_clock_stats(&(instance->peer->srcadr), instance->pp->a_lastcode);
1658         instance->pollcnt = 2;
1659
1660         if (instance->polled) {
1661                 instance->polled = 0;
1662 /*
1663                 instance->pp->dispersion = instance->pp->skew = 0;
1664 */
1665                 refclock_receive(instance->peer);
1666         }
1667 }
1668
1669
1670
1671 /*
1672  * Try to use Oncore UT+ Auto Survey Feature
1673  *      If its not there (VP), set flag to do it ourselves.
1674  */
1675 static void
1676 oncore_msg_At(
1677         struct instance *instance,
1678         u_char *buf,
1679         u_int len
1680         )
1681 {
1682         if (instance->site_survey != ONCORE_SS_UNKNOWN)
1683                 return;
1684
1685         if (buf[4] == 2) {
1686                 record_clock_stats(&(instance->peer->srcadr),
1687                                 "Initiating hardware 3D site survey");
1688                 instance->site_survey = ONCORE_SS_HW;
1689         } else {
1690                 char Msg[160];
1691                 /*
1692                  * Probably a VP or an older UT which can't do site-survey.
1693                  * We will have to do it ourselves
1694                  */
1695
1696                 sprintf(Msg, "Initiating software 3D site survey (%d samples)",
1697                                 POS_HOLD_AVERAGE);
1698                 record_clock_stats(&(instance->peer->srcadr), Msg);
1699                 instance->site_survey = ONCORE_SS_SW;
1700
1701                 oncore_cmd_At[2] = 0;
1702                 instance->ss_lat = instance->ss_long = instance->ss_ht = 0;
1703                 oncore_sendmsg(instance->ttyfd, oncore_cmd_At, sizeof oncore_cmd_At);
1704         }
1705 }
1706
1707
1708
1709 /* get leap-second warning message */
1710
1711 /*
1712  * @@Bj does NOT behave as documented in current Oncore firmware.
1713  * It turns on the LEAP indicator when the data is set, and does not,
1714  * as documented, wait until the beginning of the month when the
1715  * leap second will occur.
1716  * Until this firmware bug is fixed, @@Bj is only called in June/December.
1717  */
1718
1719 static void
1720 oncore_msg_Bj(
1721         struct instance *instance,
1722         u_char *buf,
1723         u_int len
1724         )
1725 {
1726         const char      *cp;
1727
1728         switch(buf[4]) {
1729         case 1:
1730                 instance->peer->leap = LEAP_ADDSECOND;
1731                 cp = "Set peer.leap to LEAP_ADDSECOND";
1732                 break;
1733         case 2:
1734                 instance->peer->leap = LEAP_DELSECOND;
1735                 cp = "Set peer.leap to LEAP_DELSECOND";
1736                 break;
1737         case 0:
1738         default:
1739                 instance->peer->leap = LEAP_NOWARNING;
1740                 cp = "Set peer.leap to LEAP_NOWARNING";
1741                 break;
1742         }
1743         record_clock_stats(&(instance->peer->srcadr), cp);
1744 }
1745
1746
1747
1748 /*
1749  * get Position hold position
1750  */
1751 static void
1752 oncore_msg_As(
1753         struct instance *instance,
1754         u_char *buf,
1755         u_int len
1756         )
1757 {
1758         char Msg[120], ew, ns;
1759         const char *Ht;
1760         double xd, xm, xs, yd, ym, ys, hm, hft;
1761         int idx, idy, is, imx, imy;
1762         long lat, lon, ht;
1763
1764         if (!instance->printed || instance->As)
1765                 return;
1766
1767         instance->As = 1;
1768
1769         lat = buf_w32(&buf[4]);
1770         instance->ss_lat = lat;
1771
1772         lon = buf_w32(&buf[8]);
1773         instance->ss_long = lon;
1774
1775         ht = buf_w32(&buf[12]);
1776         instance->ss_ht = ht;
1777
1778         instance->ss_ht_type = buf[16];
1779
1780         /* Print out Position */
1781
1782         record_clock_stats(&(instance->peer->srcadr), "Posn:");
1783         ew = 'E';
1784         lon = instance->ss_long;
1785         if (lon < 0) {
1786                 ew = 'W';
1787                 lon = -lon;
1788         }
1789
1790         ns = 'N';
1791         lat = instance->ss_lat;
1792         if (lat < 0) {
1793                 ns = 'S';
1794                 lat = -lat;
1795         }
1796
1797         hm = instance->ss_ht/100.;
1798         hft= hm/0.3048;
1799         Ht = instance->ss_ht_type ? "MSL" : "GPS";
1800
1801         xd = lat/3600000.;      /* lat, lon in int msec arc, ht in cm. */
1802         yd = lon/3600000.;
1803         sprintf(Msg, "Lat = %c %11.7fdeg,    Long = %c %11.7fdeg,    Alt = %5.2fm (%5.2fft) %s", ns, xd, ew, yd, hm, hft, Ht);
1804         record_clock_stats(&(instance->peer->srcadr), Msg);
1805
1806         idx = xd;
1807         idy = yd;
1808         imx = lat%3600000;
1809         imy = lon%3600000;
1810         xm = imx/60000.;
1811         ym = imy/60000.;
1812         sprintf(Msg, "Lat = %c %3ddeg %7.4fm,   Long = %c %3ddeg %8.5fm,  Alt = %5.2fm (%5.2fft) %s", ns, idx, xm, ew, idy, ym, hm, hft, Ht);
1813         record_clock_stats(&(instance->peer->srcadr), Msg);
1814
1815         imx = xm;
1816         imy = ym;
1817         is  = lat%60000;
1818         xs  = is/1000.;
1819         is  = lon%60000;
1820         ys  = is/1000.;
1821         sprintf(Msg, "Lat = %c %3ddeg %2dm %5.2fs, Long = %c %3ddeg %2dm %5.2fs, Alt = %5.2fm (%5.2fft) %s", ns, idx, imx, xs, ew, idy, imy, ys, hm, hft, Ht);
1822         record_clock_stats(&(instance->peer->srcadr), Msg);
1823 }
1824
1825
1826
1827 /*
1828  * get PPS Offset
1829  * Nb. @@Ay is not supported for early UT (no plus) model
1830  */
1831 static void
1832 oncore_msg_Ay(
1833         struct instance *instance,
1834         u_char *buf,
1835         u_int len
1836         )
1837 {
1838         char Msg[120];
1839
1840         if (!instance->printed || instance->Ay)
1841                 return;
1842
1843         instance->Ay = 1;
1844
1845         instance->offset = buf_w32(&buf[4]);
1846
1847         sprintf(Msg, "PPS Offset  is set to %ld ns", instance->offset);
1848         record_clock_stats(&(instance->peer->srcadr), Msg);
1849 }
1850
1851
1852
1853 /*
1854  * get Cable Delay
1855  */
1856 static void
1857 oncore_msg_Az(
1858         struct instance *instance,
1859         u_char *buf,
1860         u_int len
1861         )
1862 {
1863         char Msg[120];
1864
1865         if (!instance->printed || instance->Az)
1866                 return;
1867
1868         instance->Az = 1;
1869
1870         instance->delay = buf_w32(&buf[4]);
1871
1872         sprintf(Msg, "Cable delay is set to %ld ns", instance->delay);
1873         record_clock_stats(&(instance->peer->srcadr), Msg);
1874 }
1875 #else
1876 int refclock_oncore_bs;
1877 #endif /* REFCLOCK */