]> git.ipfire.org Git - thirdparty/ntp.git/commitdiff
refclock_oncore.c:
authorHarlan Stenn <stenn@ntp.org>
Tue, 25 Mar 2003 09:23:12 +0000 (04:23 -0500)
committerHarlan Stenn <stenn@ntp.org>
Tue, 25 Mar 2003 09:23:12 +0000 (04:23 -0500)
  Driver restructured to make it easier to follow.
  The driver no longer uses the Oncore model number to
  determine what features are available, but rather tests
  for them.  The driver now supports the M12+T.
  From Reg Clemens.

bk: 3e802000hFL7C4rLA4NVChAeMuK_sg

ntpd/refclock_oncore.c

index 43a38fb6dd71b7c040b124319adf918d20b5275f..625ef8978701227dad6697783246b675427ecdce 100644 (file)
@@ -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:
  *                                     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
- */
-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_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
  */
-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,72 +836,196 @@ 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);
-       }
 
-       /*
-        * This will return the Model Number of the Oncore receiver.
-        */
 
-       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;
+#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;
 
-       instance->pollcnt = 2;
-       return (1);
-}
+       /*
+       * 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 loose 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);
+       }
 
-/*
- * Read Input file if it exists.
- */
+       /* OK, we now create the NEW SHMEM. */
 
