summaryrefslogtreecommitdiffstats
path: root/contrib/ntp/ntpd/refclock_oncore.c
diff options
context:
space:
mode:
authorroberto <roberto@FreeBSD.org>2004-07-20 15:01:56 +0000
committerroberto <roberto@FreeBSD.org>2004-07-20 15:01:56 +0000
commit118e757284cbb8fc4f43a713e892b41504b50a5f (patch)
tree528d12dda44ebdc3ffcc38050f159ac553a69c17 /contrib/ntp/ntpd/refclock_oncore.c
parenta85d9ae25e8e8696677bc30feb6eaf7fc150e529 (diff)
downloadFreeBSD-src-118e757284cbb8fc4f43a713e892b41504b50a5f.zip
FreeBSD-src-118e757284cbb8fc4f43a713e892b41504b50a5f.tar.gz
Virgin import of ntpd 4.2.0
Diffstat (limited to 'contrib/ntp/ntpd/refclock_oncore.c')
-rw-r--r--contrib/ntp/ntpd/refclock_oncore.c3763
1 files changed, 2339 insertions, 1424 deletions
diff --git a/contrib/ntp/ntpd/refclock_oncore.c b/contrib/ntp/ntpd/refclock_oncore.c
index 43a38fb..14db92f 100644
--- a/contrib/ntp/ntpd/refclock_oncore.c
+++ b/contrib/ntp/ntpd/refclock_oncore.c
@@ -9,8 +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.
+ * should work with Basic, PVT6, VP, UT, UT+, GT, GT+, SL, M12, M12+T
+ * The receivers with TRAIM (VP, UT, UT+, M12+T), will be more accurate
+ * than the others.
* The receivers without position hold (GT, GT+) will be less accurate.
*
* Tested with:
@@ -28,16 +29,16 @@
* 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
+ * COPYRIGHT 1991-1994 MOTOROLA INC. COPYRIGHT 1991-2000 MOTOROLA INC.
+ * SFTW P/N # 98-P39949M SFTW P/N # 61-G10002A
+ * SOFTWARE VER # 5 SOFTWARE VER # 1
+ * SOFTWARE REV # 0 SOFTWARE REV # 3
+ * SOFTWARE DATE 20 JAN 1994 SOFTWARE DATE Mar 13 2000
+ * MODEL # A11121P116 MODEL # P143T12NR1
* HDWR P/N # _ HWDR P/N # 1
- * SERIAL # SSG0226478 SERIAL # P003UD
- * MANUFACTUR DATE 7E02 MANUFACTUR DATE 0C27
- * OPTIONS LIST IB
+ * SERIAL # SSG0049809 SERIAL # P003UD
+ * MANUFACTUR DATE 417AMA199 MANUFACTUR DATE 0C27
+ * OPTIONS LIST AB
*
* --------------------------------------------------------------------------
* This code uses the two devices
@@ -138,7 +139,9 @@ struct ppsclockev {
enum receive_state {
ONCORE_NO_IDEA,
- ONCORE_ID_SENT,
+ ONCORE_CHECK_ID,
+ ONCORE_CHECK_CHAN,
+ ONCORE_HAVE_CHAN,
ONCORE_RESET_SENT,
ONCORE_TEST_SENT,
ONCORE_INIT,
@@ -154,6 +157,14 @@ enum site_survey_state {
ONCORE_SS_DONE
};
+enum antenna_state {
+ ONCORE_ANTENNA_UNKNOWN = -1,
+ ONCORE_ANTENNA_OK = 0,
+ ONCORE_ANTENNA_OC = 1,
+ ONCORE_ANTENNA_UC = 2,
+ ONCORE_ANTENNA_NV = 3
+};
+
/* Model Name, derived from the @@Cj message.
* Used to initialize some variables.
*/
@@ -204,7 +215,7 @@ struct instance {
int ttyfd; /* TTY file descriptor */
int ppsfd; /* PPS file descriptor */
- int statusfd; /* Status shm descriptor */
+ int shmemfd; /* Status shm descriptor */
#ifdef HAVE_PPSAPI
pps_handle_t pps_h;
pps_params_t pps_p;
@@ -212,6 +223,7 @@ struct instance {
enum receive_state o_state; /* Receive state */
enum posn_mode mode; /* 0D, 2D, 3D */
enum site_survey_state site_survey; /* Site Survey state */
+ enum antenna_state ant_state; /* antenna state */
int Bj_day;
@@ -224,9 +236,10 @@ struct instance {
u_int shmem_Ba;
u_int shmem_Ea;
u_int shmem_Ha;
- u_char shmem_first;
u_char shmem_reset;
u_char shmem_Posn;
+ u_char shmem_bad_Ea;
+ u_char almanac_from_shmem;
double ss_lat;
double ss_long;
@@ -240,59 +253,98 @@ struct instance {
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 */
+ s_char traim; /* do we have traim? yes UT/VP, no BASIC, GT, M12+T, -1 unknown, 0 no, +1 yes */
+
+ /* the following 7 are all timing counters */
u_char traim_delay; /* seconds counter, waiting for reply */
+ u_char count; /* cycles thru Ea before starting */
+ u_char count1; /* cycles thru Ea after SS_TESTING, waiting for SS_HW */
+ u_char count2; /* cycles thru Ea after count, to check for @@Ea */
+ u_char count3; /* cycles thru Ea checking for # channels */
+ u_char count4; /* cycles thru leap after Gj to issue Bj */
+ u_char pollcnt;
+ u_char timeout; /* count to retry Cj after Fa self-test */
struct RSM rsm; /* bits extracted from Receiver Status Msg in @@Ea */
u_char printed;
u_char polled;
- int pollcnt;
- u_int ev_serial;
+ u_long ev_serial;
int Rcvptr;
u_char Rcvbuf[500];
- u_char Ea[160]; /* Ba, Ea or Ha */
- u_char En[70]; /* Bn or En */
+ u_char BEHa[160]; /* Ba, Ea or Ha */
+ u_char BEHn[80]; /* Bn , En , or Hn */
u_char Cj[300];
- u_char As;
- u_char Ay;
- u_char Az;
+ u_char Ag; /* Satellite mask angle */
+ u_char saw_At;
+ u_char saw_Ay;
+ u_char saw_Az;
+ s_char saw_Gj;
u_char have_dH;
u_char init_type;
s_char saw_tooth;
- u_int timeout; /* count to retry Cj after Fa self-test */
- u_char count; /* cycles thru Ea before starting */
+ s_char chan_in; /* chan number from INPUT, will always use it */
+ u_char chan_id; /* chan number determined from part number */
+ u_char chan_ck; /* chan number determined by sending commands to hardware */
+ s_char traim_in; /* TRAIM from INPUT, will always use it */
+ s_char traim_id; /* TRAIM determined from part number */
+ u_char traim_ck; /* TRAIM determined by sending commands to hardware */
+ u_char once; /* one pass code at top of BaEaHa */
s_char assert;
- u_int saw_At;
+ u_char hardpps;
};
#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 *, 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 int oncore_start P((int, struct peer *));
+static void oncore_control P((int, struct refclockstat *, struct refclockstat *, struct peer *));
+static void oncore_poll P((int, struct peer *));
+static void oncore_shutdown P((int, struct peer *));
+static void oncore_consume P((struct instance *));
+static void oncore_read_config P((struct instance *));
+static void oncore_receive P((struct recvbuf *));
+static int oncore_ppsapi P((struct instance *));
+static void oncore_get_timestamp P((struct instance *, long, long));
+static void oncore_init_shmem P((struct instance *));
+
+static void oncore_antenna_report P((struct instance *, enum antenna_state));
+static void oncore_chan_test P((struct instance *));
+static void oncore_check_almanac P((struct instance *));
+static void oncore_check_antenna P((struct instance *));
+static void oncore_check_leap_sec P((struct instance *));
+static int oncore_checksum_ok P((u_char *, int));
+static void oncore_compute_dH P((struct instance *));
+static void oncore_load_almanac P((struct instance *));
+static void oncore_print_Cb P((struct instance *, u_char *));
+/* static void oncore_print_array P((u_char *, int)); */
+static void oncore_print_posn P((struct instance *));
+static void oncore_sendmsg P((int, u_char *, size_t));
+static void oncore_set_posn P((struct instance *));
+static void oncore_set_traim P((struct instance *));
+static void oncore_shmem_get_3D P((struct instance *));
+static void oncore_ss P((struct instance *));
+static int oncore_wait_almanac P((struct instance *));
static void oncore_msg_any P((struct instance *, u_char *, size_t, int));
+static void oncore_msg_Adef P((struct instance *, u_char *, size_t));
+static void oncore_msg_Ag P((struct instance *, u_char *, size_t));
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_Bd 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_BnEnHn 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_Ga P((struct instance *, u_char *, size_t));
+static void oncore_msg_Gb P((struct instance *, u_char *, size_t));
+static void oncore_msg_Gd 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));
@@ -300,7 +352,7 @@ struct refclock refclock_oncore = {
oncore_start, /* start up driver */
oncore_shutdown, /* shut down driver */
oncore_poll, /* transmit poll message */
- noentry, /* not used */
+ oncore_control, /* fudge (flag) control messages */
noentry, /* not used */
noentry, /* not used */
NOFLAGS /* not used */
@@ -322,13 +374,15 @@ static struct msg_desc {
{ "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" },
+ { "Bn", 59, oncore_msg_BnEnHn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffC" },
+ { "En", 69, oncore_msg_BnEnHn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffsffffsffffC" },
+ { "Hn", 78, oncore_msg_BnEnHn, "" },
{ "Ab", 10, 0, "" },
{ "Ac", 11, 0, "" },
- { "Ad", 11, 0, "" },
- { "Ae", 11, 0, "" },
- { "Af", 15, 0, "" },
+ { "Ad", 11, oncore_msg_Adef, "" },
+ { "Ae", 11, oncore_msg_Adef, "" },
+ { "Af", 15, oncore_msg_Adef, "" },
+ { "Ag", 8, oncore_msg_Ag, "" }, /* Satellite mask angle */
{ "As", 20, oncore_msg_As, "" },
{ "At", 8, oncore_msg_At, "" },
{ "Au", 12, 0, "" },
@@ -338,6 +392,7 @@ static struct msg_desc {
{ "Az", 11, oncore_msg_Az, "" },
{ "AB", 8, 0, "" },
{ "Bb", 92, 0, "" },
+ { "Bd", 23, oncore_msg_Bd, "" },
{ "Bj", 8, oncore_msg_Bj, "" },
{ "Ca", 9, oncore_msg_CaFaIa, "" },
{ "Cb", 33, oncore_msg_Cb, "" },
@@ -347,132 +402,92 @@ static struct msg_desc {
{ "Cj", 294, oncore_msg_Cj, "" },
{ "Ek", 71, 0, "" },
{ "Fa", 9, oncore_msg_CaFaIa, "" },
- { "Gd", 8, 0, "" },
+ { "Ga", 20, oncore_msg_Ga, "" },
+ { "Gb", 17, oncore_msg_Gb, "" },
+ { "Gc", 8, 0, "" },
+ { "Gd", 8, oncore_msg_Gd, "" },
+ { "Ge", 8, 0, "" },
{ "Gj", 21, oncore_msg_Gj, "" },
{ "Ia", 10, oncore_msg_CaFaIa, "" },
{ "Sz", 8, oncore_msg_Sz, "" },
{ {0}, 7, 0, "" }
};
-/*
- * 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_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 */
-
-/*
- * 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).
- */
-u_char oncore_cmd_Aw[] = { 'A', 'w', 1 };
-
-/*
- * Output Almanac when it changes
- */
-u_char oncore_cmd_Be[] = { 'B', 'e', 1 };
-/*
- * Read back PPS Offset for Output
- */
-u_char oncore_cmd_Ay[] = { 'A', 'y', 0, 0, 0, 0 };
-u_char oncore_cmd_Ayx[] = { 'A', 'y', 0xff, 0xff, 0xff, 0xff };
-
-/*
- * Read back Cable Delay for Output
+static u_char oncore_cmd_Aa[] = { 'A', 'a', 0, 0, 0 }; /* 6/8 Time of Day */
+static u_char oncore_cmd_Ab[] = { 'A', 'b', 0, 0, 0 }; /* 6/8 GMT Correction */
+static u_char oncore_cmd_AB[] = { 'A', 'B', 4 }; /* VP Application Type: Static */
+static u_char oncore_cmd_Ac[] = { 'A', 'c', 0, 0, 0, 0 }; /* 6/8 Date */
+static u_char oncore_cmd_Ad[] = { 'A', 'd', 0,0,0,0 }; /* 6/8 Latitude */
+static u_char oncore_cmd_Ae[] = { 'A', 'e', 0,0,0,0 }; /* 6/8 Longitude */
+static u_char oncore_cmd_Af[] = { 'A', 'f', 0,0,0,0, 0 }; /* 6/8 Height */
+static u_char oncore_cmd_Ag[] = { 'A', 'g', 0 }; /* 6/8/12 Satellite Mask Angle */
+static u_char oncore_cmd_Agx[] = { 'A', 'g', 0xff }; /* 6/8/12 Satellite Mask Angle: read */
+static u_char oncore_cmd_As[] = { 'A', 's', 0,0,0,0, 0,0,0,0, 0,0,0,0, 0 }; /* 6/8/12 Posn Hold Parameters */
+static u_char oncore_cmd_Asx[] = { 'A', 's', 0x7f,0xff,0xff,0xff, /* 6/8/12 Posn Hold Readback */
+ 0x7f,0xff,0xff,0xff, /* on UT+ this doesnt work with 0xff */
+ 0x7f,0xff,0xff,0xff, 0xff }; /* but does work with 0x7f (sigh). */
+static u_char oncore_cmd_At0[] = { 'A', 't', 0 }; /* 6/8 Posn Hold: off */
+static u_char oncore_cmd_At1[] = { 'A', 't', 1 }; /* 6/8 Posn Hold: on */
+static u_char oncore_cmd_At2[] = { 'A', 't', 2 }; /* 6/8 Posn Hold: Start Site Survey */
+static u_char oncore_cmd_Atx[] = { 'A', 't', 0xff }; /* 6/8 Posn Hold: Read Back */
+static u_char oncore_cmd_Au[] = { 'A', 'u', 0,0,0,0, 0 }; /* GT/M12 Altitude Hold Ht. */
+static u_char oncore_cmd_Av0[] = { 'A', 'v', 0 }; /* VP/GT Altitude Hold: off */
+static u_char oncore_cmd_Av1[] = { 'A', 'v', 1 }; /* VP/GT Altitude Hold: on */
+static u_char oncore_cmd_Aw[] = { 'A', 'w', 1 }; /* 6/8/12 UTC/GPS time selection */
+static u_char oncore_cmd_Ay[] = { 'A', 'y', 0, 0, 0, 0 }; /* Timing 1PPS time offset: set */
+static u_char oncore_cmd_Ayx[] = { 'A', 'y', 0xff, 0xff, 0xff, 0xff }; /* Timing 1PPS time offset: Read */
+static u_char oncore_cmd_Az[] = { 'A', 'z', 0, 0, 0, 0 }; /* 6/8UT/12 1PPS Cable Delay: set */
+static u_char oncore_cmd_Azx[] = { 'A', 'z', 0xff, 0xff, 0xff, 0xff }; /* 6/8UT/12 1PPS Cable Delay: Read */
+static u_char oncore_cmd_Ba0[] = { 'B', 'a', 0 }; /* 6 Position/Data/Status: off */
+static u_char oncore_cmd_Ba[] = { 'B', 'a', 1 }; /* 6 Position/Data/Status: on */
+static u_char oncore_cmd_Bb[] = { 'B', 'b', 1 }; /* 6/8/12 Visible Satellites */
+static u_char oncore_cmd_Bd[] = { 'B', 'd', 1 }; /* 6/8/12? Almanac Status Msg. */
+static u_char oncore_cmd_Be[] = { 'B', 'e', 1 }; /* 6/8/12 Request Almanac Data */
+static u_char oncore_cmd_Bj[] = { 'B', 'j', 0 }; /* 6/8 Leap Second Pending */
+static u_char oncore_cmd_Bn0[] = { 'B', 'n', 0, 1, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 6 TRAIM setup/status: msg off, traim on */
+static u_char oncore_cmd_Bn[] = { 'B', 'n', 1, 1, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 6 TRAIM setup/status: msg on traim on */
+static u_char oncore_cmd_Bnx[] = { 'B', 'n', 1, 0, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 6 TRAIM setup/status: msg on traim off */
+static u_char oncore_cmd_Ca[] = { 'C', 'a' }; /* 6 Self Test */
+static u_char oncore_cmd_Cf[] = { 'C', 'f' }; /* 6/8/12 Set to Defaults */
+static u_char oncore_cmd_Cg[] = { 'C', 'g', 1 }; /* VP Posn Fix/Idle Mode */
+static u_char oncore_cmd_Cj[] = { 'C', 'j' }; /* 6/8/12 Receiver ID */
+static u_char oncore_cmd_Ea0[] = { 'E', 'a', 0 }; /* 8 Position/Data/Status: off */
+static u_char oncore_cmd_Ea[] = { 'E', 'a', 1 }; /* 8 Position/Data/Status: on */
+static u_char oncore_cmd_Ek[] = { 'E', 'k', 0 }; /* just turn off */ /* 8 Posn/Status/Data - extension */
+static u_char oncore_cmd_En0[] = { 'E', 'n', 0, 1, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 8/GT TRAIM setup/status: msg off, traim on */
+static u_char oncore_cmd_En[] = { 'E', 'n', 1, 1, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 8/GT TRAIM setup/status: msg on traim on */
+static u_char oncore_cmd_Enx[] = { 'E', 'n', 1, 0, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 8/GT TRAIM setup/status: msg on traim off */
+static u_char oncore_cmd_Fa[] = { 'F', 'a' }; /* 8 Self Test */
+static u_char oncore_cmd_Ga[] = { 'G', 'a', 0,0,0,0, 0,0,0,0, 0,0,0,0, 0 }; /* 12 Position Set */
+static u_char oncore_cmd_Gax[] = { 'G', 'a', 0xff, 0xff, 0xff, 0xff, /* 12 Position Set: Read */
+ 0xff, 0xff, 0xff, 0xff, /* */
+ 0xff, 0xff, 0xff, 0xff, 0xff }; /* */
+static u_char oncore_cmd_Gb[] = { 'G', 'b', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* 12 set Date/Time */
+static u_char oncore_cmd_Gc[] = { 'G', 'c', 1 }; /* 12 PPS Control: On Cont */
+static u_char oncore_cmd_Gd0[] = { 'G', 'd', 0 }; /* 12 Position Control: 3D (no hold) */
+static u_char oncore_cmd_Gd1[] = { 'G', 'd', 1 }; /* 12 Position Control: 0D (3D hold) */
+static u_char oncore_cmd_Gd2[] = { 'G', 'd', 2 }; /* 12 Position Control: 2D (Alt Hold) */
+static u_char oncore_cmd_Gd3[] = { 'G', 'd', 3 }; /* 12 Position Coltrol: Start Site Survey */
+static u_char oncore_cmd_Ge0[] = { 'G', 'e', 0 }; /* M12+T TRAIM: off */
+static u_char oncore_cmd_Ge[] = { 'G', 'e', 1 }; /* M12+T TRAIM: on */
+static u_char oncore_cmd_Gj[] = { 'G', 'j' }; /* 8?/12 Leap Second Pending */
+static u_char oncore_cmd_Ha0[] = { 'H', 'a', 0 }; /* 12 Position/Data/Status: off */
+static u_char oncore_cmd_Ha[] = { 'H', 'a', 1 }; /* 12 Position/Data/Status: on */
+static u_char oncore_cmd_Hn0[] = { 'H', 'n', 0 }; /* 12 TRAIM Status: off */
+static u_char oncore_cmd_Hn[] = { 'H', 'n', 1 }; /* 12 TRAIM Status: on */
+static u_char oncore_cmd_Ia[] = { 'I', 'a' }; /* 12 Self Test */
+
+/* it appears that as of 1997/1998, the UT had As,At, but not Au,Av
+ * the GT had Au,Av, but not As,At
+ * This was as of v2.0 of both firmware sets. possibly 1.3 for UT.
+ * Bj in UT at v1.3
+ * dont see Bd in UT/GT thru 1999
+ * Gj in UT as of 3.0, 1999 , Bj as of 1.3
*/
-u_char oncore_cmd_Az[] = { 'A', 'z', 0, 0, 0, 0 };
-u_char oncore_cmd_Azx[] = { 'A', 'z', 0xff, 0xff, 0xff, 0xff };
-/*
- * Application type = static.
- */
-u_char oncore_cmd_AB[] = { 'A', 'B', 4 };
-
-/*
- * Visible Satellite Status Msg.
- */
-u_char oncore_cmd_Bb[] = { 'B', 'b', 1 };
-
-/*
- * Leap Second Pending Message
- * Request message once
- */
-u_char oncore_cmd_Bj[] = { 'B', 'j', 0 };
-u_char oncore_cmd_Gj[] = { 'G', 'j' };
-
-/*
- * Set to Defaults
- */
-static u_char oncore_cmd_Cf[] = { 'C', 'f' };
-
-/*
- * Set to Position Fix mode (only needed on VP).
- */
-u_char oncore_cmd_Cg[] = { 'C', 'g', 1 };
-
-/*
- * Receiver Id
- */
-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_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
- */
-u_char oncore_cmd_Ek[] = { 'E', 'k', 0 }; /* just turn off */
-
-/*
- * Time Raim Setup & Status Message
- * Send once per second
- * Time-RAIM on
- * 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_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_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 */
+static char *Month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jly",
+ "Aug", "Sep", "Oct", "Nov", "Dec" };
#define DEVICE1 "/dev/oncore.serial.%d" /* name of serial device */
#define DEVICE2 "/dev/oncore.pps.%d" /* name of pps device */
@@ -502,10 +517,6 @@ static u_char oncore_cmd_Ia[] = { 'I', 'a' }; /* 12 Chan */
/* from buffer, char *buf, result to an int */
#define buf_w32(buf) (((buf)[0]&0200) ? (-(~w32(buf)+1)) : w32(buf))
-extern int pps_assert;
-extern int pps_hardpps;
-
-
/*
* oncore_start - initialize data for processing
@@ -519,7 +530,7 @@ oncore_start(
{
register struct instance *instance;
struct refclockproc *pp;
- int fd1, fd2, mode;
+ int fd1, fd2;
char device1[30], device2[30];
const char *cp;
struct stat stat1, stat2;
@@ -548,6 +559,14 @@ oncore_start(
exit(1);
}
+ /* create instance structure for this unit */
+
+ if (!(instance = (struct instance *) malloc(sizeof *instance))) {
+ perror("malloc");
+ return (0);
+ }
+ memset((char *) instance, 0, sizeof *instance);
+
if ((stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino)) {
/* same device here */
if (!(fd1 = refclock_open(device1, SPEED, LDISC_RAW
@@ -559,7 +578,7 @@ oncore_start(
exit(1);
}
fd2 = fd1;
- } else { /* different devices here */
+ } else { /* different devices here */
if (!(fd1=refclock_open(device1, SPEED, LDISC_RAW))) {
perror("ONCORE: fd1");
exit(1);
@@ -570,24 +589,18 @@ oncore_start(
}
}
- /* Devices now open, create instance structure for this unit */
-
- if (!(instance = (struct instance *) malloc(sizeof *instance))) {
- perror("malloc");
- close(fd1);
- return (0);
- }
- memset((char *) instance, 0, sizeof *instance);
-
- /* link instance up and down */
+ /* initialize miscellaneous variables */
pp = peer->procptr;
pp->unitptr = (caddr_t) instance;
instance->pp = pp;
instance->unit = unit;
instance->peer = peer;
+ instance->assert = 1;
+ instance->once = 1;
- /* initialize miscellaneous variables */
+ cp = "ONCORE DRIVER -- CONFIGURING";
+ record_clock_stats(&(instance->peer->srcadr), cp);
instance->o_state = ONCORE_NO_IDEA;
cp = "state = ONCORE_NO_IDEA";
@@ -597,11 +610,14 @@ oncore_start(
instance->ppsfd = fd2;
instance->Bj_day = -1;
- instance->assert = pps_assert;
instance->traim = -1;
+ instance->traim_in = -1;
+ instance->chan_in = -1;
instance->model = ONCORE_UNKNOWN;
instance->mode = MODE_UNKNOWN;
instance->site_survey = ONCORE_SS_UNKNOWN;
+ instance->Ag = 0xff; /* Satellite mask angle, unset by user */
+ instance->ant_state = ONCORE_ANTENNA_UNKNOWN;
peer->precision = -26;
peer->minpoll = 4;
@@ -609,7 +625,7 @@ oncore_start(
pp->clockdesc = "Motorola Oncore GPS Receiver";
memcpy((char *)&pp->refid, "GPS\0", (size_t) 4);
- /* go read any input data in /etc/ntp.oncoreX */
+ /* go read any input data in /etc/ntp.oncoreX or /etc/ntp/oncore.X */
oncore_read_config(instance);
@@ -619,15 +635,183 @@ oncore_start(
return(0);
}
+ if (instance->assert)
+ cp = "Initializing timing to Assert.";
+ else
+ cp = "Initializing timing to Clear.";
+ record_clock_stats(&(instance->peer->srcadr), cp);
+
+ if (instance->hardpps) {
+ cp = "HARDPPS Set.";
+ record_clock_stats(&(instance->peer->srcadr), cp);
+ }
+
+ if (!oncore_ppsapi(instance))
+ return(0);
+#endif
+
+ pp->io.clock_recv = oncore_receive;
+ pp->io.srcclock = (caddr_t)peer;
+ pp->io.datalen = 0;
+ pp->io.fd = fd1;
+ if (!io_addclock(&pp->io)) {
+ perror("io_addclock");
+ (void) close(fd1);
+ free(instance);
+ return (0);
+ }
+
+#ifdef ONCORE_SHMEM_STATUS
+ /*
+ * Before starting ONCORE, lets setup SHMEM
+ * This will include merging an old SHMEM into the new one if
+ * an old one is found.
+ */
+
+ oncore_init_shmem(instance);
+#endif
+
+ /*
+ * This will return the Model of the Oncore receiver.
+ * and start the Initialization loop in oncore_msg_Cj.
+ */
+
+ instance->o_state = ONCORE_CHECK_ID;
+ cp = "state = ONCORE_CHECK_ID";
+ record_clock_stats(&(instance->peer->srcadr), cp);
+
+ instance->timeout = 4;
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Set Posn Fix mode (not Idle (VP)) */
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
+
+ instance->pollcnt = 2;
+ return (1);
+}
+
+
+/*
+ * Fudge control (get Flag2 and Flag3, not available at oncore_start time.
+ */
+
+static void
+oncore_control(
+ int unit, /* unit (not used) */
+ struct refclockstat *in, /* input parameters (not used) */
+ struct refclockstat *out, /* output parameters (not used) */
+ struct peer *peer /* peer structure pointer */
+ )
+{
+ char *cp;
+ struct refclockproc *pp;
+ struct instance *instance;
+
+ pp = peer->procptr;
+ instance = (struct instance *) pp->unitptr;
+
+ instance->assert = !(pp->sloppyclockflag & CLK_FLAG2);
+ instance->hardpps = pp->sloppyclockflag & CLK_FLAG3;
+
+ if (instance->assert)
+ cp = "Resetting timing to Assert.";
+ else
+ cp = "Resetting timing to Clear.";
+ record_clock_stats(&(instance->peer->srcadr), cp);
+
+ if (instance->hardpps) {
+ cp = "HARDPPS Set.";
+ record_clock_stats(&(instance->peer->srcadr), cp);
+ }
+
+ (void) oncore_ppsapi(instance);
+}
+
+
+
+/*
+ * oncore_shutdown - shut down the clock
+ */
+
+static void
+oncore_shutdown(
+ int unit,
+ struct peer *peer
+ )
+{
+ register struct instance *instance;
+ struct refclockproc *pp;
+
+ pp = peer->procptr;
+ instance = (struct instance *) pp->unitptr;
+
+ io_closeclock(&pp->io);
+
+ close(instance->ttyfd);
+ close(instance->ppsfd);
+ if (instance->shmemfd)
+ close(instance->shmemfd);
+ free(instance);
+}
+
+
+
+/*
+ * oncore_poll - called by the transmit procedure
+ */
+
+static void
+oncore_poll(
+ int unit,
+ struct peer *peer
+ )
+{
+ struct instance *instance;
+
+ instance = (struct instance *) peer->procptr->unitptr;
+ if (instance->timeout) {
+ char *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;
+ }
+
+ if (!instance->pollcnt)
+ refclock_report(peer, CEVNT_TIMEOUT);
+ else
+ instance->pollcnt--;
+ peer->procptr->polls++;
+ instance->polled = 1;
+}
+
+
+
+/*
+ * Initialize PPSAPI
+ */
+
+#ifdef HAVE_PPSAPI
+static int
+oncore_ppsapi(
+ struct instance *instance
+ )
+{
+ int mode;
+
if (time_pps_getcap(instance->pps_h, &mode) < 0) {
- msyslog(LOG_ERR,
- "refclock_ioctl: time_pps_getcap failed: %m");
+ msyslog(LOG_ERR, "refclock_ioctl: time_pps_getcap failed: %m");
return (0);
}
if (time_pps_getparams(instance->pps_h, &instance->pps_p) < 0) {
- msyslog(LOG_ERR,
- "refclock_ioctl: time_pps_getparams failed: %m");
+ msyslog(LOG_ERR, "refclock_ioctl: time_pps_getparams failed: %m");
return (0);
}
@@ -652,59 +836,183 @@ oncore_start(
exit(1);
}
- if (pps_device && pps_device[0]) {
- if (stat(pps_device, &stat1)) {
- perror("ONCORE: stat pps_device");
- return(0);
- }
+ /* If HARDPPS is on, we tell kernel */
- /* must have hardpps ON, and fd2 must be the same device as on the pps line */
+ if (instance->hardpps) {
+ int i;
- if (pps_hardpps && ((stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino))) {
- int i;
+ if (instance->assert)
+ i = PPS_CAPTUREASSERT;
+ else
+ i = PPS_CAPTURECLEAR;
- 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) {
- msyslog(LOG_ERR,
- "refclock_ioctl: time_pps_kcbind failed: %m");
- return (0);
- }
- pps_enable = 1;
+ if (i&mode) {
+ if (time_pps_kcbind(instance->pps_h, PPS_KC_HARDPPS, i,
+ PPS_TSFMT_TSPEC) < 0) {
+ msyslog(LOG_ERR, "refclock_ioctl: time_pps_kcbind failed: %m");
+ return (0);
}
+ pps_enable = 1;
}
}
+ return(1);
+}
#endif
- pp->io.clock_recv = oncore_receive;
- pp->io.srcclock = (caddr_t)peer;
- pp->io.datalen = 0;
- pp->io.fd = fd1;
- if (!io_addclock(&pp->io)) {
- perror("io_addclock");
- (void) close(fd1);
- free(instance);
- return (0);
+
+
+#ifdef ONCORE_SHMEM_STATUS
+static void
+oncore_init_shmem(
+ struct instance *instance
+ )
+{
+ int i, l, n, fd, shmem_old_size, n1;
+ char *buf, Msg[160];
+ u_char *cp, *cp1, *shmem_old;
+ struct msg_desc *mp;
+ struct stat sbuf;
+ size_t shmem_length;
+
+ /*
+ * The first thing we do is see if there is an instance->shmem_fname file (still)
+ * out there from a previous run. If so, we copy it in and use it to initialize
+ * shmem (so we won't lose our almanac if we need it).
+ */
+
+ shmem_old = 0;
+ if ((fd = open(instance->shmem_fname, O_RDONLY)) < 0)
+ perror("LOAD:SHMEM");
+ else {
+ fstat(fd, &sbuf);
+ shmem_old_size = sbuf.st_size;
+ shmem_old = (u_char *) malloc((unsigned) sbuf.st_size);
+ if (shmem_old == NULL) {
+ perror("malloc");
+ close(fd);
+ return;
+ }
+
+ read(fd, shmem_old, shmem_old_size);
+ close(fd);
}
- /*
- * This will return the Model Number of the Oncore receiver.
+ /* OK, we now create the NEW SHMEM. */
+
+ if ((instance->shmemfd = open(instance->shmem_fname, O_RDWR|O_CREAT|O_TRUNC, 0644)) < 0) {
+ perror(instance->shmem_fname);
+ return;
+ }
+
+ /* see how big it needs to be */
+
+ 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);
+ }
+ shmem_length = n + 2;
+ fprintf(stderr, "ONCORE: SHMEM length: %d bytes\n", (int) shmem_length);
+
+ buf = malloc(shmem_length);
+ if (buf == NULL) {
+ perror("malloc");
+ close(instance->shmemfd);
+ return;
+ }
+
+ memset(buf, 0, shmem_length);
+
+ /* next build the new SHMEM buffer in memory */
+
+ for (mp=oncore_messages; mp->flag[0]; mp++) {
+ l = mp->shmem;
+ buf[l + 0] = mp->len >> 8;
+ buf[l + 1] = mp->len & 0xff;
+ buf[l + 2] = 0;
+ buf[l + 3] = '@';
+ buf[l + 4] = '@';
+ buf[l + 5] = mp->flag[0];
+ buf[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++) {
+ buf[l + i * (mp->len+3) + 0] = mp->len >> 8;
+ buf[l + i * (mp->len+3) + 1] = mp->len & 0xff;
+ buf[l + i * (mp->len+3) + 2] = 0;
+ buf[l + i * (mp->len+3) + 3] = '@';
+ buf[l + i * (mp->len+3) + 4] = '@';
+ buf[l + i * (mp->len+3) + 5] = mp->flag[0];
+ buf[l + i * (mp->len+3) + 6] = mp->flag[1];
+ }
+ }
+ }
+
+ /* we now walk thru the two buffers (shmem_old and buf, soon to become shmem)
+ * copying the data in shmem_old to buf. When we are done we write it out
+ * and free both buffers.
+ * If the structures change (an addition or deletion) I will stop copying.
+ * The two will be the same unless we add/subtract from the oncore_messages list
+ * so this should work most of the time, and takes a lot less code than doing it right.
*/
- 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;
+ if (shmem_old) {
+ for (cp=buf+4, cp1=shmem_old+4; (n = 256*(*(cp-3)) + *(cp-2)); cp+=(n+3), cp1+=(n+3)) {
+ n1 = 256*(*(cp1-3)) + *(cp1-2);
+ if (n1 != n || strncmp(cp, cp1, 4))
+ break;
- instance->pollcnt = 2;
- return (1);
+ memcpy(cp, cp1, (size_t) n);
+ }
+ free(shmem_old);
+ }
+
+ i = write(instance->shmemfd, buf, shmem_length);
+ free(buf);
+
+ if (i != shmem_length) {
+ perror(instance->shmem_fname);
+ close(instance->shmemfd);
+ return;
+ }
+
+ instance->shmem = (u_char *) mmap(0, shmem_length,
+ PROT_READ | PROT_WRITE,
+#ifdef MAP_HASSEMAPHORE
+ MAP_HASSEMAPHORE |
+#endif
+ MAP_SHARED, instance->shmemfd, (off_t)0);
+
+ if (instance->shmem == (u_char *)MAP_FAILED) {
+ instance->shmem = 0;
+ close(instance->shmemfd);
+ return;
+ }
+
+ sprintf(Msg, "SHMEM (size = %d) is CONFIGURED and available as %s", shmem_length, instance->shmem_fname);
+ record_clock_stats(&(instance->peer->srcadr), Msg);
}
+#endif /* ONCORE_SHMEM_STATUS */
@@ -751,8 +1059,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, ASSERT, CLEAR, STATUS,
- * POSN3D, POSN2D, CHAN, TRAIM
+ * MODE, LAT, LON, (HT, HTGPS, HTMSL), DELAY, OFFSET, ASSERT, CLEAR, HARDPPS,
+ * 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).
*
@@ -773,7 +1081,7 @@ oncore_read_config(
* 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
+ * If the receiver reports height in both GPS and MSL, then we will report
* the difference GPS-MSL on the clockstats file.
*
* There is an optional line, starting with DELAY, followed
@@ -793,24 +1101,36 @@ oncore_read_config(
* 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.
+ * ASSERT/CLEAR can also be set with FLAG2 of the ntp.conf input.
+ * For Flag2, ASSERT=0, and hence is default.
+ *
+ * There is an optional line, with HARDPPS on it. Including this line causes
+ * the PPS signal to control the kernel PLL.
+ * HARDPPS can also be set with FLAG3 of the ntp.conf input.
+ * For Flag3, 0 is disabled, and the default.
*
- * 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.
+ * There are three options that have to do with using the shared memory option.
+ * First, to enable the option there must be a SHMEM 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.
+ * In shared memory, there is one 'record' for each returned variable.
+ * For the @@Ea data there are three 'records' containing position data.
+ * There will always be data in the record corresponding to the '0D' @@Ea record,
+ * and the user has a choice of filling the '3D' 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.
+ * to allow the user to override either the # of channels, or the existence of TRAIM.
* CHAN expects to be followed by in integer: 6, 8, or 12. TRAIM expects to be
* followed by YES or NO.
*
+ * There is an optional line with MASK on it followed by one integer field in the
+ * range 0 to 89. This sets the satellite mask angle and will determine the minimum
+ * elevation angle for satellites to be tracked by the receiver. The default value
+ * is 10 deg for the VP and 0 deg for all other receivers.
+ *
* So acceptable input would be
* # these are my coordinates (RWC)
* LON -106 34.610
@@ -821,7 +1141,7 @@ oncore_read_config(
FILE *fd;
char *cp, *cc, *ca, line[100], units[2], device[20], Msg[160];
- int i, sign, lat_flg, long_flg, ht_flg, mode;
+ int i, sign, lat_flg, long_flg, ht_flg, mode, mask;
double f1, f2, f3;
sprintf(device, "%s%d", INIT_FILE, instance->unit); /* try "ntp.oncore0" first */
@@ -835,7 +1155,7 @@ oncore_read_config(
}
}
- mode = 0;
+ mode = mask = 0;
lat_flg = long_flg = ht_flg = 0;
while (fgets(line, 100, fd)) {
@@ -871,12 +1191,6 @@ oncore_read_config(
for (; *ca && isascii((int)*ca) && (isspace((int)*ca) || (*ca == '=')); ca++)
continue;
- /*
- * 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));
@@ -963,6 +1277,8 @@ oncore_read_config(
instance->assert = 1;
} else if (!strncmp(cc, "CLEAR", (size_t) 5)) {
instance->assert = 0;
+ } else if (!strncmp(cc, "HARDPPS", (size_t) 7)) {
+ instance->hardpps = 1;
} else if (!strncmp(cc, "POSN2D", (size_t) 6)) {
instance->shmem_Posn = 2;
} else if (!strncmp(cc, "POSN3D", (size_t) 6)) {
@@ -970,11 +1286,15 @@ oncore_read_config(
} else if (!strncmp(cc, "CHAN", (size_t) 4)) {
sscanf(ca, "%d", &i);
if ((i == 6) || (i == 8) || (i == 12))
- instance->chan = i;
+ instance->chan_in = i;
} else if (!strncmp(cc, "TRAIM", (size_t) 5)) {
- instance->traim = 1; /* so TRAIM alone is YES */
+ instance->traim_in = 1; /* so TRAIM alone is YES */
if (!strcmp(ca, "NO") || !strcmp(ca, "OFF")) /* Yes/No, On/Off */
- instance->traim = 0;
+ instance->traim_in = 0;
+ } else if (!strncmp(cc, "MASK", (size_t) 4)) {
+ sscanf(ca, "%d", &mask);
+ if (mask > -1 && mask < 90)
+ instance->Ag = mask; /* Satellite mask angle */
}
}
fclose(fd);
@@ -985,7 +1305,7 @@ oncore_read_config(
*/
instance->posn_set = 1;
- if ((lat_flg || long_flg || ht_flg) && !(lat_flg * long_flg * ht_flg)) {
+ if (!( lat_flg && long_flg && ht_flg )) {
printf("ONCORE: incomplete data on %s\n", INIT_FILE);
instance->posn_set = 0;
if (mode == 1 || mode == 3) {
@@ -1002,170 +1322,8 @@ oncore_read_config(
-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 */
-}
-
-
-
/*
- * oncore_shutdown - shut down the clock
- */
-
-static void
-oncore_shutdown(
- int unit,
- struct peer *peer
- )
-{
- register struct instance *instance;
- struct refclockproc *pp;
-
- pp = peer->procptr;
- instance = (struct instance *) pp->unitptr;
-
- io_closeclock(&pp->io);
-
- free(instance);
-}
-
-
-
-/*
- * oncore_poll - called by the transmit procedure
- */
-
-static void
-oncore_poll(
- int unit,
- struct peer *peer
- )
-{
- struct instance *instance;
-
- instance = (struct instance *) peer->procptr->unitptr;
- if (instance->timeout) {
- char *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;
- }
-
- if (!instance->pollcnt)
- refclock_report(peer, CEVNT_TIMEOUT);
- else
- instance->pollcnt--;
- peer->procptr->polls++;
- instance->polled = 1;
-}
-
-
-
-/*
- * move data from NTP to buffer (toss in unlikely case it wont fit)
+ * move data from NTP to buffer (toss the extra in the unlikely case it won't fit)
*/
static void
@@ -1215,7 +1373,7 @@ oncore_consume(
struct instance *instance
)
{
- int i, j, m;
+ int i, m;
unsigned l;
while (rcvptr >= 7) {
@@ -1261,10 +1419,7 @@ oncore_consume(
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 (oncore_checksum_ok(rcvbuf, l)) {
if (instance->shmem != NULL) {
instance->shmem[oncore_messages[m].shmem + 2]++;
memcpy(instance->shmem + oncore_messages[m].shmem + 3,
@@ -1274,7 +1429,7 @@ oncore_consume(
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]: Checksum mismatch!\n", instance->unit);
printf("ONCORE[%d]: @@%c%c ", instance->unit, rcvbuf[2], rcvbuf[3]);
for (i=4; i<l; i++)
printf("%03o ", rcvbuf[i]);
@@ -1290,29 +1445,317 @@ oncore_consume(
-/*
- * write message to Oncore.
- */
-
static void
-oncore_sendmsg(
- int fd,
- u_char *ptr,
- size_t len
+oncore_get_timestamp(
+ struct instance *instance,
+ long dt1, /* tick offset THIS time step */
+ long dt2 /* tick offset NEXT time step */
)
{
- u_char cs = 0;
+ int Rsm;
+ u_long i, j;
+ l_fp ts, ts_tmp;
+ double dmy;
+#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 */
+#ifdef HAVE_CIOGETEV
+ struct ppsclockev ev;
+ int r = CIOGETEV;
+#endif
+#ifdef HAVE_TIOCGPPSEV
+ struct ppsclockev ev;
+ int r = TIOCGPPSEV;
+#endif
+#if TIOCDCDTIMESTAMP
+ struct timeval tv;
+#endif
+#endif /* ! HAVE_PPS_API */
- 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, (size_t) 1);
- write(fd, "\r\n", (size_t) 2);
+#if 1
+ /* If we are in SiteSurvey mode, then we are in 3D mode, and we fall thru.
+ * If we have Finished the SiteSurvey, then we fall thru for the 14/15
+ * times we get here in 0D mode (the 1/15 is in 3D for SHMEM).
+ * This gives good time, which gets better when the SS is done.
+ */
+
+ if ((instance->site_survey == ONCORE_SS_DONE) && (instance->mode != MODE_0D))
+#else
+ /* old check, only fall thru for SS_DONE and 0D mode, 2h45m wait for ticks */
+
+ if ((instance->site_survey != ONCORE_SS_DONE) || (instance->mode != MODE_0D))
+#endif
+ return;
+
+ /* Don't do anything without an almanac to define the GPS->UTC delta */
+
+ if (instance->rsm.bad_almanac)
+ return;
+
+#ifdef HAVE_PPSAPI
+ j = instance->ev_serial;
+ timeout.tv_sec = 0;
+ timeout.tv_nsec = 0;
+ if (time_pps_fetch(instance->pps_h, PPS_TSFMT_TSPEC, &pps_i,
+ &timeout) < 0) {
+ printf("ONCORE: time_pps_fetch failed\n");
+ return;
+ }
+
+ if (instance->assert) {
+ tsp = &pps_i.assert_timestamp;
+
+ 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_get_timestamp, error serial pps\n");
+ return;
+ }
+ instance->ev_serial = pps_i.assert_sequence;
+ } else {
+ tsp = &pps_i.clear_timestamp;
+
+ 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_get_timestamp, error serial pps\n");
+ return;
+ }
+ instance->ev_serial = pps_i.clear_sequence;
+ }
+
+ /* convert timespec -> ntp l_fp */
+
+ dmy = tsp->tv_nsec;
+ dmy /= 1e9;
+ ts.l_uf = dmy * 4294967296.0;
+ ts.l_ui = tsp->tv_sec;
+#if 0
+ alternate code for previous 4 lines is
+ dmy = 1.0e-9*tsp->tv_nsec; /* fractional part */
+ DTOLFP(dmy, &ts);
+ dmy = tsp->tv_sec; /* integer part */
+ DTOLFP(dmy, &ts_tmp);
+ L_ADD(&ts, &ts_tmp);
+ or more simply
+ dmy = 1.0e-9*tsp->tv_nsec; /* fractional part */
+ DTOLFP(dmy, &ts);
+ ts.l_ui = tsp->tv_sec;
+#endif /* 0 */
+#else
+# if defined(HAVE_TIOCGPPSEV) || defined(HAVE_CIOGETEV)
+ j = instance->ev_serial;
+ if (ioctl(instance->ppsfd, r, (caddr_t) &ev) < 0) {
+ perror("ONCORE: IOCTL:");
+ return;
+ }
+
+ 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_get_timestamp, error serial pps\n");
+ return;
+ }
+ instance->ev_serial = ev.serial;
+
+ /* convert timeval -> ntp l_fp */
+
+ TVTOTS(tsp, &ts);
+# else
+# if defined(TIOCDCDTIMESTAMP)
+ if(ioctl(instance->ppsfd, TIOCDCDTIMESTAMP, &tv) < 0) {
+ perror("ONCORE: ioctl(TIOCDCDTIMESTAMP)");
+ return;
+ }
+ tsp = &tv;
+ TVTOTS(tsp, &ts);
+# else
+#error "Cannot compile -- no PPS mechanism configured!"
+# endif
+# endif
+#endif
+ /* now have timestamp in ts */
+ /* 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. */
+
+ /* offset in ns, and is positive (late), we subtract */
+ /* to put the PPS time transition back where it belongs */
+
+#ifdef HAVE_PPSAPI
+ /* 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 = -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;
+ }
+
+ /* 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 add the */
+ /* offset for THIS second */
+
+ dmy = -1.0e-9*dt1;
+ DTOLFP(dmy, &ts_tmp);
+ L_ADD(&ts, &ts_tmp);
+#endif
+ /* have time from UNIX origin, convert to NTP origin. */
+
+ ts.l_ui += JAN_1970;
+ instance->pp->lastrec = ts;
+
+ /* print out information about this timestamp (long line) */
+
+ 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 */
+
+ Rsm = 0;
+ if (instance->chan == 6)
+ Rsm = instance->BEHa[64];
+ else if (instance->chan == 8)
+ Rsm = instance->BEHa[72];
+ else if (instance->chan == 12)
+ Rsm = ((instance->BEHa[129]<<8) | instance->BEHa[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 %2d 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->BEHa[35]+instance->BEHa[36]),
+ /*rsat dop */
+ instance->BEHa[38], instance->BEHa[39], instance->BEHn[21],
+ /* nsat visible, nsat tracked, traim */
+ instance->BEHn[23]*256+instance->BEHn[24], (s_char) instance->BEHn[25],
+ /* sigma neg-sawtooth */
+ /*sat*/ instance->BEHa[41], instance->BEHa[45], instance->BEHa[49], instance->BEHa[53],
+ instance->BEHa[57], instance->BEHa[61], instance->BEHa[65], instance->BEHa[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 traim %d sigma %d neg-sawtooth %3d 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->BEHa[53]+instance->BEHa[54]),
+ /*rsat dop */
+ instance->BEHa[55], instance->BEHa[56], instance->BEHn[6],
+ /* nsat visible, nsat tracked traim */
+ instance->BEHn[12]*256+instance->BEHn[13], (s_char) instance->BEHn[14],
+ /* sigma neg-sawtooth */
+ /*sat*/ instance->BEHa[58], instance->BEHa[64], instance->BEHa[70], instance->BEHa[76],
+ instance->BEHa[82], instance->BEHa[88], instance->BEHa[94], instance->BEHa[100],
+ instance->BEHa[106], instance->BEHa[112], instance->BEHa[118], instance->BEHa[124]
+ );
+ }
+
+ if (debug > 2) {
+ int n;
+ n = strlen(instance->pp->a_lastcode);
+ printf("ONCORE[%d]: len = %d %s\n", instance->unit, n, instance->pp->a_lastcode);
+ }
+
+ /* and some things I dont understnd (magic ntp things) */
+
+ if (!refclock_process(instance->pp)) {
+ refclock_report(instance->peer, CEVNT_BADTIME);
+ return;
+ }
+
+ record_clock_stats(&(instance->peer->srcadr), instance->pp->a_lastcode);
+ instance->pollcnt = 2;
+
+ if (instance->polled) {
+ instance->polled = 0;
+/*
+ instance->pp->dispersion = instance->pp->skew = 0;
+*/
+ instance->pp->lastref = instance->pp->lastrec;
+ refclock_receive(instance->peer);
+ }
}
+/*************** oncore_msg_XX routines start here *******************/
+
/*
* print Oncore response message.
@@ -1336,9 +1779,9 @@ oncore_msg_any(
if (debug > 3) {
#ifdef HAVE_GETCLOCK
- (void) getclock(TIMEOFDAY, &ts);
- tv.tv_sec = ts.tv_sec;
- tv.tv_usec = ts.tv_nsec / 1000;
+ (void) getclock(TIMEOFDAY, &ts);
+ tv.tv_sec = ts.tv_sec;
+ tv.tv_usec = ts.tv_nsec / 1000;
#else
GETTIMEOFDAY(&tv, 0);
#endif
@@ -1368,542 +1811,344 @@ oncore_msg_any(
-/*
- * Demultiplex the almanac into shmem
- */
+/* Latitude, Longitude, Height */
static void
-oncore_msg_Cb(
+oncore_msg_Adef(
struct instance *instance,
u_char *buf,
size_t len
)
{
- int i;
+}
- if (instance->shmem == NULL)
- return;
- if (buf[4] == 5)
- i = buf[5];
- else if (buf[4] == 4 && buf[5] <= 5)
- i = buf[5] + 24;
- else if (buf[4] == 4 && buf[5] <= 10)
- i = buf[5] + 23;
- else
- i = 34;
- i *= 36;
- instance->shmem[instance->shmem_Cb + i + 2]++;
- memcpy(instance->shmem + instance->shmem_Cb + i + 3, buf, (size_t) (len + 3));
-}
+/* Mask Angle */
+static void
+oncore_msg_Ag(
+ struct instance *instance,
+ u_char *buf,
+ size_t len
+ )
+{ char Msg[160], *cp;
+
+ cp = "set to";
+ if (instance->o_state == ONCORE_RUN)
+ cp = "is";
+
+ instance->Ag = buf[4];
+ sprintf(Msg, "Satellite mask angle %s %d degrees", cp, (int) instance->Ag);
+ record_clock_stats(&(instance->peer->srcadr), Msg);
+}
-/*
- * 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.
- */
/*
- * 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.
+ * get Position hold position
*/
static void
-oncore_msg_Cj(
+oncore_msg_As(
struct instance *instance,
u_char *buf,
size_t len
)
{
- memcpy(instance->Cj, buf, len);
+ instance->ss_lat = buf_w32(&buf[4]);
+ instance->ss_long = buf_w32(&buf[8]);
+ instance->ss_ht = buf_w32(&buf[12]);
- 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);
+ /* Print out Position */
+ oncore_print_posn(instance);
}
-/* 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.
+/*
+ * Try to use Oncore UT+ Auto Survey Feature
+ * If its not there (VP), set flag to do it ourselves.
*/
static void
-oncore_msg_Cj_id(
+oncore_msg_At(
struct instance *instance,
u_char *buf,
size_t len
)
{
- char *cp, *cp1, *cp2, Model[21], Msg[160];
- int mode;
+ char *cp;
- /* Write Receiver ID message to clockstats file */
+ 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->Cj[294] = '\0';
- for (cp=(char *)instance->Cj; cp< (char *) &instance->Cj[294]; ) {
- cp1 = strchr(cp, '\r');
- if (!cp1)
- cp1 = (char *)&instance->Cj[294];
- *cp1 = '\0';
- record_clock_stats(&(instance->peer->srcadr), cp);
- *cp1 = '\r';
- cp = cp1+2;
+ cp = "SSstate = ONCORE_SS_HW";
+ record_clock_stats(&(instance->peer->srcadr), cp);
+ instance->site_survey = ONCORE_SS_HW;
+ }
}
+}
- /* 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';
+/*
+ * get PPS Offset
+ * Nb. @@Ay is not supported for early UT (no plus) model
+ */
- 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;
- }
+static void
+oncore_msg_Ay(
+ struct instance *instance,
+ u_char *buf,
+ size_t len
+ )
+{
+ char Msg[120];
- 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->saw_Ay)
+ return;
- 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;
- }
+ instance->saw_Ay = 1;
- 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;
- }
+ instance->offset = buf_w32(&buf[4]);
- sprintf(Msg, "Channels = %d, TRAIM = %s", instance->chan,
- ((instance->traim < 0) ? "UNKNOWN" : ((instance->traim > 0) ? "ON" : "OFF")));
+ sprintf(Msg, "PPS Offset is set to %ld ns", instance->offset);
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
- */
+/*
+ * get Cable Delay
+ */
- if (instance->shmem_fname);
- oncore_init_shmem(instance);
+static void
+oncore_msg_Az(
+ struct instance *instance,
+ u_char *buf,
+ size_t len
+ )
+{
+ char Msg[120];
- if (instance->shmem)
- cp = "SHMEM is available";
- else
- cp = "SHMEM is NOT available";
- record_clock_stats(&(instance->peer->srcadr), cp);
+ if (instance->saw_Az)
+ return;
-#ifdef HAVE_PPSAPI
- if (instance->assert)
- cp = "Timing on Assert.";
- else
- cp = "Timing on Clear.";
- record_clock_stats(&(instance->peer->srcadr), cp);
-#endif
+ instance->saw_Az = 1;
- 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->delay = buf_w32(&buf[4]);
- instance->o_state = ONCORE_TEST_SENT;
- cp = "state = ONCORE_TEST_SENT";
- record_clock_stats(&(instance->peer->srcadr), cp);
- instance->timeout = 4;
- }
+ sprintf(Msg, "Cable delay is set to %ld ns", instance->delay);
+ record_clock_stats(&(instance->peer->srcadr), Msg);
}
+/* Ba, Ea and Ha come here, these contain Position */
+
static void
-oncore_msg_Cj_init(
+oncore_msg_BaEaHa(
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[%d]: INIT mode = %d\n", instance->unit, mode);
- printf("ONCORE[%d]: chan = %d\n", instance->unit, instance->chan);
- }
+ const char *cp;
+ char Msg[160];
+ int mode;
- /* 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 do Site Survey.
+ /* OK, we are close to the RUN state now.
+ * But we have a few more items to initialize first.
+ *
+ * At the beginning of this routine there are several 'timers'.
+ * We enter this routine 1/sec, and since the upper levels of NTP have usurped
+ * the use of timers, we use the 1/sec entry to do things that
+ * we would normally do with timers...
*/
-
- 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;
+ if (instance->o_state == ONCORE_CHECK_CHAN) { /* here while checking for the # chan */
+ if (buf[2] == 'B') { /* 6chan */
+ if (instance->chan_ck < 6) instance->chan_ck = 6;
+ } else if (buf[2] == 'E') { /* 8chan */
+ if (instance->chan_ck < 8) instance->chan_ck = 8;
+ } else if (buf[2] == 'H') { /* 12chan */
+ if (instance->chan_ck < 12) instance->chan_ck = 12;
}
- }
+ if (instance->count3++ < 5)
+ return;
- switch (mode) {
- case 0: /* NO initialization, don't change anything */
- instance->site_survey = ONCORE_SS_DONE;
- break;
+ instance->count3 = 0;
- case 1:
- case 3: /* Use given Position */
- instance->site_survey = ONCORE_SS_DONE;
- break;
+ if (instance->chan_in != -1) /* set in Input */
+ instance->chan = instance->chan_in;
+ else /* set from test */
+ instance->chan = instance->chan_ck;
- case 2:
- 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));
- }
- break;
- }
+ sprintf(Msg, "Input says chan = %d", instance->chan_in);
+ record_clock_stats(&(instance->peer->srcadr), Msg);
+ sprintf(Msg, "Model # says chan = %d", instance->chan_id);
+ record_clock_stats(&(instance->peer->srcadr), Msg);
+ sprintf(Msg, "Testing says chan = %d", instance->chan_ck);
+ record_clock_stats(&(instance->peer->srcadr), Msg);
+ sprintf(Msg, "Using chan = %d", instance->chan);
+ record_clock_stats(&(instance->peer->srcadr), Msg);
- if (mode != 0) {
- /* cable delay in ns */
- memcpy(Cmd, oncore_cmd_Az, sizeof(oncore_cmd_Az));
- w32_buf(&Cmd[2], instance->delay);
- oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Az));
+ instance->o_state = ONCORE_HAVE_CHAN;
+ cp = "state = ONCORE_HAVE_CHAN";
+ record_clock_stats(&(instance->peer->srcadr), cp);
- /* PPS offset in ns */
- 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;
- }
- }
+ instance->timeout = 4;
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
+ return;
}
- /* 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);
-}
-
-
-
-/*
- * 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_ALMANAC && instance->o_state != ONCORE_RUN)
+ return;
- 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));
+ /* PAUSE 5sec */
- instance->o_state = ONCORE_TEST_SENT;
- cp = "state = ONCORE_TEST_SENT";
- record_clock_stats(&(instance->peer->srcadr), cp);
+ if (instance->count) {
+ if (instance->count++ < 5) /* make sure results are stable, using position */
+ return;
+ instance->count = 0;
}
-}
-
+ memcpy(instance->BEHa, buf, (size_t) (len+3)); /* Ba, Ea or Ha */
-/* Here for @@Ca, @@Fa and @@Ia messages */
+ /* check the antenna and almanac for changes (did it get unplugged, is it ready?) */
-/* 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).
- */
+ oncore_check_almanac(instance);
+ oncore_check_antenna(instance);
-static void
-oncore_msg_CaFaIa(
- struct instance *instance,
- u_char *buf,
- size_t len
- )
-{
- char *cp;
+ /* Almanac mode, waiting for Almanac, we can't do anything till we have it */
+ /* When we have an almanac, we will start the Bn/En/@@Hn messages */
- if (instance->o_state == ONCORE_TEST_SENT) {
- int antenna;
+ if (instance->o_state == ONCORE_ALMANAC)
+ if (oncore_wait_almanac(instance))
+ return;
- instance->timeout = 0;
+ /* do some things once when we get this far in BaEaHa */
- 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]);
- }
+ if (instance->once) {
+ instance->once = 0;
+ instance->count2 = 1;
- antenna = buf[4] & 0xc0;
- antenna >>= 6;
- buf[4] &= ~0xc0;
+ /* Have we seen an @@At (position hold) command response */
+ /* if not, message out */
- if (buf[4] || buf[5] || ((buf[2] == 'I') && buf[6])) {
- cp = "ONCORE: Self Test Failed, shutting down driver";
+ if (instance->chan != 12 && !instance->saw_At) {
+ cp = "Not Good, no @@At command (no Position Hold), must be a GT/GT+";
record_clock_stats(&(instance->peer->srcadr), cp);
- oncore_shutdown(instance->unit, instance->peer);
- return;
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1));
}
- if (antenna) {
- char *cp1, Msg[160];
- cp1 = (antenna == 0x1) ? "(Over Current)" :
- ((antenna == 0x2) ? "(Under Current)" : "(No Voltage)");
+ /* have an Almanac, can start the SiteSurvey
+ * (actually only need to get past the almanac_load where we diddle with At
+ * command,- we can't change it after we start the HW_SS below
+ */
- cp = "ONCORE: Self Test, NonFatal Antenna Problems ";
- strcpy(Msg, cp);
- strcat(Msg, cp1);
- record_clock_stats(&(instance->peer->srcadr), Msg);
+ mode = instance->init_type;
+ switch (mode) {
+ case 0: /* NO initialization, don't change anything */
+ case 1: /* Use given Position */
+ case 3:
+ instance->site_survey = ONCORE_SS_DONE;
+ cp = "SSstate = ONCORE_SS_DONE";
+ record_clock_stats(&(instance->peer->srcadr), cp);
+ break;
+
+ case 2:
+ case 4: /* Site Survey */
+ cp = "SSstate = ONCORE_SS_TESTING";
+ record_clock_stats(&(instance->peer->srcadr), cp);
+ instance->site_survey = ONCORE_SS_TESTING;
+ instance->count1 = 1;
+ if (instance->chan == 12)
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd3, sizeof(oncore_cmd_Gd3)); /* M12+T */
+ else
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_At2, sizeof(oncore_cmd_At2)); /* not GT, arg not VP */
+ break;
}
- 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);
- }
-}
+ /* Read back PPS Offset for Output */
+ /* 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 */
-/* Ba, Ea and Ha come here */
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Azx, sizeof(oncore_cmd_Azx));
-static void
-oncore_msg_BaEaHa(
- struct instance *instance,
- u_char *buf,
- size_t len
- )
-{
- const char *cp;
- char Msg[160], Cmd[20];
- u_char *vp; /* pointer to start of shared mem for Ba/Ea/Ha */
- size_t Len;
+ /* Read back Satellite Mask Angle for Output */
+
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Agx, sizeof(oncore_cmd_Agx));
+ }
+
+ if (instance->count1) {
+ if (instance->count1++ > 5 || instance->site_survey == ONCORE_SS_HW) {
+ instance->count1 = 0;
+ if (instance->site_survey == ONCORE_SS_TESTING) {
+ /*
+ * For instance->site_survey to still be ONCORE_SS_TESTING, then after a 5sec
+ * wait after the @@At2/@@Gd3 command we have not changed the state to
+ * ONCORE_SS_HW. If the Hardware is capable of doing a Site Survey, then
+ * the variable would have been changed by now.
+ * There are three possibilities:
+ * 6/8chan
+ * (a) We did not get a response to the @@At0 or @@At2 commands,
+ * and it must be a GT/GT+/SL with no position hold mode.
+ * We will have to do it ourselves.
+ * (b) We saw the @@At0, @@At2 commands, but @@At2 failed,
+ * must be a VP or older UT which doesn't have Site Survey mode.
+ * We will have to do it ourselves.
+ * 12chan
+ * (c) We saw the @@Gd command, but @@Gd3 failed,
+ * 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);
- /* 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...
- */
+ record_clock_stats(&(instance->peer->srcadr), "SSstate = ONCORE_SS_SW");
+ instance->site_survey = ONCORE_SS_SW;
- if (instance->count) {
- if (instance->count++ < 5) /* make sure results are stable, using position */
- return;
- instance->count = 0;
+ instance->ss_lat = instance->ss_long = instance->ss_ht = 0;
+ if (instance->chan == 12)
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* disable */
+ else {
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_At0, sizeof(oncore_cmd_At0)); /* disable */
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); /* disable */
+ }
+ }
+ }
}
- if (instance->o_state != ONCORE_ALMANAC && instance->o_state != ONCORE_RUN)
- return;
-
- Len = len+3; /* message length @@ -> CR,LF */
- memcpy(instance->Ea, buf, Len); /* Ba, Ea or Ha */
+ /* check the mode we are in 0/2/3D */
- if (buf[2] == 'B') { /* 6chan */
- if (instance->Ea[64]&0x8)
+ if (instance->chan == 6) {
+ if (instance->BEHa[64]&0x8)
instance->mode = MODE_0D;
- else if (instance->Ea[64]&0x10)
+ else if (instance->BEHa[64]&0x10)
instance->mode = MODE_2D;
- else if (instance->Ea[64]&0x20)
+ else if (instance->BEHa[64]&0x20)
instance->mode = MODE_3D;
- } else if (buf[2] == 'E') { /* 8chan */
- if (instance->Ea[72]&0x8)
+ } else if (instance->chan == 8) {
+ if (instance->BEHa[72]&0x8)
instance->mode = MODE_0D;
- else if (instance->Ea[72]&0x10)
+ else if (instance->BEHa[72]&0x10)
instance->mode = MODE_2D;
- else if (instance->Ea[72]&0x20)
+ else if (instance->BEHa[72]&0x20)
instance->mode = MODE_3D;
- } else if (buf[2] == 'H') { /* 12chan */
+ } else if (instance->chan == 12) {
int bits;
- bits = (instance->Ea[129]>>5) & 0x7; /* actually Ha */
+ bits = (instance->BEHa[129]>>5) & 0x7; /* actually Ha */
if (bits == 0x4)
instance->mode = MODE_0D;
else if (bits == 0x6)
@@ -1912,131 +2157,36 @@ oncore_msg_BaEaHa(
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);
- }
-
- /* 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 */
- }
+ /* copy the record to the (extra) location in SHMEM */
if (instance->shmem) {
int i;
+ u_char *smp; /* pointer to start of shared mem for Ba/Ea/Ha */
- 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);
+ switch(instance->chan) {
+ case 6: smp = &instance->shmem[instance->shmem_Ba]; break;
+ case 8: smp = &instance->shmem[instance->shmem_Ea]; break;
+ case 12: smp = &instance->shmem[instance->shmem_Ha]; break;
+ default: smp = (u_char) 0; break;
}
- }
- /* Almanac mode, waiting for Almanac, cant do anything till we have it */
- /* When we have an almanac, start the En/Bn messages */
+ switch (instance->mode) {
+ case MODE_0D: i = 1; break; /* 0D, Position Hold */
+ case MODE_2D: i = 2; break; /* 2D, Altitude Hold */
+ case MODE_3D: i = 3; break; /* 3D fix */
+ default: i = 0; break;
+ }
- if (instance->o_state == ONCORE_ALMANAC) {
- if (instance->rsm.bad_almanac) {
- if (debug)
- printf("ONCORE: waiting for almanac\n");
- return;
- } 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);
+ if (i) {
+ i *= (len+6);
+ smp[i + 2]++;
+ memcpy(&smp[i+3], buf, (size_t) (len+3));
}
}
/*
* check if timer active
- * if it hasnt been cleared, then @@En/@@Bn did not respond
+ * if it hasn't been cleared, then @@Bn/@@En/@@Hn did not respond
*/
if (instance->traim_delay) {
@@ -2045,175 +2195,135 @@ fprintf(stderr, "ONCORE: DEBUG BITS: (%x %x), (%x %x), %x %x %x %x %x\n",
instance->traim_delay = 0;
cp = "ONCORE: Did not detect TRAIM response, TRAIM = OFF";
record_clock_stats(&(instance->peer->srcadr), cp);
- }
+
+ oncore_set_traim(instance);
+ } else
+ return;
+
}
+ /* by now should have a @@Ba/@@Ea/@@Ha with good data in it */
+
+ if (!instance->have_dH && !instance->traim_delay)
+ oncore_compute_dH(instance);
+
/*
* must be ONCORE_RUN if we are here.
+ * Have # chan and TRAIM by now.
*/
- 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->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.
+ * Are we doing a Hardware or Software Site Survey?
*/
- if ((instance->site_survey == ONCORE_SS_HW) && !(instance->Ea[37] & 0x20)) {
- record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode");
- instance->site_survey = ONCORE_SS_DONE;
- }
+ if (instance->site_survey == ONCORE_SS_HW || instance->site_survey == ONCORE_SS_SW)
+ oncore_ss(instance);
- 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);
+ /* see if we ever saw a response from the @@Ayx above */
- /* Read back PPS Offset for Output */
- /* Nb. This will fail silently for early UT (no plus) and M12 models */
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Ayx, sizeof(oncore_cmd_Ayx));
+ if (instance->count2) {
+ if (instance->count2++ > 5) { /* this delay to check on @@Ay command */
+ instance->count2 = 0;
- /* Read back Cable Delay for Output */
- oncore_sendmsg(instance->ttyfd, oncore_cmd_Azx, sizeof(oncore_cmd_Azx));
+ /* Have we seen an Ay (1PPS time offset) command response */
+ /* if not, and non-zero offset, zero the offset, and send message */
+
+ if (!instance->saw_Ay && instance->offset) {
+ cp = "No @@Ay command, PPS OFFSET ignored";
+ record_clock_stats(&(instance->peer->srcadr), cp);
+ instance->offset = 0;
+ }
+ }
}
/*
* 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));
- }
- }
+ oncore_check_leap_sec(instance);
/*
* if SHMEM active, every 15s, steal one 'tick' to get 2D or 3D posn.
*/
- 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));
- }
- }
- }
+ if (instance->shmem && !instance->shmem_bad_Ea && instance->shmem_Posn && (instance->site_survey == ONCORE_SS_DONE))
+ oncore_shmem_get_3D(instance);
- if (instance->traim == 0) /* NO traim, go get tick */
+ if (!instance->traim) /* NO traim, no BnEnHn, 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.
- */
-
- if (instance->rsm.bad_fix) /* Not if poor geometry or less than 3 sats */
- return;
- 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 ellipsoid */
- instance->ss_count++;
+/* Almanac Status */
- if (instance->ss_count != POS_HOLD_AVERAGE)
- return;
-
- instance->ss_lat /= POS_HOLD_AVERAGE;
- instance->ss_long /= POS_HOLD_AVERAGE;
- instance->ss_ht /= POS_HOLD_AVERAGE;
+static void
+oncore_msg_Bd(
+ struct instance *instance,
+ u_char *buf,
+ size_t len
+ )
+{
+ char Msg[160];
- sprintf(Msg, "Surveyed posn: lat %.3f long %.3f ht %.3f",
- instance->ss_lat, instance->ss_long, instance->ss_ht);
+ sprintf(Msg, "Bd: Almanac %s, week = %d, t = %d, %d SVs: %x",
+ ((buf[4]) ? "LOADED" : "(NONE)"), buf[5], buf[6], buf[7], w32(&buf[8]) );
record_clock_stats(&(instance->peer->srcadr), Msg);
+}
- /* 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 */
+/* get leap-second warning message */
- 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));
+/*
+ * @@Bj does NOT behave as documented in current Oncore firmware.
+ * It turns on the LEAP indicator when the data is set, and does not,
+ * as documented, wait until the beginning of the month when the
+ * leap second will occur.
+ * Since this firmware bug will never be fixed in all the outstanding Oncore receivers
+ * @@Bj is only called in June/December.
+ */
- /* and set Position Hold */
+static void
+oncore_msg_Bj(
+ struct instance *instance,
+ u_char *buf,
+ size_t len
+ )
+{
+ const char *cp;
- 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));
+ switch(buf[4]) {
+ case 1:
+ instance->peer->leap = LEAP_ADDSECOND;
+ cp = "Set peer.leap to LEAP_ADDSECOND";
+ break;
+ case 2:
+ instance->peer->leap = LEAP_DELSECOND;
+ cp = "Set peer.leap to LEAP_DELSECOND";
+ break;
+ case 0:
+ default:
+ instance->peer->leap = LEAP_NOWARNING;
+ cp = "Set peer.leap to LEAP_NOWARNING";
+ break;
}
-
- record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode");
- instance->site_survey = ONCORE_SS_DONE;
+ record_clock_stats(&(instance->peer->srcadr), cp);
}
static void
-oncore_msg_BnEn(
+oncore_msg_BnEnHn(
struct instance *instance,
u_char *buf,
- size_t len
+ size_t len
)
{
long dt1, dt2;
@@ -2222,385 +2332,570 @@ oncore_msg_BnEn(
if (instance->o_state != ONCORE_RUN)
return;
- if (instance->traim_delay) { /* flag that @@En/@@Bn returned */
- instance->traim = 1;
+ if (instance->traim_delay) { /* flag that @@Bn/@@En/Hn returned */
+ instance->traim_ck = 1;
instance->traim_delay = 0;
cp = "ONCORE: Detected TRAIM, TRAIM = ON";
record_clock_stats(&(instance->peer->srcadr), cp);
+
+ oncore_set_traim(instance);
}
- memcpy(instance->En, buf, len); /* En or Bn */
+ memcpy(instance->BEHn, buf, (size_t) len); /* Bn or En or Hn */
/* If Time RAIM doesn't like it, don't trust it */
- if (instance->En[21])
- return;
+ if (buf[2] == 'H') {
+ if (instance->BEHn[6]) /* bad TRAIM */
+ 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 */
+ dt1 = instance->saw_tooth + instance->offset; /* dt this time step */
+ instance->saw_tooth = (s_char) instance->BEHn[10]; /* update for next time Hn[10] */
+ dt2 = instance->saw_tooth + instance->offset; /* dt next time step */
+ } else {
+ if (instance->BEHn[21]) /* bad TRAIM */
+ return;
+
+ dt1 = instance->saw_tooth + instance->offset; /* dt this time step */
+ instance->saw_tooth = (s_char) instance->BEHn[25]; /* update for next time */
+ dt2 = instance->saw_tooth + instance->offset; /* dt next time step */
+ }
oncore_get_timestamp(instance, dt1, dt2);
}
+/* Here for @@Ca, @@Fa and @@Ia messages */
+
+/* These are Self test Commands for 6, 8, and 12 chan receivers.
+ * There are good reasons NOT to do a @@Ca, @@Fa or @@Ia command with the ONCORE.
+ * 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 wasteful, and may cause trouble for some OS's, repeating
+ * itimer, we set a flag, and test it at the next POLL. If it hasn't
+ * 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_get_timestamp(
+oncore_msg_CaFaIa(
struct instance *instance,
- long dt1, /* tick offset THIS time step */
- long dt2 /* tick offset NEXT time step */
+ u_char *buf,
+ size_t len
)
{
- int Rsm;
- u_long i, j;
- l_fp ts, ts_tmp;
- double dmy;
-#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 */
-#ifdef HAVE_CIOGETEV
- struct ppsclockev ev;
- int r = CIOGETEV;
-#endif
-#ifdef HAVE_TIOCGPPSEV
- struct ppsclockev ev;
- int r = TIOCGPPSEV;
-#endif
-#if TIOCDCDTIMESTAMP
- struct timeval tv;
-#endif
-#endif /* ! HAVE_PPS_API */
-
- if ((instance->site_survey == ONCORE_SS_DONE) && (instance->mode != MODE_0D))
- return;
-
- /* Don't do anything without an almanac to define the GPS->UTC delta */
-
- if (instance->rsm.bad_almanac)
- return;
+ char *cp;
+ int i;
-#ifdef HAVE_PPSAPI
- j = instance->ev_serial;
- timeout.tv_sec = 0;
- timeout.tv_nsec = 0;
- if (time_pps_fetch(instance->pps_h, PPS_TSFMT_TSPEC, &pps_i,
- &timeout) < 0) {
- printf("ONCORE: time_pps_fetch failed\n");
- return;
- }
+ if (instance->o_state == ONCORE_TEST_SENT) {
+ enum antenna_state antenna;
- if (instance->assert) {
- tsp = &pps_i.assert_timestamp;
+ instance->timeout = 0;
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 (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]);
}
- if (pps_i.assert_sequence == j) {
- printf("ONCORE: oncore_get_timestamp, error serial pps\n");
- return;
- }
- instance->ev_serial = pps_i.assert_sequence;
- } else {
- tsp = &pps_i.clear_timestamp;
+ antenna = (buf[4] & 0xc0) >> 6;
+ buf[4] &= ~0xc0;
- 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
- }
+ i = buf[4] || buf[5];
+ if (buf[2] == 'I') i = i || buf[6];
+ if (i) {
+ if (buf[2] == 'I') {
+ msyslog(LOG_ERR, "ONCORE[%d]: self test failed: result %02x %02x %02x",
+ instance->unit, buf[4], buf[5], buf[6]);
+ } else {
+ msyslog(LOG_ERR, "ONCORE[%d]: self test failed: result %02x %02x",
+ instance->unit, buf[4], buf[5]);
+ }
+ cp = "ONCORE: self test failed, shutting down driver";
+ record_clock_stats(&instance->peer->srcadr, cp);
- if (pps_i.clear_sequence == j) {
- printf("ONCORE: oncore_get_timestamp, error serial pps\n");
+ refclock_report(instance->peer, CEVNT_FAULT);
+ oncore_shutdown(instance->unit, instance->peer);
return;
}
- instance->ev_serial = pps_i.clear_sequence;
- }
- /* convert timespec -> ntp l_fp */
+ /* report the current antenna state */
- dmy = tsp->tv_nsec;
- dmy /= 1e9;
- ts.l_uf = dmy * 4294967296.0;
- ts.l_ui = tsp->tv_sec;
-#if 0
- alternate code for previous 4 lines is
- dmy = 1.0e-9*tsp->tv_nsec; /* fractional part */
- DTOLFP(dmy, &ts);
- dmy = tsp->tv_sec; /* integer part */
- DTOLFP(dmy, &ts_tmp);
- L_ADD(&ts, &ts_tmp);
- or more simply
- dmy = 1.0e-9*tsp->tv_nsec; /* fractional part */
- DTOLFP(dmy, &ts);
- ts.l_ui = tsp->tv_sec;
-#endif /* 0 */
-#else
-# if defined(HAVE_TIOCGPPSEV) || defined(HAVE_CIOGETEV)
- j = instance->ev_serial;
- if (ioctl(instance->ppsfd, r, (caddr_t) &ev) < 0) {
- perror("ONCORE: IOCTL:");
- return;
+ oncore_antenna_report(instance, antenna);
+
+ instance->o_state = ONCORE_INIT;
+ cp = "state = ONCORE_INIT";
+ record_clock_stats(&(instance->peer->srcadr), cp);
+
+ instance->timeout = 4;
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
}
+}
- 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_get_timestamp, error serial pps\n");
+/*
+ * Demultiplex the almanac into shmem
+ */
+
+static void
+oncore_msg_Cb(
+ struct instance *instance,
+ u_char *buf,
+ size_t len
+ )
+{
+ int i;
+
+ if (instance->shmem == NULL)
return;
- }
- instance->ev_serial = ev.serial;
- /* convert timeval -> ntp l_fp */
+ if (buf[4] == 5 && buf[5] > 0 && buf[5] < 26)
+ i = buf[5];
+ else if (buf[4] == 4 && buf[5] <= 5)
+ i = buf[5] + 24;
+ else if (buf[4] == 4 && buf[5] <= 10)
+ i = buf[5] + 23;
+ else if (buf[4] == 4 && buf[5] == 25)
+ i = 34;
+ else {
+ char *cp;
- TVTOTS(tsp, &ts);
-# else
-# if defined(TIOCDCDTIMESTAMP)
- if(ioctl(instance->ppsfd, TIOCDCDTIMESTAMP, &tv) < 0) {
- perror("ONCORE: ioctl(TIOCDCDTIMESTAMP)");
+ cp = "Cb: Response is NO ALMANAC";
+ record_clock_stats(&(instance->peer->srcadr), cp);
return;
}
- tsp = &tv;
- TVTOTS(tsp, &ts);
-# else
-#error "Cannot compile -- no PPS mechanism configured!"
-# endif
-# endif
+
+ i *= 36;
+ instance->shmem[instance->shmem_Cb + i + 2]++;
+ memcpy(instance->shmem + instance->shmem_Cb + i + 3, buf, (size_t) (len + 3));
+
+#if 1
+ {
+ char Msg[160];
+ sprintf(Msg, "See Cb [%d,%d]", buf[4], buf[5]);
+ record_clock_stats(&(instance->peer->srcadr), Msg);
+ }
#endif
- /* now have timestamp in ts */
- /* 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. */
- /* offset in ns, and is positive (late), we subtract */
- /* to put the PPS time transition back where it belongs */
-#ifdef HAVE_PPSAPI
- /* 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 */
+/*
+ * Set to Factory Defaults (Reasonable for UT w/ no Battery Backup
+ * not so for VP (eeprom) or any unit with a battery
+ */
- if (instance->assert)
- instance->pps_p.assert_offset.tv_nsec = -dt2;
- else
- instance->pps_p.clear_offset.tv_nsec = -dt2;
+static void
+oncore_msg_Cf(
+ struct instance *instance,
+ u_char *buf,
+ size_t len
+ )
+{
+ const char *cp;
- /* 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 (instance->o_state == ONCORE_RESET_SENT) {
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Return to Posn Fix mode */
+ /* Reset set VP to IDLE */
+ instance->o_state = ONCORE_TEST_SENT;
+ cp = "state = ONCORE_TEST_SENT";
+ record_clock_stats(&(instance->peer->srcadr), cp);
- if (time_pps_getcap(instance->pps_h, &current_mode) < 0) {
- msyslog(LOG_ERR,
- "refclock_ioctl: time_pps_getcap failed: %m");
- return;
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
}
+}
- if (time_pps_getparams(instance->pps_h, &current_params) < 0) {
- msyslog(LOG_ERR,
- "refclock_ioctl: time_pps_getparams failed: %m");
- return;
- }
- /* 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;
+/*
+ * This is the Grand Central Station for the Preliminary Initialization.
+ * Once done here we move on to oncore_msg_BaEaHa for final Initialization and Running.
+ *
+ * We do an @@Cj whenever we need a safe command for all Oncores.
+ * The @@Cj gets us back here where we can switch to the next phase of setup.
+ *
+ * o Once at the very beginning (in start) to get the Model number.
+ * This info is printed, but no longer used.
+ * o Again after we have determined the number of Channels in the receiver.
+ * 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.
+ */
- 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 add the */
- /* offset for THIS second */
+static void
+oncore_msg_Cj(
+ struct instance *instance,
+ u_char *buf,
+ size_t len
+ )
+{
+ int mode;
+ char *cp;
- dmy = -1.0e-9*dt1;
- DTOLFP(dmy, &ts_tmp);
- L_ADD(&ts, &ts_tmp);
-#endif
- /* have time from UNIX origin, convert to NTP origin. */
+ memcpy(instance->Cj, buf, len);
- ts.l_ui += JAN_1970;
- instance->pp->lastrec = ts;
- instance->pp->msec = 0;
+ instance->timeout = 0;
+ if (instance->o_state == ONCORE_CHECK_ID) {
+ oncore_msg_Cj_id(instance, buf, len);
+ oncore_chan_test(instance);
+ } else if (instance->o_state == ONCORE_HAVE_CHAN) {
+ mode = instance->init_type;
+ if (mode == 3 || mode == 4) { /* Cf will return here to check for TEST */
+ instance->o_state = ONCORE_RESET_SENT;
+ cp = "state = ONCORE_RESET_SENT";
+ record_clock_stats(&(instance->peer->srcadr), cp);
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Cf, sizeof(oncore_cmd_Cf));
+ } else {
+ instance->o_state = ONCORE_TEST_SENT;
+ cp = "state = ONCORE_TEST_SENT";
+ record_clock_stats(&(instance->peer->srcadr), cp);
+ }
+ }
- 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 */
+ if (instance->o_state == ONCORE_TEST_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));
+ } else if (instance->o_state == ONCORE_INIT)
+ oncore_msg_Cj_init(instance, buf, len);
+}
- 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 n;
- n = strlen(instance->pp->a_lastcode);
- printf("ONCORE[%d]: len = %d %s\n", instance->unit, n, instance->pp->a_lastcode);
- }
+/* The information on determining 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 didn't give the information out.
+ *
+ * Determine the Type from the Model #, this determines #chan and if TRAIM is
+ * available.
+ *
+ * The Information from this routine is NO LONGER USED.
+ * The RESULTS are PRINTED, BUT NOT USED, and the routine COULD BE DELETED
+ */
- if (!refclock_process(instance->pp)) {
- refclock_report(instance->peer, CEVNT_BADTIME);
- return;
+static void
+oncore_msg_Cj_id(
+ struct instance *instance,
+ u_char *buf,
+ size_t len
+ )
+{
+ char *cp, *cp1, *cp2, Model[21], Msg[160];
+
+ /* Write Receiver ID message to clockstats file */
+
+ instance->Cj[294] = '\0';
+ for (cp=(char *)instance->Cj; cp< (char *) &instance->Cj[294]; ) {
+ cp1 = strchr(cp, '\r');
+ if (!cp1)
+ cp1 = (char *)&instance->Cj[294];
+ *cp1 = '\0';
+ record_clock_stats(&(instance->peer->srcadr), cp);
+ *cp1 = '\r';
+ cp = cp1+2;
}
- record_clock_stats(&(instance->peer->srcadr), instance->pp->a_lastcode);
- instance->pollcnt = 2;
+ /* next, the Firmware Version and Revision numbers */
- if (instance->polled) {
- instance->polled = 0;
-/*
- instance->pp->dispersion = instance->pp->skew = 0;
-*/
- refclock_receive(instance->peer);
+ 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 (Model[0] == 'P') {
+ cp = "M12";
+ instance->model = ONCORE_M12;
+ } else if (Model[0] == 'R' || Model[0] == 'D' || Model[0] == 'S') {
+ 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;
}
+
+ /* use MODEL to set CHAN and TRAIM and possibly zero SHMEM */
+
+ 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);
+
+ instance->chan_id = 8; /* default */
+ if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6)
+ instance->chan_id = 6;
+ else if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || instance->model == ONCORE_UTPLUS)
+ instance->chan_id = 8;
+ else if (instance->model == ONCORE_M12)
+ instance->chan_id = 12;
+
+ instance->traim_id = 0; /* default */
+ if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6)
+ instance->traim_id = 0;
+ else if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || instance->model == ONCORE_UTPLUS)
+ instance->traim_id = 1;
+ else if (instance->model == ONCORE_M12)
+ instance->traim_id = -1;
+
+ sprintf(Msg, "Channels = %d, TRAIM = %s", instance->chan_id,
+ ((instance->traim_id < 0) ? "UNKNOWN" : ((instance->traim_id > 0) ? "ON" : "OFF")));
+ record_clock_stats(&(instance->peer->srcadr), Msg);
}
-/*
- * Try to use Oncore UT+ Auto Survey Feature
- * If its not there (VP), set flag to do it ourselves.
+/* OK, know type of Oncore, have possibly reset it, and have tested it.
+ * We know the number of channels.
+ * We will determine whether we have TRAIM before we actually start.
+ * Now initialize.
*/
static void
-oncore_msg_At(
+oncore_msg_Cj_init(
struct instance *instance,
u_char *buf,
size_t len
)
{
- 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;
+ char *cp, Cmd[20], Msg[160];
+ int mode;
+
+
+ /* The M12 with 1.3 or 2.0 Firmware, loses track of all Satellites and has to
+ * start again if we go from 0D -> 3D, then loses them again when we
+ * go from 3D -> 0D. We do this to get a @@Ea message for SHMEM.
+ * For NOW we will turn this aspect of filling SHMEM off for the M12
+ */
+
+ if (instance->chan == 12) {
+ instance->shmem_bad_Ea = 1;
+ sprintf(Msg, "*** SHMEM partially enabled for ONCORE M12 s/w v%d.%d ***", instance->version, instance->revision);
+ record_clock_stats(&(instance->peer->srcadr), Msg);
+ }
+
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Return to Posn Fix mode */
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Bb, sizeof(oncore_cmd_Bb)); /* turn on for shmem (6/8/12) */
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Ek, sizeof(oncore_cmd_Ek)); /* turn off (VP) */
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Aw, sizeof(oncore_cmd_Aw)); /* UTC time (6/8/12) */
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_AB, sizeof(oncore_cmd_AB)); /* Appl type static (VP) */
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Be, sizeof(oncore_cmd_Be)); /* Tell us the Almanac for shmem (6/8/12) */
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Bd, sizeof(oncore_cmd_Bd)); /* Tell us when Almanac changes */
+
+ mode = instance->init_type;
+
+ /* 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 do Site Survey.
+ */
+
+ if (instance->posn_set) {
+ record_clock_stats(&(instance->peer->srcadr), "Setting Posn from input data");
+ oncore_set_posn(instance); /* this should print posn indirectly thru the As cmd */
+ } else /* must issue an @@At here to check on 6/8 Position Hold, set_posn would have */
+ if (instance->chan != 12)
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Atx, sizeof(oncore_cmd_Atx));
+
+ if (mode != 0) {
+ /* cable delay in ns */
+ memcpy(Cmd, oncore_cmd_Az, (size_t) sizeof(oncore_cmd_Az));
+ w32_buf(&Cmd[-2+4], instance->delay);
+ oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Az)); /* 6,8,12 */
+
+ /* PPS offset in ns */
+ if (instance->offset) {
+ memcpy(Cmd, oncore_cmd_Ay, (size_t) sizeof(oncore_cmd_Ay)); /* some have it, some don't */
+ w32_buf(&Cmd[-2+4], instance->offset); /* will check for hw response */
+ oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ay));
+ }
+
+ /* Satellite mask angle */
+
+ if (instance->Ag != 0xff) { /* will have 0xff in it if not set by user */
+ memcpy(Cmd, oncore_cmd_Ag, (size_t) sizeof(oncore_cmd_Ag));
+ Cmd[-2+4] = instance->Ag;
+ oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ag));
}
}
+
+ /* 6, 8 12 chan - Position/Status/Data Output Message, 1/s
+ * now we're really running
+ * these were ALL started in the chan test,
+ * However, if we had mode=3,4 then commands got turned off, so we turn
+ * them on again here just in case
+ */
+
+ if (instance->chan == 6) { /* start 6chan, kill 8,12chan commands, possibly testing VP in 6chan mode */
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea0, sizeof(oncore_cmd_Ea0));
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_En0, sizeof(oncore_cmd_En0));
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Ha0, sizeof(oncore_cmd_Ha0));
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0));
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Ba, sizeof(oncore_cmd_Ba ));
+ } else if (instance->chan == 8) { /* start 8chan, kill 6,12chan commands */
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Ba0, sizeof(oncore_cmd_Ba0));
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Bn0, sizeof(oncore_cmd_Bn0));
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Ha0, sizeof(oncore_cmd_Ha0));
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0));
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea, sizeof(oncore_cmd_Ea ));
+ } else if (instance->chan == 12){ /* start 12chan, kill 6,12chan commands */
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Ba0, sizeof(oncore_cmd_Ba0));
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Bn0, sizeof(oncore_cmd_Bn0));
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea0, sizeof(oncore_cmd_Ea0));
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_En0, sizeof(oncore_cmd_En0));
+ 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);
}
-/* get leap-second warning message */
+/* 12chan position */
+
+static void
+oncore_msg_Ga(
+ struct instance *instance,
+ u_char *buf,
+ size_t len
+ )
+{
+ char Msg[160];
+ long lat, lon, ht;
+ double Lat, Lon, Ht;
+
+
+ lat = buf_w32(&buf[4]);
+ lon = buf_w32(&buf[8]);
+ ht = buf_w32(&buf[12]); /* GPS ellipsoid */
+
+ Lat = lat;
+ Lon = lon;
+ Ht = ht;
+
+ Lat /= 3600000;
+ Lon /= 3600000;
+ Ht /= 100;
+
+
+ sprintf(Msg, "Ga Posn Lat = %.7f, Lon = %.7f, Ht = %.2f", Lat, Lon, Ht);
+ record_clock_stats(&(instance->peer->srcadr), Msg);
+
+ instance->ss_lat = lat;
+ instance->ss_long = lon;
+ instance->ss_ht = ht;
+
+ oncore_print_posn(instance);
+}
+
+
+
+/* 12 chan time/date */
+
+static void
+oncore_msg_Gb(
+ struct instance *instance,
+ u_char *buf,
+ size_t len
+ )
+{
+ char Msg[160], *gmts;
+ int mo, d, y, h, m, s, gmth, gmtm;
+
+ mo = buf[4];
+ d = buf[5];
+ y = 256*buf[6]+buf[7];
+
+ h = buf[8];
+ m = buf[9];
+ s = buf[10];
+
+ gmts = ((buf[11] == 0) ? "+" : "-");
+ gmth = buf[12];
+ gmtm = buf[13];
+
+ sprintf(Msg, "Date/Time set to: %d%s%d %2d:%02d:%02d GMT (GMT offset is %s%02d:%02d)",
+ d, Month[mo+1], y, h, m, s, gmts, gmth, gmtm);
+ record_clock_stats(&(instance->peer->srcadr), Msg);
+}
+
+
/*
- * @@Bj does NOT behave as documented in current Oncore firmware.
- * It turns on the LEAP indicator when the data is set, and does not,
- * as documented, wait until the beginning of the month when the
- * leap second will occur.
- * Until this firmware bug is fixed, @@Bj is only called in June/December.
+ * Try to use Oncore M12+Timing Auto Survey Feature
+ * If its not there (M12), set flag to do it ourselves.
*/
static void
-oncore_msg_Bj(
+oncore_msg_Gd(
struct instance *instance,
u_char *buf,
size_t len
)
{
- const char *cp;
+ char *cp;
- switch(buf[4]) {
- case 1:
- instance->peer->leap = LEAP_ADDSECOND;
- cp = "Set peer.leap to LEAP_ADDSECOND";
- break;
- case 2:
- instance->peer->leap = LEAP_DELSECOND;
- cp = "Set peer.leap to LEAP_DELSECOND";
- break;
- case 0:
- default:
- instance->peer->leap = LEAP_NOWARNING;
- cp = "Set peer.leap to LEAP_NOWARNING";
- break;
+ if (instance->site_survey == ONCORE_SS_TESTING) {
+ if (buf[4] == 3) {
+ record_clock_stats(&(instance->peer->srcadr),
+ "Initiating hardware 3D site survey");
+
+ cp = "SSstate = ONCORE_SS_HW";
+ record_clock_stats(&(instance->peer->srcadr), cp);
+ instance->site_survey = ONCORE_SS_HW;
+ }
}
- record_clock_stats(&(instance->peer->srcadr), cp);
}
+
+
/* Leap Second for M12, gives all info from satellite message */
+/* also in UT v3.0 */
static void
oncore_msg_Gj(
@@ -2611,8 +2906,8 @@ oncore_msg_Gj(
{
int dt;
char Msg[160], *cp;
- static char *Month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jly",
- "Aug", "Sep", "Oct", "Nov", "Dec" };
+
+ instance->saw_Gj = 1; /* flag, saw_Gj, dont need to try Bj in check_leap */
/* print the message to verify whats there */
@@ -2639,8 +2934,8 @@ oncore_msg_Gj(
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 (buf[6] == instance->BEHa[6] && buf[7] == instance->BEHa[7] && /* year */
+ buf[8] == instance->BEHa[4]) { /* month */
if (dt) {
if (dt < 0) {
instance->peer->leap = LEAP_DELSECOND;
@@ -2656,34 +2951,426 @@ oncore_msg_Gj(
-/*
- * get Position hold position
- */
+/* Power on failure */
static void
-oncore_msg_As(
+oncore_msg_Sz(
struct instance *instance,
u_char *buf,
size_t len
)
{
- if (!instance->printed || instance->As)
+ 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);
+ }
+}
+
+/************** Small Subroutines ***************/
+
+
+static void
+oncore_antenna_report(
+ struct instance *instance,
+ enum antenna_state new_state)
+{
+ char *cp;
+
+ if (instance->ant_state == new_state)
return;
- instance->As = 1;
+ switch (new_state) {
+ case ONCORE_ANTENNA_OK: cp = "GPS antenna: OK"; break;
+ case ONCORE_ANTENNA_OC: cp = "GPS antenna: short (overcurrent)"; break;
+ case ONCORE_ANTENNA_UC: cp = "GPS antenna: open (not connected)"; break;
+ case ONCORE_ANTENNA_NV: cp = "GPS antenna: short (no voltage)"; break;
+ default: cp = "GPS antenna: ?"; break;
+ }
- instance->ss_lat = buf_w32(&buf[4]);
- instance->ss_long = buf_w32(&buf[8]);
- instance->ss_ht = buf_w32(&buf[12]);
+ instance->ant_state = new_state;
+ record_clock_stats(&instance->peer->srcadr, cp);
+}
- /* Print out Position */
- oncore_print_As(instance);
+
+
+static void
+oncore_chan_test(
+ struct instance *instance
+ )
+{
+ char *cp;
+
+ /* subroutine oncore_Cj_id has determined the number of channels from the
+ * model number of the attached oncore. This is not always correct since
+ * the oncore could have non-standard firmware. Here we check (independently) by
+ * trying a 6, 8, and 12 chan command, and see which responds.
+ * Caution: more than one CAN respond.
+ *
+ * This #chan is used by the code rather than that calculated from the model number.
+ */
+
+ instance->o_state = ONCORE_CHECK_CHAN;
+ cp = "state = ONCORE_CHECK_CHAN";
+ record_clock_stats(&(instance->peer->srcadr), cp);
+
+ instance->count3 = 1;
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Ba, sizeof(oncore_cmd_Ba));
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea, sizeof(oncore_cmd_Ea));
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Ha, sizeof(oncore_cmd_Ha));
+}
+
+
+
+/* check for a GOOD Almanac, have we got one yet? */
+
+static void
+oncore_check_almanac(
+ struct instance *instance
+ )
+{
+ if (instance->chan == 6) {
+ instance->rsm.bad_almanac = instance->BEHa[64]&0x1;
+ instance->rsm.bad_fix = instance->BEHa[64]&0x52;
+ } else if (instance->chan == 8) {
+ instance->rsm.bad_almanac = instance->BEHa[72]&0x1;
+ instance->rsm.bad_fix = instance->BEHa[72]&0x52;
+ } else if (instance->chan == 12) {
+ int bits1, bits2;
+
+ bits1 = (instance->BEHa[129]>>5) & 0x7; /* actually Ha */
+ bits2 = instance->BEHa[130];
+ instance->rsm.bad_almanac = (bits2 & 0x80);
+ instance->rsm.bad_fix = (bits2 & 0x8) || (bits1 == 0x2);
+ /* too few sat Bad Geom */
+#if 0
+ fprintf(stderr, "ONCORE[%d]: DEBUG BITS: (%x %x), (%x %x), %x %x %x %x %x\n",
+ instance->unit,
+ instance->BEHa[129], instance->BEHa[130], bits1, bits2, instance->mode == MODE_0D,
+ instance->mode == MODE_2D, instance->mode == MODE_3D,
+ instance->rsm.bad_almanac, instance->rsm.bad_fix);
+#endif
+ }
+}
+
+
+
+/* check the antenna for changes (did it get unplugged?) */
+
+static void
+oncore_check_antenna(
+ struct instance *instance
+ )
+{
+ enum antenna_state antenna; /* antenna state */
+
+ antenna = instance->ant_state;
+ if (instance->chan == 12)
+ antenna = (instance->BEHa[130] & 0x6 ) >> 1;
+ else
+ antenna = (instance->BEHa[37] & 0xc0) >> 6; /* prob unset 6, set GT, UT unset VP */
+
+ oncore_antenna_report (instance, antenna);
+}
+
+
+
+/*
+ * Check the leap second status once per day.
+ *
+ * Note that the ONCORE firmware for the Bj command is wrong at
+ * least in the VP.
+ * It starts advertising a LEAP SECOND as soon as the GPS satellite
+ * data message (page 18, subframe 4) is updated to a date in the
+ * future, and does not wait for the month that it will occur.
+ * The event will usually be advertised several months in advance.
+ * Since there is a one bit flag, there is no way to tell if it is
+ * this month, or when...
+ *
+ * As such, we have the workaround below, of only checking for leap
+ * seconds with the Bj command in June/December.
+ *
+ * The Gj command gives more information, and we can tell in which
+ * month to apply the correction.
+ *
+ * Note that with the VP we COULD read the raw data message, and
+ * interpret it ourselves, but since this is specific to this receiver
+ * only, and the above workaround is adequate, we don't bother.
+ */
+
+static void
+oncore_check_leap_sec(
+ struct instance *instance
+ )
+{
+ if (instance->Bj_day != instance->BEHa[5]) { /* do this 1/day */
+ instance->Bj_day = instance->BEHa[5];
+
+ if (instance->saw_Gj < 0) { /* -1 DONT have Gj use Bj */
+ if ((instance->BEHa[4] == 6) || (instance->BEHa[4] == 12))
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Bj, sizeof(oncore_cmd_Bj));
+ return;
+ }
+
+ if (instance->saw_Gj == 0) /* 0 is dont know if we have Gj */
+ instance->count4 = 1;
+
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Gj, sizeof(oncore_cmd_Gj));
+ return;
+ }
+
+ /* Gj works for some 6/8 chan UT and the M12 */
+ /* if no response from Gj in 5 sec, we try Bj */
+ /* which isnt implemented in all the GT/UT either */
+
+ if (instance->count4) { /* delay, waiting for Gj response */
+ if (instance->saw_Gj == 1)
+ instance->count4 = 0;
+ else if (instance->count4++ > 5) { /* delay, waiting for Gj response */
+ instance->saw_Gj = -1; /* didnt see it, will use Bj */
+ instance->count4 = 0;
+ if ((instance->BEHa[4] == 6) || (instance->BEHa[4] == 12))
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Bj, sizeof(oncore_cmd_Bj));
+ }
+ }
+}
+
+
+
+/* check the message checksum,
+ * buf points to START of message ( @@ )
+ * len is length WITH CR/LF.
+ */
+
+static int
+oncore_checksum_ok(
+ u_char *buf,
+ int len
+ )
+{
+ int i, j;
+
+ j = 0;
+ for (i = 2; i < len-3; i++)
+ j ^= buf[i];
+
+ return(j == buf[len-3]);
+}
+
+
+
+static void
+oncore_compute_dH(
+ struct instance *instance
+ )
+{
+ int GPS, MSL;
+ char Msg[160];
+
+ /* Here calculate dH = GPS - MSL for output message */
+ /* also set Altitude Hold mode if GT */
+
+ instance->have_dH = 1;
+ if (instance->chan == 12) {
+ GPS = buf_w32(&instance->BEHa[39]);
+ MSL = buf_w32(&instance->BEHa[43]);
+ } else {
+ GPS = buf_w32(&instance->BEHa[23]);
+ MSL = buf_w32(&instance->BEHa[27]);
+ }
+ instance->dH = GPS - MSL;
+ instance->dH /= 100.;
+
+ /* if MSL is not set, the calculation is meaningless */
+
+ if (MSL) { /* not set ! */
+ sprintf(Msg, "dH = (GPS - MSL) = %.2fm", instance->dH);
+ record_clock_stats(&(instance->peer->srcadr), Msg);
+ }
+}
+
+
+
+/*
+ * try loading Almanac from shmem (where it was copied from shmem_old
+ */
+
+static void
+oncore_load_almanac(
+ struct instance *instance
+ )
+{
+ u_char *cp, Cmd[20];
+ int n;
+ struct timeval tv;
+ struct tm *tm;
+
+ if (!instance->shmem)
+ return;
+
+#if 1
+ for (cp=instance->shmem+4; (n = 256*(*(cp-3)) + *(cp-2)); cp+=(n+3)) {
+ if (!strncmp(cp, "@@Cb", 4) &&
+ oncore_checksum_ok(cp, 33) &&
+ (*(cp+4) == 4 || *(cp+4) == 5)) {
+ write(instance->ttyfd, cp, n);
+#if 1
+ oncore_print_Cb(instance, cp);
+#endif
+ }
+ }
+#else
+/************DEBUG************/
+ for (cp=instance->shmem+4; (n = 256*(*(cp-3)) + *(cp-2)); cp+=(n+3)) {
+ char Msg[160];
+
+ sprintf(Msg, "See %c%c%c%c %d", *(cp), *(cp+1), *(cp+2), *(cp+3), *(cp+4));
+ record_clock_stats(&(instance->peer->srcadr), Msg);
+
+ if (!strncmp(cp, "@@Cb", 4)) {
+ oncore_print_Cb(instance, cp);
+ if (oncore_checksum_ok(cp, 33)) {
+ if (*(cp+4) == 4 || *(cp+4) == 5) {
+ record_clock_stats(&(instance->peer->srcadr), "GOOD SF");
+ write(instance->ttyfd, cp, n);
+ } else
+ record_clock_stats(&(instance->peer->srcadr), "BAD SF");
+ } else
+ record_clock_stats(&(instance->peer->srcadr), "BAD CHECKSUM");
+ }
+ }
+/************DEBUG************/
+#endif
+
+ /* Must load position and time or the Almanac doesn't do us any good */
+
+ if (!instance->posn_set) { /* if we input a posn use it, else from SHMEM */
+ record_clock_stats(&(instance->peer->srcadr), "Loading Posn from SHMEM");
+ for (cp=instance->shmem+4; (n = 256*(*(cp-3)) + *(cp-2)); cp+=(n+3)) {
+ if ((instance->chan == 6 && (!strncmp(cp, "@@Ba", 4) && oncore_checksum_ok(cp, 68))) ||
+ (instance->chan == 8 && (!strncmp(cp, "@@Ea", 4) && oncore_checksum_ok(cp, 76))) ||
+ (instance->chan == 12 && (!strncmp(cp, "@@Ha", 4) && oncore_checksum_ok(cp, 154)))) {
+ int ii, jj, kk;
+
+ instance->posn_set = 1;
+ ii = buf_w32(cp + 15);
+ jj = buf_w32(cp + 19);
+ kk = buf_w32(cp + 23);
+{
+char Msg[160];
+sprintf(Msg, "SHMEM posn = %d (%d, %d, %d)", cp-instance->shmem, ii, jj, kk);
+record_clock_stats(&(instance->peer->srcadr), Msg);
+}
+ if (ii != 0 || jj != 0 || kk != 0) { /* phk asked for this test */
+ instance->ss_lat = ii;
+ instance->ss_long = jj;
+ instance->ss_ht = kk;
+ }
+ }
+ }
+ }
+ oncore_set_posn(instance);
+
+ /* and set time to time from Computer clock */
+
+ gettimeofday(&tv, 0);
+ tm = gmtime((const time_t *) &tv.tv_sec);
+#if 1
+ {
+ char Msg[160];
+ sprintf(Msg, "DATE %d %d %d, %d %d %d", 1900+tm->tm_year, tm->tm_mon, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+ record_clock_stats(&(instance->peer->srcadr), Msg);
+ }
+#endif
+ if (instance->chan == 12) {
+ memcpy(Cmd, oncore_cmd_Gb, (size_t) sizeof(oncore_cmd_Gb));
+ Cmd[-2+4] = tm->tm_mon;
+ Cmd[-2+5] = tm->tm_mday;
+ Cmd[-2+6] = (1900+tm->tm_year)/256;
+ Cmd[-2+7] = (1900+tm->tm_year)%256;
+ Cmd[-2+8] = tm->tm_hour;
+ Cmd[-2+9] = tm->tm_min;
+ Cmd[-2+10] = tm->tm_sec;
+ Cmd[-2+11] = 0;
+ Cmd[-2+12] = 0;
+ Cmd[-2+13] = 0;
+ oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Gb));
+ } else {
+ /* First set GMT offset to zero */
+
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Ab, sizeof(oncore_cmd_Ab));
+
+ memcpy(Cmd, oncore_cmd_Ac, (size_t) sizeof(oncore_cmd_Ac));
+ Cmd[-2+4] = tm->tm_mon;
+ Cmd[-2+5] = tm->tm_mday;
+ Cmd[-2+6] = (1900+tm->tm_year)/256;
+ Cmd[-2+7] = (1900+tm->tm_year)%256;
+ oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ac));
+
+ memcpy(Cmd, oncore_cmd_Aa, (size_t) sizeof(oncore_cmd_Aa));
+ Cmd[-2+4] = tm->tm_hour;
+ Cmd[-2+5] = tm->tm_min;
+ Cmd[-2+6] = tm->tm_sec;
+ oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Aa));
+ }
+
+ record_clock_stats(&(instance->peer->srcadr), "Setting Posn and Time after Loading Almanac");
}
+/* Almanac data input */
+
static void
-oncore_print_As(
+oncore_print_Cb(
+ struct instance *instance,
+ u_char *cp
+ )
+{
+#if 0
+ int ii;
+ char Msg[160];
+
+ printf("DEBUG: See: %c%c%c%c\n", *(cp), *(cp+1), *(cp+2), *(cp+3));
+ printf("DEBUG: Cb: [%d,%d]", *(cp+4), *(cp+5));
+ for(ii=0; ii<33; ii++)
+ printf(" %d", *(cp+ii));
+ printf("\n");
+
+ sprintf(Msg, "Debug: Cb: [%d,%d]", *(cp+4), *(cp+5));
+ record_clock_stats(&(instance->peer->srcadr), Msg);
+#endif
+}
+
+
+#if 0
+static void
+oncore_print_array(
+ u_char *cp,
+ int n
+ )
+{
+ int jj, i, j, nn;
+
+ nn = 0;
+ printf("\nTOP\n");
+ jj = n/16;
+ for (j=0; j<jj; j++) {
+ printf("%4d: ", nn);
+ nn += 16;
+ for (i=0; i<16; i++)
+ printf(" %o", *cp++);
+ printf("\n");
+ }
+}
+#endif
+
+
+static void
+oncore_print_posn(
struct instance *instance
)
{
@@ -2721,7 +3408,8 @@ oncore_print_As(
imy = lon%3600000;
xm = imx/60000.;
ym = imy/60000.;
- 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);
+ 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;
@@ -2730,79 +3418,306 @@ oncore_print_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 = %7.2fm (%7.2fft) GPS", ns, idx, imx, xs, ew, idy, imy, ys, hm, hft);
+ 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);
}
/*
- * get PPS Offset
- * Nb. @@Ay is not supported for early UT (no plus) model
+ * write message to Oncore.
*/
static void
-oncore_msg_Ay(
- struct instance *instance,
- u_char *buf,
+oncore_sendmsg(
+ int fd,
+ u_char *ptr,
size_t len
)
{
- char Msg[120];
+ u_char cs = 0;
- if (!instance->printed || instance->Ay)
- return;
+ if (debug > 4)
+ 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, (size_t) 1);
+ write(fd, "\r\n", (size_t) 2);
+}
- instance->Ay = 1;
- instance->offset = buf_w32(&buf[4]);
- sprintf(Msg, "PPS Offset is set to %ld ns", instance->offset);
+static void
+oncore_set_posn(
+ struct instance *instance
+ )
+{
+ int mode;
+ char Cmd[20];
+
+ /* 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)); /* (12) */
+ else {
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_At0, sizeof(oncore_cmd_At0)); /* (6/8) */
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); /* (6/8) */
+ }
+
+ mode = instance->init_type;
+
+ if (mode != 0) { /* first set posn hold position */
+ memcpy(Cmd, oncore_cmd_As, (size_t) sizeof(oncore_cmd_As)); /* don't modify static variables */
+ w32_buf(&Cmd[-2+4], (int) instance->ss_lat);
+ w32_buf(&Cmd[-2+8], (int) instance->ss_long);
+ w32_buf(&Cmd[-2+12], (int) instance->ss_ht);
+ Cmd[-2+16] = 0;
+ oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_As)); /* posn hold 3D posn (6/8/12) */
+
+ memcpy(Cmd, oncore_cmd_Au, (size_t) sizeof(oncore_cmd_Au));
+ w32_buf(&Cmd[-2+4], (int) instance->ss_ht);
+ Cmd[-2+8] = 0;
+ oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Au)); /* altitude hold (6/8/12 not UT, M12T) */
+
+ /* next set current position */
+
+ if (instance->chan == 12) {
+ memcpy(Cmd, oncore_cmd_Ga, (size_t) sizeof(oncore_cmd_Ga));
+ w32_buf(&Cmd[-2+4], (int) instance->ss_lat);
+ w32_buf(&Cmd[-2+8], (int) instance->ss_long);
+ w32_buf(&Cmd[-2+12],(int) instance->ss_ht);
+ Cmd[-2+16] = 0;
+ oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ga)); /* 3d posn (12) */
+ } else {
+ memcpy(Cmd, oncore_cmd_Ad, (size_t) sizeof(oncore_cmd_Ad));
+ w32_buf(&Cmd[-2+4], (int) instance->ss_lat);
+ oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ad)); /* lat (6/8) */
+
+ memcpy(Cmd, oncore_cmd_Ae, (size_t) sizeof(oncore_cmd_Ae));
+ w32_buf(&Cmd[-2+4], (int) instance->ss_long);
+ oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ae)); /* long (6/8) */
+
+ memcpy(Cmd, oncore_cmd_Af, (size_t) sizeof(oncore_cmd_Af));
+ w32_buf(&Cmd[-2+4], (int) instance->ss_ht);
+ Cmd[-2+8] = 0;
+ oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Af)); /* ht (6/8) */
+ }
+
+ /* Finally, turn on position hold */
+
+ if (instance->chan == 12)
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd1, sizeof(oncore_cmd_Gd1));
+ else
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_At1, sizeof(oncore_cmd_At1));
+ }
+}
+
+
+
+static void
+oncore_set_traim(
+ struct instance *instance
+ )
+{
+ char Msg[160];
+
+ if (instance->traim_in != -1) /* set in Input */
+ instance->traim = instance->traim_in;
+ else
+ instance->traim = instance->traim_ck;
+
+ sprintf(Msg, "Input says TRAIM = %d", instance->traim_in);
+ record_clock_stats(&(instance->peer->srcadr), Msg);
+ sprintf(Msg, "Model # says TRAIM = %d", instance->traim_id);
+ record_clock_stats(&(instance->peer->srcadr), Msg);
+ sprintf(Msg, "Testing says TRAIM = %d", instance->traim_ck);
record_clock_stats(&(instance->peer->srcadr), Msg);
+ sprintf(Msg, "Using TRAIM = %d", instance->traim);
+ record_clock_stats(&(instance->peer->srcadr), Msg);
+
+ if (instance->traim_ck == 1 && instance->traim == 0) {
+ /* if it should be off, and I turned it on during testing,
+ then turn it off again */
+ if (instance->chan == 6)
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Bnx, sizeof(oncore_cmd_Bnx));
+ else if (instance->chan == 8)
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Enx, sizeof(oncore_cmd_Enx));
+ else /* chan == 12 */
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Ge0, sizeof(oncore_cmd_Ge0));
+ }
}
/*
- * get Cable Delay
+ * if SHMEM active, every 15s, steal one 'tick' to get 2D or 3D posn.
*/
static void
-oncore_msg_Az(
- struct instance *instance,
- u_char *buf,
- size_t len
+oncore_shmem_get_3D(
+ struct instance *instance
)
{
- char Msg[120];
-
- if (!instance->printed || instance->Az)
- return;
+ if (instance->pp->second%15 == 3) { /* start the sequence */ /* by changing mode */
+ 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) { /* out of 0D -> 3D mode */
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_At0, sizeof(oncore_cmd_At0));
+ if (instance->shmem_Posn == 2) /* 3D -> 2D mode */
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1));
+ } 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) /* 2D -> 3D or 0D mode */
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0));
+ 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->Az = 1;
- instance->delay = buf_w32(&buf[4]);
- sprintf(Msg, "Cable delay is set to %ld ns", instance->delay);
- record_clock_stats(&(instance->peer->srcadr), Msg);
-}
+/*
+ * Here we do the Software SiteSurvey.
+ * We have to average our own position for the Position Hold Mode
+ * We use Heights from the GPS ellipsoid.
+ * We check for the END of either HW or SW SiteSurvey.
+ */
static void
-oncore_msg_Sz(
- struct instance *instance,
- u_char *buf,
- size_t len
+oncore_ss(
+ struct instance *instance
)
{
- const char *cp;
+ char *cp, Msg[160];
+ double lat, lon, ht;
- cp = "Oncore: System Failure at Power On";
- if (instance && instance->peer) {
+
+ if (instance->site_survey == ONCORE_SS_HW) {
+
+ /*
+ * Check to see if Hardware SiteSurvey has Finished.
+ */
+
+ if ((instance->chan == 8 && !(instance->BEHa[37] & 0x20)) ||
+ (instance->chan == 12 && !(instance->BEHa[130] & 0x10))) {
+ record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode");
+
+ if (instance->chan == 12)
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Gax, sizeof(oncore_cmd_Gax));
+ else
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Asx, sizeof(oncore_cmd_Asx));
+
+ cp = "SSstate = ONCORE_SS_DONE";
+ record_clock_stats(&(instance->peer->srcadr), cp);
+ instance->site_survey = ONCORE_SS_DONE;
+ }
+ } else {
+ /*
+ * Must be a Software Site Survey.
+ */
+
+ if (instance->rsm.bad_fix) /* Not if poor geometry or less than 3 sats */
+ return;
+
+ if (instance->mode != MODE_3D) /* Use only 3D Fixes */
+ return;
+
+ instance->ss_lat += buf_w32(&instance->BEHa[15]);
+ instance->ss_long += buf_w32(&instance->BEHa[19]);
+ instance->ss_ht += buf_w32(&instance->BEHa[23]); /* GPS ellipsoid */
+ instance->ss_count++;
+
+ if (instance->ss_count != POS_HOLD_AVERAGE)
+ return;
+
+ instance->ss_lat /= POS_HOLD_AVERAGE;
+ instance->ss_long /= POS_HOLD_AVERAGE;
+ instance->ss_ht /= POS_HOLD_AVERAGE;
+
+ sprintf(Msg, "Surveyed posn: lat %.3f (mas) long %.3f (mas) ht %.3f (cm)",
+ instance->ss_lat, instance->ss_long, instance->ss_ht);
+ record_clock_stats(&(instance->peer->srcadr), Msg);
+ lat = instance->ss_lat/3600000.;
+ lon = instance->ss_long/3600000.;
+ ht = instance->ss_ht/100;
+ sprintf(Msg, "Surveyed posn: lat %.7f (deg) long %.7f (deg) ht %.2f (m)",
+ lat, lon, ht);
+ record_clock_stats(&(instance->peer->srcadr), Msg);
+
+ oncore_set_posn(instance);
+
+ record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode");
+
+ cp = "SSstate = ONCORE_SS_DONE";
record_clock_stats(&(instance->peer->srcadr), cp);
- oncore_shutdown(instance->unit, instance->peer);
+ instance->site_survey = ONCORE_SS_DONE;
}
}
+
+
+static int
+oncore_wait_almanac(
+ struct instance *instance
+ )
+{
+ if (instance->rsm.bad_almanac) {
+ if (debug)
+ printf("ONCORE[%d]: waiting for almanac\n", instance->unit);
+
+ /*
+ * If we get here (first time) then we don't have an almanac in memory.
+ * Check if we have a SHMEM, and if so try to load whatever is there.
+ */
+
+ if (!instance->almanac_from_shmem) {
+ instance->almanac_from_shmem = 1;
+ oncore_load_almanac(instance);
+ }
+ return(1);
+ } else { /* Here we have the Almanac, we will be starting the @@Bn/@@En/@@Hn
+ commands, and can finally check for TRAIM. Again, we set a delay
+ (5sec) and wait for things to settle down */
+
+ 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));
+ else if (instance->chan == 12) {
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Gc, sizeof(oncore_cmd_Gc)); /* 1PPS on, continuous */
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Ge, sizeof(oncore_cmd_Ge)); /* TRAIM on */
+ oncore_sendmsg(instance->ttyfd, oncore_cmd_Hn, sizeof(oncore_cmd_Hn)); /* TRAIM status 1/s */
+ }
+ instance->traim_delay = 1;
+
+ record_clock_stats(&(instance->peer->srcadr), "Have now loaded an ALMANAC");
+
+ instance->o_state = ONCORE_RUN;
+ record_clock_stats(&(instance->peer->srcadr), "state = ONCORE_RUN");
+ }
+ return(0);
+}
+
+
+
#else
int refclock_oncore_bs;
#endif /* REFCLOCK */
OpenPOWER on IntegriCloud