diff options
Diffstat (limited to 'contrib/ntp/ntpd/refclock_oncore.c')
-rw-r--r-- | contrib/ntp/ntpd/refclock_oncore.c | 2039 |
1 files changed, 1485 insertions, 554 deletions
diff --git a/contrib/ntp/ntpd/refclock_oncore.c b/contrib/ntp/ntpd/refclock_oncore.c index e0ba177..dbb9f5d 100644 --- a/contrib/ntp/ntpd/refclock_oncore.c +++ b/contrib/ntp/ntpd/refclock_oncore.c @@ -9,6 +9,9 @@ * refclock_oncore.c * * Driver for some of the various the Motorola Oncore GPS receivers. + * should work with Basic, PVT6, VP, UT, UT+, GT, GT+, SL, M12. + * The receivers with TRAIM (VP, UT, UT+), will be more accurate than the others. + * The receivers without position hold (GT, GT+) will be less accurate. * * Tested with: * @@ -24,28 +27,40 @@ * MANUFACTUR DATE 6H07 MANUFACTUR DATE 7E02 * OPTIONS LIST IB * + * (Basic) (M12) + * COPYRIGHT 1991-1996 MOTOROLA INC. COPYRIGHT 1991-2000 MOTOROLA INC. + * SFTW P/N # 98-P36830P SFTW P/N # 61-G10002A + * SOFTWARE VER # 8 SOFTWARE VER # 1 + * SOFTWARE REV # 8 SOFTWARE REV # 3 + * SOFTWARE DATE 06 Aug 1996 SOFTWARE DATE Mar 13 2000 + * MODEL # B4121P1155 MODEL # P143T12NR1 + * HDWR P/N # _ HWDR P/N # 1 + * SERIAL # SSG0226478 SERIAL # P003UD + * MANUFACTUR DATE 7E02 MANUFACTUR DATE 0C27 + * OPTIONS LIST IB + * * -------------------------------------------------------------------------- * This code uses the two devices - * /dev/oncore.serial.n - * /dev/oncore.pps.n + * /dev/oncore.serial.n + * /dev/oncore.pps.n * which may be linked to the same device. * and can read initialization data from the file - * /etc/ntp.oncoreN (where n and N are the unit number, viz 127.127.30.N) - * or /etc/ntp.oncore + * /etc/ntp.oncoreN, /etc/ntp.oncore.N, or /etc/ntp.oncore, where + * n or N are the unit number, viz 127.127.30.N. * -------------------------------------------------------------------------- * Reg.Clemens <reg@dwf.com> Sep98. * Original code written for FreeBSD. - * With these mods it works on SunOS, Solaris (untested) and Linux - * (RedHat 5.1 2.0.35 + PPSKit, 2.1.126 + changes). + * With these mods it works on FreeBSD, SunOS, Solaris and Linux + * (SunOS 4.1.3 + ppsclock) + * (Solaris7 + MU4) + * (RedHat 5.1 2.0.35 + PPSKit, 2.1.126 + or later). * * Lat,Long,Ht, cable-delay, offset, and the ReceiverID (along with the * state machine state) are printed to CLOCKSTATS if that file is enabled * in /etc/ntp.conf. * * -------------------------------------------------------------------------- - */ - -/* + * * According to the ONCORE manual (TRM0003, Rev 3.2, June 1998, page 3.13) * doing an average of 10000 valid 2D and 3D fixes is what the automatic * site survey mode does. Looking at the output from the receiver @@ -58,20 +73,26 @@ /* * ONCORE_SHMEM_STATUS will create a mmap(2)'ed file named according to a * "STATUS" line in the oncore config file, which contains the most recent - * copy of all types of messages we recognize. This file can be mmap(2)'ed + * copy of all types of messages we recognize. This file can be mmap(2)'ed * by monitoring and statistics programs. + * + * See separate HTML documentation for this option. */ #ifdef HAVE_CONFIG_H #include <config.h> #endif -#if defined(REFCLOCK) && defined(CLOCK_ONCORE) +#if defined(REFCLOCK) && defined(CLOCK_ONCORE) && defined(HAVE_PPSAPI) + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_unixtime.h" +#include "ntp_refclock.h" +#include "ntp_stdlib.h" #include <stdio.h> #include <ctype.h> -#include <sys/types.h> -#include <sys/time.h> #include <sys/stat.h> #ifdef ONCORE_SHMEM_STATUS # ifdef HAVE_SYS_MMAN_H @@ -83,11 +104,11 @@ #endif /* ONCORE_SHMEM_STATUS */ #ifdef HAVE_PPSAPI -# ifdef HAVE_TIMEPPS_H -# include <timepps.h> +# ifdef HAVE_TIMEPPS_H +# include <timepps.h> # else # ifdef HAVE_SYS_TIMEPPS_H -# include <sys/timepps.h> +# include <sys/timepps.h> # endif # endif #endif @@ -96,14 +117,8 @@ # include <sys/sio.h> #endif -#include "ntpd.h" -#include "ntp_io.h" -#include "ntp_unixtime.h" -#include "ntp_refclock.h" -#include "ntp_stdlib.h" - #ifdef HAVE_SYS_TERMIOS_H -#include <sys/termios.h> +# include <sys/termios.h> #endif #ifdef HAVE_SYS_PPSCLOCK_H @@ -112,7 +127,7 @@ #ifndef HAVE_STRUCT_PPSCLOCKEV struct ppsclockev { -# ifdef HAVE_TIMESPEC +# ifdef HAVE_STRUCT_TIMESPEC struct timespec tv; # else struct timeval tv; @@ -123,90 +138,163 @@ struct ppsclockev { enum receive_state { ONCORE_NO_IDEA, + ONCORE_ID_SENT, ONCORE_RESET_SENT, ONCORE_TEST_SENT, - ONCORE_ID_SENT, + ONCORE_INIT, ONCORE_ALMANAC, ONCORE_RUN }; enum site_survey_state { ONCORE_SS_UNKNOWN, + ONCORE_SS_TESTING, ONCORE_SS_HW, ONCORE_SS_SW, ONCORE_SS_DONE }; +/* Model Name, derived from the @@Cj message. + * Used to initialize some variables. + */ + +enum oncore_model { + ONCORE_BASIC, + ONCORE_PVT6, + ONCORE_VP, + ONCORE_UT, + ONCORE_UTPLUS, + ONCORE_GT, + ONCORE_GTPLUS, + ONCORE_SL, + ONCORE_M12, + ONCORE_UNKNOWN +}; + +/* the bits that describe these properties are in the same place + * on the VP/UT, but have moved on the M12. As such we extract + * them, and use them from this struct. + * + */ + +struct RSM { + u_char posn0D; + u_char posn2D; + u_char posn3D; + u_char bad_almanac; + u_char bad_fix; +}; + +/* It is possible to test the VP/UT each cycle (@@Ea or equivalent) to + * see what mode it is in. The bits on the M12 are multiplexed with + * other messages, so we have to 'keep' the last known mode here. + */ + +enum posn_mode { + MODE_UNKNOWN, + MODE_0D, + MODE_2D, + MODE_3D +}; + struct instance { int unit; /* 127.127.30.unit */ + struct refclockproc *pp; + struct peer *peer; + int ttyfd; /* TTY file descriptor */ int ppsfd; /* PPS file descriptor */ int statusfd; /* Status shm descriptor */ - u_char *shmem; #ifdef HAVE_PPSAPI pps_handle_t pps_h; pps_params_t pps_p; #endif enum receive_state o_state; /* Receive state */ - + enum posn_mode mode; /* 0D, 2D, 3D */ enum site_survey_state site_survey; /* Site Survey state */ - struct refclockproc *pp; - struct peer *peer; - int Bj_day; - long delay; /* ns */ + u_long delay; /* ns */ long offset; /* ns */ + u_char *shmem; + char *shmem_fname; + u_int shmem_Cb; + u_int shmem_Ba; + u_int shmem_Ea; + u_int shmem_Ha; + u_char shmem_first; + u_char shmem_reset; + u_char shmem_Posn; + double ss_lat; double ss_long; double ss_ht; + double dH; int ss_count; - u_char ss_ht_type; - u_char posn_set; + u_char posn_set; - u_char printed; - u_char polled; + enum oncore_model model; + u_int version; + u_int revision; + + u_char chan; /* 6 for PVT6 or BASIC, 8 for UT/VP, 12 for m12, 0 if unknown */ + s_char traim; /* do we have traim? yes UT/VP, no BASIC, GT, -1 unknown, 0 no, +1 yes */ + u_char traim_delay; /* seconds counter, waiting for reply */ + + struct RSM rsm; /* bits extracted from Receiver Status Msg in @@Ea */ + u_char printed; + u_char polled; int pollcnt; u_int ev_serial; int Rcvptr; u_char Rcvbuf[500]; - u_char Ea[77]; - u_char En[70]; + u_char Ea[160]; /* Ba, Ea or Ha */ + u_char En[70]; /* Bn or En */ u_char Cj[300]; u_char As; u_char Ay; u_char Az; + u_char have_dH; u_char init_type; s_char saw_tooth; - u_char timeout; /* flag to retry Cj after Fa reset */ - s_char assert; + u_int timeout; /* count to retry Cj after Fa self-test */ + u_char count; /* cycles thru Ea before starting */ + s_char assert; + u_int saw_At; }; #define rcvbuf instance->Rcvbuf #define rcvptr instance->Rcvptr -static void oncore_consume P((struct instance *)); -static void oncore_poll P((int, struct peer *)); -static void oncore_read_config P((struct instance *)); -static void oncore_receive P((struct recvbuf *)); -static void oncore_sendmsg P((int fd, u_char *, u_int)); -static void oncore_shutdown P((int, struct peer *)); -static int oncore_start P((int, struct peer *)); - -static void oncore_msg_any P((struct instance *, u_char *, u_int, int)); -static void oncore_msg_As P((struct instance *, u_char *, u_int)); -static void oncore_msg_At P((struct instance *, u_char *, u_int)); -static void oncore_msg_Ay P((struct instance *, u_char *, u_int)); -static void oncore_msg_Az P((struct instance *, u_char *, u_int)); -static void oncore_msg_Bj P((struct instance *, u_char *, u_int)); -static void oncore_msg_Cb P((struct instance *, u_char *, u_int)); -static void oncore_msg_Cf P((struct instance *, u_char *, u_int)); -static void oncore_msg_Cj P((struct instance *, u_char *, u_int)); -static void oncore_msg_Ea P((struct instance *, u_char *, u_int)); -static void oncore_msg_En P((struct instance *, u_char *, u_int)); -static void oncore_msg_Fa P((struct instance *, u_char *, u_int)); +static void oncore_consume P((struct instance *)); +static void oncore_poll P((int, struct peer *)); +static void oncore_read_config P((struct instance *)); +static void oncore_receive P((struct recvbuf *)); +static void oncore_sendmsg P((int fd, u_char *, size_t)); +static void oncore_shutdown P((int, struct peer *)); +static int oncore_start P((int, struct peer *)); +static void oncore_get_timestamp P((struct instance *, long, long)); +static void oncore_init_shmem P((struct instance *)); +static void oncore_print_As P((struct instance *)); + +static void oncore_msg_any P((struct instance *, u_char *, size_t, int)); +static void oncore_msg_As P((struct instance *, u_char *, size_t)); +static void oncore_msg_At P((struct instance *, u_char *, size_t)); +static void oncore_msg_Ay P((struct instance *, u_char *, size_t)); +static void oncore_msg_Az P((struct instance *, u_char *, size_t)); +static void oncore_msg_BaEaHa P((struct instance *, u_char *, size_t)); +static void oncore_msg_Bj P((struct instance *, u_char *, size_t)); +static void oncore_msg_BnEn P((struct instance *, u_char *, size_t)); +static void oncore_msg_CaFaIa P((struct instance *, u_char *, size_t)); +static void oncore_msg_Cb P((struct instance *, u_char *, size_t)); +static void oncore_msg_Cf P((struct instance *, u_char *, size_t)); +static void oncore_msg_Cj P((struct instance *, u_char *, size_t)); +static void oncore_msg_Cj_id P((struct instance *, u_char *, size_t)); +static void oncore_msg_Cj_init P((struct instance *, u_char *, size_t)); +static void oncore_msg_Gj P((struct instance *, u_char *, size_t)); +static void oncore_msg_Sz P((struct instance *, u_char *, size_t)); struct refclock refclock_oncore = { oncore_start, /* start up driver */ @@ -220,65 +308,83 @@ struct refclock refclock_oncore = { /* * Understanding the next bit here is not easy unless you have a manual - * for the the UT or VP Oncore. + * for the the various Oncore Models. */ static struct msg_desc { const char flag[3]; const int len; - void (*handler) P((struct instance *, u_char *, u_int)); + void (*handler) P((struct instance *, u_char *, size_t)); const char *fmt; int shmem; } oncore_messages[] = { - /* Ea and En first since they're most common */ - { "Ea", 76, oncore_msg_Ea, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdimsdimsdsC" }, - { "En", 69, oncore_msg_En, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffsffffsffffC" }, - { "Ab", 10, 0, "" }, - { "Ac", 11, 0, "" }, - { "Ad", 11, 0, "" }, - { "Ae", 11, 0, "" }, - { "Af", 15, 0, "" }, - { "As", 20, oncore_msg_As, "" }, - { "At", 8, oncore_msg_At, "" }, - { "Aw", 8, 0, "" }, - { "Ay", 11, oncore_msg_Ay, "" }, - { "Az", 11, oncore_msg_Az, "" }, - { "AB", 8, 0, "" }, - { "Bb", 92, 0, "" }, - { "Bj", 8, oncore_msg_Bj, "" }, - { "Cb", 33, oncore_msg_Cb, "" }, - { "Cf", 7, oncore_msg_Cf, "" }, - { "Cg", 8, 0, "" }, - { "Ch", 9, 0, "" }, - { "Cj", 294, oncore_msg_Cj, "" }, - { "Ek", 71, 0, "" }, - { "Fa", 9, oncore_msg_Fa, "" }, - { "Sz", 8, 0, "" }, - { {0}, 7, 0, ""} + /* Ea and En first since they're most common */ + { "Ea", 76, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdimsdimsdsC" }, + { "Ba", 68, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdsC" }, + { "Ha", 154, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmaaaaoooohhhhmmmmVVvvhhddntimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddssrrccooooTTushmvvvvvvC" }, + { "En", 69, oncore_msg_BnEn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffsffffsffffC" }, + { "Bn", 59, oncore_msg_BnEn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffC" }, + { "Ab", 10, 0, "" }, + { "Ac", 11, 0, "" }, + { "Ad", 11, 0, "" }, + { "Ae", 11, 0, "" }, + { "Af", 15, 0, "" }, + { "As", 20, oncore_msg_As, "" }, + { "At", 8, oncore_msg_At, "" }, + { "Au", 12, 0, "" }, + { "Av", 8, 0, "" }, + { "Aw", 8, 0, "" }, + { "Ay", 11, oncore_msg_Ay, "" }, + { "Az", 11, oncore_msg_Az, "" }, + { "AB", 8, 0, "" }, + { "Bb", 92, 0, "" }, + { "Bj", 8, oncore_msg_Bj, "" }, + { "Ca", 9, oncore_msg_CaFaIa, "" }, + { "Cb", 33, oncore_msg_Cb, "" }, + { "Cf", 7, oncore_msg_Cf, "" }, + { "Cg", 8, 0, "" }, + { "Ch", 9, 0, "" }, + { "Cj", 294, oncore_msg_Cj, "" }, + { "Ek", 71, 0, "" }, + { "Fa", 9, oncore_msg_CaFaIa, "" }, + { "Gd", 8, 0, "" }, + { "Gj", 21, oncore_msg_Gj, "" }, + { "Ia", 10, oncore_msg_CaFaIa, "" }, + { "Sz", 8, oncore_msg_Sz, "" }, + { {0}, 7, 0, "" } }; -static unsigned int oncore_shmem_Cb; - /* * Position Set. */ u_char oncore_cmd_Ad[] = { 'A', 'd', 0,0,0,0 }; u_char oncore_cmd_Ae[] = { 'A', 'e', 0,0,0,0 }; u_char oncore_cmd_Af[] = { 'A', 'f', 0,0,0,0, 0 }; +u_char oncore_cmd_Ga[] = { 'G', 'a', 0,0,0,0, 0,0,0,0, 0,0,0,0, 0 }; /* * Position-Hold Mode * Start automatic site survey */ -static u_char oncore_cmd_At[] = { 'A', 't', 2 }; +static u_char oncore_cmd_At0[] = { 'A', 't', 0 }; /* Posn Hold off */ +static u_char oncore_cmd_At1[] = { 'A', 't', 1 }; /* Posn Hold on */ +static u_char oncore_cmd_At2[] = { 'A', 't', 2 }; /* Start Site Survey */ /* - * Position-Hold Position + * 0D/2D Position and Set. */ u_char oncore_cmd_As[] = { 'A', 's', 0,0,0,0, 0,0,0,0, 0,0,0,0, 0 }; u_char oncore_cmd_Asx[]= { 'A', 's', 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff }; +u_char oncore_cmd_Au[] = { 'A', 'u', 0,0,0,0,0 }; + +u_char oncore_cmd_Av0[] = { 'A', 'v', 0 }; +u_char oncore_cmd_Av1[] = { 'A', 'v', 1 }; + +u_char oncore_cmd_Gd0[] = { 'G', 'd', 0 }; /* 3D */ +u_char oncore_cmd_Gd1[] = { 'G', 'd', 1 }; /* 0D */ +u_char oncore_cmd_Gd2[] = { 'G', 'd', 2 }; /* 2D */ /* * Set to UTC time (not GPS). @@ -317,6 +423,7 @@ u_char oncore_cmd_Bb[] = { 'B', 'b', 1 }; * Request message once */ u_char oncore_cmd_Bj[] = { 'B', 'j', 0 }; +u_char oncore_cmd_Gj[] = { 'G', 'j' }; /* * Set to Defaults @@ -337,7 +444,11 @@ static u_char oncore_cmd_Cj[] = { 'C', 'j' }; * Position/Status/Data message * Send once per second */ -static u_char oncore_cmd_Ea[] = { 'E', 'a', 1 }; +static u_char oncore_cmd_Ea[] = { 'E', 'a', 1 }; +static u_char oncore_cmd_Ba[] = { 'B', 'a', 1 }; +static u_char oncore_cmd_Ha[] = { 'H', 'a', 1 }; +static u_char oncore_cmd_Ea0[] = { 'E', 'a', 0 }; +static u_char oncore_cmd_Ba0[] = { 'B', 'a', 0 }; /* * Position/Status Extension Msg @@ -351,12 +462,17 @@ u_char oncore_cmd_Ek[] = { 'E', 'k', 0 }; /* just turn off */ * Alarm limit 1us * PPS on when we have the first sat */ -static u_char oncore_cmd_En[] = { 'E', 'n', 1, 1, 0,10, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +static u_char oncore_cmd_En[] = { 'E', 'n', 1, 1, 0,10, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +static u_char oncore_cmd_En0[] = { 'E', 'n', 0, 1, 0,10, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +static u_char oncore_cmd_Bn[] = { 'B', 'n', 1, 1, 0,10, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +static u_char oncore_cmd_Bn0[] = { 'B', 'n', 0, 1, 0,10, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* * Self-test */ -static u_char oncore_cmd_Fa[] = { 'F', 'a' }; +static u_char oncore_cmd_Ca[] = { 'C', 'a' }; /* 6 Chan */ +static u_char oncore_cmd_Fa[] = { 'F', 'a' }; /* 8 Chan */ +static u_char oncore_cmd_Ia[] = { 'I', 'a' }; /* 12 Chan */ #define DEVICE1 "/dev/oncore.serial.%d" /* name of serial device */ #define DEVICE2 "/dev/oncore.pps.%d" /* name of pps device */ @@ -370,7 +486,7 @@ static u_char oncore_cmd_Fa[] = { 'F', 'a' }; */ /* to buffer, int w, u_char *buf */ -#define w32_buf(buf,w) { unsigned int i_tmp; \ +#define w32_buf(buf,w) { u_int i_tmp; \ i_tmp = (w<0) ? (~(-w)+1) : (w); \ (buf)[0] = (i_tmp >> 24) & 0xff; \ (buf)[1] = (i_tmp >> 16) & 0xff; \ @@ -390,9 +506,11 @@ extern int pps_assert; extern int pps_hardpps; + /* * oncore_start - initialize data for processing */ + static int oncore_start( int unit, @@ -452,22 +570,44 @@ oncore_start( } } - /* Devices now open, initialize instance structure */ + /* Devices now open, create instance structure for this unit */ - if (!(instance = (struct instance *)emalloc(sizeof *instance))) { + if (!(instance = (struct instance *) malloc(sizeof *instance))) { perror("malloc"); close(fd1); return (0); } memset((char *) instance, 0, sizeof *instance); + + /* link instance up and down */ + pp = peer->procptr; - pp->unitptr = (caddr_t)instance; - instance->unit = unit; + pp->unitptr = (caddr_t) instance; + instance->pp = pp; + instance->unit = unit; + instance->peer = peer; + + /* initialize miscellaneous variables */ + + instance->o_state = ONCORE_NO_IDEA; + cp = "state = ONCORE_NO_IDEA"; + record_clock_stats(&(instance->peer->srcadr), cp); + instance->ttyfd = fd1; instance->ppsfd = fd2; instance->Bj_day = -1; instance->assert = pps_assert; + instance->traim = -1; + instance->model = ONCORE_UNKNOWN; + instance->mode = MODE_UNKNOWN; + instance->site_survey = ONCORE_SS_UNKNOWN; + + peer->precision = -26; + peer->minpoll = 4; + peer->maxpoll = 4; + pp->clockdesc = "Motorola Oncore GPS Receiver"; + memcpy((char *)&pp->refid, "GPS\0", (size_t) 4); /* go read any input data in /etc/ntp.oncoreX */ @@ -492,10 +632,10 @@ oncore_start( } /* nb. only turn things on, if someone else has turned something - * on before we get here, leave it alone! + * on before we get here, leave it alone! */ - if (instance->assert) { /* nb, default or ON */ + if (instance->assert) { /* nb, default or ON */ instance->pps_p.mode = PPS_CAPTUREASSERT | PPS_OFFSETASSERT; instance->pps_p.assert_offset.tv_sec = 0; instance->pps_p.assert_offset.tv_nsec = 0; @@ -505,7 +645,7 @@ oncore_start( instance->pps_p.clear_offset.tv_nsec = 0; } instance->pps_p.mode |= PPS_TSFMT_TSPEC; - instance->pps_p.mode &= mode; /* only do it if it is legal */ + instance->pps_p.mode &= mode; /* only set what is legal */ if (time_pps_setparams(instance->pps_h, &instance->pps_p) < 0) { perror("time_pps_setparams"); @@ -517,17 +657,17 @@ oncore_start( perror("ONCORE: stat pps_device"); return(0); } - + /* must have hardpps ON, and fd2 must be the same device as on the pps line */ - + if (pps_hardpps && ((stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino))) { - int i; - + int i; + if (instance->assert) i = PPS_CAPTUREASSERT; else i = PPS_CAPTURECLEAR; - + if (i&mode) { if (time_pps_kcbind(instance->pps_h, PPS_KC_HARDPPS, i, PPS_TSFMT_TSPEC) < 0) { @@ -535,27 +675,12 @@ oncore_start( "refclock_ioctl: time_pps_kcbind failed: %m"); return (0); } + pps_enable = 1; } } } #endif - instance->pp = pp; - instance->peer = peer; - instance->o_state = ONCORE_NO_IDEA; - cp = "state = ONCORE_NO_IDEA"; - record_clock_stats(&(instance->peer->srcadr), cp); - - /* - * Initialize miscellaneous variables - */ - - peer->precision = -26; - peer->minpoll = 4; - peer->maxpoll = 4; - pp->clockdesc = "Motorola UT/VP Oncore GPS Receiver"; - memcpy((char *)&pp->refid, "GPS\0", 4); - pp->io.clock_recv = oncore_receive; pp->io.srcclock = (caddr_t)peer; pp->io.datalen = 0; @@ -566,26 +691,16 @@ oncore_start( free(instance); return (0); } - pp->unitptr = (caddr_t)instance; /* - * This will start the Oncore receiver. - * We send info from config to Oncore later. + * This will return the Model Number of the Oncore receiver. */ - instance->timeout = 1; - mode = instance->init_type; - if (mode == 3 || mode == 4) { - oncore_sendmsg(instance->ttyfd, oncore_cmd_Cf, sizeof oncore_cmd_Cf); - instance->o_state = ONCORE_RESET_SENT; - cp = "state = ONCORE_RESET_SENT"; - record_clock_stats(&(instance->peer->srcadr), cp); - } else { - oncore_sendmsg(instance->ttyfd, oncore_cmd_Fa, sizeof oncore_cmd_Fa); - instance->o_state = ONCORE_TEST_SENT; - cp = "state = ONCORE_TEST_SENT"; - record_clock_stats(&(instance->peer->srcadr), cp); - } + oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj)); + instance->o_state = ONCORE_ID_SENT; + cp = "state = ONCORE_ID SENT"; + record_clock_stats(&(instance->peer->srcadr), cp); + instance->timeout = 4; instance->pollcnt = 2; return (1); @@ -593,94 +708,25 @@ oncore_start( -static void -oncore_init_shmem(struct instance *instance, char *filename) -{ -#ifdef ONCORE_SHMEM_STATUS - int i, l, n; - char *buf; - struct msg_desc *mp; - static unsigned int oncore_shmem_length; - - if (oncore_messages[0].shmem == 0) { - n = 1; - for (mp = oncore_messages; mp->flag[0]; mp++) { - mp->shmem = n; - /* Allocate space for multiplexed almanac */ - if (!strcmp(mp->flag, "Cb")) { - oncore_shmem_Cb = n; - n += (mp->len + 2) * 34; - } - n += mp->len + 2; - } - oncore_shmem_length = n + 2; - fprintf(stderr, "ONCORE: SHMEM length: %d bytes\n", oncore_shmem_length); - } - instance->statusfd = open(filename, O_RDWR|O_CREAT|O_TRUNC, 0644); - if (instance->statusfd < 0) { - perror(filename); - exit(4); - } - buf = malloc(oncore_shmem_length); - if (buf == NULL) { - perror("malloc"); - exit(4); - } - memset(buf, 0, sizeof(buf)); - i = write(instance->statusfd, buf, oncore_shmem_length); - if (i != oncore_shmem_length) { - perror(filename); - exit(4); - } - free(buf); - instance->shmem = (u_char *) mmap(0, oncore_shmem_length, - PROT_READ | PROT_WRITE, -#ifdef MAP_HASSEMAPHORE - MAP_HASSEMAPHORE | -#endif - MAP_SHARED, - instance->statusfd, (off_t)0); - if (instance->shmem == MAP_FAILED) { - instance->shmem = 0; - close (instance->statusfd); - exit(4); - } - for (mp = oncore_messages; mp->flag[0]; mp++) { - l = mp->shmem; - instance->shmem[l + 0] = mp->len >> 8; - instance->shmem[l + 1] = mp->len & 0xff; - instance->shmem[l + 2] = '@'; - instance->shmem[l + 3] = '@'; - instance->shmem[l + 4] = mp->flag[0]; - instance->shmem[l + 5] = mp->flag[1]; - if (!strcmp(mp->flag, "Cb")) { - for (i = 1; i < 35; i++) { - instance->shmem[l + i * 35 + 0] = mp->len >> 8; - instance->shmem[l + i * 35 + 1] = mp->len & 0xff; - instance->shmem[l + i * 35 + 2] = '@'; - instance->shmem[l + i * 35 + 3] = '@'; - instance->shmem[l + i * 35 + 4] = mp->flag[0]; - instance->shmem[l + i * 35 + 5] = mp->flag[1]; - } - } - } -#endif /* ONCORE_SHMEM_STATUS */ -} - /* * Read Input file if it exists. */ + static void oncore_read_config( struct instance *instance ) { /* - * First we try to open the configuration file /etc/ntp.oncoreN, where - * N is the unit number viz 127.127.30.N. - * If we don't find it, then we try the file /etc/ntp.oncore. + * First we try to open the configuration file + * /etc/oncoreN + * where N is the unit number viz 127.127.30.N. + * If we don't find it we try + * /etc/ntp.oncore.N + * and then + * /etc/ntp.oncore * - * If we find NEITHER then we don't have the cable delay or PPS offset + * If we don't find any then we don't have the cable delay or PPS offset * and we choose MODE (4) below. * * Five Choices for MODE @@ -705,7 +751,8 @@ oncore_read_config( * ------------------------------------------------------------------------------- * * If we open one or the other of the files, we read it looking for - * MODE, LAT, LON, (HT, HTGPS, HTMSL), DELAY, OFFSET + * MODE, LAT, LON, (HT, HTGPS, HTMSL), DELAY, OFFSET, ASSERT, CLEAR, STATUS, + * POSN3D, POSN2D, CHAN, TRAIM * then initialize using method MODE. For Mode = (1,3) all of (LAT, LON, HT) must * be present or mode reverts to (2,4). * @@ -723,26 +770,47 @@ oncore_read_config( * DDD MMM.mmm * DDD MMM SSS.sss * - * Expect to see one line with 'HT' (or 'HTMSL' or 'HTGPS') as first field. - * followed by 1-2 fields. First is a number, the second is 'FT' or 'M'. - * for feet or meters. HT is the same as HTGPS. - * HTMSL = HT above mean_sea_level, - * HTGPS = HT above GPS ellipse. + * Expect to see one line with 'HT' as first field, + * followed by 1-2 fields. First is a number, the second is 'FT' or 'M' + * for feet or meters. HT is the height above the GPS ellipsoid. + * If the reciever reports height in both GPS and MSL, then we will report + * the difference GPS-MSL on the clockstats file. * - * There are two optional lines, starting with DELAY and OFFSET, followed + * There is an optional line, starting with DELAY, followed * by 1 or two fields. The first is a number (a time) the second is * 'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds. - * DELAY is cable delay, typically a few tens of ns. - * OFFSET is the offset of the PPS pulse from 0. (only fully implemented + * DELAY is cable delay, typically a few tens of ns. + * + * There is an optional line, starting with OFFSET, followed + * by 1 or two fields. The first is a number (a time) the second is + * 'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds. + * OFFSET is the offset of the PPS pulse from 0. (only fully implemented * with the PPSAPI, we need to be able to tell the Kernel about this * offset if the Kernel PLL is in use, but can only do this presently * when using the PPSAPI interface. If not using the Kernel PLL, * then there is no problem. * - * There is another optional line, with either ASSERT or CLEAR on it, which + * There is an optional line, with either ASSERT or CLEAR on it, which * determine which transition of the PPS signal is used for timing by the * PPSAPI. If neither is present, then ASSERT is assumed. * + * There are three options that have to do with using the shared memory opition. + * First, to enable the option there must be an ASSERT line with a file name. + * The file name is the file associated with the shared memory. + * + * In the shared memory there are three 'records' containing the @@Ea (or equivalent) + * data, and this contains the position data. There will always be data in the + * record cooresponding to the '0D' @@Ea record, and the user has a choice of + * filling the '3D' @@Ea record by specifying POSN3D, or the '2D' record by + * specifying POSN2D. In either case the '2D' or '3D' record is filled once + * every 15s. + * + * Two additional variables that can be set are CHAN and TRAIM. These should be + * set correctly by the code examining the @@Cj record, but we bring them out here + * to allow the user to override either the # of channels, or the existance of TRAIM. + * CHAN expects to be followed by in integer: 6, 8, or 12. TRAIM expects to be + * followed by YES or NO. + * * So acceptable input would be * # these are my coordinates (RWC) * LON -106 34.610 @@ -752,16 +820,20 @@ oncore_read_config( */ FILE *fd; - char *cp, *cc, *ca, line[100], units[2], device[20]; + char *cp, *cc, *ca, line[100], units[2], device[20], Msg[160]; int i, sign, lat_flg, long_flg, ht_flg, mode; double f1, f2, f3; - sprintf(device, "%s%d", INIT_FILE, instance->unit); - if ((fd=fopen(device, "r")) == NULL) - if ((fd=fopen(INIT_FILE, "r")) == NULL) { - instance->init_type = 4; - return; + sprintf(device, "%s%d", INIT_FILE, instance->unit); /* try "ntp.oncore0" first */ + if ((fd=fopen(device, "r")) == NULL) { /* it was in the original documentation */ + sprintf(device, "%s.%d", INIT_FILE, instance->unit); /* then try "ntp.oncore.0 */ + if ((fd=fopen(device, "r")) == NULL) { + if ((fd=fopen(INIT_FILE, "r")) == NULL) { /* and finally "ntp.oncore" */ + instance->init_type = 4; + return; + } } + } mode = 0; lat_flg = long_flg = ht_flg = 0; @@ -770,7 +842,7 @@ oncore_read_config( /* Remove comments */ if ((cp = strchr(line, '#'))) *cp = '\0'; - + /* Remove trailing space */ for (i = strlen(line); i > 0 && isascii((int)line[i - 1]) && isspace((int)line[i - 1]); @@ -785,24 +857,30 @@ oncore_read_config( if (!*cc) continue; - /* Lowercase the command and find the arg */ + /* Uppercase the command and find the arg */ for (ca = cc; *ca; ca++) { - if (isascii((int)*ca) && islower((int)*ca)) { - *ca = toupper(*ca); - } else if (isascii((int)*ca) && isspace((int)*ca)) { - break; - } else if (*ca == '=') { - *ca = ' '; - break; + if (isascii((int)*ca)) { + if (islower((int)*ca)) { + *ca = toupper(*ca); + } else if (isspace((int)*ca) || (*ca == '=')) + break; } } - - /* Remove space leading the arg */ - for (; *ca && isascii((int)*ca) && isspace((int)*ca); ca++) + + /* Remove space (and possible =) leading the arg */ + for (; *ca && isascii((int)*ca) && (isspace((int)*ca) || (*ca == '=')); ca++) continue; - if (!strncmp(cc, "STATUS", 6)) { - oncore_init_shmem(instance, ca); + /* + * move call to oncore_shmem_init() from here to after + * we have determined Oncore Model, so we can ignore + * request if model doesnt 'support' it + */ + + if (!strncmp(cc, "STATUS", (size_t) 6) || !strncmp(cc, "SHMEM", (size_t) 5)) { + i = strlen(ca); + instance->shmem_fname = (char *) malloc((unsigned) (i+1)); + strcpy(instance->shmem_fname, ca); continue; } @@ -811,7 +889,7 @@ oncore_read_config( if (isascii((int)*cp) && islower((int)*cp)) *cp = toupper(*cp); - if (!strncmp(cc, "LAT", 3)) { + if (!strncmp(cc, "LAT", (size_t) 3)) { f1 = f2 = f3 = 0; sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3); sign = 1; @@ -821,7 +899,7 @@ oncore_read_config( } instance->ss_lat = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/ lat_flg++; - } else if (!strncmp(cc, "LON", 3)) { + } else if (!strncmp(cc, "LON", (size_t) 3)) { f1 = f2 = f3 = 0; sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3); sign = 1; @@ -831,13 +909,7 @@ oncore_read_config( } instance->ss_long = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/ long_flg++; - } else if (!strncmp(cc, "HT", 2)) { - if (!strncmp(cc, "HTGPS", 5)) - instance->ss_ht_type = 0; - else if (!strncmp(cc, "HTMSL", 5)) - instance->ss_ht_type = 1; - else - instance->ss_ht_type = 0; + } else if (!strncmp(cc, "HT", (size_t) 2)) { f1 = 0; units[0] = '\0'; sscanf(ca, "%lf %1s", &f1, units); @@ -845,7 +917,7 @@ oncore_read_config( f1 = 0.3048 * f1; instance->ss_ht = 100 * f1; /* cm */ ht_flg++; - } else if (!strncmp(cc, "DELAY", 5)) { + } else if (!strncmp(cc, "DELAY", (size_t) 5)) { f1 = 0; units[0] = '\0'; sscanf(ca, "%lf %1s", &f1, units); @@ -859,8 +931,12 @@ oncore_read_config( f1 = 1000000000 * f1; if (f1 < 0 || f1 > 1.e9) f1 = 0; - instance->delay = f1; /* delay in ns */ - } else if (!strncmp(cc, "OFFSET", 6)) { + if (f1 < 0 || f1 > 999999) { + sprintf(Msg, "PPS Cable delay of %fns out of Range, ignored", f1); + record_clock_stats(&(instance->peer->srcadr), Msg); + } else + instance->delay = f1; /* delay in ns */ + } else if (!strncmp(cc, "OFFSET", (size_t) 6)) { f1 = 0; units[0] = '\0'; sscanf(ca, "%lf %1s", &f1, units); @@ -874,16 +950,31 @@ oncore_read_config( f1 = 1000000000 * f1; if (f1 < 0 || f1 > 1.e9) f1 = 0; - instance->offset = f1; /* offset in ns */ - } else if (!strncmp(cc, "MODE", 4)) { + if (f1 < 0 || f1 > 999999999.) { + sprintf(Msg, "PPS Offset of %fns out of Range, ignored", f1); + record_clock_stats(&(instance->peer->srcadr), Msg); + } else + instance->offset = f1; /* offset in ns */ + } else if (!strncmp(cc, "MODE", (size_t) 4)) { sscanf(ca, "%d", &mode); if (mode < 0 || mode > 4) mode = 4; - instance->init_type = mode; - } else if (!strncmp(cc, "ASSERT", 6)) { + } else if (!strncmp(cc, "ASSERT", (size_t) 6)) { instance->assert = 1; - } else if (!strncmp(cc, "CLEAR", 5)) { + } else if (!strncmp(cc, "CLEAR", (size_t) 5)) { instance->assert = 0; + } else if (!strncmp(cc, "POSN2D", (size_t) 6)) { + instance->shmem_Posn = 2; + } else if (!strncmp(cc, "POSN3D", (size_t) 6)) { + instance->shmem_Posn = 3; + } else if (!strncmp(cc, "CHAN", (size_t) 4)) { + sscanf(ca, "%d", &i); + if ((i == 6) || (i == 8) || (i == 12)) + instance->chan = i; + } else if (!strncmp(cc, "TRAIM", (size_t) 5)) { + instance->traim = 1; /* so TRAIM alone is YES */ + if (!strcmp(ca, "NO") || !strcmp(ca, "OFF")) /* Yes/No, On/Off */ + instance->traim = 0; } } fclose(fd); @@ -897,9 +988,116 @@ oncore_read_config( if ((lat_flg || long_flg || ht_flg) && !(lat_flg * long_flg * ht_flg)) { printf("ONCORE: incomplete data on %s\n", INIT_FILE); instance->posn_set = 0; - if (mode == 1 || mode == 3) - instance->init_type++; + if (mode == 1 || mode == 3) { + sprintf(Msg, "Input Mode = %d, but no/incomplete position, mode set to %d", mode, mode+1); + record_clock_stats(&(instance->peer->srcadr), Msg); + mode++; + } } + instance->init_type = mode; + + sprintf(Msg, "Input mode = %d", mode); + record_clock_stats(&(instance->peer->srcadr), Msg); +} + + + +static void +oncore_init_shmem( + struct instance *instance + ) +{ +#ifdef ONCORE_SHMEM_STATUS + int i, l, n; + char *buf; + struct msg_desc *mp; + size_t oncore_shmem_length; + + if (instance->shmem_first) + return; + + instance->shmem_first++; + + if ((instance->statusfd = open(instance->shmem_fname, O_RDWR|O_CREAT|O_TRUNC, 0644)) < 0) { + perror(instance->shmem_fname); + return; + } + + n = 1; + for (mp = oncore_messages; mp->flag[0]; mp++) { + mp->shmem = n; + /* Allocate space for multiplexed almanac, and 0D/2D/3D @@Ea records */ + if (!strcmp(mp->flag, "Cb")) { + instance->shmem_Cb = n; + n += (mp->len + 3) * 34; + } + if (!strcmp(mp->flag, "Ba")) { + instance->shmem_Ba = n; + n += (mp->len + 3) * 3; + } + if (!strcmp(mp->flag, "Ea")) { + instance->shmem_Ea = n; + n += (mp->len + 3) * 3; + } + if (!strcmp(mp->flag, "Ha")) { + instance->shmem_Ha = n; + n += (mp->len + 3) * 3; + } + n += (mp->len + 3); + } + oncore_shmem_length = n + 2; + fprintf(stderr, "ONCORE: SHMEM length: %d bytes\n", (int) oncore_shmem_length); + + buf = malloc(oncore_shmem_length); + if (buf == NULL) { + perror("malloc"); + return; + } + memset(buf, 0, sizeof(buf)); + i = write(instance->statusfd, buf, oncore_shmem_length); + if (i != oncore_shmem_length) { + perror(instance->shmem_fname); + return; + } + free(buf); + instance->shmem = (u_char *) mmap(0, oncore_shmem_length, + PROT_READ | PROT_WRITE, +#ifdef MAP_HASSEMAPHORE + MAP_HASSEMAPHORE | +#endif + MAP_SHARED, + instance->statusfd, (off_t)0); + if (instance->shmem == (u_char *)MAP_FAILED) { + instance->shmem = 0; + close (instance->statusfd); + return; + } + for (mp = oncore_messages; mp->flag[0]; mp++) { + l = mp->shmem; + instance->shmem[l + 0] = mp->len >> 8; + instance->shmem[l + 1] = mp->len & 0xff; + instance->shmem[l + 2] = 0; + instance->shmem[l + 3] = '@'; + instance->shmem[l + 4] = '@'; + instance->shmem[l + 5] = mp->flag[0]; + instance->shmem[l + 6] = mp->flag[1]; + if (!strcmp(mp->flag, "Cb") || !strcmp(mp->flag, "Ba") || !strcmp(mp->flag, "Ea") || !strcmp(mp->flag, "Ha")) { + if (!strcmp(mp->flag, "Cb")) + n = 35; + else + n = 4; + for (i = 1; i < n; i++) { + instance->shmem[l + i * (mp->len+3) + 0] = mp->len >> 8; + instance->shmem[l + i * (mp->len+3) + 1] = mp->len & 0xff; + instance->shmem[l + i * (mp->len+3) + 2] = 0; + instance->shmem[l + i * (mp->len+3) + 3] = '@'; + instance->shmem[l + i * (mp->len+3) + 4] = '@'; + instance->shmem[l + i * (mp->len+3) + 5] = mp->flag[0]; + instance->shmem[l + i * (mp->len+3) + 6] = mp->flag[1]; + } + } + } +#endif /* ONCORE_SHMEM_STATUS */ } @@ -907,6 +1105,7 @@ oncore_read_config( /* * oncore_shutdown - shut down the clock */ + static void oncore_shutdown( int unit, @@ -918,6 +1117,9 @@ oncore_shutdown( pp = peer->procptr; instance = (struct instance *) pp->unitptr; + + io_closeclock(&pp->io); + free(instance); } @@ -926,6 +1128,7 @@ oncore_shutdown( /* * oncore_poll - called by the transmit procedure */ + static void oncore_poll( int unit, @@ -936,12 +1139,18 @@ oncore_poll( instance = (struct instance *) peer->procptr->unitptr; if (instance->timeout) { - char *cp; + char *cp; - oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof oncore_cmd_Cj); - instance->o_state = ONCORE_ID_SENT; - cp = "state = ONCORE_ID_SENT"; - record_clock_stats(&(instance->peer->srcadr), cp); + instance->timeout--; + if (instance->timeout == 0) { + cp = "Oncore: No response from @@Cj, shutting down driver"; + record_clock_stats(&(instance->peer->srcadr), cp); + oncore_shutdown(unit, peer); + } else { + oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj)); + cp = "Oncore: Resend @@Cj"; + record_clock_stats(&(instance->peer->srcadr), cp); + } return; } @@ -956,14 +1165,15 @@ oncore_poll( /* - * move dta from NTP to buffer (toss in unlikely case it wont fit) + * move data from NTP to buffer (toss in unlikely case it wont fit) */ + static void oncore_receive( struct recvbuf *rbufp ) { - u_int i; + size_t i; u_char *p; struct peer *peer; struct instance *instance; @@ -999,6 +1209,7 @@ oncore_receive( /* * Deal with any complete messages */ + static void oncore_consume( struct instance *instance @@ -1014,49 +1225,65 @@ oncore_consume( if (rcvbuf[i] == '@' && rcvbuf[i+1] == '@') break; if (debug > 4) - printf("ONCORE: >>> skipping %d chars\n", i); + printf("ONCORE[%d]: >>> skipping %d chars\n", instance->unit, i); if (i != rcvptr) - memcpy(rcvbuf, rcvbuf+i, (unsigned)(rcvptr-i)); + memcpy(rcvbuf, rcvbuf+i, (size_t)(rcvptr-i)); rcvptr -= i; + continue; } /* Ok, we have a header now */ l = sizeof(oncore_messages)/sizeof(oncore_messages[0]) -1; for(m=0; m<l; m++) - if (!strncmp(oncore_messages[m].flag, (char *)(rcvbuf+2), 2)) + if (!strncmp(oncore_messages[m].flag, (char *)(rcvbuf+2), (size_t) 2)) break; + if (m == l) { + if (debug > 4) + printf("ONCORE[%d]: >>> Unknown MSG, skipping 4 (%c%c)\n", instance->unit, rcvbuf[2], rcvbuf[3]); + memcpy(rcvbuf, rcvbuf+4, (size_t) 4); + rcvptr -= 4; + continue; + } + l = oncore_messages[m].len; #if 0 if (debug > 3) - printf("ONCORE: GOT: %c%c %d of %d entry %d\n", rcvbuf[2], rcvbuf[3], rcvptr, l, m); + printf("ONCORE[%d]: GOT: %c%c %d of %d entry %d\n", instance->unit, rcvbuf[2], rcvbuf[3], rcvptr, l, m); #endif /* Got the entire message ? */ if (rcvptr < l) return; - /* Check the checksum */ - - j = 0; - for (i = 2; i < l-3; i++) - j ^= rcvbuf[i]; - if (j == rcvbuf[l-3]) { - if (instance->shmem != NULL) - memcpy(instance->shmem + oncore_messages[m].shmem + 2, - rcvbuf, l); - oncore_msg_any(instance, rcvbuf, (unsigned) (l-3), m); - if (oncore_messages[m].handler) - oncore_messages[m].handler(instance, rcvbuf, (unsigned) (l-3)); - } else if (debug) { - printf("ONCORE: Checksum mismatch! calc %o is %o\n", j, rcvbuf[l-3]); - printf("ONCORE: @@%c%c ", rcvbuf[2], rcvbuf[3]); - for (i=4; i<l; i++) - printf("%03o ", rcvbuf[i]); - printf("\n"); + /* are we at the end of message? should be <Cksum><CR><LF> */ + + if (rcvbuf[l-2] != '\r' || rcvbuf[l-1] != '\n') { + if (debug) + printf("ONCORE[%d]: NO <CR><LF> at end of message\n", instance->unit); + } else { /* check the CheckSum */ + j = 0; + for (i = 2; i < l-3; i++) + j ^= rcvbuf[i]; + if (j == rcvbuf[l-3]) { + if (instance->shmem != NULL) { + instance->shmem[oncore_messages[m].shmem + 2]++; + memcpy(instance->shmem + oncore_messages[m].shmem + 3, + rcvbuf, (size_t) l); + } + oncore_msg_any(instance, rcvbuf, (size_t) (l-3), m); + if (oncore_messages[m].handler) + oncore_messages[m].handler(instance, rcvbuf, (size_t) (l-3)); + } else if (debug) { + printf("ONCORE[%d]: Checksum mismatch! calc %o is %o\n", instance->unit, j, rcvbuf[l-3]); + printf("ONCORE[%d]: @@%c%c ", instance->unit, rcvbuf[2], rcvbuf[3]); + for (i=4; i<l; i++) + printf("%03o ", rcvbuf[i]); + printf("\n"); + } } if (l != rcvptr) - memcpy(rcvbuf, rcvbuf+l, (unsigned) (rcvptr-l)); + memcpy(rcvbuf, rcvbuf+l, (size_t) (rcvptr-l)); rcvptr -= l; } } @@ -1066,42 +1293,56 @@ oncore_consume( /* * write message to Oncore. */ + static void oncore_sendmsg( int fd, u_char *ptr, - u_int len + size_t len ) { u_char cs = 0; - printf("ONCORE: Send @@%c%c %d\n", ptr[0], ptr[1], len); - write(fd, "@@", 2); + printf("ONCORE: Send @@%c%c %d\n", ptr[0], ptr[1], (int) len); + write(fd, "@@", (size_t) 2); write(fd, ptr, len); while (len--) cs ^= *ptr++; - write(fd, &cs, 1); - write(fd, "\r\n", 2); + write(fd, &cs, (size_t) 1); + write(fd, "\r\n", (size_t) 2); } +/* + * print Oncore response message. + */ + static void oncore_msg_any( struct instance *instance, u_char *buf, - u_int len, + size_t len, int idx ) { int i; const char *fmt = oncore_messages[idx].fmt; const char *p; +#ifdef HAVE_GETCLOCK + struct timespec ts; +#endif struct timeval tv; if (debug > 3) { +#ifdef HAVE_GETCLOCK + (void) getclock(TIMEOFDAY, &ts); + tv.tv_sec = ts.tv_sec; + tv.tv_usec = ts.tv_nsec / 1000; +#else GETTIMEOFDAY(&tv, 0); - printf("ONCORE: %ld.%06ld\n", (long) tv.tv_sec, (long) tv.tv_usec); +#endif + printf("ONCORE[%d]: %ld.%06ld\n", instance->unit, (long) tv.tv_sec, (long) tv.tv_usec); if (!*fmt) { printf(">>@@%c%c ", buf[2], buf[3]); @@ -1130,11 +1371,12 @@ oncore_msg_any( /* * Demultiplex the almanac into shmem */ + static void oncore_msg_Cb( struct instance *instance, u_char *buf, - u_int len + size_t len ) { int i; @@ -1142,7 +1384,7 @@ oncore_msg_Cb( if (instance->shmem == NULL) return; - if (buf[4] == 5) + if (buf[4] == 5) i = buf[5]; else if (buf[4] == 4 && buf[5] <= 5) i = buf[5] + 24; @@ -1150,88 +1392,63 @@ oncore_msg_Cb( i = buf[5] + 23; else i = 34; - i *= 35; - memcpy(instance->shmem + oncore_shmem_Cb + i + 2, buf, len + 3); + i *= 36; + instance->shmem[instance->shmem_Cb + i + 2]++; + memcpy(instance->shmem + instance->shmem_Cb + i + 3, buf, (size_t) (len + 3)); } -/* - * Set to Factory Defaults (Reasonable for UT w/ no Battery Backup - * not so for VP (eeprom) or UT with battery - */ -static void -oncore_msg_Cf( - struct instance *instance, - u_char *buf, - u_int len - ) -{ - const char *cp; - if (instance->o_state == ONCORE_RESET_SENT) { - oncore_sendmsg(instance->ttyfd, oncore_cmd_Fa, sizeof oncore_cmd_Fa); - instance->o_state = ONCORE_TEST_SENT; - cp = "state = ONCORE_TEST_SENT"; - record_clock_stats(&(instance->peer->srcadr), cp); - } -} +/* + * We do an @@Cj twice in the initialization sequence. + * o Once at the very beginning to get the Model number so we know what commands + * we can issue, + * o And once later after we have done a reset and test, (which may hang), + * as we are about to initialize the Oncore and start it running. + * o We have one routine below for each case. + */ -/* there are good reasons NOT to do a @@Fa command with the ONCORE. - * Doing it, it was found that under some circumstances the following - * command would fail if issued immediately after the return from the - * @@Fa, but a 2sec delay seemed to fix things. Since simply calling - * sleep(2) is wastefull, and may cause trouble for some OS's, repeating - * itimer, we set a flag, and test it at the next POLL. If it hasnt - * been cleared, we reissue the @@Ca that is issued below. +/* + * Determine the Type from the Model #, this determines #chan and if TRAIM is + * available. We use ONLY the #chans, and determint TRAIM by trying it. */ static void -oncore_msg_Fa( +oncore_msg_Cj( struct instance *instance, u_char *buf, - u_int len + size_t len ) { - const char *cp; - - if (instance->o_state == ONCORE_TEST_SENT) { - if (debug > 2) - printf("ONCORE: >>@@Fa %x %x\n", buf[4], buf[5]); - if (buf[4] || buf[5]) { - printf("ONCORE: SELF TEST FAILED\n"); - exit(1); - } + memcpy(instance->Cj, buf, len); - oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof oncore_cmd_Cj); - instance->o_state = ONCORE_ID_SENT; - cp = "state = ONCORE_ID_SENT"; - record_clock_stats(&(instance->peer->srcadr), cp); - } + instance->timeout = 0; + if (instance->o_state == ONCORE_ID_SENT) + oncore_msg_Cj_id(instance, buf, len); + else if (instance->o_state == ONCORE_INIT) + oncore_msg_Cj_init(instance, buf, len); } -/* - * preliminaries out of the way, this is the REAL start of initialization +/* The information on determing a Oncore 'Model', viz VP, UT, etc, from + * the Model Number comes from "Richard M. Hambly" <rick@cnssys.com> + * and from Motorola. Until recently Rick was the only source of + * this information as Motorola didnt give the information out. */ + static void -oncore_msg_Cj( +oncore_msg_Cj_id( struct instance *instance, u_char *buf, - u_int len + size_t len ) { - char *cp, *cp1; + char *cp, *cp1, *cp2, Model[21], Msg[160]; int mode; - instance->timeout = 0; - if (instance->o_state != ONCORE_ID_SENT) - return; - - memcpy(instance->Cj, buf, len); - - /* Write Receiver ID to clockstats file */ + /* Write Receiver ID message to clockstats file */ instance->Cj[294] = '\0'; for (cp=(char *)instance->Cj; cp< (char *) &instance->Cj[294]; ) { @@ -1243,6 +1460,114 @@ oncore_msg_Cj( *cp1 = '\r'; cp = cp1+2; } + + /* next, the Firmware Version and Revision numbers */ + + instance->version = atoi(&instance->Cj[83]); + instance->revision = atoi(&instance->Cj[111]); + + /* from model number decide which Oncore this is, + and then the number of channels */ + + for (cp=&instance->Cj[160]; *cp == ' '; cp++) /* start right after 'Model #' */ + ; + cp1 = cp; + cp2 = Model; + for (; !isspace((int)*cp) && cp-cp1 < 20; cp++, cp2++) + *cp2 = *cp; + *cp2 = '\0'; + + cp = 0; + if (!strncmp(Model, "PVT6", (size_t) 4)) { + cp = "PVT6"; + instance->model = ONCORE_PVT6; + } else if (Model[0] == 'A') { + cp = "Basic"; + instance->model = ONCORE_BASIC; + } else if (Model[0] == 'B' || !strncmp(Model, "T8", (size_t) 2)) { + cp = "VP"; + instance->model = ONCORE_VP; + } else if (!strncmp(Model, "P1", (size_t) 2)) { + cp = "M12"; + instance->model = ONCORE_M12; + } else if (Model[0] == 'R') { + if (Model[5] == 'N') { + cp = "GT"; + instance->model = ONCORE_GT; + } else if ((Model[1] == '3' || Model[1] == '4') && Model[5] == 'G') { + cp = "GT+"; + instance->model = ONCORE_GTPLUS; + } else if ((Model[1] == '5' && Model[5] == 'U') || (Model[1] == '1' && Model[5] == 'A')) { + cp = "UT"; + instance->model = ONCORE_UT; + } else if (Model[1] == '5' && Model[5] == 'G') { + cp = "UT+"; + instance->model = ONCORE_UTPLUS; + } else if (Model[1] == '6' && Model[5] == 'G') { + cp = "SL"; + instance->model = ONCORE_SL; + } else { + cp = "Unknown"; + instance->model = ONCORE_UNKNOWN; + } + } else { + cp = "Unknown"; + instance->model = ONCORE_UNKNOWN; + } + + sprintf(Msg, "This looks like an Oncore %s with version %d.%d firmware.", cp, instance->version, instance->revision); + record_clock_stats(&(instance->peer->srcadr), Msg); + + if (instance->chan == 0) { /* dont reset if set in input data */ + instance->chan = 8; /* default */ + if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6) + instance->chan = 6; + else if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || instance->model == ONCORE_UTPLUS) + instance->chan = 8; + else if (instance->model == ONCORE_M12) + instance->chan = 12; + } + + if (instance->traim == -1) { /* dont reset if set in input data */ + instance->traim = 0; /* default */ + if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6) + instance->traim = 0; + else if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || instance->model == ONCORE_UTPLUS) + instance->traim = 1; + else if (instance->model == ONCORE_M12) + instance->traim = 0; + } + + sprintf(Msg, "Channels = %d, TRAIM = %s", instance->chan, + ((instance->traim < 0) ? "UNKNOWN" : ((instance->traim > 0) ? "ON" : "OFF"))); + record_clock_stats(&(instance->peer->srcadr), Msg); + + /* The M12 with 1.3 Firmware, looses track of all Satellites and has to + * start again if we go from 0D -> 3D, then looses them again when we + * go from 3D -> 0D. We do this to get a @@Ea message for SHMEM. + * For NOW we have SHMEM turned off for the M12, v1.3 + */ + +/*BAD M12*/ if (instance->model == ONCORE_M12 && instance->version == 1 && instance->revision <= 3) { + instance->shmem_fname = 0; + cp = "*** SHMEM turned off for ONCORE M12 ***"; + record_clock_stats(&(instance->peer->srcadr), cp); + } + + /* + * we now know model number and have zeroed + * instance->shmem_fname if SHMEM is not supported + */ + + if (instance->shmem_fname); + oncore_init_shmem(instance); + + if (instance->shmem) + cp = "SHMEM is available"; + else + cp = "SHMEM is NOT available"; + record_clock_stats(&(instance->peer->srcadr), cp); + #ifdef HAVE_PPSAPI if (instance->assert) cp = "Timing on Assert."; @@ -1251,72 +1576,180 @@ oncore_msg_Cj( record_clock_stats(&(instance->peer->srcadr), cp); #endif - oncore_sendmsg(instance->ttyfd, oncore_cmd_Cg, sizeof oncore_cmd_Cg); /* Set Posn Fix mode (not Idle (VP)) */ - oncore_sendmsg(instance->ttyfd, oncore_cmd_Bb, sizeof oncore_cmd_Bb); /* turn off */ - oncore_sendmsg(instance->ttyfd, oncore_cmd_Ek, sizeof oncore_cmd_Ek); /* turn off */ - oncore_sendmsg(instance->ttyfd, oncore_cmd_Aw, sizeof oncore_cmd_Aw); /* UTC time */ - oncore_sendmsg(instance->ttyfd, oncore_cmd_AB, sizeof oncore_cmd_AB); /* Appl type static */ - oncore_sendmsg(instance->ttyfd, oncore_cmd_Be, sizeof oncore_cmd_Be); /* Tell us the Almanac */ + mode = instance->init_type; + if (mode == 3 || mode == 4) { /* Cf will call Fa */ + oncore_sendmsg(instance->ttyfd, oncore_cmd_Cf, sizeof(oncore_cmd_Cf)); + instance->o_state = ONCORE_RESET_SENT; + cp = "state = ONCORE_RESET_SENT"; + record_clock_stats(&(instance->peer->srcadr), cp); + } else { + if (instance->chan == 6) + oncore_sendmsg(instance->ttyfd, oncore_cmd_Ca, sizeof(oncore_cmd_Ca)); + else if (instance->chan == 8) + oncore_sendmsg(instance->ttyfd, oncore_cmd_Fa, sizeof(oncore_cmd_Fa)); + else if (instance->chan == 12) + oncore_sendmsg(instance->ttyfd, oncore_cmd_Ia, sizeof(oncore_cmd_Ia)); + + instance->o_state = ONCORE_TEST_SENT; + cp = "state = ONCORE_TEST_SENT"; + record_clock_stats(&(instance->peer->srcadr), cp); + instance->timeout = 4; + } +} + + + +static void +oncore_msg_Cj_init( + struct instance *instance, + u_char *buf, + size_t len + ) +{ + char *cp, Cmd[20], Msg[160]; + int mode; + + /* OK, know type of Oncore, have possibly reset, and have tested. + * If we have or don't have TRAIM and position hold may still be unknown. + * Now initialize. + */ + + oncore_sendmsg(instance->ttyfd, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Set Posn Fix mode (not Idle (VP)) */ + oncore_sendmsg(instance->ttyfd, oncore_cmd_Bb, sizeof(oncore_cmd_Bb)); /* turn on for shmem */ + oncore_sendmsg(instance->ttyfd, oncore_cmd_Ek, sizeof(oncore_cmd_Ek)); /* turn off */ + oncore_sendmsg(instance->ttyfd, oncore_cmd_Aw, sizeof(oncore_cmd_Aw)); /* UTC time */ + oncore_sendmsg(instance->ttyfd, oncore_cmd_AB, sizeof(oncore_cmd_AB)); /* Appl type static */ + oncore_sendmsg(instance->ttyfd, oncore_cmd_Be, sizeof(oncore_cmd_Be)); /* Tell us the Almanac for shmem */ + + /* Turn OFF position hold, it needs to be off to set position (for some units), + will get set ON in @@Ea later */ + + if (instance->chan == 12) + oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); + else { + oncore_sendmsg(instance->ttyfd, oncore_cmd_At0, sizeof(oncore_cmd_At0)); + oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); + } mode = instance->init_type; - if (debug) - printf("ONCORE: INIT mode = %d\n", mode); + if (debug) { + printf("ONCORE[%d]: INIT mode = %d\n", instance->unit, mode); + printf("ONCORE[%d]: chan = %d\n", instance->unit, instance->chan); + } /* If there is Position input in the Config file * and mode = (1,3) set it as posn hold posn, goto 0D mode. - * or mode = (2,4) set it as INITIAL position, and Site Survey. + * or mode = (2,4) set it as INITIAL position, and do Site Survey. */ + + if (instance->posn_set) { + switch (mode) { /* if we have a position, put it in as posn and posn-hold posn */ + case 0: + break; + case 1: + case 2: + case 3: + case 4: + memcpy(Cmd, oncore_cmd_As, sizeof(oncore_cmd_As)); /* dont modify static variables */ + w32_buf(&Cmd[2], (int) instance->ss_lat); + w32_buf(&Cmd[6], (int) instance->ss_long); + w32_buf(&Cmd[10], (int) instance->ss_ht); + Cmd[14] = 0; + oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_As)); + + memcpy(Cmd, oncore_cmd_Au, sizeof(oncore_cmd_Au)); + w32_buf(&Cmd[2], (int) instance->ss_ht); + Cmd[6] = 0; + oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Au)); + + if (instance->chan == 12) { + memcpy(Cmd, oncore_cmd_Ga, sizeof(oncore_cmd_Ga)); + w32_buf(&Cmd[2], (int) instance->ss_lat); + w32_buf(&Cmd[6], (int) instance->ss_long); + w32_buf(&Cmd[10], (int) instance->ss_ht); + Cmd[14] = 0; + oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ga)); + oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd1, sizeof(oncore_cmd_Gd1)); + } else { + memcpy(Cmd, oncore_cmd_Ad, sizeof(oncore_cmd_Ad)); + w32_buf(&Cmd[2], (int) instance->ss_lat); + oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ad)); + + memcpy(Cmd, oncore_cmd_Ae, sizeof(oncore_cmd_Ae)); + w32_buf(&Cmd[2], (int) instance->ss_long); + oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ae)); + + memcpy(Cmd, oncore_cmd_Af, sizeof(oncore_cmd_Af)); + w32_buf(&Cmd[2], (int) instance->ss_ht); + Cmd[6] = 0; + oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Af)); + oncore_sendmsg(instance->ttyfd, oncore_cmd_At1, sizeof(oncore_cmd_At1)); + } + break; + } + } + + switch (mode) { case 0: /* NO initialization, don't change anything */ instance->site_survey = ONCORE_SS_DONE; break; case 1: - case 3: - w32_buf(&oncore_cmd_As[2], (int) instance->ss_lat); - w32_buf(&oncore_cmd_As[6], (int) instance->ss_long); - w32_buf(&oncore_cmd_As[10], (int) instance->ss_ht); - oncore_cmd_As[14] = instance->ss_ht_type; - oncore_sendmsg(instance->ttyfd, oncore_cmd_As, sizeof oncore_cmd_As); - + case 3: /* Use given Position */ instance->site_survey = ONCORE_SS_DONE; - oncore_cmd_At[2] = 1; - oncore_sendmsg(instance->ttyfd, oncore_cmd_At, sizeof oncore_cmd_At); - record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode"); break; case 2: - case 4: - if (instance->posn_set) { - w32_buf(&oncore_cmd_Ad[2], (int) instance->ss_lat); - w32_buf(&oncore_cmd_Ae[2], (int) instance->ss_long); - w32_buf(&oncore_cmd_Af[2], (int) instance->ss_ht); - oncore_cmd_Af[6] = instance->ss_ht_type; - oncore_sendmsg(instance->ttyfd, oncore_cmd_Ad, sizeof oncore_cmd_Ad); - oncore_sendmsg(instance->ttyfd, oncore_cmd_Ae, sizeof oncore_cmd_Ae); - oncore_sendmsg(instance->ttyfd, oncore_cmd_Af, sizeof oncore_cmd_Af); + case 4: /* Site Survey */ + if (instance->chan == 12) { /* no 12chan site survey command */ + instance->site_survey = ONCORE_SS_SW; + sprintf(Msg, "Initiating software 3D site survey (%d samples)", POS_HOLD_AVERAGE); + record_clock_stats(&(instance->peer->srcadr), Msg); + } else { + instance->site_survey = ONCORE_SS_TESTING; + oncore_sendmsg(instance->ttyfd, oncore_cmd_At2, sizeof(oncore_cmd_At2)); } - instance->site_survey = ONCORE_SS_UNKNOWN; - oncore_cmd_At[2] = 2; - oncore_sendmsg(instance->ttyfd, oncore_cmd_At, sizeof oncore_cmd_At); break; } if (mode != 0) { /* cable delay in ns */ - w32_buf(&oncore_cmd_Az[2], instance->delay); - oncore_sendmsg(instance->ttyfd, oncore_cmd_Az, sizeof oncore_cmd_Az); + memcpy(Cmd, oncore_cmd_Az, sizeof(oncore_cmd_Az)); + w32_buf(&Cmd[2], instance->delay); + oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Az)); /* PPS offset in ns */ - w32_buf(&oncore_cmd_Ay[2], instance->offset); - oncore_sendmsg(instance->ttyfd, oncore_cmd_Ay, sizeof oncore_cmd_Ay); + if (instance->offset) { + if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || + instance->model == ONCORE_UTPLUS) { + memcpy(Cmd, oncore_cmd_Ay, sizeof(oncore_cmd_Ay)); + w32_buf(&Cmd[2], instance->offset); + oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ay)); + } else { + cp = "Can only set PPS OFFSET for VP/UT/UT+, offset ignored"; + record_clock_stats(&(instance->peer->srcadr), cp); + instance->offset = 0; + } + } } - /* 8chan - Position/Status/Data Output Message, 1/s */ - - oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea, sizeof oncore_cmd_Ea); - + /* 6, 8 12 chan - Position/Status/Data Output Message, 1/s */ + /* now we're really running */ + + if (instance->chan == 6) { /* kill 8 chan commands, possibly testing VP in 6chan mode */ + oncore_sendmsg(instance->ttyfd, oncore_cmd_Ba, sizeof(oncore_cmd_Ba)); + oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea0, sizeof(oncore_cmd_Ea0)); + oncore_sendmsg(instance->ttyfd, oncore_cmd_En0, sizeof(oncore_cmd_En0)); + } else if (instance->chan == 8) { /* kill 6chan commands */ + oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea, sizeof(oncore_cmd_Ea)); + oncore_sendmsg(instance->ttyfd, oncore_cmd_Ba0, sizeof(oncore_cmd_Ba0)); + oncore_sendmsg(instance->ttyfd, oncore_cmd_Bn0, sizeof(oncore_cmd_Bn0)); + } else if (instance->chan == 12) + oncore_sendmsg(instance->ttyfd, oncore_cmd_Ha, sizeof(oncore_cmd_Ha)); + + instance->count = 1; instance->o_state = ONCORE_ALMANAC; cp = "state = ONCORE_ALMANAC"; record_clock_stats(&(instance->peer->srcadr), cp); @@ -1324,104 +1757,412 @@ oncore_msg_Cj( +/* + * Set to Factory Defaults (Reasonable for UT w/ no Battery Backup + * not so for VP (eeprom) or any unit with a battery + */ + +static void +oncore_msg_Cf( + struct instance *instance, + u_char *buf, + size_t len + ) +{ + const char *cp; + + if (instance->o_state == ONCORE_RESET_SENT) { + if (instance->chan == 6) + oncore_sendmsg(instance->ttyfd, oncore_cmd_Ca, sizeof(oncore_cmd_Ca)); + else if (instance->chan == 8) + oncore_sendmsg(instance->ttyfd, oncore_cmd_Fa, sizeof(oncore_cmd_Fa)); + else if (instance->chan == 12) + oncore_sendmsg(instance->ttyfd, oncore_cmd_Ia, sizeof(oncore_cmd_Ia)); + + instance->o_state = ONCORE_TEST_SENT; + cp = "state = ONCORE_TEST_SENT"; + record_clock_stats(&(instance->peer->srcadr), cp); + } +} + + + +/* Here for @@Ca, @@Fa and @@Ia messages */ + +/* There are good reasons NOT to do a @@Ca or @@Fa command with the ONCORE. + * Doing it, it was found that under some circumstances the following + * command would fail if issued immediately after the return from the + * @@Fa, but a 2sec delay seemed to fix things. Since simply calling + * sleep(2) is wastefull, and may cause trouble for some OS's, repeating + * itimer, we set a flag, and test it at the next POLL. If it hasnt + * been cleared, we reissue the @@Cj that is issued below. + * Note that we do a @@Cj at the beginning, and again here. + * The first is to get the info, the 2nd is just used as a safe command + * after the @@Fa for all Oncores (and it was in this posn in the + * original code). + */ + +static void +oncore_msg_CaFaIa( + struct instance *instance, + u_char *buf, + size_t len + ) +{ + char *cp; + + if (instance->o_state == ONCORE_TEST_SENT) { + int antenna; + + instance->timeout = 0; + + if (debug > 2) { + if (buf[2] == 'I') + printf("ONCORE[%d]: >>@@%ca %x %x %x\n", instance->unit, buf[2], buf[4], buf[5], buf[6]); + else + printf("ONCORE[%d]: >>@@%ca %x %x\n", instance->unit, buf[2], buf[4], buf[5]); + } + + antenna = buf[4] & 0xc0; + antenna >>= 6; + buf[4] &= ~0xc0; + + if (buf[4] || buf[5] || ((buf[2] == 'I') && buf[6])) { + cp = "ONCORE: Self Test Failed, shutting down driver"; + record_clock_stats(&(instance->peer->srcadr), cp); + oncore_shutdown(instance->unit, instance->peer); + return; + } + if (antenna) { + char *cp1, Msg[160]; + + cp1 = (antenna == 0x1) ? "(Over Current)" : + ((antenna == 0x2) ? "(Under Current)" : "(No Voltage)"); + + cp = "ONCORE: Self Test, NonFatal Antenna Problems "; + strcpy(Msg, cp); + strcat(Msg, cp1); + record_clock_stats(&(instance->peer->srcadr), Msg); + } + + oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj)); + instance->o_state = ONCORE_INIT; + cp = "state = ONCORE_INIT"; + record_clock_stats(&(instance->peer->srcadr), cp); + } +} + + + +/* Ba, Ea and Ha come here */ + static void -oncore_msg_Ea( +oncore_msg_BaEaHa( struct instance *instance, u_char *buf, - u_int len + size_t len ) { const char *cp; - char Msg[160]; + char Msg[160], Cmd[20]; + u_char *vp; /* pointer to start of shared mem for Ba/Ea/Ha */ + size_t Len; + + /* At the beginning of Ea here there are various 'timers'. + * We enter Ea 1/sec, and since the upper levels of NTP have usurped + * the use of timers, we use the 1/sec entry to Ea to do things that + * we would normally do with timers... + */ + + if (instance->count) { + if (instance->count++ < 5) /* make sure results are stable, using position */ + return; + instance->count = 0; + } if (instance->o_state != ONCORE_ALMANAC && instance->o_state != ONCORE_RUN) return; - memcpy(instance->Ea, buf, len); + Len = len+3; /* message length @@ -> CR,LF */ + memcpy(instance->Ea, buf, Len); /* Ba, Ea or Ha */ + + if (buf[2] == 'B') { /* 6chan */ + if (instance->Ea[64]&0x8) + instance->mode = MODE_0D; + else if (instance->Ea[64]&0x10) + instance->mode = MODE_2D; + else if (instance->Ea[64]&0x20) + instance->mode = MODE_3D; + } else if (buf[2] == 'E') { /* 8chan */ + if (instance->Ea[72]&0x8) + instance->mode = MODE_0D; + else if (instance->Ea[72]&0x10) + instance->mode = MODE_2D; + else if (instance->Ea[72]&0x20) + instance->mode = MODE_3D; + } else if (buf[2] == 'H') { /* 12chan */ + int bits; + + bits = (instance->Ea[129]>>5) & 0x7; /* actually Ha */ + if (bits == 0x4) + instance->mode = MODE_0D; + else if (bits == 0x6) + instance->mode = MODE_2D; + else if (bits == 0x7) + instance->mode = MODE_3D; + } + + vp = (u_char) 0; /* just to keep compiler happy */ + if (instance->chan == 6) { + instance->rsm.bad_almanac = instance->Ea[64]&0x1; + instance->rsm.bad_fix = instance->Ea[64]&0x52; + vp = &instance->shmem[instance->shmem_Ba]; + } else if (instance->chan == 8) { + instance->rsm.bad_almanac = instance->Ea[72]&0x1; + instance->rsm.bad_fix = instance->Ea[72]&0x52; + vp = &instance->shmem[instance->shmem_Ea]; + } else if (instance->chan == 12) { + int bits1, bits2; + + bits1 = (instance->Ea[129]>>5) & 0x7; /* actually Ha */ + bits2 = instance->Ea[130]; + instance->rsm.bad_almanac = (bits2 & 0x80); + instance->rsm.bad_fix = (bits2 & 0x8) || (bits1 == 0x2); + /* too few sat Bad Geom */ + vp = &instance->shmem[instance->shmem_Ha]; +#if 0 +fprintf(stderr, "ONCORE: DEBUG BITS: (%x %x), (%x %x), %x %x %x %x %x\n", + instance->Ea[129], instance->Ea[130], bits1, bits2, instance->mode == MODE_0D, instance->mode == MODE_2D, + instance->mode == MODE_3D, instance->rsm.bad_almanac, instance->rsm.bad_fix); +#endif + } + + /* Here calculate dH = GPS - MSL for output message */ + /* also set Altitude Hold mode if GT */ + + if (!instance->have_dH) { + int GPS, MSL; + + instance->have_dH++; + if (instance->chan == 12) { + GPS = buf_w32(&instance->Ea[39]); + MSL = buf_w32(&instance->Ea[43]); + } else { + GPS = buf_w32(&instance->Ea[23]); + MSL = buf_w32(&instance->Ea[27]); + } + instance->dH = GPS - MSL; + instance->dH /= 100.; + + if (MSL) { /* not set ! */ + sprintf(Msg, "dH = (GPS - MSL) = %.2fm", instance->dH); + record_clock_stats(&(instance->peer->srcadr), Msg); + } - /* When we have an almanac, start the En messages */ + /* stuck in here as it only gets done once */ + + if (instance->chan != 12 && !instance->saw_At) { + cp = "Not Good, no @@At command, must be a GT/GT+"; + record_clock_stats(&(instance->peer->srcadr), cp); + oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1)); + } + } + + /* + * For instance->site_survey to be ONCORE_SS_TESTING, this must be the first + * time thru @@Ea. There are two choices + * (a) We did not get a response to the @@At0 or @@At2 commands, + * must be a GT/GT+/SL with no position hold mode. + * (b) Saw the @@At0, @@At2 commands, but @@At2 failed, + * must be a VP or older UT which doesnt have Site Survey mode. + * We will have to do it ourselves. + */ + + if (instance->site_survey == ONCORE_SS_TESTING) { /* first time thru Ea */ + sprintf(Msg, "Initiating software 3D site survey (%d samples)", + POS_HOLD_AVERAGE); + record_clock_stats(&(instance->peer->srcadr), Msg); + instance->site_survey = ONCORE_SS_SW; + + instance->ss_lat = instance->ss_long = instance->ss_ht = 0; + oncore_sendmsg(instance->ttyfd, oncore_cmd_At0, sizeof(oncore_cmd_At0)); /* disable */ + } + + if (instance->shmem) { + int i; + + i = 0; + if (instance->mode == MODE_0D) /* 0D, Position Hold */ + i = 1; + else if (instance->mode == MODE_2D) /* 2D, Altitude Hold */ + i = 2; + else if (instance->mode == MODE_3D) /* 3D fix */ + i = 3; + if (i) { + i *= (Len+3); + vp[i + 2]++; + memcpy(&vp[i+3], buf, Len); + } + } + + /* Almanac mode, waiting for Almanac, cant do anything till we have it */ + /* When we have an almanac, start the En/Bn messages */ if (instance->o_state == ONCORE_ALMANAC) { - if ((instance->Ea[72] & 1)) { + if (instance->rsm.bad_almanac) { if (debug) printf("ONCORE: waiting for almanac\n"); return; - } else { - oncore_sendmsg(instance->ttyfd, oncore_cmd_En, sizeof oncore_cmd_En); + } else { /* Here we have almanac. + Start TRAIM (@@En/@@Bn) dependant on TRAIM flag. + If flag == -1, then we dont know if this unit supports + traim, and we issue the command and then wait up to + 5sec to see if we get a reply */ + + if (instance->traim != 0) { /* either yes or unknown */ + if (instance->chan == 6) + oncore_sendmsg(instance->ttyfd, oncore_cmd_Bn, sizeof(oncore_cmd_Bn)); + else if (instance->chan == 8) + oncore_sendmsg(instance->ttyfd, oncore_cmd_En, sizeof(oncore_cmd_En)); + + if (instance->traim == -1) + instance->traim_delay = 1; + } instance->o_state = ONCORE_RUN; cp = "state = ONCORE_RUN"; record_clock_stats(&(instance->peer->srcadr), cp); } } - /* must be ONCORE_RUN if we are here */ - /* First check if Hardware SiteSurvey has Finished */ + /* + * check if timer active + * if it hasnt been cleared, then @@En/@@Bn did not respond + */ + + if (instance->traim_delay) { + if (instance->traim_delay++ > 5) { + instance->traim = 0; + instance->traim_delay = 0; + cp = "ONCORE: Did not detect TRAIM response, TRAIM = OFF"; + record_clock_stats(&(instance->peer->srcadr), cp); + } + } + + /* + * must be ONCORE_RUN if we are here. + */ + + instance->pp->year = buf[6]*256+buf[7]; + instance->pp->day = ymd2yd(buf[6]*256+buf[7], buf[4], buf[5]); + instance->pp->hour = buf[8]; + instance->pp->minute = buf[9]; + instance->pp->second = buf[10]; + + /* + * Check to see if Hardware SiteSurvey has Finished. + */ if ((instance->site_survey == ONCORE_SS_HW) && !(instance->Ea[37] & 0x20)) { - instance->site_survey = ONCORE_SS_DONE; record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode"); + instance->site_survey = ONCORE_SS_DONE; } - if (!instance->printed && instance->site_survey == ONCORE_SS_DONE) { /* will print to clockstat when all */ - instance->printed = 1; /* three messages respond */ - /* Read back Position Hold Params */ - oncore_sendmsg(instance->ttyfd, oncore_cmd_Asx, sizeof oncore_cmd_Asx); + if (!instance->printed && instance->site_survey == ONCORE_SS_DONE) { + instance->printed = 1; + /* Read back Position Hold Params (cant for GT) */ + if (instance->saw_At) + oncore_sendmsg(instance->ttyfd, oncore_cmd_Asx, sizeof(oncore_cmd_Asx)); + else + oncore_print_As(instance); + /* Read back PPS Offset for Output */ - /* Nb. This will fail silently for early UT (no plus) model */ - oncore_sendmsg(instance->ttyfd, oncore_cmd_Ayx, sizeof oncore_cmd_Ayx); + /* Nb. This will fail silently for early UT (no plus) and M12 models */ + oncore_sendmsg(instance->ttyfd, oncore_cmd_Ayx, sizeof(oncore_cmd_Ayx)); + /* Read back Cable Delay for Output */ - oncore_sendmsg(instance->ttyfd, oncore_cmd_Azx, sizeof oncore_cmd_Azx); + oncore_sendmsg(instance->ttyfd, oncore_cmd_Azx, sizeof(oncore_cmd_Azx)); } - /* Check the leap second status once per day */ + /* + * Check the leap second status once per day. + */ + + if (instance->Bj_day != buf[5]) { /* do this 1/day */ + instance->Bj_day = buf[5]; + + if (instance->chan == 12) + oncore_sendmsg(instance->ttyfd, oncore_cmd_Gj, sizeof(oncore_cmd_Gj)); + else { + /* + * The following additional check, checking for June/December, is a + * workaround for incorrect ONCORE firmware. The oncore starts + * reporting the leap second when the GPS satellite data message + * (page 18, subframe 4) is updated to a date in the future, which + * can be several months before the leap second. WWV and other + * services seem to wait until the month of the event to turn + * on their indicators (which is usually a single bit). + */ + + if ((buf[4] == 6) || (buf[4] == 12)) + oncore_sendmsg(instance->ttyfd, oncore_cmd_Bj, sizeof(oncore_cmd_Bj)); + } + } /* - * The following additional check, checking for June/December, is a - * workaround for incorrect ONCORE firmware. The oncore starts - * reporting the leap second when the GPS satellite data message - * (page 18, subframe 4) is updated to a date in the future, which - * which can be several months before the leap second. WWV and other - * services seem to wait until the month of the event to turn - * on their indicators (which are usually a single bit). + * if SHMEM active, every 15s, steal one 'tick' to get 2D or 3D posn. */ - if ((buf[4] == 6) || (buf[4] == 12)) { - if (instance->Bj_day != buf[5]) { /* do this 1/day */ - instance->Bj_day = buf[5]; - oncore_sendmsg(instance->ttyfd, oncore_cmd_Bj, sizeof oncore_cmd_Bj); + if (instance->shmem && instance->shmem_Posn && (instance->site_survey == ONCORE_SS_DONE)) { /* dont screw up the SS by changing mode */ + if (instance->pp->second%15 == 3) { /* start the sequence */ + instance->shmem_reset = 1; + if (instance->chan == 12) { + if (instance->shmem_Posn == 2) + oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd2, sizeof(oncore_cmd_Gd2)); /* 2D */ + else + oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* 3D */ + } else { + if (instance->saw_At) { + oncore_sendmsg(instance->ttyfd, oncore_cmd_At0, sizeof(oncore_cmd_At0)); /* out of 0D to 3D mode */ + if (instance->shmem_Posn == 2) + oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1)); /* 3D to 2D mode */ + } else + oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); + } + } else if (instance->shmem_reset || (instance->mode != MODE_0D)) { + instance->shmem_reset = 0; + if (instance->chan == 12) + oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd1, sizeof(oncore_cmd_Gd1)); /* 0D */ + else { + if (instance->saw_At) { + if (instance->mode == MODE_2D) + oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); /* 2D -> 3D or 0D */ + oncore_sendmsg(instance->ttyfd, oncore_cmd_At1, sizeof(oncore_cmd_At1)); /* to 0D mode */ + } else + oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1)); + } } } - instance->pp->year = buf[6]*256+buf[7]; - instance->pp->day = ymd2yd(buf[6]*256+buf[7], buf[4], buf[5]); - instance->pp->hour = buf[8]; - instance->pp->minute = buf[9]; - instance->pp->second = buf[10]; + + if (instance->traim == 0) /* NO traim, go get tick */ + oncore_get_timestamp(instance, instance->offset, instance->offset); if (instance->site_survey != ONCORE_SS_SW) return; /* * We have to average our own position for the Position Hold Mode + * We use Heights from the GPS ellipsoid. */ - /* We only take PDOP/3D fixes */ - - if (instance->Ea[37] & 1) + if (instance->rsm.bad_fix) /* Not if poor geometry or less than 3 sats */ return; - /* Not if poor geometry or less than 3 sats */ - - if (instance->Ea[72] & 0x52) - return; - - /* Only 3D fix */ - - if (!(instance->Ea[72] & 0x20)) + if (instance->mode != MODE_3D) /* Only 3D Fix */ return; instance->ss_lat += buf_w32(&instance->Ea[15]); instance->ss_long += buf_w32(&instance->Ea[19]); - instance->ss_ht += buf_w32(&instance->Ea[23]); /* GPS ellipse */ + instance->ss_ht += buf_w32(&instance->Ea[23]); /* GPS ellipsoid */ instance->ss_count++; if (instance->ss_count != POS_HOLD_AVERAGE) @@ -1435,14 +2176,33 @@ oncore_msg_Ea( instance->ss_lat, instance->ss_long, instance->ss_ht); record_clock_stats(&(instance->peer->srcadr), Msg); - w32_buf(&oncore_cmd_As[2], (int) instance->ss_lat); - w32_buf(&oncore_cmd_As[6], (int) instance->ss_long); - w32_buf(&oncore_cmd_As[10], (int) instance->ss_ht); - oncore_cmd_As[14] = 0; - oncore_sendmsg(instance->ttyfd, oncore_cmd_As, sizeof oncore_cmd_As); + /* set newly determined position as 3D Position hold position */ + + memcpy(Cmd, oncore_cmd_As, sizeof(oncore_cmd_As)); + w32_buf(&Cmd[2], (int) instance->ss_lat); + w32_buf(&Cmd[6], (int) instance->ss_long); + w32_buf(&Cmd[10], (int) instance->ss_ht); + Cmd[14] = 0; + oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_As)); + + /* set height seperately for 2D */ + + memcpy(Cmd, oncore_cmd_Au, sizeof(oncore_cmd_Au)); + w32_buf(&Cmd[2], (int) instance->ss_ht); + Cmd[6] = 0; + oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Au)); + + /* and set Position Hold */ + + if (instance->chan == 12) + oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd1, sizeof(oncore_cmd_Gd1)); + else { + if (instance->saw_At) + oncore_sendmsg(instance->ttyfd, oncore_cmd_At1, sizeof(oncore_cmd_At1)); + else + oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1)); + } - oncore_cmd_At[2] = 1; - oncore_sendmsg(instance->ttyfd, oncore_cmd_At, sizeof oncore_cmd_At); record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode"); instance->site_survey = ONCORE_SS_DONE; } @@ -1450,21 +2210,60 @@ oncore_msg_Ea( static void -oncore_msg_En( +oncore_msg_BnEn( struct instance *instance, u_char *buf, - u_int len + size_t len ) { - int j; + long dt1, dt2; + char *cp; + + if (instance->o_state != ONCORE_RUN) + return; + + if (instance->traim_delay) { /* flag that @@En/@@Bn returned */ + instance->traim = 1; + instance->traim_delay = 0; + cp = "ONCORE: Detected TRAIM, TRAIM = ON"; + record_clock_stats(&(instance->peer->srcadr), cp); + } + + memcpy(instance->En, buf, len); /* En or Bn */ + + /* If Time RAIM doesn't like it, don't trust it */ + + if (instance->En[21]) + return; + + dt1 = instance->saw_tooth + instance->offset; /* dt this time step */ + instance->saw_tooth = (s_char) instance->En[25]; /* update for next time */ + dt2 = instance->saw_tooth + instance->offset; /* dt next time step */ + + oncore_get_timestamp(instance, dt1, dt2); +} + + + +static void +oncore_get_timestamp( + struct instance *instance, + long dt1, /* tick offset THIS time step */ + long dt2 /* tick offset NEXT time step */ + ) +{ + int Rsm; + u_long i, j; l_fp ts, ts_tmp; double dmy; -#ifdef HAVE_TIMESPEC +#ifdef HAVE_STRUCT_TIMESPEC struct timespec *tsp = 0; #else struct timeval *tsp = 0; #endif #ifdef HAVE_PPSAPI + int current_mode; + pps_params_t current_params; struct timespec timeout; pps_info_t pps_i; #else /* ! HAVE_PPSAPI */ @@ -1481,19 +2280,12 @@ oncore_msg_En( #endif #endif /* ! HAVE_PPS_API */ - if (instance->o_state != ONCORE_RUN) + if ((instance->site_survey == ONCORE_SS_DONE) && (instance->mode != MODE_0D)) return; - memcpy(instance->En, buf, len); - /* Don't do anything without an almanac to define the GPS->UTC delta */ - if (instance->Ea[72] & 1) - return; - - /* If Time RAIM doesn't like it, don't trust it */ - - if (instance->En[21]) + if (instance->rsm.bad_almanac) return; #ifdef HAVE_PPSAPI @@ -1509,24 +2301,40 @@ oncore_msg_En( if (instance->assert) { tsp = &pps_i.assert_timestamp; - if (debug > 2) - printf("ONCORE: serial/j (%d, %d) %ld.%09ld\n", - pps_i.assert_sequence, j, tsp->tv_sec, tsp->tv_nsec); + if (debug > 2) { + i = (u_long) pps_i.assert_sequence; +#ifdef HAVE_STRUCT_TIMESPEC + printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%09ld\n", + instance->unit, i, j, + (long)tsp->tv_sec, (long)tsp->tv_nsec); +#else + printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%06ld\n", + instance->unit, i, j, + (long)tsp->tv_sec, (long)tsp->tv_usec); +#endif + } if (pps_i.assert_sequence == j) { - printf("ONCORE: oncore_msg_En, error serial pps\n"); + printf("ONCORE: oncore_get_timestamp, error serial pps\n"); return; } instance->ev_serial = pps_i.assert_sequence; } else { tsp = &pps_i.clear_timestamp; - if (debug > 2) - printf("ONCORE: serial/j (%d, %d) %ld.%09ld\n", - pps_i.clear_sequence, j, tsp->tv_sec, tsp->tv_nsec); + if (debug > 2) { + i = (u_long) pps_i.clear_sequence; +#ifdef HAVE_STRUCT_TIMESPEC + printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%09ld\n", + instance->unit, i, j, (long)tsp->tv_sec, (long)tsp->tv_nsec); +#else + printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%06ld\n", + instance->unit, i, j, (long)tsp->tv_sec, (long)tsp->tv_usec); +#endif + } if (pps_i.clear_sequence == j) { - printf("ONCORE: oncore_msg_En, error serial pps\n"); + printf("ONCORE: oncore_get_timestamp, error serial pps\n"); return; } instance->ev_serial = pps_i.clear_sequence; @@ -1561,11 +2369,16 @@ oncore_msg_En( tsp = &ev.tv; if (debug > 2) +#ifdef HAVE_STRUCT_TIMESPEC + printf("ONCORE: serial/j (%d, %d) %ld.%09ld\n", + ev.serial, j, tsp->tv_sec, tsp->tv_nsec); +#else printf("ONCORE: serial/j (%d, %d) %ld.%06ld\n", ev.serial, j, tsp->tv_sec, tsp->tv_usec); +#endif if (ev.serial == j) { - printf("ONCORE: oncore_msg_En, error serial pps\n"); + printf("ONCORE: oncore_get_timestamp, error serial pps\n"); return; } instance->ev_serial = ev.serial; @@ -1587,7 +2400,7 @@ oncore_msg_En( # endif #endif /* now have timestamp in ts */ - /* add in saw_tooth and offset */ + /* add in saw_tooth and offset, these will be ZERO if no TRAIM */ /* saw_tooth not really necessary if using TIMEVAL */ /* since its only precise to us, but do it anyway. */ @@ -1595,26 +2408,57 @@ oncore_msg_En( /* offset in ns, and is positive (late), we subtract */ /* to put the PPS time transition back where it belongs */ - j = instance->saw_tooth + instance->offset; - instance->saw_tooth = (s_char) buf[25]; /* update for next time */ #ifdef HAVE_PPSAPI - /* must hand this offset off to the Kernel to do the addition */ - /* so that the Kernel PLL sees the offset too */ + /* must hand the offset for the NEXT sec off to the Kernel to do */ + /* the addition, so that the Kernel PLL sees the offset too */ - if (instance->assert) { - instance->pps_p.assert_offset.tv_nsec = - -(instance->saw_tooth + instance->offset); - } else { - instance->pps_p.clear_offset.tv_nsec = - -(instance->saw_tooth + instance->offset); + if (instance->assert) + instance->pps_p.assert_offset.tv_nsec = -dt2; + else + instance->pps_p.clear_offset.tv_nsec = -dt2; + + /* The following code is necessary, and not just a time_pps_setparams, + * using the saved instance->pps_p, since some other process on the + * machine may have diddled with the mode bits (say adding something + * that it needs). We take what is there and ADD what we need. + * [[ The results from the time_pps_getcap is unlikely to change so + * we could probably just save it, but I choose to do the call ]] + * Unfortunately, there is only ONE set of mode bits in the kernel per + * interface, and not one set for each open handle. + * + * There is still a race condition here where we might mess up someone + * elses mode, but if he is being careful too, he should survive. + */ + + if (time_pps_getcap(instance->pps_h, ¤t_mode) < 0) { + msyslog(LOG_ERR, + "refclock_ioctl: time_pps_getcap failed: %m"); + return; + } + + if (time_pps_getparams(instance->pps_h, ¤t_params) < 0) { + msyslog(LOG_ERR, + "refclock_ioctl: time_pps_getparams failed: %m"); + return; } - if (time_pps_setparams(instance->pps_h, &instance->pps_p)) + /* or current and mine */ + current_params.mode |= instance->pps_p.mode; + /* but only set whats legal */ + current_params.mode &= current_mode; + + current_params.assert_offset.tv_sec = 0; + current_params.assert_offset.tv_nsec = -dt2; + current_params.clear_offset.tv_sec = 0; + current_params.clear_offset.tv_nsec = -dt2; + + if (time_pps_setparams(instance->pps_h, ¤t_params)) perror("time_pps_setparams"); #else - /* if not PPSAPI, no way to inform kernel of OFFSET, just do it */ + /* if not PPSAPI, no way to inform kernel of OFFSET, just add the */ + /* offset for THIS second */ - dmy = -1.0e-9*j; + dmy = -1.0e-9*dt1; DTOLFP(dmy, &ts_tmp); L_ADD(&ts, &ts_tmp); #endif @@ -1625,28 +2469,55 @@ oncore_msg_En( instance->pp->msec = 0; ts_tmp = ts; - ts_tmp.l_ui = 0; /* zero integer part */ - LFPTOD(&ts_tmp, dmy); /* convert fractional part to a double */ - j = 1.0e9*dmy; /* then to integer ns */ - sprintf(instance->pp->a_lastcode, - "%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", - ts.l_ui, j, - instance->pp->year, instance->pp->day, - instance->pp->hour, instance->pp->minute, instance->pp->second, - (long) tsp->tv_sec % 60, - - instance->Ea[72], instance->Ea[37], instance->Ea[38], instance->Ea[39], instance->En[21], - /*rstat dop nsat visible, nsat tracked, raim */ - instance->En[23]*256+instance->En[24], (s_char) buf[25], - /* sigma neg-sawtooth */ - /*sat*/ instance->Ea[41], instance->Ea[45], instance->Ea[49], instance->Ea[53], - instance->Ea[57], instance->Ea[61], instance->Ea[65], instance->Ea[69] - ); + ts_tmp.l_ui = 0; /* zero integer part */ + LFPTOD(&ts_tmp, dmy); /* convert fractional part to a double */ + j = 1.0e9*dmy; /* then to integer ns */ + + Rsm = 0; + if (instance->chan == 6) + Rsm = instance->Ea[64]; + else if (instance->chan == 8) + Rsm = instance->Ea[72]; + else if (instance->chan == 12) + Rsm = ((instance->Ea[129]<<8) | instance->Ea[130]); + + if (instance->chan == 6 || instance->chan == 8) { + sprintf(instance->pp->a_lastcode, /* MAX length 128, currently at 117 */ + "%u.%09lu %d %d %2d %2d %2d %2ld rstat %02x dop %4.1f nsat %2d,%d traim %d sigma %d neg-sawtooth %3d sat %d%d%d%d%d%d%d%d", + ts.l_ui, j, + instance->pp->year, instance->pp->day, + instance->pp->hour, instance->pp->minute, instance->pp->second, + (long) tsp->tv_sec % 60, + Rsm, 0.1*(256*instance->Ea[35]+instance->Ea[36]), + /*rsat dop */ + instance->Ea[38], instance->Ea[39], instance->En[21], + /* nsat visible, nsat tracked, traim */ + instance->En[23]*256+instance->En[24], (s_char) instance->En[25], + /* sigma neg-sawtooth */ + /*sat*/ instance->Ea[41], instance->Ea[45], instance->Ea[49], instance->Ea[53], + instance->Ea[57], instance->Ea[61], instance->Ea[65], instance->Ea[69] + ); /* will be 0 for 6 chan */ + } else if (instance->chan == 12) { + sprintf(instance->pp->a_lastcode, + "%u.%09lu %d %d %2d %2d %2d %2ld rstat %02x dop %4.1f nsat %2d,%d sat %d%d%d%d%d%d%d%d%d%d%d%d", + ts.l_ui, j, + instance->pp->year, instance->pp->day, + instance->pp->hour, instance->pp->minute, instance->pp->second, + (long) tsp->tv_sec % 60, + Rsm, 0.1*(256*instance->Ea[53]+instance->Ea[54]), + /*rsat dop */ + instance->Ea[55], instance->Ea[56], + /* nsat visible, nsat tracked */ + /*sat*/ instance->Ea[58], instance->Ea[64], instance->Ea[70], instance->Ea[76], + instance->Ea[82], instance->Ea[88], instance->Ea[94], instance->Ea[100], + instance->Ea[106], instance->Ea[112], instance->Ea[118], instance->Ea[124] + ); + } if (debug > 2) { - int i; - i = strlen(instance->pp->a_lastcode); - printf("ONCORE: len = %d %s\n", i, instance->pp->a_lastcode); + int n; + n = strlen(instance->pp->a_lastcode); + printf("ONCORE[%d]: len = %d %s\n", instance->unit, n, instance->pp->a_lastcode); } if (!refclock_process(instance->pp)) { @@ -1672,35 +2543,21 @@ oncore_msg_En( * Try to use Oncore UT+ Auto Survey Feature * If its not there (VP), set flag to do it ourselves. */ + static void oncore_msg_At( struct instance *instance, u_char *buf, - u_int len + size_t len ) { - if (instance->site_survey != ONCORE_SS_UNKNOWN) - return; - - if (buf[4] == 2) { - record_clock_stats(&(instance->peer->srcadr), - "Initiating hardware 3D site survey"); - instance->site_survey = ONCORE_SS_HW; - } else { - char Msg[160]; - /* - * Probably a VP or an older UT which can't do site-survey. - * We will have to do it ourselves - */ - - sprintf(Msg, "Initiating software 3D site survey (%d samples)", - POS_HOLD_AVERAGE); - record_clock_stats(&(instance->peer->srcadr), Msg); - instance->site_survey = ONCORE_SS_SW; - - oncore_cmd_At[2] = 0; - instance->ss_lat = instance->ss_long = instance->ss_ht = 0; - oncore_sendmsg(instance->ttyfd, oncore_cmd_At, sizeof oncore_cmd_At); + instance->saw_At = 1; + if (instance->site_survey == ONCORE_SS_TESTING) { + if (buf[4] == 2) { + record_clock_stats(&(instance->peer->srcadr), + "Initiating hardware 3D site survey"); + instance->site_survey = ONCORE_SS_HW; + } } } @@ -1720,7 +2577,7 @@ static void oncore_msg_Bj( struct instance *instance, u_char *buf, - u_int len + size_t len ) { const char *cp; @@ -1743,41 +2600,97 @@ oncore_msg_Bj( record_clock_stats(&(instance->peer->srcadr), cp); } +/* Leap Second for M12, gives all info from satellite message */ + +static void +oncore_msg_Gj( + struct instance *instance, + u_char *buf, + size_t len + ) +{ + int dt; + char Msg[160], *cp; + static char *Month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jly", + "Aug", "Sep", "Oct", "Nov", "Dec" }; + + /* print the message to verify whats there */ + + dt = buf[5] - buf[4]; + +#if 1 + sprintf(Msg, "ONCORE[%d]: Leap Sec Msg: %d %d %d %d %d %d %d %d %d %d", + instance->unit, + buf[4], buf[5], 256*buf[6]+buf[7], buf[8], buf[9], buf[10], + (buf[14]+256*(buf[13]+256*(buf[12]+256*buf[11]))), + buf[15], buf[16], buf[17]); + record_clock_stats(&(instance->peer->srcadr), Msg); +#endif + if (dt) { + sprintf(Msg, "ONCORE[%d]: Leap second (%d) scheduled for %d%s%d at %d:%d:%d", + instance->unit, + dt, buf[9], Month[buf[8]], 256*buf[6]+buf[7], + buf[15], buf[16], buf[17]); + record_clock_stats(&(instance->peer->srcadr), Msg); + } + + /* Only raise warning within a month of the leap second */ + + instance->peer->leap = LEAP_NOWARNING; + cp = "Set peer.leap to LEAP_NOWARNING"; + + if (buf[6] == instance->Ea[6] && buf[7] == instance->Ea[7] && /* year */ + buf[8] == instance->Ea[4]) { /* month */ + if (dt) { + if (dt < 0) { + instance->peer->leap = LEAP_DELSECOND; + cp = "Set peer.leap to LEAP_DELSECOND"; + } else { + instance->peer->leap = LEAP_ADDSECOND; + cp = "Set peer.leap to LEAP_ADDSECOND"; + } + } + } + record_clock_stats(&(instance->peer->srcadr), cp); +} + /* * get Position hold position */ + static void oncore_msg_As( struct instance *instance, u_char *buf, - u_int len + size_t len ) { - char Msg[120], ew, ns; - const char *Ht; - double xd, xm, xs, yd, ym, ys, hm, hft; - int idx, idy, is, imx, imy; - long lat, lon, ht; - if (!instance->printed || instance->As) return; instance->As = 1; - lat = buf_w32(&buf[4]); - instance->ss_lat = lat; + instance->ss_lat = buf_w32(&buf[4]); + instance->ss_long = buf_w32(&buf[8]); + instance->ss_ht = buf_w32(&buf[12]); - lon = buf_w32(&buf[8]); - instance->ss_long = lon; + /* Print out Position */ + oncore_print_As(instance); +} - ht = buf_w32(&buf[12]); - instance->ss_ht = ht; - instance->ss_ht_type = buf[16]; - /* Print out Position */ +static void +oncore_print_As( + struct instance *instance + ) +{ + char Msg[120], ew, ns; + double xd, xm, xs, yd, ym, ys, hm, hft; + int idx, idy, is, imx, imy; + long lat, lon; record_clock_stats(&(instance->peer->srcadr), "Posn:"); ew = 'E'; @@ -1796,11 +2709,10 @@ oncore_msg_As( hm = instance->ss_ht/100.; hft= hm/0.3048; - Ht = instance->ss_ht_type ? "MSL" : "GPS"; xd = lat/3600000.; /* lat, lon in int msec arc, ht in cm. */ yd = lon/3600000.; - sprintf(Msg, "Lat = %c %11.7fdeg, Long = %c %11.7fdeg, Alt = %5.2fm (%5.2fft) %s", ns, xd, ew, yd, hm, hft, Ht); + sprintf(Msg, "Lat = %c %11.7fdeg, Long = %c %11.7fdeg, Alt = %5.2fm (%5.2fft) GPS", ns, xd, ew, yd, hm, hft); record_clock_stats(&(instance->peer->srcadr), Msg); idx = xd; @@ -1809,7 +2721,7 @@ oncore_msg_As( imy = lon%3600000; xm = imx/60000.; ym = imy/60000.; - 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); + sprintf(Msg, "Lat = %c %3ddeg %7.4fm, Long = %c %3ddeg %8.5fm, Alt = %7.2fm (%7.2fft) GPS", ns, idx, xm, ew, idy, ym, hm, hft); record_clock_stats(&(instance->peer->srcadr), Msg); imx = xm; @@ -1818,7 +2730,7 @@ oncore_msg_As( xs = is/1000.; is = lon%60000; ys = is/1000.; - 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); + sprintf(Msg, "Lat = %c %3ddeg %2dm %5.2fs, Long = %c %3ddeg %2dm %5.2fs, Alt = %7.2fm (%7.2fft) GPS", ns, idx, imx, xs, ew, idy, imy, ys, hm, hft); record_clock_stats(&(instance->peer->srcadr), Msg); } @@ -1828,11 +2740,12 @@ oncore_msg_As( * get PPS Offset * Nb. @@Ay is not supported for early UT (no plus) model */ + static void oncore_msg_Ay( struct instance *instance, u_char *buf, - u_int len + size_t len ) { char Msg[120]; @@ -1853,11 +2766,12 @@ oncore_msg_Ay( /* * get Cable Delay */ + static void oncore_msg_Az( struct instance *instance, u_char *buf, - u_int len + size_t len ) { char Msg[120]; @@ -1872,6 +2786,23 @@ oncore_msg_Az( sprintf(Msg, "Cable delay is set to %ld ns", instance->delay); record_clock_stats(&(instance->peer->srcadr), Msg); } + +static void +oncore_msg_Sz( + struct instance *instance, + u_char *buf, + size_t len + ) +{ + const char *cp; + + cp = "Oncore: System Failure at Power On"; + if (instance && instance->peer) { + record_clock_stats(&(instance->peer->srcadr), cp); + oncore_shutdown(instance->unit, instance->peer); + } +} + #else int refclock_oncore_bs; #endif /* REFCLOCK */ |