-static void
-oncore_read_config(
-       struct instance *instance
-       )
-{
-/*
+       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.
+        */
+
+       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;
+
+                       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 */
+
+
+
+/*
+ * Read Input file if it exists.
+ */
+
+static void
+oncore_read_config(
+       struct instance *instance
+       )
+{
+/*
  * First we try to open the configuration file
  *    /etc/oncoreN
  * where N is the unit number viz 127.127.30.N.
@@ -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,55 +1445,343 @@ oncore_consume(
 
 
 
-/*
- * write message to Oncore.
- */
-
-static void
-oncore_sendmsg(
-       int     fd,
-       u_char *ptr,
-       size_t len
-       )
-{
-       u_char cs = 0;
-
-       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);
-}
-
-
-
-/*
- * print Oncore response message.
- */
-
 static void
-oncore_msg_any(
+oncore_get_timestamp(
        struct instance *instance,
-       u_char *buf,
-       size_t len,
-       int idx
+       long dt1,       /* tick offset THIS time step */
+       long dt2        /* tick offset NEXT time step */
        )
 {
-       int i;
-       const char *fmt = oncore_messages[idx].fmt;
-       const char *p;
-#ifdef HAVE_GETCLOCK
-       struct timespec ts;
-#endif
-       struct timeval tv;
-
-       if (debug > 3) {
+       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 1
+       /* If we are in SiteSurvey mode, then we are in 3D mode, and we fall thru.
+        * If we have Finished the SiteSurvey, then we fall thru for the 14/15
+        *  times we get here in 0D mode (the 1/15 is in 3D for SHMEM).
+        * This gives good time, which gets better when the SS is done.
+        */
+
+       if ((instance->site_survey == ONCORE_SS_DONE) && (instance->mode != MODE_0D))
+#else
+       /* old check, only fall thru for SS_DONE and 0D mode, 2h45m wait for ticks */
+
+       if ((instance->site_survey != ONCORE_SS_DONE) || (instance->mode != MODE_0D))
+#endif
+               return;
+
+       /* Don't do anything without an almanac to define the GPS->UTC delta */
+
+       if (instance->rsm.bad_almanac)
+               return;
+
+#ifdef HAVE_PPSAPI
+       j = instance->ev_serial;
+       timeout.tv_sec = 0;
+       timeout.tv_nsec = 0;
+       if (time_pps_fetch(instance->pps_h, PPS_TSFMT_TSPEC, &pps_i,
+           &timeout) < 0) {
+               printf("ONCORE: time_pps_fetch failed\n");
+               return;
+       }
+
+       if (instance->assert) {
+               tsp = &pps_i.assert_timestamp;
+
+               if (debug > 2) {
+                       i = (u_long) pps_i.assert_sequence;
+#ifdef HAVE_STRUCT_TIMESPEC
+                       printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%09ld\n",
+                           instance->unit, i, j,
+                           (long)tsp->tv_sec, (long)tsp->tv_nsec);
+#else
+                       printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%06ld\n",
+                           instance->unit, i, j,
+                           (long)tsp->tv_sec, (long)tsp->tv_usec);
+#endif
+               }
+
+               if (pps_i.assert_sequence == j) {
+                       printf("ONCORE: oncore_get_timestamp, error serial pps\n");
+                       return;
+               }
+               instance->ev_serial = pps_i.assert_sequence;
+       } else {
+               tsp = &pps_i.clear_timestamp;
+
+               if (debug > 2) {
+                       i = (u_long) pps_i.clear_sequence;
+#ifdef HAVE_STRUCT_TIMESPEC
+                       printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%09ld\n",
+                           instance->unit, i, j, (long)tsp->tv_sec, (long)tsp->tv_nsec);
+#else
+                       printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%06ld\n",
+                           instance->unit, i, j, (long)tsp->tv_sec, (long)tsp->tv_usec);
+#endif
+               }
+
+               if (pps_i.clear_sequence == j) {
+                       printf("ONCORE: oncore_get_timestamp, error serial pps\n");
+                       return;
+               }
+               instance->ev_serial = pps_i.clear_sequence;
+       }
+
+       /* convert timespec -> ntp l_fp */
+
+       dmy = tsp->tv_nsec;
+       dmy /= 1e9;
+       ts.l_uf =  dmy * 4294967296.0;
+       ts.l_ui = tsp->tv_sec;
+#if 0
+     alternate code for previous 4 lines is
+       dmy = 1.0e-9*tsp->tv_nsec;      /* fractional part */
+       DTOLFP(dmy, &ts);
+       dmy = tsp->tv_sec;              /* integer part */
+       DTOLFP(dmy, &ts_tmp);
+       L_ADD(&ts, &ts_tmp);
+     or more simply
+       dmy = 1.0e-9*tsp->tv_nsec;      /* fractional part */
+       DTOLFP(dmy, &ts);
+       ts.l_ui = tsp->tv_sec;
+#endif /* 0 */
+#else
+# if defined(HAVE_TIOCGPPSEV) || defined(HAVE_CIOGETEV)
+       j = instance->ev_serial;
+       if (ioctl(instance->ppsfd, r, (caddr_t) &ev) < 0) {
+               perror("ONCORE: IOCTL:");
+               return;
+       }
+
+       tsp = &ev.tv;
+
+       if (debug > 2)
+#ifdef HAVE_STRUCT_TIMESPEC
+               printf("ONCORE: serial/j (%d, %d) %ld.%09ld\n",
+                       ev.serial, j, tsp->tv_sec, tsp->tv_nsec);
+#else
+               printf("ONCORE: serial/j (%d, %d) %ld.%06ld\n",
+                       ev.serial, j, tsp->tv_sec, tsp->tv_usec);
+#endif
+
+       if (ev.serial == j) {
+               printf("ONCORE: oncore_get_timestamp, error serial pps\n");
+               return;
+       }
+       instance->ev_serial = ev.serial;
+
+       /* convert timeval -> ntp l_fp */
+
+       TVTOTS(tsp, &ts);
+# else
+#  if defined(TIOCDCDTIMESTAMP)
+       if(ioctl(instance->ppsfd, TIOCDCDTIMESTAMP, &tv) < 0) {
+               perror("ONCORE: ioctl(TIOCDCDTIMESTAMP)");
+               return;
+       }
+       tsp = &tv;
+       TVTOTS(tsp, &ts);
+#  else
+#error "Cannot compile -- no PPS mechanism configured!"
+#  endif
+# endif
+#endif
+       /* now have timestamp in ts */
+       /* add in saw_tooth and offset, these will be ZERO if no TRAIM */
+
+       /* saw_tooth not really necessary if using TIMEVAL */
+       /* since its only precise to us, but do it anyway. */
+
+       /* offset in ns, and is positive (late), we subtract */
+       /* to put the PPS time transition back where it belongs */
+
+#ifdef HAVE_PPSAPI
+       /* must hand the offset for the NEXT sec off to the Kernel to do */
+       /* the addition, so that the Kernel PLL sees the offset too */
+
+       if (instance->assert)
+               instance->pps_p.assert_offset.tv_nsec = -dt2;
+       else
+               instance->pps_p.clear_offset.tv_nsec  = -dt2;
+
+       /* The following code is necessary, and not just a time_pps_setparams,
+        * using the saved instance->pps_p, since some other process on the
+        * machine may have diddled with the mode bits (say adding something
+        * that it needs).  We take what is there and ADD what we need.
+        * [[ The results from the time_pps_getcap is unlikely to change so
+        *    we could probably just save it, but I choose to do the call ]]
+        * Unfortunately, there is only ONE set of mode bits in the kernel per
+        * interface, and not one set for each open handle.
+        *
+        * There is still a race condition here where we might mess up someone
+        * elses mode, but if he is being careful too, he should survive.
+        */
+
+       if (time_pps_getcap(instance->pps_h, &current_mode) < 0) {
+               msyslog(LOG_ERR, "refclock_ioctl: time_pps_getcap failed: %m");
+               return;
+       }
+
+       if (time_pps_getparams(instance->pps_h, &current_params) < 0) {
+               msyslog(LOG_ERR, "refclock_ioctl: time_pps_getparams failed: %m");
+               return;
+       }
+
+               /* or current and mine */
+       current_params.mode |= instance->pps_p.mode;
+               /* but only set whats legal */
+       current_params.mode &= current_mode;
+
+       current_params.assert_offset.tv_sec = 0;
+       current_params.assert_offset.tv_nsec = -dt2;
+       current_params.clear_offset.tv_sec = 0;
+       current_params.clear_offset.tv_nsec = -dt2;
+
+       if (time_pps_setparams(instance->pps_h, &current_params))
+               perror("time_pps_setparams");
+#else
+       /* if not PPSAPI, no way to inform kernel of OFFSET, just add the */
+       /* offset for THIS second */
+
+       dmy = -1.0e-9*dt1;
+       DTOLFP(dmy, &ts_tmp);
+       L_ADD(&ts, &ts_tmp);
+#endif
+       /* have time from UNIX origin, convert to NTP origin. */
+
+       ts.l_ui += JAN_1970;
+       instance->pp->lastrec = ts;
+
+       /* print out information about this timestamp (long line) */
+
+       ts_tmp = ts;
+       ts_tmp.l_ui = 0;        /* zero integer part */
+       LFPTOD(&ts_tmp, dmy);   /* convert fractional part to a double */
+       j = 1.0e9*dmy;          /* then to integer ns */
+
+       Rsm = 0;
+       if (instance->chan == 6)
+               Rsm = instance->BEHa[64];
+       else if (instance->chan == 8)
+               Rsm = instance->BEHa[72];
+       else if (instance->chan == 12)
+               Rsm = ((instance->BEHa[129]<<8) | instance->BEHa[130]);
+
+       if (instance->chan == 6 || instance->chan == 8) {
+               sprintf(instance->pp->a_lastcode,       /* MAX length 128, currently at 117 */
+       "%u.%09lu %d %d %2d %2d %2d %2ld rstat   %02x dop %4.1f nsat %2d,%d traim %d sigma %2d neg-sawtooth %3d sat %d%d%d%d%d%d%d%d",
+                   ts.l_ui, j,
+                   instance->pp->year, instance->pp->day,
+                   instance->pp->hour, instance->pp->minute, instance->pp->second,
+                   (long) tsp->tv_sec % 60,
+                   Rsm, 0.1*(256*instance->BEHa[35]+instance->BEHa[36]),
+                   /*rsat      dop */
+                   instance->BEHa[38], instance->BEHa[39], instance->BEHn[21],
+                   /*  nsat visible,     nsat tracked,     traim */
+                   instance->BEHn[23]*256+instance->BEHn[24], (s_char) instance->BEHn[25],
+                   /* sigma                               neg-sawtooth */
+         /*sat*/   instance->BEHa[41], instance->BEHa[45], instance->BEHa[49], instance->BEHa[53],
+                   instance->BEHa[57], instance->BEHa[61], instance->BEHa[65], instance->BEHa[69]
+                   );                                  /* will be 0 for 6 chan */
+       } else if (instance->chan == 12) {
+               sprintf(instance->pp->a_lastcode,
+ "%u.%09lu %d %d %2d %2d %2d %2ld rstat %02x dop %4.1f nsat %2d,%d traim %d sigma %d neg-sawtooth %3d sat %d%d%d%d%d%d%d%d%d%d%d%d",
+                   ts.l_ui, j,
+                   instance->pp->year, instance->pp->day,
+                   instance->pp->hour, instance->pp->minute, instance->pp->second,
+                   (long) tsp->tv_sec % 60,
+                   Rsm, 0.1*(256*instance->BEHa[53]+instance->BEHa[54]),
+                   /*rsat      dop */
+                   instance->BEHa[55], instance->BEHa[56], instance->BEHn[6],
+                   /*  nsat visible,     nsat tracked   traim */
+                   instance->BEHn[12]*256+instance->BEHn[13], (s_char) instance->BEHn[14],
+                   /* sigma                               neg-sawtooth */
+         /*sat*/   instance->BEHa[58], instance->BEHa[64], instance->BEHa[70], instance->BEHa[76],
+                   instance->BEHa[82], instance->BEHa[88], instance->BEHa[94], instance->BEHa[100],
+                   instance->BEHa[106], instance->BEHa[112], instance->BEHa[118], instance->BEHa[124]
+                   );
+       }
+
+       if (debug > 2) {
+               int n;
+               n = strlen(instance->pp->a_lastcode);
+               printf("ONCORE[%d]: len = %d %s\n", instance->unit, n, instance->pp->a_lastcode);
+       }
+
+       /* and some things I dont understnd (magic ntp things) */
+
+       if (!refclock_process(instance->pp)) {
+               refclock_report(instance->peer, CEVNT_BADTIME);
+               return;
+       }
+
+       record_clock_stats(&(instance->peer->srcadr), instance->pp->a_lastcode);
+       instance->pollcnt = 2;
+
+       if (instance->polled) {
+               instance->polled = 0;
+/*
+               instance->pp->dispersion = instance->pp->skew = 0;
+*/
+               instance->pp->lastref = instance->pp->lastrec;
+               refclock_receive(instance->peer);
+       }
+}
+
+
+/*************** oncore_msg_XX routines start here *******************/
+
+
+/*
+ * print Oncore response message.
+ */
+
+static void
+oncore_msg_any(
+       struct instance *instance,
+       u_char *buf,
+       size_t len,
+       int idx
+       )
+{
+       int i;
+       const char *fmt = oncore_messages[idx].fmt;
+       const char *p;
 #ifdef HAVE_GETCLOCK
-               (void) getclock(TIMEOFDAY, &ts); 
-               tv.tv_sec = ts.tv_sec; 
-               tv.tv_usec = ts.tv_nsec / 1000; 
+       struct timespec ts;
+#endif
+       struct timeval tv;
+
+       if (debug > 3) {
+#ifdef HAVE_GETCLOCK
+               (void) getclock(TIMEOFDAY, &ts);
+               tv.tv_sec = ts.tv_sec;
+               tv.tv_usec = ts.tv_nsec / 1000;
 #else
                GETTIMEOFDAY(&tv, 0);
 #endif
@@ -1368,433 +1811,570 @@ oncore_msg_any(
 
 
 
+/* Latitude, Longitude, Height */
+
+static void
+oncore_msg_Adef(
+       struct instance *instance,
+       u_char *buf,
+       size_t len
+       )
+{
+}
+
+
+
+/* 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);
+}
+
+
+
 /*
- * Demultiplex the almanac into shmem
+ * get Position hold position
  */
 
 static void
-oncore_msg_Cb(
+oncore_msg_As(
        struct instance *instance,
        u_char *buf,
        size_t len
        )
 {
-       int i;
+       instance->ss_lat  = buf_w32(&buf[4]);
+       instance->ss_long = buf_w32(&buf[8]);
+       instance->ss_ht   = buf_w32(&buf[12]);
 
-       if (instance->shmem == NULL)
-               return;
+       /* Print out Position */
+       oncore_print_posn(instance);
+}
 
-       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));
+
+
+/*
+ * Try to use Oncore UT+ Auto Survey Feature
+ *     If its not there (VP), set flag to do it ourselves.
+ */
+
+static void
+oncore_msg_At(
+       struct instance *instance,
+       u_char *buf,
+       size_t len
+       )
+{
+       char    *cp;
+
+       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");
+
+                       cp = "SSstate = ONCORE_SS_HW";
+                       record_clock_stats(&(instance->peer->srcadr), cp);
+                       instance->site_survey = ONCORE_SS_HW;
+               }
+       }
 }
 
 
 
 /*
- * 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.
+ * get PPS Offset
+ * Nb. @@Ay is not supported for early UT (no plus) model
  */
 
