diff options
author | roberto <roberto@FreeBSD.org> | 2004-07-20 15:01:56 +0000 |
---|---|---|
committer | roberto <roberto@FreeBSD.org> | 2004-07-20 15:01:56 +0000 |
commit | 118e757284cbb8fc4f43a713e892b41504b50a5f (patch) | |
tree | 528d12dda44ebdc3ffcc38050f159ac553a69c17 /contrib/ntp/ntpd/refclock_oncore.c | |
parent | a85d9ae25e8e8696677bc30feb6eaf7fc150e529 (diff) | |
download | FreeBSD-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.c | 3763 |
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, ¤t_mode) < 0) { + msyslog(LOG_ERR, "refclock_ioctl: time_pps_getcap failed: %m"); + return; + } + + if (time_pps_getparams(instance->pps_h, ¤t_params) < 0) { + msyslog(LOG_ERR, "refclock_ioctl: time_pps_getparams failed: %m"); + return; + } + + /* or current and mine */ + current_params.mode |= instance->pps_p.mode; + /* but only set whats legal */ + current_params.mode &= current_mode; + + current_params.assert_offset.tv_sec = 0; + current_params.assert_offset.tv_nsec = -dt2; + current_params.clear_offset.tv_sec = 0; + current_params.clear_offset.tv_nsec = -dt2; + + if (time_pps_setparams(instance->pps_h, ¤t_params)) + perror("time_pps_setparams"); +#else + /* if not PPSAPI, no way to inform kernel of OFFSET, just 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, ¤t_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, ¤t_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, ¤t_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 */ |