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 * ----------------------------------------------------------------------------
11 * Driver for some of the various the Motorola Oncore GPS receivers.
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
27 * --------------------------------------------------------------------------
28 * This code uses the two devices
29 * /dev/oncore.serial.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)
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).
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
45 * --------------------------------------------------------------------------
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.
56 #define POS_HOLD_AVERAGE 10000 /* nb, 10000s ~= 2h45m */
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.
69 #if defined(REFCLOCK) && defined(CLOCK_ONCORE)
73 #include <sys/types.h>
76 #ifdef ONCORE_SHMEM_STATUS
77 # ifdef HAVE_SYS_MMAN_H
78 # include <sys/mman.h>
80 # define MAP_FAILED ((u_char *) -1)
81 # endif /* not MAP_FAILED */
82 # endif /* HAVE_SYS_MMAN_H */
83 #endif /* ONCORE_SHMEM_STATUS */
86 # ifdef HAVE_TIMEPPS_H
89 # ifdef HAVE_SYS_TIMEPPS_H
90 # include <sys/timepps.h>
101 #include "ntp_unixtime.h"
102 #include "ntp_refclock.h"
103 #include "ntp_stdlib.h"
105 #ifdef HAVE_SYS_TERMIOS_H
106 #include <sys/termios.h>
109 #ifdef HAVE_SYS_PPSCLOCK_H
110 # include <sys/ppsclock.h>
113 #ifndef HAVE_STRUCT_PPSCLOCKEV
115 # ifdef HAVE_TIMESPEC
122 #endif /* not HAVE_STRUCT_PPSCLOCKEV */
133 enum site_survey_state {
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 */
150 enum receive_state o_state; /* Receive state */
152 enum site_survey_state site_survey; /* Site Survey state */
154 struct refclockproc *pp;
160 long offset; /* ns */
183 u_char timeout; /* flag to retry Cj after Fa reset */
187 #define rcvbuf instance->Rcvbuf
188 #define rcvptr instance->Rcvptr
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 *));
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));
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 */
222 * Understanding the next bit here is not easy unless you have a manual
223 * for the the UT or VP Oncore.
226 static struct msg_desc {
229 void (*handler) P((struct instance *, u_char *, u_int));
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" },
241 { "As", 20, oncore_msg_As, "" },
242 { "At", 8, oncore_msg_At, "" },
244 { "Ay", 11, oncore_msg_Ay, "" },
245 { "Az", 11, oncore_msg_Az, "" },
248 { "Bj", 8, oncore_msg_Bj, "" },
249 { "Cb", 33, oncore_msg_Cb, "" },
250 { "Cf", 7, oncore_msg_Cf, "" },
253 { "Cj", 294, oncore_msg_Cj, "" },
255 { "Fa", 9, oncore_msg_Fa, "" },
260 static unsigned int oncore_shmem_Cb;
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 };
271 * Start automatic site survey
273 static u_char oncore_cmd_At[] = { 'A', 't', 2 };
276 * Position-Hold Position
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 };
284 * Set to UTC time (not GPS).
286 u_char oncore_cmd_Aw[] = { 'A', 'w', 1 };
289 * Output Almanac when it changes
291 u_char oncore_cmd_Be[] = { 'B', 'e', 1 };
294 * Read back PPS Offset for Output
296 u_char oncore_cmd_Ay[] = { 'A', 'y', 0, 0, 0, 0 };
297 u_char oncore_cmd_Ayx[] = { 'A', 'y', 0xff, 0xff, 0xff, 0xff };
300 * Read back Cable Delay for Output
302 u_char oncore_cmd_Az[] = { 'A', 'z', 0, 0, 0, 0 };
303 u_char oncore_cmd_Azx[] = { 'A', 'z', 0xff, 0xff, 0xff, 0xff };
306 * Application type = static.
308 u_char oncore_cmd_AB[] = { 'A', 'B', 4 };
311 * Visible Satellite Status Msg.
313 u_char oncore_cmd_Bb[] = { 'B', 'b', 1 };
316 * Leap Second Pending Message
317 * Request message once
319 u_char oncore_cmd_Bj[] = { 'B', 'j', 0 };
324 static u_char oncore_cmd_Cf[] = { 'C', 'f' };
327 * Set to Position Fix mode (only needed on VP).
329 u_char oncore_cmd_Cg[] = { 'C', 'g', 1 };
334 static u_char oncore_cmd_Cj[] = { 'C', 'j' };
337 * Position/Status/Data message
338 * Send once per second
340 static u_char oncore_cmd_Ea[] = { 'E', 'a', 1 };
343 * Position/Status Extension Msg
345 u_char oncore_cmd_Ek[] = { 'E', 'k', 0 }; /* just turn off */
348 * Time Raim Setup & Status Message
349 * Send once per second
352 * PPS on when we have the first sat
354 static u_char oncore_cmd_En[] = { 'E', 'n', 1, 1, 0,10, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
359 static u_char oncore_cmd_Fa[] = { 'F', 'a' };
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 */
365 #define SPEED B9600 /* Oncore Binary speed (9600 bps) */
368 * Assemble and disassemble 32bit signed quantities from a buffer.
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; \
381 #define w32(buf) (((buf)[0]&0xff) << 24 | \
382 ((buf)[1]&0xff) << 16 | \
383 ((buf)[2]&0xff) << 8 | \
386 /* from buffer, char *buf, result to an int */
387 #define buf_w32(buf) (((buf)[0]&0200) ? (-(~w32(buf)+1)) : w32(buf))
389 extern int pps_assert;
390 extern int pps_hardpps;
394 * oncore_start - initialize data for processing
402 register struct instance *instance;
403 struct refclockproc *pp;
405 char device1[30], device2[30];
407 struct stat stat1, stat2;
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
420 (void)sprintf(device1, DEVICE1, unit);
421 (void)sprintf(device2, DEVICE2, unit);
423 if (stat(device1, &stat1)) {
424 perror("ONCORE: stat fd1");
428 if (stat(device2, &stat2)) {
429 perror("ONCORE: stat fd2");
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)
440 perror("ONCORE: fd1");
444 } else { /* different devices here */
445 if (!(fd1=refclock_open(device1, SPEED, LDISC_RAW))) {
446 perror("ONCORE: fd1");
449 if ((fd2=open(device2, O_RDWR)) < 0) {
450 perror("ONCORE: fd2");
455 /* Devices now open, initialize instance structure */
457 if (!(instance = (struct instance *)emalloc(sizeof *instance))) {
462 memset((char *) instance, 0, sizeof *instance);
464 pp->unitptr = (caddr_t)instance;
465 instance->unit = unit;
466 instance->ttyfd = fd1;
467 instance->ppsfd = fd2;
469 instance->Bj_day = -1;
470 instance->assert = pps_assert;
472 /* go read any input data in /etc/ntp.oncoreX */
474 oncore_read_config(instance);
477 if (time_pps_create(fd2, &instance->pps_h) < 0) {
478 perror("time_pps_create");
482 if (time_pps_getcap(instance->pps_h, &mode) < 0) {
484 "refclock_ioctl: time_pps_getcap failed: %m");
488 if (time_pps_getparams(instance->pps_h, &instance->pps_p) < 0) {
490 "refclock_ioctl: time_pps_getparams failed: %m");
494 /* nb. only turn things on, if someone else has turned something
495 * on before we get here, leave it alone!
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;
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;
507 instance->pps_p.mode |= PPS_TSFMT_TSPEC;
508 instance->pps_p.mode &= mode; /* only do it if it is legal */
510 if (time_pps_setparams(instance->pps_h, &instance->pps_p) < 0) {
511 perror("time_pps_setparams");
516 if (stat(pps_device, &stat1)) {
517 perror("ONCORE: stat pps_device");
521 /* must have hardpps ON, and fd2 must be the same device as on the pps line */
523 if (pps_hardpps && ((stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino))) {
526 if (instance->assert)
527 i = PPS_CAPTUREASSERT;
529 i = PPS_CAPTURECLEAR;
532 if (time_pps_kcbind(instance->pps_h, PPS_KC_HARDPPS, i,
533 PPS_TSFMT_TSPEC) < 0) {
535 "refclock_ioctl: time_pps_kcbind failed: %m");
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);
550 * Initialize miscellaneous variables
553 peer->precision = -26;
556 pp->clockdesc = "Motorola UT/VP Oncore GPS Receiver";
557 memcpy((char *)&pp->refid, "GPS\0", 4);
559 pp->io.clock_recv = oncore_receive;
560 pp->io.srcclock = (caddr_t)peer;
563 if (!io_addclock(&pp->io)) {
564 perror("io_addclock");
569 pp->unitptr = (caddr_t)instance;
572 * This will start the Oncore receiver.
573 * We send info from config to Oncore later.
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);
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);
590 instance->pollcnt = 2;
597 oncore_init_shmem(struct instance *instance, char *filename)
599 #ifdef ONCORE_SHMEM_STATUS
603 static unsigned int oncore_shmem_length;
605 if (oncore_messages[0].shmem == 0) {
607 for (mp = oncore_messages; mp->flag[0]; mp++) {
609 /* Allocate space for multiplexed almanac */
610 if (!strcmp(mp->flag, "Cb")) {
612 n += (mp->len + 2) * 34;
616 oncore_shmem_length = n + 2;
617 fprintf(stderr, "ONCORE: SHMEM length: %d bytes\n", oncore_shmem_length);
619 instance->statusfd = open(filename, O_RDWR|O_CREAT|O_TRUNC, 0644);
620 if (instance->statusfd < 0) {
624 buf = malloc(oncore_shmem_length);
629 memset(buf, 0, sizeof(buf));
630 i = write(instance->statusfd, buf, oncore_shmem_length);
631 if (i != oncore_shmem_length) {
636 instance->shmem = (u_char *) mmap(0, oncore_shmem_length,
637 PROT_READ | PROT_WRITE,
638 #ifdef MAP_HASSEMAPHORE
642 instance->statusfd, (off_t)0);
643 if (instance->shmem == MAP_FAILED) {
645 close (instance->statusfd);
648 for (mp = oncore_messages; mp->flag[0]; mp++) {
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];
667 #endif /* ONCORE_SHMEM_STATUS */
671 * Read Input file if it exists.
675 struct instance *instance
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.
683 * If we find NEITHER then we don't have the cable delay or PPS offset
684 * and we choose MODE (4) below.
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 * -------------------------------------------------------------------------------
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).
714 * # is comment to end of line
715 * = allowed between 1st and 2nd fields.
717 * Expect to see one line with 'MODE' as first field, followed by an integer
718 * in the range 0-4 (default = 4).
720 * Expect to see two lines with 'LONG', 'LAT' followed by 1-3 fields.
721 * All numbers are floating point.
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.
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.
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.
746 * So acceptable input would be
747 * # these are my coordinates (RWC)
750 * HT 1589 # could equally well say HT 5215 FT
755 char *cp, *cc, *ca, line[100], units[2], device[20];
756 int i, sign, lat_flg, long_flg, ht_flg, mode;
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;
767 lat_flg = long_flg = ht_flg = 0;
768 while (fgets(line, 100, fd)) {
770 /* Remove comments */
771 if ((cp = strchr(line, '#')))
774 /* Remove trailing space */
775 for (i = strlen(line);
776 i > 0 && isascii((int)line[i - 1]) && isspace((int)line[i - 1]);
780 /* Remove leading space */
781 for (cc = line; *cc && isascii((int)*cc) && isspace((int)*cc); cc++)
784 /* Stop if nothing left */
788 /* Lowercase the command and find the arg */
789 for (ca = cc; *ca; ca++) {
790 if (isascii((int)*ca) && islower((int)*ca)) {
792 } else if (isascii((int)*ca) && isspace((int)*ca)) {
794 } else if (*ca == '=') {
800 /* Remove space leading the arg */
801 for (; *ca && isascii((int)*ca) && isspace((int)*ca); ca++)
804 if (!strncmp(cc, "STATUS", 6)) {
805 oncore_init_shmem(instance, ca);
809 /* Uppercase argument as well */
810 for (cp = ca; *cp; cp++)
811 if (isascii((int)*cp) && islower((int)*cp))
814 if (!strncmp(cc, "LAT", 3)) {
816 sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3);
822 instance->ss_lat = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/
824 } else if (!strncmp(cc, "LON", 3)) {
826 sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3);
832 instance->ss_long = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/
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;
840 instance->ss_ht_type = 0;
843 sscanf(ca, "%lf %1s", &f1, units);
846 instance->ss_ht = 100 * f1; /* cm */
848 } else if (!strncmp(cc, "DELAY", 5)) {
851 sscanf(ca, "%lf %1s", &f1, units);
854 else if (units[0] == 'U')
856 else if (units[0] == 'M')
859 f1 = 1000000000 * f1;
860 if (f1 < 0 || f1 > 1.e9)
862 instance->delay = f1; /* delay in ns */
863 } else if (!strncmp(cc, "OFFSET", 6)) {
866 sscanf(ca, "%lf %1s", &f1, units);
869 else if (units[0] == 'U')
871 else if (units[0] == 'M')
874 f1 = 1000000000 * f1;
875 if (f1 < 0 || f1 > 1.e9)
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)
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;
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).
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++;
908 * oncore_shutdown - shut down the clock
916 register struct instance *instance;
917 struct refclockproc *pp;
920 instance = (struct instance *) pp->unitptr;
927 * oncore_poll - called by the transmit procedure
935 struct instance *instance;
937 instance = (struct instance *) peer->procptr->unitptr;
938 if (instance->timeout) {
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);
948 if (!instance->pollcnt)
949 refclock_report(peer, CEVNT_TIMEOUT);
952 peer->procptr->polls++;
953 instance->polled = 1;
959 * move dta from NTP to buffer (toss in unlikely case it wont fit)
963 struct recvbuf *rbufp
969 struct instance *instance;
971 peer = (struct peer *)rbufp->recv_srcclock;
972 instance = (struct instance *) peer->procptr->unitptr;
973 p = (u_char *) &rbufp->recv_space;
978 printf("ONCORE: >>>");
979 for(i=0; i<rbufp->recv_length; i++)
980 printf("%02x ", p[i]);
982 printf("ONCORE: >>>");
983 for(i=0; i<rbufp->recv_length; i++)
984 printf("%03o ", p[i]);
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);
994 oncore_consume(instance);
1000 * Deal with any complete messages
1004 struct instance *instance
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] == '@')
1017 printf("ONCORE: >>> skipping %d chars\n", i);
1019 memcpy(rcvbuf, rcvbuf+i, (unsigned)(rcvptr-i));
1023 /* Ok, we have a header now */
1024 l = sizeof(oncore_messages)/sizeof(oncore_messages[0]) -1;
1026 if (!strncmp(oncore_messages[m].flag, (char *)(rcvbuf+2), 2))
1028 l = oncore_messages[m].len;
1031 printf("ONCORE: GOT: %c%c %d of %d entry %d\n", rcvbuf[2], rcvbuf[3], rcvptr, l, m);
1033 /* Got the entire message ? */
1038 /* Check the checksum */
1041 for (i = 2; i < l-3; i++)
1043 if (j == rcvbuf[l-3]) {
1044 if (instance->shmem != NULL)
1045 memcpy(instance->shmem + oncore_messages[m].shmem + 2,
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));
1051 printf("ONCORE: Checksum mismatch! calc %o is %o\n", j, rcvbuf[l-3]);
1052 printf("ONCORE: @@%c%c ", rcvbuf[2], rcvbuf[3]);
1054 printf("%03o ", rcvbuf[i]);
1059 memcpy(rcvbuf, rcvbuf+l, (unsigned) (rcvptr-l));
1067 * write message to Oncore.
1078 printf("ONCORE: Send @@%c%c %d\n", ptr[0], ptr[1], len);
1080 write(fd, ptr, len);
1084 write(fd, "\r\n", 2);
1091 struct instance *instance,
1098 const char *fmt = oncore_messages[idx].fmt;
1103 GETTIMEOFDAY(&tv, 0);
1104 printf("ONCORE: %ld.%06ld\n", (long) tv.tv_sec, (long) tv.tv_usec);
1107 printf(">>@@%c%c ", buf[2], buf[3]);
1108 for(i=2; i < len && i < 2400 ; i++)
1109 printf("%02x", buf[i]);
1114 for (p = fmt; *p; p++) {
1118 printf("\n%c%c", buf[2], buf[3]);
1120 for (p = fmt; *p; p++) {
1121 printf("%02x", buf[i++]);
1131 * Demultiplex the almanac into shmem
1135 struct instance *instance,
1142 if (instance->shmem == NULL)
1147 else if (buf[4] == 4 && buf[5] <= 5)
1149 else if (buf[4] == 4 && buf[5] <= 10)
1154 memcpy(instance->shmem + oncore_shmem_Cb + i + 2, buf, len + 3);
1158 * Set to Factory Defaults (Reasonable for UT w/ no Battery Backup
1159 * not so for VP (eeprom) or UT with battery
1163 struct instance *instance,
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);
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.
1191 struct instance *instance,
1198 if (instance->o_state == ONCORE_TEST_SENT) {
1200 printf("ONCORE: >>@@Fa %x %x\n", buf[4], buf[5]);
1201 if (buf[4] || buf[5]) {
1202 printf("ONCORE: SELF TEST FAILED\n");
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);
1216 * preliminaries out of the way, this is the REAL start of initialization
1220 struct instance *instance,
1228 instance->timeout = 0;
1229 if (instance->o_state != ONCORE_ID_SENT)
1232 memcpy(instance->Cj, buf, len);
1234 /* Write Receiver ID to clockstats file */
1236 instance->Cj[294] = '\0';
1237 for (cp=(char *)instance->Cj; cp< (char *) &instance->Cj[294]; ) {
1238 cp1 = strchr(cp, '\r');
1240 cp1 = (char *)&instance->Cj[294];
1242 record_clock_stats(&(instance->peer->srcadr), cp);
1247 if (instance->assert)
1248 cp = "Timing on Assert.";
1250 cp = "Timing on Clear.";
1251 record_clock_stats(&(instance->peer->srcadr), cp);
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 */
1261 mode = instance->init_type;
1263 printf("ONCORE: INIT mode = %d\n", mode);
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.
1271 case 0: /* NO initialization, don't change anything */
1272 instance->site_survey = ONCORE_SS_DONE;
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);
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");
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);
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);
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);
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);
1316 /* 8chan - Position/Status/Data Output Message, 1/s */
1318 oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea, sizeof oncore_cmd_Ea);
1320 instance->o_state = ONCORE_ALMANAC;
1321 cp = "state = ONCORE_ALMANAC";
1322 record_clock_stats(&(instance->peer->srcadr), cp);
1329 struct instance *instance,
1337 if (instance->o_state != ONCORE_ALMANAC && instance->o_state != ONCORE_RUN)
1340 memcpy(instance->Ea, buf, len);
1342 /* When we have an almanac, start the En messages */
1344 if (instance->o_state == ONCORE_ALMANAC) {
1345 if ((instance->Ea[72] & 1)) {
1347 printf("ONCORE: waiting for almanac\n");
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);
1357 /* must be ONCORE_RUN if we are here */
1358 /* First check if Hardware SiteSurvey has Finished */
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");
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);
1376 /* Check the leap second status once per day */
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).
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);
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];
1400 if (instance->site_survey != ONCORE_SS_SW)
1404 * We have to average our own position for the Position Hold Mode
1407 /* We only take PDOP/3D fixes */
1409 if (instance->Ea[37] & 1)
1412 /* Not if poor geometry or less than 3 sats */
1414 if (instance->Ea[72] & 0x52)
1419 if (!(instance->Ea[72] & 0x20))
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++;
1427 if (instance->ss_count != POS_HOLD_AVERAGE)
1430 instance->ss_lat /= POS_HOLD_AVERAGE;
1431 instance->ss_long /= POS_HOLD_AVERAGE;
1432 instance->ss_ht /= POS_HOLD_AVERAGE;
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);
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);
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;
1454 struct instance *instance,
1462 #ifdef HAVE_TIMESPEC
1463 struct timespec *tsp = 0;
1465 struct timeval *tsp = 0;
1468 struct timespec timeout;
1470 #else /* ! HAVE_PPSAPI */
1471 #ifdef HAVE_CIOGETEV
1472 struct ppsclockev ev;
1475 #ifdef HAVE_TIOCGPPSEV
1476 struct ppsclockev ev;
1479 #if TIOCDCDTIMESTAMP
1482 #endif /* ! HAVE_PPS_API */
1484 if (instance->o_state != ONCORE_RUN)
1487 memcpy(instance->En, buf, len);
1489 /* Don't do anything without an almanac to define the GPS->UTC delta */
1491 if (instance->Ea[72] & 1)
1494 /* If Time RAIM doesn't like it, don't trust it */
1496 if (instance->En[21])
1500 j = instance->ev_serial;
1502 timeout.tv_nsec = 0;
1503 if (time_pps_fetch(instance->pps_h, PPS_TSFMT_TSPEC, &pps_i,
1505 printf("ONCORE: time_pps_fetch failed\n");
1509 if (instance->assert) {
1510 tsp = &pps_i.assert_timestamp;
1513 printf("ONCORE: serial/j (%d, %d) %ld.%09ld\n",
1514 pps_i.assert_sequence, j, tsp->tv_sec, tsp->tv_nsec);
1516 if (pps_i.assert_sequence == j) {
1517 printf("ONCORE: oncore_msg_En, error serial pps\n");
1520 instance->ev_serial = pps_i.assert_sequence;
1522 tsp = &pps_i.clear_timestamp;
1525 printf("ONCORE: serial/j (%d, %d) %ld.%09ld\n",
1526 pps_i.clear_sequence, j, tsp->tv_sec, tsp->tv_nsec);
1528 if (pps_i.clear_sequence == j) {
1529 printf("ONCORE: oncore_msg_En, error serial pps\n");
1532 instance->ev_serial = pps_i.clear_sequence;
1535 /* convert timespec -> ntp l_fp */
1539 ts.l_uf = dmy * 4294967296.0;
1540 ts.l_ui = tsp->tv_sec;
1542 alternate code for previous 4 lines is
1543 dmy = 1.0e-9*tsp->tv_nsec; /* fractional part */
1545 dmy = tsp->tv_sec; /* integer part */
1546 DTOLFP(dmy, &ts_tmp);
1547 L_ADD(&ts, &ts_tmp);
1549 dmy = 1.0e-9*tsp->tv_nsec; /* fractional part */
1551 ts.l_ui = tsp->tv_sec;
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:");
1564 printf("ONCORE: serial/j (%d, %d) %ld.%06ld\n",
1565 ev.serial, j, tsp->tv_sec, tsp->tv_usec);
1567 if (ev.serial == j) {
1568 printf("ONCORE: oncore_msg_En, error serial pps\n");
1571 instance->ev_serial = ev.serial;
1573 /* convert timeval -> ntp l_fp */
1577 # if defined(TIOCDCDTIMESTAMP)
1578 if(ioctl(instance->ppsfd, TIOCDCDTIMESTAMP, &tv) < 0) {
1579 perror("ONCORE: ioctl(TIOCDCDTIMESTAMP)");
1585 #error "Cannot compile -- no PPS mechanism configured!"
1589 /* now have timestamp in ts */
1590 /* add in saw_tooth and offset */
1592 /* saw_tooth not really necessary if using TIMEVAL */
1593 /* since its only precise to us, but do it anyway. */
1595 /* offset in ns, and is positive (late), we subtract */
1596 /* to put the PPS time transition back where it belongs */
1598 j = instance->saw_tooth + instance->offset;
1599 instance->saw_tooth = (s_char) buf[25]; /* update for next time */
1601 /* must hand this offset off to the Kernel to do the addition */
1602 /* so that the Kernel PLL sees the offset too */
1604 if (instance->assert) {
1605 instance->pps_p.assert_offset.tv_nsec =
1606 -(instance->saw_tooth + instance->offset);
1608 instance->pps_p.clear_offset.tv_nsec =
1609 -(instance->saw_tooth + instance->offset);
1612 if (time_pps_setparams(instance->pps_h, &instance->pps_p))
1613 perror("time_pps_setparams");
1615 /* if not PPSAPI, no way to inform kernel of OFFSET, just do it */
1618 DTOLFP(dmy, &ts_tmp);
1619 L_ADD(&ts, &ts_tmp);
1621 /* have time from UNIX origin, convert to NTP origin. */
1623 ts.l_ui += JAN_1970;
1624 instance->pp->lastrec = ts;
1625 instance->pp->msec = 0;
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",
1634 instance->pp->year, instance->pp->day,
1635 instance->pp->hour, instance->pp->minute, instance->pp->second,
1636 (long) tsp->tv_sec % 60,
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]
1648 i = strlen(instance->pp->a_lastcode);
1649 printf("ONCORE: len = %d %s\n", i, instance->pp->a_lastcode);
1652 if (!refclock_process(instance->pp)) {
1653 refclock_report(instance->peer, CEVNT_BADTIME);
1657 record_clock_stats(&(instance->peer->srcadr), instance->pp->a_lastcode);
1658 instance->pollcnt = 2;
1660 if (instance->polled) {
1661 instance->polled = 0;
1663 instance->pp->dispersion = instance->pp->skew = 0;
1665 refclock_receive(instance->peer);
1672 * Try to use Oncore UT+ Auto Survey Feature
1673 * If its not there (VP), set flag to do it ourselves.
1677 struct instance *instance,
1682 if (instance->site_survey != ONCORE_SS_UNKNOWN)
1686 record_clock_stats(&(instance->peer->srcadr),
1687 "Initiating hardware 3D site survey");
1688 instance->site_survey = ONCORE_SS_HW;
1692 * Probably a VP or an older UT which can't do site-survey.
1693 * We will have to do it ourselves
1696 sprintf(Msg, "Initiating software 3D site survey (%d samples)",
1698 record_clock_stats(&(instance->peer->srcadr), Msg);
1699 instance->site_survey = ONCORE_SS_SW;
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);
1709 /* get leap-second warning message */
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.
1721 struct instance *instance,
1730 instance->peer->leap = LEAP_ADDSECOND;
1731 cp = "Set peer.leap to LEAP_ADDSECOND";
1734 instance->peer->leap = LEAP_DELSECOND;
1735 cp = "Set peer.leap to LEAP_DELSECOND";
1739 instance->peer->leap = LEAP_NOWARNING;
1740 cp = "Set peer.leap to LEAP_NOWARNING";
1743 record_clock_stats(&(instance->peer->srcadr), cp);
1749 * get Position hold position
1753 struct instance *instance,
1758 char Msg[120], ew, ns;
1760 double xd, xm, xs, yd, ym, ys, hm, hft;
1761 int idx, idy, is, imx, imy;
1764 if (!instance->printed || instance->As)
1769 lat = buf_w32(&buf[4]);
1770 instance->ss_lat = lat;
1772 lon = buf_w32(&buf[8]);
1773 instance->ss_long = lon;
1775 ht = buf_w32(&buf[12]);
1776 instance->ss_ht = ht;
1778 instance->ss_ht_type = buf[16];
1780 /* Print out Position */
1782 record_clock_stats(&(instance->peer->srcadr), "Posn:");
1784 lon = instance->ss_long;
1791 lat = instance->ss_lat;
1797 hm = instance->ss_ht/100.;
1799 Ht = instance->ss_ht_type ? "MSL" : "GPS";
1801 xd = lat/3600000.; /* lat, lon in int msec arc, ht in cm. */
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);
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);
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);
1829 * Nb. @@Ay is not supported for early UT (no plus) model
1833 struct instance *instance,
1840 if (!instance->printed || instance->Ay)
1845 instance->offset = buf_w32(&buf[4]);
1847 sprintf(Msg, "PPS Offset is set to %ld ns", instance->offset);
1848 record_clock_stats(&(instance->peer->srcadr), Msg);
1858 struct instance *instance,
1865 if (!instance->printed || instance->Az)
1870 instance->delay = buf_w32(&buf[4]);
1872 sprintf(Msg, "Cable delay is set to %ld ns", instance->delay);
1873 record_clock_stats(&(instance->peer->srcadr), Msg);
1876 int refclock_oncore_bs;
1877 #endif /* REFCLOCK */