+static void
+oncore_msg_Ay(
+       struct instance *instance,
+       u_char *buf,
+       size_t len
+       )
+{
+       char Msg[120];
+
+       if (instance->saw_Ay)
+               return;
+
+       instance->saw_Ay = 1;
+
+       instance->offset = buf_w32(&buf[4]);
+
+       sprintf(Msg, "PPS Offset is set to %ld ns", instance->offset);
+       record_clock_stats(&(instance->peer->srcadr), Msg);
+}
+
+
 
 /*
- * 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 Cable Delay
  */
 
 static void
-oncore_msg_Cj(
+oncore_msg_Az(
        struct instance *instance,
        u_char *buf,
        size_t len
        )
 {
-       memcpy(instance->Cj, buf, len);
+       char Msg[120];
+
+       if (instance->saw_Az)
+               return;
+
+       instance->saw_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);
+}
+
+
+
+/* Ba, Ea and Ha come here, these contain Position */
+
+static void
+oncore_msg_BaEaHa(
+       struct instance *instance,
+       u_char *buf,
+       size_t len
+       )
+{
+       const char      *cp;
+       char            Msg[160];
+       int             mode;
+
+       /* 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->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;
+
+               instance->count3 = 0;
+
+               if (instance->chan_in != -1)    /* set in Input */
+                       instance->chan = instance->chan_in;
+               else                            /* set from test */
+                       instance->chan = instance->chan_ck;
+
+               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);
+
+               instance->o_state = ONCORE_HAVE_CHAN;
+               cp = "state = ONCORE_HAVE_CHAN";
+               record_clock_stats(&(instance->peer->srcadr), cp);
+
+               instance->timeout = 4;
+               oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
+               return;
+       }
+
+       if (instance->o_state != ONCORE_ALMANAC && instance->o_state != ONCORE_RUN)
+               return;
+
+       /* PAUSE 5sec */
+
+       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 */
+
+       /* check the antenna and almanac for changes (did it get unplugged, is it ready?) */
+
+       oncore_check_almanac(instance);
+       oncore_check_antenna(instance);
+
+       /* 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_ALMANAC)
+               if (oncore_wait_almanac(instance))
+                       return;
+
+       /* do some things once when we get this far in BaEaHa */
+
+       if (instance->once) {
+               instance->once = 0;
+               instance->count2 = 1;
+
+               /* Have we seen an @@At (position hold) command response */
+               /* if not, message out */
+
+               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_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1));
+               }
+
+               /* 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
+                */
+
+               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;
 
-       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);
-}
+               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;
+               }
 
+               /* 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));
 
-/* 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.
- */
+               /* Read back Cable Delay for Output */
 
