summaryrefslogtreecommitdiffstats
path: root/contrib/ntp/ntpd/refclock_oncore.c
diff options
context:
space:
mode:
authorroberto <roberto@FreeBSD.org>2001-08-29 14:35:15 +0000
committerroberto <roberto@FreeBSD.org>2001-08-29 14:35:15 +0000
commit40b8e415eb0f835a9dd7a473ddf134ec67877fd7 (patch)
tree3cfb63f1a112ee17469b17fc1593a88d004ddda6 /contrib/ntp/ntpd/refclock_oncore.c
parenta5a8dc6136fcee95f261a31609a25669038c3861 (diff)
downloadFreeBSD-src-40b8e415eb0f835a9dd7a473ddf134ec67877fd7.zip
FreeBSD-src-40b8e415eb0f835a9dd7a473ddf134ec67877fd7.tar.gz
Virgin import of ntpd 4.1.0
Diffstat (limited to 'contrib/ntp/ntpd/refclock_oncore.c')
-rw-r--r--contrib/ntp/ntpd/refclock_oncore.c2039
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, &current_mode) < 0) {
+ msyslog(LOG_ERR,
+ "refclock_ioctl: time_pps_getcap failed: %m");
+ return;
+ }
+
+ if (time_pps_getparams(instance->pps_h, &current_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, &current_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 */
OpenPOWER on IntegriCloud