-static void
-oncore_msg_Cj_id(
-       struct instance *instance,
-       u_char *buf,
-       size_t len
-       )
-{
-       char *cp, *cp1, *cp2, Model[21], Msg[160];
-       int     mode;
+               oncore_sendmsg(instance->ttyfd, oncore_cmd_Azx,  sizeof(oncore_cmd_Azx));
 
-       /* Write Receiver ID message to clockstats file */
+               /* 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);
 
-       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), "SSstate = ONCORE_SS_SW");
+                               instance->site_survey = ONCORE_SS_SW;
+
+                               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 */
+                               }
+                       }
+               }
        }
 
-       /* next, the Firmware Version and Revision numbers */
+       /* check the mode we are in 0/2/3D */
 
-       instance->version  = atoi(&instance->Cj[83]);
-       instance->revision = atoi(&instance->Cj[111]);
+       if (instance->chan == 6) {
+               if (instance->BEHa[64]&0x8)
+                       instance->mode = MODE_0D;
+               else if (instance->BEHa[64]&0x10)
+                       instance->mode = MODE_2D;
+               else if (instance->BEHa[64]&0x20)
+                       instance->mode = MODE_3D;
+       } else if (instance->chan == 8) {
+               if (instance->BEHa[72]&0x8)
+                       instance->mode = MODE_0D;
+               else if (instance->BEHa[72]&0x10)
+                       instance->mode = MODE_2D;
+               else if (instance->BEHa[72]&0x20)
+                       instance->mode = MODE_3D;
+       } else if (instance->chan == 12) {
+               int bits;
 
-       /* from model number decide which Oncore this is,
-               and then the number of channels */
+               bits = (instance->BEHa[129]>>5) & 0x7;  /* actually Ha */
+               if (bits == 0x4)
+                       instance->mode = MODE_0D;
+               else if (bits == 0x6)
+                       instance->mode = MODE_2D;
+               else if (bits == 0x7)
+                       instance->mode = MODE_3D;
+       }
 
-       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';
+       /* copy the record to the (extra) location in SHMEM */
 
-       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;
+       if (instance->shmem) {
+               int     i;
+               u_char  *smp;    /* pointer to start of shared mem for Ba/Ea/Ha */
+
+               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;
                }
-       } else  {
-               cp = "Unknown";
-               instance->model = ONCORE_UNKNOWN;
-       }
 
-       sprintf(Msg, "This looks like an Oncore %s with version %d.%d firmware.", cp, instance->version, instance->revision);
-       record_clock_stats(&(instance->peer->srcadr), Msg);
+               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->chan == 0) {      /* dont reset if set in input data */
-               instance->chan = 8;     /* default */
-               if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6)
-                       instance->chan = 6;
-               else if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || instance->model == ONCORE_UTPLUS)
-                       instance->chan = 8;
-               else if (instance->model == ONCORE_M12)
-                       instance->chan = 12;
+               if (i) {
+                       i *= (len+6);
+                       smp[i + 2]++;
+                       memcpy(&smp[i+3], buf, (size_t) (len+3));
+               }
        }
 
-       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)
+       /*
+        * check if timer active
+        * if it hasn't been cleared, then @@Bn/@@En/@@Hn did not respond
+        */
+
+       if (instance->traim_delay) {
+               if (instance->traim_delay++ > 5) {
                        instance->traim = 0;
+                       instance->traim_delay = 0;
+                       cp = "ONCORE: Did not detect TRAIM response, TRAIM = OFF";
+                       record_clock_stats(&(instance->peer->srcadr), cp);
+
+                       oncore_set_traim(instance);
+               } else
+                       return;
+
        }
 
-       sprintf(Msg, "Channels = %d, TRAIM = %s", instance->chan,
-               ((instance->traim < 0) ? "UNKNOWN" : ((instance->traim > 0) ? "ON" : "OFF")));
-       record_clock_stats(&(instance->peer->srcadr), Msg);
+       /* by now should have a @@Ba/@@Ea/@@Ha with good data in it */
 
-       /* 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
+       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.
         */
 
-/*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);
-       }
+       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];
 
        /*
-        * we now know model number and have zeroed
-        * instance->shmem_fname if SHMEM is not supported
+        * Are we doing a Hardware or Software Site Survey?
         */
 
-       if (instance->shmem_fname);
-               oncore_init_shmem(instance);
+       if (instance->site_survey == ONCORE_SS_HW || instance->site_survey == ONCORE_SS_SW)
+               oncore_ss(instance);
 
-       if (instance->shmem)
-               cp = "SHMEM is available";
-       else
-               cp = "SHMEM is NOT available";
-       record_clock_stats(&(instance->peer->srcadr), cp);
+       /* see if we ever saw a response from the @@Ayx above */
 
-#ifdef HAVE_PPSAPI
-       if (instance->assert)
-               cp = "Timing on Assert.";
-       else
-               cp = "Timing on Clear.";
-       record_clock_stats(&(instance->peer->srcadr), cp);
-#endif
+       if (instance->count2) {
+               if (instance->count2++ > 5) {   /* this delay to check on @@Ay command */
+                       instance->count2 = 0;
 
-       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));
+                       /* Have we seen an Ay (1PPS time offset) command response */
+                       /* if not, and non-zero offset, zero the offset, and send message */
 
-               instance->o_state = ONCORE_TEST_SENT;
-               cp = "state = ONCORE_TEST_SENT";
-               record_clock_stats(&(instance->peer->srcadr), cp);
-               instance->timeout = 4;
+                       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.
+        */
+
+       oncore_check_leap_sec(instance);
+
+       /*
+        * if SHMEM active, every 15s, steal one 'tick' to get 2D or 3D posn.
+        */
+
+       if (instance->shmem && !instance->shmem_bad_Ea && instance->shmem_Posn && (instance->site_survey == ONCORE_SS_DONE))
+               oncore_shmem_get_3D(instance);
+
+       if (!instance->traim)   /* NO traim, no BnEnHn, go get tick */
+               oncore_get_timestamp(instance, instance->offset, instance->offset);
 }
 
 
 
+/* Almanac Status */
+
 static void
-oncore_msg_Cj_init(
+oncore_msg_Bd(
        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));
-       }
+       char Msg[160];
 
-       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);
-       }
+       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);
+}
 
-       /* 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) {
-               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;
-               }
-       }
+/* get leap-second warning message */
 
+/*
+ * @@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.
+ */
 
-       switch (mode) {
-       case 0: /* NO initialization, don't change anything */
-               instance->site_survey = ONCORE_SS_DONE;
-               break;
+static void
+oncore_msg_Bj(
+       struct instance *instance,
+       u_char *buf,
+       size_t len
+       )
+{
+       const char      *cp;
 
+       switch(buf[4]) {
        case 1:
-       case 3: /* Use given Position */
-               instance->site_survey = ONCORE_SS_DONE;
+               instance->peer->leap = LEAP_ADDSECOND;
+               cp = "Set peer.leap to LEAP_ADDSECOND";
                break;
-
        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));
-               }
+               instance->peer->leap = LEAP_DELSECOND;
+               cp = "Set peer.leap to LEAP_DELSECOND";
                break;
-       }
-
-       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));
-
-                       /* 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;
-                       }
-               }
-       }
-
-       /* 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";
+       case 0:
+       default:
+               instance->peer->leap = LEAP_NOWARNING;
+               cp = "Set peer.leap to LEAP_NOWARNING";
+               break;
+       }
        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(
+oncore_msg_BnEnHn(
        struct instance *instance,
        u_char *buf,
-       size_t len
+       size_t  len
        )
 {
-       const char *cp;
+       long    dt1, dt2;
+       char    *cp;
 
-       if (instance->o_state == ONCORE_RESET_SENT) {
-               if (instance->chan == 6)
-                       oncore_sendmsg(instance->ttyfd, oncore_cmd_Ca, sizeof(oncore_cmd_Ca));
-               else if (instance->chan == 8)
-                       oncore_sendmsg(instance->ttyfd, oncore_cmd_Fa, sizeof(oncore_cmd_Fa));
-               else if (instance->chan == 12)
-                       oncore_sendmsg(instance->ttyfd, oncore_cmd_Ia, sizeof(oncore_cmd_Ia));
+       if (instance->o_state != ONCORE_RUN)
+               return;
 
-               instance->o_state = ONCORE_TEST_SENT;
-               cp = "state = ONCORE_TEST_SENT";
-               record_clock_stats(&(instance->peer->srcadr), cp);
+       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->BEHn, buf, (size_t) len);      /* Bn or En or Hn */
+
+       /* If Time RAIM doesn't like it, don't trust it */
+
+       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->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 */
 
-/* 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
+/* 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 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
+ * 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
@@ -1810,9 +2390,10 @@ oncore_msg_CaFaIa(
        )
 {
        char *cp;
+       int     i;
 
        if (instance->o_state == ONCORE_TEST_SENT) {
-               int     antenna;
+               enum antenna_state antenna;
 
                instance->timeout = 0;
 
@@ -1823,867 +2404,973 @@ oncore_msg_CaFaIa(
                                printf("ONCORE[%d]: >>@@%ca %x %x\n", instance->unit, buf[2], buf[4], buf[5]);
                }
 
-               antenna = buf[4] & 0xc0;
-               antenna >>= 6;
+               antenna = (buf[4] & 0xc0) >> 6;
                buf[4] &= ~0xc0;
 
-               if (buf[4] || buf[5] || ((buf[2] == 'I') && buf[6])) {
-                       cp = "ONCORE: Self Test Failed, shutting down driver";
-                       record_clock_stats(&(instance->peer->srcadr), cp);
+               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);
+
+                       refclock_report(instance->peer, CEVNT_FAULT);
                        oncore_shutdown(instance->unit, instance->peer);
                        return;
                }
-               if (antenna) {
-                       char *cp1, Msg[160];
 
-                       cp1 = (antenna == 0x1) ? "(Over Current)" :
-                               ((antenna == 0x2) ? "(Under Current)" : "(No Voltage)");
+               /* report the current antenna state */
 
-                       cp = "ONCORE: Self Test, NonFatal Antenna Problems ";
-                       strcpy(Msg, cp);
-                       strcat(Msg, cp1);
-                       record_clock_stats(&(instance->peer->srcadr), Msg);
-               }
+               oncore_antenna_report(instance, antenna);
 
-               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);
+
+               instance->timeout = 4;
+               oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
        }
 }
 
 
 
-/* Ba, Ea and Ha come here */
+/*
+ * Demultiplex the almanac into shmem
+ */
 
 static void
-oncore_msg_BaEaHa(
+oncore_msg_Cb(
        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;
+       int i;
 
-       /* At the beginning of Ea here there are various 'timers'.
-        * We enter Ea 1/sec, and since the upper levels of NTP have usurped
-        * the use of timers, we use the 1/sec entry to Ea to do things that
-        * we would normally do with timers...
-        */
+       if (instance->shmem == NULL)
+               return;
 
-       if (instance->count) {
-               if (instance->count++ < 5)      /* make sure results are stable, using position */
-                       return;
-               instance->count = 0;
-       }
+       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;
 
-       if (instance->o_state != ONCORE_ALMANAC && instance->o_state != ONCORE_RUN)
+               cp = "Cb: Response is NO ALMANAC";
+               record_clock_stats(&(instance->peer->srcadr), cp);
                return;
+       }
 
-       Len = len+3;            /* message length @@ -> CR,LF */
-       memcpy(instance->Ea, buf, Len);         /* Ba, Ea or Ha */
-
-       if (buf[2] == 'B') {                    /* 6chan */
-               if (instance->Ea[64]&0x8)
-                       instance->mode = MODE_0D;
-               else if (instance->Ea[64]&0x10)
-                       instance->mode = MODE_2D;
-               else if (instance->Ea[64]&0x20)
-                       instance->mode = MODE_3D;
-       } else if (buf[2] == 'E') {             /* 8chan */
-               if (instance->Ea[72]&0x8)
-                       instance->mode = MODE_0D;
-               else if (instance->Ea[72]&0x10)
-                       instance->mode = MODE_2D;
-               else if (instance->Ea[72]&0x20)
-                       instance->mode = MODE_3D;
-       } else if (buf[2] == 'H') {             /* 12chan */
-               int bits;
+       i *= 36;
+       instance->shmem[instance->shmem_Cb + i + 2]++;
+       memcpy(instance->shmem + instance->shmem_Cb + i + 3, buf, (size_t) (len + 3));
 
-               bits = (instance->Ea[129]>>5) & 0x7;        /* actually Ha */
-               if (bits == 0x4)
-                       instance->mode = MODE_0D;
-               else if (bits == 0x6)
-                       instance->mode = MODE_2D;
-               else if (bits == 0x7)
-                       instance->mode = MODE_3D;
+#if 1
+       {
+       char Msg[160];
+       sprintf(Msg, "See Cb [%d,%d]", buf[4], buf[5]);
+       record_clock_stats(&(instance->peer->srcadr), Msg);
        }
+#endif
+}
 
-       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
+
+/*
+ * Set to Factory Defaults (Reasonable for UT w/ no Battery Backup
+ *     not so for VP (eeprom) or any unit with a battery
+ */
+
+static void
+oncore_msg_Cf(
+       struct instance *instance,
+       u_char *buf,
+       size_t len
+       )
+{
+       const char *cp;
+
+       if (instance->o_state == ONCORE_RESET_SENT) {
+               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);
+
+               oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
        }
+}
 
-       /* 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]);
+/*
+ * 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.
+ */
+
+static void
+oncore_msg_Cj(
+       struct instance *instance,
+       u_char *buf,
+       size_t len
+       )
+{
+       int     mode;
+       char    *cp;
+
+       memcpy(instance->Cj, buf, len);
+
+       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 {
-                       GPS = buf_w32(&instance->Ea[23]);
-                       MSL = buf_w32(&instance->Ea[27]);
+                       instance->o_state = ONCORE_TEST_SENT;
+                       cp = "state = ONCORE_TEST_SENT";
+                       record_clock_stats(&(instance->peer->srcadr), cp);
                }
-               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);
-               }
+       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);
+}
 
-               /* 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));
+
+/* 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
+ */
+
+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;
+       }
+
+       /* next, the Firmware Version and Revision numbers */
+
+       instance->version  = atoi(&instance->Cj[83]);
+       instance->revision = atoi(&instance->Cj[111]);
+
+       /* from model number decide which Oncore this is,
+               and then the number of channels */
+
+       for (cp=&instance->Cj[160]; *cp == ' '; cp++)   /* start right after 'Model #' */
+               ;
+       cp1 = cp;
+       cp2 = Model;
+       for (; !isspace((int)*cp) && cp-cp1 < 20; cp++, cp2++)
+               *cp2 = *cp;
+       *cp2 = '\0';
+
+       cp = 0;
+       if (!strncmp(Model, "PVT6", (size_t) 4)) {
+               cp = "PVT6";
+               instance->model = ONCORE_PVT6;
+       } else if (Model[0] == 'A') {
+               cp = "Basic";
+               instance->model = ONCORE_BASIC;
+       } else if (Model[0] == 'B' || !strncmp(Model, "T8", (size_t) 2)) {
+               cp = "VP";
+               instance->model = ONCORE_VP;
+       } else if (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;
        }
 
-       /*
-        * 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.
-        */
+       /* 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);
 
-       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->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);
+}
 
-               instance->ss_lat = instance->ss_long = instance->ss_ht = 0;
-               oncore_sendmsg(instance->ttyfd, oncore_cmd_At0, sizeof(oncore_cmd_At0)); /* disable */
-       }
 
-       if (instance->shmem) {
-               int     i;
 
-               i = 0;
-               if (instance->mode == MODE_0D)         /* 0D, Position Hold */
-                       i = 1;
-               else if (instance->mode == MODE_2D)    /* 2D, Altitude Hold */
-                       i = 2;
-               else if (instance->mode == MODE_3D)    /* 3D fix */
-                       i = 3;
-               if (i) {
-                       i *= (Len+3);
-                       vp[i + 2]++;
-                       memcpy(&vp[i+3], buf, Len);
-               }
-       }
+/* 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.
+ */
 
-       /* Almanac mode, waiting for Almanac, cant do anything till we have it */
-       /* When we have an almanac, start the En/Bn messages */
+static void
+oncore_msg_Cj_init(
+       struct instance *instance,
+       u_char *buf,
+       size_t len
+       )
+{
+       char *cp, Cmd[20], Msg[160];
+       int     mode;
 
-       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);
-               }
-       }
 
-       /*
-        * check if timer active
-        * if it hasnt been cleared, then @@En/@@Bn did not respond
+       /* The M12 with 1.3 or 2.0 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 will turn this aspect of filling SHMEM off for the M12
         */
 
-       if (instance->traim_delay) {
-               if (instance->traim_delay++ > 5) {
-                       instance->traim = 0;
-                       instance->traim_delay = 0;
-                       cp = "ONCORE: Did not detect TRAIM response, TRAIM = OFF";
-                       record_clock_stats(&(instance->peer->srcadr), cp);
-               }
+       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);
        }
 
-       /*
-        * must be ONCORE_RUN if we are here.
-        */
+       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 */
 
-       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];
+       mode = instance->init_type;
 
-       /*
-        * Check to see if Hardware SiteSurvey has Finished.
+       /* 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->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->printed && instance->site_survey == ONCORE_SS_DONE) {
-               instance->printed = 1;
-                       /* Read back Position Hold Params (cant for GT) */
-               if (instance->saw_At)
-                       oncore_sendmsg(instance->ttyfd, oncore_cmd_Asx,  sizeof(oncore_cmd_Asx));
-               else
-                       oncore_print_As(instance);
-
-                       /* Read back PPS Offset for Output */
-                       /* Nb. This will fail silently for early UT (no plus) and M12 models */
-               oncore_sendmsg(instance->ttyfd, oncore_cmd_Ayx,  sizeof(oncore_cmd_Ayx));
+       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));
 
-                       /* Read back Cable Delay for Output */
-               oncore_sendmsg(instance->ttyfd, oncore_cmd_Azx,  sizeof(oncore_cmd_Azx));
-       }
+       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 */
 
-       /*
-        * Check the leap second status once per day.
-        */
+                       /* 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));
+               }
 
-       if (instance->Bj_day != buf[5]) {     /* do this 1/day */
-               instance->Bj_day = buf[5];
+               /* Satellite mask angle */
 
-               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));
+               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));
                }
        }
 
-       /*
-        * if SHMEM active, every 15s, steal one 'tick' to get 2D or 3D posn.
+       /* 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->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->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 ));
        }
 
-       if (instance->traim == 0)       /* NO traim, go get tick */
-               oncore_get_timestamp(instance, instance->offset, instance->offset);
+       instance->count = 1;
+       instance->o_state = ONCORE_ALMANAC;
+       cp = "state = ONCORE_ALMANAC";
+       record_clock_stats(&(instance->peer->srcadr), cp);
+}
 
-       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;
+/* 12chan position */
 
-       if (instance->mode != MODE_3D)  /* Only 3D Fix */
-               return;
+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;
 
-       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++;
 
-       if (instance->ss_count != POS_HOLD_AVERAGE)
-               return;
+       lat = buf_w32(&buf[4]);
+       lon = buf_w32(&buf[8]);
+       ht  = buf_w32(&buf[12]);  /* GPS ellipsoid */
 
-       instance->ss_lat  /= POS_HOLD_AVERAGE;
-       instance->ss_long /= POS_HOLD_AVERAGE;
-       instance->ss_ht   /= POS_HOLD_AVERAGE;
+       Lat = lat;
+       Lon = lon;
+       Ht  = ht;
 
-       sprintf(Msg, "Surveyed posn:  lat %.3f long %.3f ht %.3f",
-                       instance->ss_lat, instance->ss_long, instance->ss_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);
 
-       /* set newly determined position as 3D Position hold position */
+       instance->ss_lat  = lat;
+       instance->ss_long = lon;
+       instance->ss_ht   = ht;
 
-       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));
+       oncore_print_posn(instance);
+}
 
-       /* set height seperately for 2D */
 
-       memcpy(Cmd, oncore_cmd_Au, sizeof(oncore_cmd_Au));
-       w32_buf(&Cmd[2], (int) instance->ss_ht);
-       Cmd[6] = 0;
-       oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Au));
 
-       /* and set Position Hold */
+/* 12 chan time/date */
 
-       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));
-       }
+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;
 
-       record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode");
-       instance->site_survey = ONCORE_SS_DONE;
+       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);
 }
 
 
 
+/*
+ * Try to use Oncore M12+Timing Auto Survey Feature
+ *     If its not there (M12), set flag to do it ourselves.
+ */
+
 static void
-oncore_msg_BnEn(
+oncore_msg_Gd(
        struct instance *instance,
        u_char *buf,
        size_t len
        )
 {
-       long    dt1, dt2;
        char    *cp;
 
-       if (instance->o_state != ONCORE_RUN)
-               return;
+       if (instance->site_survey == ONCORE_SS_TESTING) {
+               if (buf[4] == 3) {
+                       record_clock_stats(&(instance->peer->srcadr),
+                                       "Initiating hardware 3D site survey");
 
-       if (instance->traim_delay) {     /* flag that @@En/@@Bn returned */
-                       instance->traim = 1;
-                       instance->traim_delay = 0;
-                       cp = "ONCORE: Detected TRAIM, TRAIM = ON";
+                       cp = "SSstate = ONCORE_SS_HW";
                        record_clock_stats(&(instance->peer->srcadr), cp);
+                       instance->site_survey = ONCORE_SS_HW;
+                       }
        }
-
-       memcpy(instance->En, buf, len);         /* En or Bn */
-
-       /* If Time RAIM doesn't like it, don't trust it */
-
-       if (instance->En[21])
-               return;
-
-       dt1 = instance->saw_tooth + instance->offset;    /* dt this time step */
-       instance->saw_tooth = (s_char) instance->En[25]; /* update for next time */
-       dt2 = instance->saw_tooth + instance->offset;    /* dt next time step */
-
-       oncore_get_timestamp(instance, dt1, dt2);
 }
 
 
 
+/* Leap Second for M12, gives all info from satellite message */
+/* also in UT v3.0 */
+
 static void
-oncore_get_timestamp(
+oncore_msg_Gj(
        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 */
+       int dt;
+       char Msg[160], *cp;
 
-       if (instance->rsm.bad_almanac)
-               return;
+       instance->saw_Gj = 1; /* flag, saw_Gj, dont need to try Bj in check_leap */
 
-#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;
-       }
+       /* print the message to verify whats there */
 
-       if (instance->assert) {
-               tsp = &pps_i.assert_timestamp;
+       dt = buf[5] - buf[4];
 
-               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);
+#if 1
+       sprintf(Msg, "ONCORE[%d]: Leap Sec Msg: %d %d %d %d %d %d %d %d %d %d",
+                       instance->unit,
+                       buf[4], buf[5], 256*buf[6]+buf[7], buf[8], buf[9], buf[10],
+                       (buf[14]+256*(buf[13]+256*(buf[12]+256*buf[11]))),
+                       buf[15], buf[16], buf[17]);
+       record_clock_stats(&(instance->peer->srcadr), Msg);
 #endif
-               }
+       if (dt) {
+               sprintf(Msg, "ONCORE[%d]: Leap second (%d) scheduled for %d%s%d at %d:%d:%d",
+                       instance->unit,
+                       dt, buf[9], Month[buf[8]], 256*buf[6]+buf[7],
+                       buf[15], buf[16], buf[17]);
+               record_clock_stats(&(instance->peer->srcadr), Msg);
+       }
 
-               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;
+       /* Only raise warning within a month of the leap second */
 
-               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
-               }
+       instance->peer->leap = LEAP_NOWARNING;
+       cp = "Set peer.leap to LEAP_NOWARNING";
 
-               if (pps_i.clear_sequence == j) {
-                       printf("ONCORE: oncore_get_timestamp, error serial pps\n");
-                       return;
+       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;
+                               cp = "Set peer.leap to LEAP_DELSECOND";
+                       } else {
+                               instance->peer->leap = LEAP_ADDSECOND;
+                               cp = "Set peer.leap to LEAP_ADDSECOND";
+                       }
                }
-               instance->ev_serial = pps_i.clear_sequence;
        }
+       record_clock_stats(&(instance->peer->srcadr), cp);
+}
 
-       /* 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;
+/* Power on failure */
 
-       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
+static void
+oncore_msg_Sz(
+       struct instance *instance,
+       u_char *buf,
+       size_t len
+       )
+{
+       const char *cp;
 
-       if (ev.serial == j) {
-               printf("ONCORE: oncore_get_timestamp, error serial pps\n");
-               return;
+       cp = "Oncore: System Failure at Power On";
+       if (instance && instance->peer) {
+               record_clock_stats(&(instance->peer->srcadr), cp);
+               oncore_shutdown(instance->unit, instance->peer);
        }
-       instance->ev_serial = ev.serial;
+}
 
-       /* convert timeval -> ntp l_fp */
+/************** Small Subroutines ***************/
 
-       TVTOTS(tsp, &ts);
-# else
-#  if defined(TIOCDCDTIMESTAMP)
-       if(ioctl(instance->ppsfd, TIOCDCDTIMESTAMP, &tv) < 0) {
-               perror("ONCORE: ioctl(TIOCDCDTIMESTAMP)");
+
+static void
+oncore_antenna_report(
+       struct instance *instance,
+       enum antenna_state new_state)
+{
+       char *cp;
+
+       if (instance->ant_state == new_state)
                return;
+
+       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;
        }
-       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. */
+       instance->ant_state = new_state;
+       record_clock_stats(&instance->peer->srcadr, cp);
+}
 
-       /* 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;
+static void
+oncore_chan_test(
+       struct instance *instance
+       )
+{
+       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.
+       /* 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.
         *
-        * 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.
+        * This #chan is used by the code rather than that calculated from the model number.
         */
 
-       if (time_pps_getcap(instance->pps_h, &current_mode) < 0) {
-               msyslog(LOG_ERR,
-                   "refclock_ioctl: time_pps_getcap failed: %m");
-               return;
-       }
-
-       if (time_pps_getparams(instance->pps_h, &current_params) < 0) {
-               msyslog(LOG_ERR,
-                   "refclock_ioctl: time_pps_getparams failed: %m");
-               return;
-       }
+       instance->o_state = ONCORE_CHECK_CHAN;
+       cp = "state = ONCORE_CHECK_CHAN";
+       record_clock_stats(&(instance->peer->srcadr), cp);
 
-               /* or current and mine */
-       current_params.mode |= instance->pps_p.mode;
-               /* but only set whats legal */
-       current_params.mode &= current_mode;
+       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));
+}
 
-       current_params.assert_offset.tv_sec = 0;
-       current_params.assert_offset.tv_nsec = -dt2;
-       current_params.clear_offset.tv_sec = 0;
-       current_params.clear_offset.tv_nsec = -dt2;
 
-       if (time_pps_setparams(instance->pps_h, &current_params))
-               perror("time_pps_setparams");
-#else
-       /* if not PPSAPI, no way to inform kernel of OFFSET, just add the */
-       /* offset for THIS second */
 
-       dmy = -1.0e-9*dt1;
-       DTOLFP(dmy, &ts_tmp);
-       L_ADD(&ts, &ts_tmp);
-#endif
-       /* have time from UNIX origin, convert to NTP origin. */
+/* check for a GOOD Almanac, have we got one yet? */
 
-       ts.l_ui += JAN_1970;
-       instance->pp->lastrec = ts;
-       instance->pp->msec = 0;
+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;
 
-       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 */
+               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
+       }
+}
 
-       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);
-       }
+/* check the antenna for changes (did it get unplugged?) */
 
-       if (!refclock_process(instance->pp)) {
-               refclock_report(instance->peer, CEVNT_BADTIME);
-               return;
-       }
+static void
+oncore_check_antenna(
+       struct instance *instance
+       )
+{
+       enum antenna_state antenna;             /* antenna state */
 
-       record_clock_stats(&(instance->peer->srcadr), instance->pp->a_lastcode);
-       instance->pollcnt = 2;
+       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 */
 
-       if (instance->polled) {
-               instance->polled = 0;
-/*
-               instance->pp->dispersion = instance->pp->skew = 0;
-*/
-               refclock_receive(instance->peer);
-       }
+       oncore_antenna_report (instance, antenna);
 }
 
 
 
 /*
- * Try to use Oncore UT+ Auto Survey Feature
- *     If its not there (VP), set flag to do it ourselves.
+ * 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_msg_At(
-       struct instance *instance,
-       u_char *buf,
-       size_t len
+oncore_check_leap_sec(
+       struct instance *instance
        )
 {
-       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;
+       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));
+               }
+       }
+}
 
 
-/* get leap-second warning message */
 
-/*
- * @@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.
+/* check the message checksum,
+ *  buf points to START of message ( @@ )
+ *  len is length WITH CR/LF.
  */
 
-static void
-oncore_msg_Bj(
-       struct instance *instance,
+static int
+oncore_checksum_ok(
        u_char *buf,
-       size_t len
+       int     len
        )
 {
-       const char      *cp;
+       int     i, j;
 
-       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;
+       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);
        }
-       record_clock_stats(&(instance->peer->srcadr), cp);
 }
 
-/* Leap Second for M12, gives all info from satellite message */
+
+
+/*
+ * try loading Almanac from shmem (where it was copied from shmem_old
+ */
 
 static void
-oncore_msg_Gj(
-       struct instance *instance,
-       u_char *buf,
-       size_t len
+oncore_load_almanac(
+       struct instance *instance
        )
 {
-       int dt;
-       char Msg[160], *cp;
-       static char *Month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jly",
-               "Aug", "Sep", "Oct", "Nov", "Dec" };
-
-       /* print the message to verify whats there */
+       u_char  *cp, Cmd[20];
+       int     n;
+       struct timeval tv;
+       struct tm *tm;
 
-       dt = buf[5] - buf[4];
+       if (!instance->shmem)
+               return;
 
 #if 1
-       sprintf(Msg, "ONCORE[%d]: Leap Sec Msg: %d %d %d %d %d %d %d %d %d %d",
-                       instance->unit,
-                       buf[4], buf[5], 256*buf[6]+buf[7], buf[8], buf[9], buf[10],
-                       (buf[14]+256*(buf[13]+256*(buf[12]+256*buf[11]))),
-                       buf[15], buf[16], buf[17]);
-       record_clock_stats(&(instance->peer->srcadr), Msg);
+       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
-       if (dt) {
-               sprintf(Msg, "ONCORE[%d]: Leap second (%d) scheduled for %d%s%d at %d:%d:%d",
-                       instance->unit,
-                       dt, buf[9], Month[buf[8]], 256*buf[6]+buf[7],
-                       buf[15], buf[16], buf[17]);
+               }
+       }
+#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
 
-       /* Only raise warning within a month of the leap second */
+       /* Must load position and time or the Almanac doesn't do us any good */
 
-       instance->peer->leap = LEAP_NOWARNING;
-       cp = "Set peer.leap to LEAP_NOWARNING";
+       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;
 
-       if (buf[6] == instance->Ea[6] && buf[7] == instance->Ea[7] && /* year */
-           buf[8] == instance->Ea[4]) {        /* month */
-               if (dt) {
-                       if (dt < 0) {
-                               instance->peer->leap = LEAP_DELSECOND;
-                               cp = "Set peer.leap to LEAP_DELSECOND";
-                       } else {
-                               instance->peer->leap = LEAP_ADDSECOND;
-                               cp = "Set peer.leap to LEAP_ADDSECOND";
+                               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;
+                               }
                        }
                }
        }
-       record_clock_stats(&(instance->peer->srcadr), cp);
+       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");
 }
 
 
 
-/*
- * get Position hold position
- */
+/* Almanac data input */
 
 static void
-oncore_msg_As(
+oncore_print_Cb(
        struct instance *instance,
-       u_char *buf,
-       size_t len
+       u_char *cp
        )
 {
-       if (!instance->printed || instance->As)
-               return;
-
-       instance->As = 1;
+#if 0
+       int     ii;
+       char    Msg[160];
 
-       instance->ss_lat  = buf_w32(&buf[4]);
-       instance->ss_long = buf_w32(&buf[8]);
-       instance->ss_ht   = buf_w32(&buf[12]);
+       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");
 
-       /* Print out Position */
-       oncore_print_As(instance);
+       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_As(
+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 */