Annotation of embedaddon/ntp/ntpd/refclock_oncore.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * ----------------------------------------------------------------------------
        !             3:  * "THE BEER-WARE LICENSE" (Revision 42):
        !             4:  * <phk@FreeBSD.ORG> wrote this file.  As long as you retain this notice you
        !             5:  * can do whatever you want with this stuff. If we meet some day, and you think
        !             6:  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
        !             7:  * ----------------------------------------------------------------------------
        !             8:  *
        !             9:  * refclock_oncore.c
        !            10:  *
        !            11:  * Driver for some of the various the Motorola Oncore GPS receivers.
        !            12:  *   should work with Basic, PVT6, VP, UT, UT+, GT, GT+, SL, M12, M12+T
        !            13:  *     The receivers with TRAIM (VP, UT, UT+, M12+T), will be more accurate
        !            14:  *     than the others.
        !            15:  *     The receivers without position hold (GT, GT+) will be less accurate.
        !            16:  *
        !            17:  * Tested with:
        !            18:  *
        !            19:  *             (UT)                               (VP)
        !            20:  *   COPYRIGHT 1991-1997 MOTOROLA INC. COPYRIGHT 1991-1996 MOTOROLA INC.
        !            21:  *   SFTW P/N #     98-P36848P         SFTW P/N # 98-P36830P
        !            22:  *   SOFTWARE VER # 2                  SOFTWARE VER # 8
        !            23:  *   SOFTWARE REV # 2                  SOFTWARE REV # 8
        !            24:  *   SOFTWARE DATE  APR 24 1998        SOFTWARE DATE  06 Aug 1996
        !            25:  *   MODEL #   R1121N1114              MODEL #    B4121P1155
        !            26:  *   HWDR P/N # 1                      HDWR P/N # _
        !            27:  *   SERIAL #  R0010A                  SERIAL #   SSG0226478
        !            28:  *   MANUFACTUR DATE 6H07              MANUFACTUR DATE 7E02
        !            29:  *                                     OPTIONS LIST    IB
        !            30:  *
        !            31:  *           (Basic)                              (M12)
        !            32:  *   COPYRIGHT 1991-1994 MOTOROLA INC. COPYRIGHT 1991-2000 MOTOROLA INC.
        !            33:  *   SFTW P/N # 98-P39949M             SFTW P/N # 61-G10002A
        !            34:  *   SOFTWARE VER # 5                  SOFTWARE VER # 1
        !            35:  *   SOFTWARE REV # 0                  SOFTWARE REV # 3
        !            36:  *   SOFTWARE DATE  20 JAN 1994        SOFTWARE DATE  Mar 13 2000
        !            37:  *   MODEL #   A11121P116              MODEL #    P143T12NR1
        !            38:  *   HDWR P/N # _                      HWDR P/N # 1
        !            39:  *   SERIAL #  SSG0049809              SERIAL #   P003UD
        !            40:  *   MANUFACTUR DATE 417AMA199         MANUFACTUR DATE 0C27
        !            41:  *   OPTIONS LIST    AB
        !            42:  *
        !            43:  *           (M12+T)                             (M12+T later version)
        !            44:  *   COPYRIGHT 1991-2002 MOTOROLA INC. COPYRIGHT 1991-2003 MOTOROLA INC.
        !            45:  *   SFTW P/N #     61-G10268A         SFTW P/N #     61-G10268A
        !            46:  *   SOFTWARE VER # 2                  SOFTWARE VER # 2
        !            47:  *   SOFTWARE REV # 0                  SOFTWARE REV # 1
        !            48:  *   SOFTWARE DATE  AUG 14 2002        SOFTWARE DATE  APR 16 2003
        !            49:  *   MODEL #   P283T12T11              MODEL #    P273T12T12
        !            50:  *   HWDR P/N # 2                      HWDR P/N # 2
        !            51:  *   SERIAL #  P04DC2                  SERIAL #   P05Z7Z
        !            52:  *   MANUFACTUR DATE 2J17              MANUFACTUR DATE 3G15
        !            53:  *
        !            54:  * --------------------------------------------------------------------------
        !            55:  * Reg Clemens (June 2009)
        !            56:  * BUG[1220] OK, big patch, but mostly done mechanically.  Change direct calls to write
        !            57:  * to clockstats to a call to oncore_log, which now calls the old routine plus msyslog.
        !            58:  * Have to set the LOG_LEVELS of the calls for msyslog, and this was done by hand. New
        !            59:  * routine oncore_log.
        !            60:  * --------------------------------------------------------------------------
        !            61:  * Reg Clemens (June 2009)
        !            62:  * BUG[1218] The comment on where the oncore driver gets its input file does not
        !            63:  * agree with the code.  Change the comment.
        !            64:  * --------------------------------------------------------------------------
        !            65:  * Reg Clemens (June 2009)
        !            66:  * change exit statements to return(0) in main program.  I had assumed that if the
        !            67:  * PPS driver did not start for some reason, we shuould stop NTPD itelf.  Others
        !            68:  * disagree.  We now give an ERR log message and stop this driver.
        !            69:  * --------------------------------------------------------------------------
        !            70:  * Reg Clemens (June 2009)
        !            71:  * A bytes available message for the input subsystem (Debug message).
        !            72:  * --------------------------------------------------------------------------
        !            73:  * Reg Clemens (Nov 2008)
        !            74:  * This code adds a message for TRAIM messages.  Users often worry about the
        !            75:  * driver not starting up, and it is often because of signal strength being low.
        !            76:  * Low signal strength will give TRAIM messages.
        !            77:  * --------------------------------------------------------------------------
        !            78:  * Reg Clemens (Nov 2008)
        !            79:  * Add waiting on Almanac Message.
        !            80:  * --------------------------------------------------------------------------
        !            81:  * Reg Clemens (Nov 2008)
        !            82:  * Add back in @@Bl code to do the @@Bj/@@Gj that is in later ONCOREs
        !            83:  * LEAP SECONDS: All of the ONCORE receivers, VP -> M12T have the @@Bj command
        !            84:  * that says 'Leap Pending'.  As documented it only becomes true in the month
        !            85:  * before the leap second is to be applied, but in practice at least some of
        !            86:  * the receivers turn this indicator on as soon as the message is posted, which
        !            87:  * can be 6months early.  As such, we use the Bj command to turn on the
        !            88:  * instance->pp->leap indicator but only run this test in December and June for
        !            89:  * updates on 1Jan and 1July.
        !            90:  *
        !            91:  * The @@Gj command exists in later ONCOREs, and it gives the exact date
        !            92:  * and size of the Leap Update.  It can be emulated in the VP using the @@Bl
        !            93:  * command which reads the raw Satellite Broadcast Messages.
        !            94:  * We use these two commands to print informative messages in the clockstats
        !            95:  * file once per day as soon as the message appears on the satellites.
        !            96:  * --------------------------------------------------------------------------
        !            97:  * Reg Clemens (Feb 2006)
        !            98:  * Fix some gcc4 compiler complaints
        !            99:  * Fix possible segfault in oncore_init_shmem
        !           100:  * change all (possible) fprintf(stderr, to record_clock_stats
        !           101:  * Apply patch from Russell J. Yount <rjy@cmu.edu> Fixed (new) MT12+T UTC not correct
        !           102:  *   immediately after new Almanac Read.
        !           103:  * Apply patch for new PPS implementation by Rodolfo Giometti <giometti@linux.it>
        !           104:  *   now code can use old Ulrich Windl <Ulrich.Windl@rz.uni-regensburg.de> or
        !           105:  *   the new one.  Compiles depending on timepps.h seen.
        !           106:  * --------------------------------------------------------------------------
        !           107:  * Luis Batanero Guerrero <luisba@rao.es> (Dec 2005) Patch for leap seconds
        !           108:  * (the oncore driver was setting the wrong ntpd variable)
        !           109:  * --------------------------------------------------------------------------
        !           110:  * Reg.Clemens (Mar 2004)
        !           111:  * Support for interfaces other than PPSAPI removed, for Solaris, SunOS,
        !           112:  * SCO, you now need to use one of the timepps.h files in the root dir.
        !           113:  * this driver will 'grab' it for you if you dont have one in /usr/include
        !           114:  * --------------------------------------------------------------------------
        !           115:  * This code uses the two devices
        !           116:  *     /dev/oncore.serial.n
        !           117:  *     /dev/oncore.pps.n
        !           118:  * which may be linked to the same device.
        !           119:  * and can read initialization data from the file
        !           120:  *     /etc/ntp.oncoreN, /etc/ntp.oncore.N, or /etc/ntp.oncore, where
        !           121:  *     n or N are the unit number, viz 127.127.30.N.
        !           122:  * --------------------------------------------------------------------------
        !           123:  * Reg.Clemens <reg@dwf.com> Sep98.
        !           124:  *  Original code written for FreeBSD.
        !           125:  *  With these mods it works on FreeBSD, SunOS, Solaris and Linux
        !           126:  *    (SunOS 4.1.3 + ppsclock)
        !           127:  *    (Solaris7 + MU4)
        !           128:  *    (RedHat 5.1 2.0.35 + PPSKit, 2.1.126 + or later).
        !           129:  *
        !           130:  *  Lat,Long,Ht, cable-delay, offset, and the ReceiverID (along with the
        !           131:  *  state machine state) are printed to CLOCKSTATS if that file is enabled
        !           132:  *  in /etc/ntp.conf.
        !           133:  *
        !           134:  * --------------------------------------------------------------------------
        !           135:  *
        !           136:  * According to the ONCORE manual (TRM0003, Rev 3.2, June 1998, page 3.13)
        !           137:  * doing an average of 10000 valid 2D and 3D fixes is what the automatic
        !           138:  * site survey mode does.  Looking at the output from the receiver
        !           139:  * it seems like it is only using 3D fixes.
        !           140:  * When we do it ourselves, take 10000 3D fixes.
        !           141:  */
        !           142: 
        !           143: #define POS_HOLD_AVERAGE       10000   /* nb, 10000s ~= 2h45m */
        !           144: 
        !           145: /*
        !           146:  * ONCORE_SHMEM_STATUS will create a mmap(2)'ed file named according to a
        !           147:  * "STATUS" line in the oncore config file, which contains the most recent
        !           148:  * copy of all types of messages we recognize. This file can be mmap(2)'ed
        !           149:  * by monitoring and statistics programs.
        !           150:  *
        !           151:  * See separate HTML documentation for this option.
        !           152:  */
        !           153: 
        !           154: #ifdef HAVE_CONFIG_H
        !           155: #include <config.h>
        !           156: #endif
        !           157: 
        !           158: #if defined(REFCLOCK) && defined(CLOCK_ONCORE)
        !           159: 
        !           160: #include "ntpd.h"
        !           161: #include "ntp_io.h"
        !           162: #include "ntp_unixtime.h"
        !           163: #include "ntp_refclock.h"
        !           164: #include "ntp_stdlib.h"
        !           165: 
        !           166: #include <stdio.h>
        !           167: #include <ctype.h>
        !           168: #include <sys/stat.h>
        !           169: #ifdef ONCORE_SHMEM_STATUS
        !           170: # ifdef HAVE_SYS_MMAN_H
        !           171: #  include <sys/mman.h>
        !           172: #  ifndef MAP_FAILED
        !           173: #   define MAP_FAILED ((u_char *) -1)
        !           174: #  endif  /* MAP_FAILED */
        !           175: # endif /* HAVE_SYS_MMAN_H */
        !           176: #endif /* ONCORE_SHMEM_STATUS */
        !           177: 
        !           178: #ifdef HAVE_PPSAPI
        !           179: # include "ppsapi_timepps.h"
        !           180: #endif
        !           181: 
        !           182: #ifdef HAVE_SYS_SIO_H
        !           183: # include <sys/sio.h>
        !           184: #endif
        !           185: 
        !           186: struct Bl {
        !           187:        int     dt_ls;
        !           188:        int     dt_lsf;
        !           189:        int     WN;
        !           190:        int     DN;
        !           191:        int     WN_lsf;
        !           192:        int     DN_lsf;
        !           193:        int     wn_flg;
        !           194:        int     lsf_flg;
        !           195:        int     Bl_day;
        !           196: } Bl;
        !           197: 
        !           198: enum receive_state {
        !           199:        ONCORE_NO_IDEA,
        !           200:        ONCORE_CHECK_ID,
        !           201:        ONCORE_CHECK_CHAN,
        !           202:        ONCORE_HAVE_CHAN,
        !           203:        ONCORE_RESET_SENT,
        !           204:        ONCORE_TEST_SENT,
        !           205:        ONCORE_INIT,
        !           206:        ONCORE_ALMANAC,
        !           207:        ONCORE_RUN
        !           208: };
        !           209: 
        !           210: enum site_survey_state {
        !           211:        ONCORE_SS_UNKNOWN,
        !           212:        ONCORE_SS_TESTING,
        !           213:        ONCORE_SS_HW,
        !           214:        ONCORE_SS_SW,
        !           215:        ONCORE_SS_DONE
        !           216: };
        !           217: 
        !           218: enum antenna_state {
        !           219:       ONCORE_ANTENNA_UNKNOWN = -1,
        !           220:       ONCORE_ANTENNA_OK      = 0,
        !           221:       ONCORE_ANTENNA_OC      = 1,
        !           222:       ONCORE_ANTENNA_UC      = 2,
        !           223:       ONCORE_ANTENNA_NV      = 3
        !           224: };
        !           225: 
        !           226: /* Model Name, derived from the @@Cj message.
        !           227:  * Used to initialize some variables.
        !           228:  */
        !           229: 
        !           230: enum oncore_model {
        !           231:        ONCORE_BASIC,
        !           232:        ONCORE_PVT6,
        !           233:        ONCORE_VP,
        !           234:        ONCORE_UT,
        !           235:        ONCORE_UTPLUS,
        !           236:        ONCORE_GT,
        !           237:        ONCORE_GTPLUS,
        !           238:        ONCORE_SL,
        !           239:        ONCORE_M12,
        !           240:        ONCORE_UNKNOWN
        !           241: };
        !           242: 
        !           243: /* the bits that describe these properties are in the same place
        !           244:  * on the VP/UT, but have moved on the M12.  As such we extract
        !           245:  * them, and use them from this struct.
        !           246:  *
        !           247:  */
        !           248: 
        !           249: struct RSM {
        !           250:        u_char  posn0D;
        !           251:        u_char  posn2D;
        !           252:        u_char  posn3D;
        !           253:        u_char  bad_almanac;
        !           254:        u_char  bad_fix;
        !           255: };
        !           256: 
        !           257: /* It is possible to test the VP/UT each cycle (@@Ea or equivalent) to
        !           258:  * see what mode it is in.  The bits on the M12 are multiplexed with
        !           259:  * other messages, so we have to 'keep' the last known mode here.
        !           260:  */
        !           261: 
        !           262: enum posn_mode {
        !           263:        MODE_UNKNOWN,
        !           264:        MODE_0D,
        !           265:        MODE_2D,
        !           266:        MODE_3D
        !           267: };
        !           268: 
        !           269: struct instance {
        !           270:        int     unit;           /* 127.127.30.unit */
        !           271:        struct  refclockproc *pp;
        !           272:        struct  peer *peer;
        !           273: 
        !           274:        int     ttyfd;          /* TTY file descriptor */
        !           275:        int     ppsfd;          /* PPS file descriptor */
        !           276:        int     shmemfd;        /* Status shm descriptor */
        !           277:        pps_handle_t pps_h;
        !           278:        pps_params_t pps_p;
        !           279:        enum receive_state o_state;             /* Receive state */
        !           280:        enum posn_mode mode;                    /* 0D, 2D, 3D */
        !           281:        enum site_survey_state site_survey;     /* Site Survey state */
        !           282:        enum antenna_state ant_state;           /* antenna state */
        !           283: 
        !           284:        int     Bj_day;
        !           285: 
        !           286:        u_long  delay;          /* ns */
        !           287:        long    offset;         /* ns */
        !           288: 
        !           289:        u_char  *shmem;
        !           290:        char    *shmem_fname;
        !           291:        u_int   shmem_Cb;
        !           292:        u_int   shmem_Ba;
        !           293:        u_int   shmem_Ea;
        !           294:        u_int   shmem_Ha;
        !           295:        u_char  shmem_reset;
        !           296:        u_char  shmem_Posn;
        !           297:        u_char  shmem_bad_Ea;
        !           298:        u_char  almanac_from_shmem;
        !           299: 
        !           300:        double  ss_lat;
        !           301:        double  ss_long;
        !           302:        double  ss_ht;
        !           303:        double  dH;
        !           304:        int     ss_count;
        !           305:        u_char  posn_set;
        !           306: 
        !           307:        enum oncore_model model;
        !           308:        u_int   version;
        !           309:        u_int   revision;
        !           310: 
        !           311:        u_char  chan;           /* 6 for PVT6 or BASIC, 8 for UT/VP, 12 for m12, 0 if unknown */
        !           312:        s_char  traim;          /* do we have traim? yes UT/VP, M12+T, no BASIC, GT, M12, -1 unknown, 0 no, +1 yes */
        !           313:                                /* the following 7 are all timing counters */
        !           314:        u_char  traim_delay;    /* seconds counter, waiting for reply */
        !           315:        u_char  count;          /* cycles thru Ea before starting */
        !           316:        u_char  count1;         /* cycles thru Ea after SS_TESTING, waiting for SS_HW */
        !           317:        u_char  count2;         /* cycles thru Ea after count, to check for @@Ea */
        !           318:        u_char  count3;         /* cycles thru Ea checking for # channels */
        !           319:        u_char  count4;         /* cycles thru leap after Gj to issue Bj */
        !           320:        u_char  count5;         /* cycles thru get_timestamp waiting for valid UTC correction */
        !           321:        u_char  count5_set;     /* only set count5 once */
        !           322:        u_char  counta;         /* count for waiting on almanac message */
        !           323:        u_char  pollcnt;
        !           324:        u_char  timeout;        /* count to retry Cj after Fa self-test */
        !           325:        u_char  max_len;        /* max length message seen by oncore_log, for debugging */
        !           326:        u_char  max_count;      /* count for message statistics */
        !           327: 
        !           328:        struct  RSM rsm;        /* bits extracted from Receiver Status Msg in @@Ea */
        !           329:        struct  Bl Bl;          /* Satellite Broadcast Data Message */
        !           330:        u_char  printed;
        !           331:        u_char  polled;
        !           332:        u_long  ev_serial;
        !           333:        int     Rcvptr;
        !           334:        u_char  Rcvbuf[500];
        !           335:        u_char  BEHa[160];      /* Ba, Ea or Ha */
        !           336:        u_char  BEHn[80];       /* Bn , En , or Hn */
        !           337:        u_char  Cj[300];
        !           338:        u_char  Ag;             /* Satellite mask angle */
        !           339:        u_char  saw_At;
        !           340:        u_char  saw_Ay;
        !           341:        u_char  saw_Az;
        !           342:        s_char  saw_Bj;
        !           343:        s_char  saw_Gj;
        !           344:        u_char  have_dH;
        !           345:        u_char  init_type;
        !           346:        s_char  saw_tooth;
        !           347:        s_char  chan_in;        /* chan number from INPUT, will always use it */
        !           348:        u_char  chan_id;        /* chan number determined from part number */
        !           349:        u_char  chan_ck;        /* chan number determined by sending commands to hardware */
        !           350:        s_char  traim_in;       /* TRAIM from INPUT, will always use ON/OFF specified */
        !           351:        s_char  traim_id;       /* TRAIM determined from part number */
        !           352:        u_char  traim_ck;       /* TRAIM determined by sending commands to hardware */
        !           353:        u_char  once;           /* one pass code at top of BaEaHa */
        !           354:        s_char  assert;
        !           355:        u_char  hardpps;
        !           356: };
        !           357: 
        !           358: #define rcvbuf instance->Rcvbuf
        !           359: #define rcvptr instance->Rcvptr
        !           360: 
        !           361: static int     oncore_start          (int, struct peer *);
        !           362: static void    oncore_poll           (int, struct peer *);
        !           363: static void    oncore_shutdown       (int, struct peer *);
        !           364: static void    oncore_consume        (struct instance *);
        !           365: static void    oncore_read_config    (struct instance *);
        !           366: static void    oncore_receive        (struct recvbuf *);
        !           367: static int     oncore_ppsapi         (struct instance *);
        !           368: static void    oncore_get_timestamp  (struct instance *, long, long);
        !           369: static void    oncore_init_shmem     (struct instance *);
        !           370: 
        !           371: static void    oncore_antenna_report (struct instance *, enum antenna_state);
        !           372: static void    oncore_chan_test      (struct instance *);
        !           373: static void    oncore_check_almanac  (struct instance *);
        !           374: static void    oncore_check_antenna  (struct instance *);
        !           375: static void    oncore_check_leap_sec (struct instance *);
        !           376: static int     oncore_checksum_ok    (u_char *, int);
        !           377: static void    oncore_compute_dH     (struct instance *);
        !           378: static void    oncore_load_almanac   (struct instance *);
        !           379: static void    oncore_log            (struct instance *, int, const char *);
        !           380: static void    oncore_print_Cb       (struct instance *, u_char *);
        !           381: /* static  void    oncore_print_array   (u_char *, int);       */
        !           382: static void    oncore_print_posn     (struct instance *);
        !           383: static void    oncore_sendmsg        (struct instance *, u_char *, size_t);
        !           384: static void    oncore_set_posn       (struct instance *);
        !           385: static void    oncore_set_traim      (struct instance *);
        !           386: static void    oncore_shmem_get_3D   (struct instance *);
        !           387: static void    oncore_ss             (struct instance *);
        !           388: static int     oncore_wait_almanac   (struct instance *);
        !           389: 
        !           390: static void    oncore_msg_any     (struct instance *, u_char *, size_t, int);
        !           391: static void    oncore_msg_Adef    (struct instance *, u_char *, size_t);
        !           392: static void    oncore_msg_Ag      (struct instance *, u_char *, size_t);
        !           393: static void    oncore_msg_As      (struct instance *, u_char *, size_t);
        !           394: static void    oncore_msg_At      (struct instance *, u_char *, size_t);
        !           395: static void    oncore_msg_Ay      (struct instance *, u_char *, size_t);
        !           396: static void    oncore_msg_Az      (struct instance *, u_char *, size_t);
        !           397: static void    oncore_msg_BaEaHa  (struct instance *, u_char *, size_t);
        !           398: static void    oncore_msg_Bd      (struct instance *, u_char *, size_t);
        !           399: static void    oncore_msg_Bj      (struct instance *, u_char *, size_t);
        !           400: static void    oncore_msg_Bl      (struct instance *, u_char *, size_t);
        !           401: static void    oncore_msg_BnEnHn  (struct instance *, u_char *, size_t);
        !           402: static void    oncore_msg_CaFaIa  (struct instance *, u_char *, size_t);
        !           403: static void    oncore_msg_Cb      (struct instance *, u_char *, size_t);
        !           404: static void    oncore_msg_Cf      (struct instance *, u_char *, size_t);
        !           405: static void    oncore_msg_Cj      (struct instance *, u_char *, size_t);
        !           406: static void    oncore_msg_Cj_id   (struct instance *, u_char *, size_t);
        !           407: static void    oncore_msg_Cj_init (struct instance *, u_char *, size_t);
        !           408: static void    oncore_msg_Ga      (struct instance *, u_char *, size_t);
        !           409: static void    oncore_msg_Gb      (struct instance *, u_char *, size_t);
        !           410: static void    oncore_msg_Gj      (struct instance *, u_char *, size_t);
        !           411: static void    oncore_msg_Sz      (struct instance *, u_char *, size_t);
        !           412: 
        !           413: struct refclock refclock_oncore = {
        !           414:        oncore_start,           /* start up driver */
        !           415:        oncore_shutdown,        /* shut down driver */
        !           416:        oncore_poll,            /* transmit poll message */
        !           417:        noentry,                /* not used */
        !           418:        noentry,                /* not used */
        !           419:        noentry,                /* not used */
        !           420:        NOFLAGS                 /* not used */
        !           421: };
        !           422: 
        !           423: /*
        !           424:  * Understanding the next bit here is not easy unless you have a manual
        !           425:  * for the the various Oncore Models.
        !           426:  */
        !           427: 
        !           428: static struct msg_desc {
        !           429:        const char      flag[3];
        !           430:        const int       len;
        !           431:        void            (*handler) (struct instance *, u_char *, size_t);
        !           432:        const char      *fmt;
        !           433:        int             shmem;
        !           434: } oncore_messages[] = {
        !           435:                        /* Ea and En first since they're most common */
        !           436:        { "Ea",  76,    oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdimsdimsdsC" },
        !           437:        { "Ba",  68,    oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdsC" },
        !           438:        { "Ha", 154,    oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmaaaaoooohhhhmmmmVVvvhhddntimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddssrrccooooTTushmvvvvvvC" },
        !           439:        { "Bn",  59,    oncore_msg_BnEnHn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffC" },
        !           440:        { "En",  69,    oncore_msg_BnEnHn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffsffffsffffC" },
        !           441:        { "Hn",  78,    oncore_msg_BnEnHn, "" },
        !           442:        { "Ab",  10,    0,                 "" },
        !           443:        { "Ac",  11,    0,                 "" },
        !           444:        { "Ad",  11,    oncore_msg_Adef,   "" },
        !           445:        { "Ae",  11,    oncore_msg_Adef,   "" },
        !           446:        { "Af",  15,    oncore_msg_Adef,   "" },
        !           447:        { "Ag",   8,    oncore_msg_Ag,     "" }, /* Satellite mask angle */
        !           448:        { "As",  20,    oncore_msg_As,     "" },
        !           449:        { "At",   8,    oncore_msg_At,     "" },
        !           450:        { "Au",  12,    0,                 "" },
        !           451:        { "Av",   8,    0,                 "" },
        !           452:        { "Aw",   8,    0,                 "" },
        !           453:        { "Ay",  11,    oncore_msg_Ay,     "" },
        !           454:        { "Az",  11,    oncore_msg_Az,     "" },
        !           455:        { "AB",   8,    0,                 "" },
        !           456:        { "Bb",  92,    0,                 "" },
        !           457:        { "Bd",  23,    oncore_msg_Bd,     "" },
        !           458:        { "Bj",   8,    oncore_msg_Bj,     "" },
        !           459:        { "Bl",  41,    oncore_msg_Bl,     "" },
        !           460:        { "Ca",   9,    oncore_msg_CaFaIa, "" },
        !           461:        { "Cb",  33,    oncore_msg_Cb,     "" },
        !           462:        { "Cf",   7,    oncore_msg_Cf,     "" },
        !           463:        { "Cg",   8,    0,                 "" },
        !           464:        { "Ch",   9,    0,                 "" },
        !           465:        { "Cj", 294,    oncore_msg_Cj,     "" },
        !           466:        { "Ek",  71,    0,                 "" },
        !           467:        { "Fa",   9,    oncore_msg_CaFaIa, "" },
        !           468:        { "Ga",  20,    oncore_msg_Ga,     "" },
        !           469:        { "Gb",  17,    oncore_msg_Gb,     "" },
        !           470:        { "Gc",   8,    0,                 "" },
        !           471:        { "Gd",   8,    0,                 "" },
        !           472:        { "Ge",   8,    0,                 "" },
        !           473:        { "Gj",  21,    oncore_msg_Gj,     "" },
        !           474:        { "Ia",  10,    oncore_msg_CaFaIa, "" },
        !           475:        { "Sz",   8,    oncore_msg_Sz,     "" },
        !           476:        { {0},    7,    0,                 "" }
        !           477: };
        !           478: 
        !           479: 
        !           480: static u_char oncore_cmd_Aa[]  = { 'A', 'a', 0, 0, 0 };                            /* 6/8      Time of Day                             */
        !           481: static u_char oncore_cmd_Ab[]  = { 'A', 'b', 0, 0, 0 };                            /* 6/8      GMT Correction                          */
        !           482: static u_char oncore_cmd_AB[]  = { 'A', 'B', 4 };                                  /* VP       Application Type: Static                */
        !           483: static u_char oncore_cmd_Ac[]  = { 'A', 'c', 0, 0, 0, 0 };                         /* 6/8      Date                                    */
        !           484: static u_char oncore_cmd_Ad[]  = { 'A', 'd', 0,0,0,0 };                            /* 6/8      Latitude                                */
        !           485: static u_char oncore_cmd_Ae[]  = { 'A', 'e', 0,0,0,0 };                            /* 6/8      Longitude                               */
        !           486: static u_char oncore_cmd_Af[]  = { 'A', 'f', 0,0,0,0, 0 };                         /* 6/8      Height                                  */
        !           487: static u_char oncore_cmd_Ag[]  = { 'A', 'g', 0 };                                  /* 6/8/12   Satellite Mask Angle                    */
        !           488: static u_char oncore_cmd_Agx[] = { 'A', 'g', 0xff };                               /* 6/8/12   Satellite Mask Angle: read              */
        !           489: 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                    */
        !           490: static u_char oncore_cmd_Asx[] = { 'A', 's', 0x7f,0xff,0xff,0xff,                  /* 6/8/12   Posn Hold Readback                      */
        !           491:                                             0x7f,0xff,0xff,0xff,                   /*           on UT+ this doesnt work with 0xff      */
        !           492:                                             0x7f,0xff,0xff,0xff, 0xff };           /*           but does work with 0x7f (sigh).        */
        !           493: static u_char oncore_cmd_At0[] = { 'A', 't', 0 };                                  /* 6/8      Posn Hold: off                          */
        !           494: static u_char oncore_cmd_At1[] = { 'A', 't', 1 };                                  /* 6/8      Posn Hold: on                           */
        !           495: static u_char oncore_cmd_At2[] = { 'A', 't', 2 };                                  /* 6/8      Posn Hold: Start Site Survey            */
        !           496: static u_char oncore_cmd_Atx[] = { 'A', 't', 0xff };                               /* 6/8      Posn Hold: Read Back                    */
        !           497: static u_char oncore_cmd_Au[]  = { 'A', 'u', 0,0,0,0, 0 };                         /* GT/M12   Altitude Hold Ht.                       */
        !           498: static u_char oncore_cmd_Av0[] = { 'A', 'v', 0 };                                  /* VP/GT    Altitude Hold: off                      */
        !           499: static u_char oncore_cmd_Av1[] = { 'A', 'v', 1 };                                  /* VP/GT    Altitude Hold: on                       */
        !           500: static u_char oncore_cmd_Aw[]  = { 'A', 'w', 1 };                                  /* 6/8/12   UTC/GPS time selection                  */
        !           501: static u_char oncore_cmd_Ay[]  = { 'A', 'y', 0, 0, 0, 0 };                         /* Timing   1PPS time offset: set                   */
        !           502: static u_char oncore_cmd_Ayx[] = { 'A', 'y', 0xff, 0xff, 0xff, 0xff };             /* Timing   1PPS time offset: Read                  */
        !           503: static u_char oncore_cmd_Az[]  = { 'A', 'z', 0, 0, 0, 0 };                         /* 6/8UT/12 1PPS Cable Delay: set                   */
        !           504: static u_char oncore_cmd_Azx[] = { 'A', 'z', 0xff, 0xff, 0xff, 0xff };             /* 6/8UT/12 1PPS Cable Delay: Read                  */
        !           505: static u_char oncore_cmd_Ba0[] = { 'B', 'a', 0 };                                  /* 6        Position/Data/Status: off               */
        !           506: static u_char oncore_cmd_Ba[]  = { 'B', 'a', 1 };                                  /* 6        Position/Data/Status: on                */
        !           507: static u_char oncore_cmd_Bb[]  = { 'B', 'b', 1 };                                  /* 6/8/12   Visible Satellites                      */
        !           508: static u_char oncore_cmd_Bd[]  = { 'B', 'd', 1 };                                  /* 6/8/12?  Almanac Status Msg.                     */
        !           509: static u_char oncore_cmd_Be[]  = { 'B', 'e', 1 };                                  /* 6/8/12   Request Almanac Data                    */
        !           510: static u_char oncore_cmd_Bj[]  = { 'B', 'j', 0 };                                  /* 6/8      Leap Second Pending                     */
        !           511: static u_char oncore_cmd_Bl[]  = { 'B', 'l', 1 };                                  /* VP       Satellite Broadcast Data Msg            */
        !           512: 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   */
        !           513: 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   */
        !           514: static u_char oncore_cmd_Bnx[] = { 'B', 'n', 0, 0, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 6       TRAIM setup/status: msg off, traim off  */
        !           515: static u_char oncore_cmd_Ca[]  = { 'C', 'a' };                                     /* 6        Self Test                               */
        !           516: static u_char oncore_cmd_Cf[]  = { 'C', 'f' };                                     /* 6/8/12   Set to Defaults                         */
        !           517: static u_char oncore_cmd_Cg[]  = { 'C', 'g', 1 };                                  /* VP       Posn Fix/Idle Mode                      */
        !           518: static u_char oncore_cmd_Cj[]  = { 'C', 'j' };                                     /* 6/8/12   Receiver ID                             */
        !           519: static u_char oncore_cmd_Ea0[] = { 'E', 'a', 0 };                                  /* 8        Position/Data/Status: off               */
        !           520: static u_char oncore_cmd_Ea[]  = { 'E', 'a', 1 };                                  /* 8        Position/Data/Status: on                */
        !           521: static u_char oncore_cmd_Ek[]  = { 'E', 'k', 0 }; /* just turn off */              /* 8        Posn/Status/Data - extension            */
        !           522: 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   */
        !           523: 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   */
        !           524: static u_char oncore_cmd_Enx[] = { 'E', 'n', 0, 0, 0,10, 2, 0,0,0, 0,0,0,0,0,0,0 }; /* 8/GT    TRAIM setup/status: msg off, traim off  */
        !           525: static u_char oncore_cmd_Fa[]  = { 'F', 'a' };                                     /* 8        Self Test                               */
        !           526: static u_char oncore_cmd_Ga[]  = { 'G', 'a', 0,0,0,0, 0,0,0,0, 0,0,0,0, 0 };       /* 12       Position Set                            */
        !           527: static u_char oncore_cmd_Gax[] = { 'G', 'a', 0xff, 0xff, 0xff, 0xff,               /* 12       Position Set: Read                      */
        !           528:                                             0xff, 0xff, 0xff, 0xff,                /*                                                  */
        !           529:                                             0xff, 0xff, 0xff, 0xff, 0xff };        /*                                                  */
        !           530: static u_char oncore_cmd_Gb[]  = { 'G', 'b', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };       /* 12       set Date/Time                           */
        !           531: static u_char oncore_cmd_Gc[]  = { 'G', 'c', 1 };                                  /* 12       PPS Control: On Cont                    */
        !           532: static u_char oncore_cmd_Gd0[] = { 'G', 'd', 0 };                                  /* 12       Position Control: 3D (no hold)          */
        !           533: static u_char oncore_cmd_Gd1[] = { 'G', 'd', 1 };                                  /* 12       Position Control: 0D (3D hold)          */
        !           534: static u_char oncore_cmd_Gd2[] = { 'G', 'd', 2 };                                  /* 12       Position Control: 2D (Alt Hold)         */
        !           535: static u_char oncore_cmd_Gd3[] = { 'G', 'd', 3 };                                  /* 12       Position Coltrol: Start Site Survey     */
        !           536: static u_char oncore_cmd_Ge0[] = { 'G', 'e', 0 };                                  /* M12+T    TRAIM: off                              */
        !           537: static u_char oncore_cmd_Ge[]  = { 'G', 'e', 1 };                                  /* M12+T    TRAIM: on                               */
        !           538: static u_char oncore_cmd_Gj[]  = { 'G', 'j' };                                     /* 8?/12    Leap Second Pending                     */
        !           539: static u_char oncore_cmd_Ha0[] = { 'H', 'a', 0 };                                  /* 12       Position/Data/Status: off               */
        !           540: static u_char oncore_cmd_Ha[]  = { 'H', 'a', 1 };                                  /* 12       Position/Data/Status: on                */
        !           541: static u_char oncore_cmd_Hn0[] = { 'H', 'n', 0 };                                  /* 12       TRAIM Status: off                       */
        !           542: static u_char oncore_cmd_Hn[]  = { 'H', 'n', 1 };                                  /* 12       TRAIM Status: on                        */
        !           543: static u_char oncore_cmd_Ia[]  = { 'I', 'a' };                                     /* 12       Self Test                               */
        !           544: 
        !           545: /* it appears that as of 1997/1998, the UT had As,At, but not Au,Av
        !           546:  *                                 the GT had Au,Av, but not As,At
        !           547:  * This was as of v2.0 of both firmware sets. possibly 1.3 for UT.
        !           548:  * Bj in UT at v1.3
        !           549:  * dont see Bd in UT/GT thru 1999
        !           550:  * Gj in UT as of 3.0, 1999 , Bj as of 1.3
        !           551:  */
        !           552: 
        !           553: static char *Month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jly",
        !           554:        "Aug", "Sep", "Oct", "Nov", "Dec" };
        !           555: 
        !           556: #define DEVICE1        "/dev/oncore.serial.%d" /* name of serial device */
        !           557: #define DEVICE2        "/dev/oncore.pps.%d"    /* name of pps device */
        !           558: 
        !           559: #define SPEED          B9600           /* Oncore Binary speed (9600 bps) */
        !           560: 
        !           561: /*
        !           562:  * Assemble and disassemble 32bit signed quantities from a buffer.
        !           563:  *
        !           564:  */
        !           565: 
        !           566:        /* to buffer, int w, u_char *buf */
        !           567: #define w32_buf(buf,w) { u_int i_tmp;                     \
        !           568:                          i_tmp = (w<0) ? (~(-w)+1) : (w); \
        !           569:                          (buf)[0] = (i_tmp >> 24) & 0xff; \
        !           570:                          (buf)[1] = (i_tmp >> 16) & 0xff; \
        !           571:                          (buf)[2] = (i_tmp >>  8) & 0xff; \
        !           572:                          (buf)[3] = (i_tmp      ) & 0xff; \
        !           573:                        }
        !           574: 
        !           575: #define w32(buf)      (((buf)[0]&0xff) << 24 | \
        !           576:                       ((buf)[1]&0xff) << 16 | \
        !           577:                       ((buf)[2]&0xff) <<  8 | \
        !           578:                       ((buf)[3]&0xff) )
        !           579: 
        !           580:        /* from buffer, char *buf, result to an int */
        !           581: #define buf_w32(buf) (((buf)[0]&0200) ? (-(~w32(buf)+1)) : w32(buf))
        !           582: 
        !           583: 
        !           584: /*
        !           585:  * oncore_start - initialize data for processing
        !           586:  */
        !           587: 
        !           588: static int
        !           589: oncore_start(
        !           590:        int unit,
        !           591:        struct peer *peer
        !           592:        )
        !           593: {
        !           594: #define STRING_LEN     32
        !           595:        register struct instance *instance;
        !           596:        struct refclockproc *pp;
        !           597:        int fd1, fd2;
        !           598:        char device1[STRING_LEN], device2[STRING_LEN], Msg[160];
        !           599:        struct stat stat1, stat2;
        !           600: 
        !           601:        /* create instance structure for this unit */
        !           602: 
        !           603:        instance = emalloc(sizeof(*instance));
        !           604:        memset(instance, 0, sizeof(*instance));
        !           605: 
        !           606:        /* initialize miscellaneous variables */
        !           607: 
        !           608:        pp = peer->procptr;
        !           609:        pp->unitptr    = (caddr_t) instance;
        !           610:        instance->pp   = pp;
        !           611:        instance->unit = unit;
        !           612:        instance->peer = peer;
        !           613:        instance->assert = 1;
        !           614:        instance->once = 1;
        !           615: 
        !           616:        instance->Bj_day = -1;
        !           617:        instance->traim = -1;
        !           618:        instance->traim_in = -1;
        !           619:        instance->chan_in = -1;
        !           620:        instance->model = ONCORE_UNKNOWN;
        !           621:        instance->mode = MODE_UNKNOWN;
        !           622:        instance->site_survey = ONCORE_SS_UNKNOWN;
        !           623:        instance->Ag = 0xff;            /* Satellite mask angle, unset by user */
        !           624:        instance->ant_state = ONCORE_ANTENNA_UNKNOWN;
        !           625: 
        !           626:        peer->precision = -26;
        !           627:        peer->minpoll = 4;
        !           628:        peer->maxpoll = 4;
        !           629:        pp->clockdesc = "Motorola Oncore GPS Receiver";
        !           630:        memcpy((char *)&pp->refid, "GPS\0", (size_t) 4);
        !           631: 
        !           632:        oncore_log(instance, LOG_NOTICE, "ONCORE DRIVER -- CONFIGURING");
        !           633:        instance->o_state = ONCORE_NO_IDEA;
        !           634:        oncore_log(instance, LOG_NOTICE, "state = ONCORE_NO_IDEA");
        !           635: 
        !           636:        /* Now open files.
        !           637:         * This is a bit complicated, a we dont want to open the same file twice
        !           638:         * (its a problem on some OS), and device2 may not exist for the new PPS
        !           639:         */
        !           640: 
        !           641:        (void)snprintf(device1, sizeof(device1), DEVICE1, unit);
        !           642:        (void)snprintf(device2, sizeof(device2), DEVICE2, unit);
        !           643: 
        !           644:        /* OPEN DEVICES */
        !           645:        /* opening different devices for fd1 and fd2 presents no problems */
        !           646:        /* opening the SAME device twice, seems to be OS dependent.
        !           647:                (a) on Linux (no streams) no problem
        !           648:                (b) on SunOS (and possibly Solaris, untested), (streams)
        !           649:                        never see the line discipline.
        !           650:           Since things ALWAYS work if we only open the device once, we check
        !           651:             to see if the two devices are in fact the same, then proceed to
        !           652:             do one open or two.
        !           653: 
        !           654:           For use with linuxPPS we assume that the N_TTY file has been opened
        !           655:             and that the line discipline has been changed to N_PPS by another
        !           656:             program (say ppsldisc) so that the two files expected by the oncore
        !           657:             driver can be opened.
        !           658: 
        !           659:           Note that the linuxPPS N_PPS file is just like a N_TTY, so we can do
        !           660:             the stat below without error even though the file has already had its
        !           661:             line discipline changed by another process.
        !           662: 
        !           663:           The Windows port of ntpd arranges to return duplicate handles for
        !           664:             multiple opens of the same serial device, and doesn't have inodes
        !           665:             for serial handles, so we just open both on Windows.
        !           666:        */
        !           667: #ifndef SYS_WINNT
        !           668:        if (stat(device1, &stat1)) {
        !           669:                snprintf(Msg, sizeof(Msg), "Can't stat fd1 (%s)",
        !           670:                         device1);
        !           671:                oncore_log(instance, LOG_ERR, Msg);
        !           672:                return(0);                      /* exit, no file, can't start driver */
        !           673:        }
        !           674: 
        !           675:        if (stat(device2, &stat2)) {
        !           676:                stat2.st_dev = stat2.st_ino = -2;
        !           677:                snprintf(Msg, sizeof(Msg),
        !           678:                         "Can't stat fd2 (%s) errno = %d",
        !           679:                         device2, errno);
        !           680:                oncore_log(instance, LOG_ERR, Msg);
        !           681:        }
        !           682: #endif /* !SYS_WINNT */
        !           683: 
        !           684:        if (!(fd1 = refclock_open(device1, SPEED, LDISC_RAW))) {
        !           685:                snprintf(Msg, sizeof(Msg), "Can't open fd1 (%s)",
        !           686:                         device1);
        !           687:                oncore_log(instance, LOG_ERR, Msg);
        !           688:                return(0);                      /* exit, can't open file, can't start driver */
        !           689:        }
        !           690: 
        !           691:        /* for LINUX the PPS device is the result of a line discipline.
        !           692:           It seems simplest to let an external program create the appropriate
        !           693:           /dev/pps<n> file, and only check (carefully) for its existance here
        !           694:         */
        !           695: 
        !           696: #ifndef SYS_WINNT
        !           697:        if ((stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino))   /* same device here */
        !           698:                fd2 = fd1;
        !           699:        else
        !           700: #endif /* !SYS_WINNT */
        !           701:        {       /* different devices here */
        !           702:                if ((fd2=tty_open(device2, O_RDWR, 0777)) < 0) {
        !           703:                        snprintf(Msg, sizeof(Msg),
        !           704:                                "Can't open fd2 (%s)", device2);
        !           705:                        oncore_log(instance, LOG_ERR, Msg);
        !           706:                        return(0);              /* exit, can't open PPS file, can't start driver */
        !           707:                }
        !           708:        }
        !           709: 
        !           710:        /* open ppsapi source */
        !           711: 
        !           712:        if (time_pps_create(fd2, &instance->pps_h) < 0) {
        !           713:                oncore_log(instance, LOG_ERR, "exit, PPSAPI not found in kernel");
        !           714:                return(0);                      /* exit, don't find PPSAPI in kernel */
        !           715:        }
        !           716: 
        !           717:        /* continue initialization */
        !           718: 
        !           719:        instance->ttyfd = fd1;
        !           720:        instance->ppsfd = fd2;
        !           721: 
        !           722:        /* go read any input data in /etc/ntp.oncoreX or /etc/ntp/oncore.X */
        !           723: 
        !           724:        oncore_read_config(instance);
        !           725: 
        !           726:        if (!oncore_ppsapi(instance))
        !           727:                return(0);
        !           728: 
        !           729:        pp->io.clock_recv = oncore_receive;
        !           730:        pp->io.srcclock = (caddr_t)peer;
        !           731:        pp->io.datalen = 0;
        !           732:        pp->io.fd = fd1;
        !           733:        if (!io_addclock(&pp->io)) {
        !           734:                oncore_log(instance, LOG_ERR, "can't do io_addclock");
        !           735:                (void) close(fd1);
        !           736:                free(instance);
        !           737:                return (0);
        !           738:        }
        !           739: 
        !           740: #ifdef ONCORE_SHMEM_STATUS
        !           741:        /*
        !           742:         * Before starting ONCORE, lets setup SHMEM
        !           743:         * This will include merging an old SHMEM into the new one if
        !           744:         * an old one is found.
        !           745:         */
        !           746: 
        !           747:        oncore_init_shmem(instance);
        !           748: #endif
        !           749: 
        !           750:        /*
        !           751:         * This will return the Model of the Oncore receiver.
        !           752:         * and start the Initialization loop in oncore_msg_Cj.
        !           753:         */
        !           754: 
        !           755:        instance->o_state = ONCORE_CHECK_ID;
        !           756:        oncore_log(instance, LOG_NOTICE, "state = ONCORE_CHECK_ID");
        !           757: 
        !           758:        instance->timeout = 4;
        !           759:        oncore_sendmsg(instance, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Set Posn Fix mode (not Idle (VP)) */
        !           760:        oncore_sendmsg(instance, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
        !           761: 
        !           762:        instance->pollcnt = 2;
        !           763:        return (1);
        !           764: }
        !           765: 
        !           766: 
        !           767: /*
        !           768:  * oncore_shutdown - shut down the clock
        !           769:  */
        !           770: 
        !           771: static void
        !           772: oncore_shutdown(
        !           773:        int unit,
        !           774:        struct peer *peer
        !           775:        )
        !           776: {
        !           777:        register struct instance *instance;
        !           778:        struct refclockproc *pp;
        !           779: 
        !           780:        pp = peer->procptr;
        !           781:        instance = (struct instance *) pp->unitptr;
        !           782: 
        !           783:        io_closeclock(&pp->io);
        !           784: 
        !           785:        time_pps_destroy (instance->pps_h);
        !           786: 
        !           787:        close(instance->ttyfd);
        !           788: 
        !           789:        if ((instance->ppsfd != -1) && (instance->ppsfd != instance->ttyfd))
        !           790:                close(instance->ppsfd);
        !           791: 
        !           792:        if (instance->shmemfd)
        !           793:                close(instance->shmemfd);
        !           794: 
        !           795:        free(instance);
        !           796: }
        !           797: 
        !           798: 
        !           799: 
        !           800: /*
        !           801:  * oncore_poll - called by the transmit procedure
        !           802:  */
        !           803: 
        !           804: static void
        !           805: oncore_poll(
        !           806:        int unit,
        !           807:        struct peer *peer
        !           808:        )
        !           809: {
        !           810:        struct instance *instance;
        !           811: 
        !           812:        instance = (struct instance *) peer->procptr->unitptr;
        !           813:        if (instance->timeout) {
        !           814:                instance->timeout--;
        !           815:                if (instance->timeout == 0) {
        !           816:                        oncore_log(instance, LOG_ERR,
        !           817:                            "Oncore: No response from @@Cj, shutting down driver");
        !           818:                        oncore_shutdown(unit, peer);
        !           819:                } else {
        !           820:                        oncore_sendmsg(instance, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
        !           821:                        oncore_log(instance, LOG_WARNING, "Oncore: Resend @@Cj");
        !           822:                }
        !           823:                return;
        !           824:        }
        !           825: 
        !           826:        if (!instance->pollcnt)
        !           827:                refclock_report(peer, CEVNT_TIMEOUT);
        !           828:        else
        !           829:                instance->pollcnt--;
        !           830:        peer->procptr->polls++;
        !           831:        instance->polled = 1;
        !           832: }
        !           833: 
        !           834: 
        !           835: 
        !           836: /*
        !           837:  * Initialize PPSAPI
        !           838:  */
        !           839: 
        !           840: static int
        !           841: oncore_ppsapi(
        !           842:        struct instance *instance
        !           843:        )
        !           844: {
        !           845:        int cap, mode, mode1;
        !           846:        char *cp, Msg[160];
        !           847: 
        !           848:        if (time_pps_getcap(instance->pps_h, &cap) < 0) {
        !           849:                msnprintf(Msg, sizeof(Msg), "time_pps_getcap failed: %m");
        !           850:                oncore_log(instance, LOG_ERR, Msg);
        !           851:                return (0);
        !           852:        }
        !           853: 
        !           854:        if (time_pps_getparams(instance->pps_h, &instance->pps_p) < 0) {
        !           855:                msnprintf(Msg, sizeof(Msg), "time_pps_getparams failed: %m");
        !           856:                oncore_log(instance, LOG_ERR, Msg);
        !           857:                return (0);
        !           858:        }
        !           859: 
        !           860:        /* nb. only turn things on, if someone else has turned something
        !           861:         *      on before we get here, leave it alone!
        !           862:         */
        !           863: 
        !           864:        if (instance->assert) {
        !           865:                cp = "Assert";
        !           866:                mode = PPS_CAPTUREASSERT;
        !           867:                mode1 = PPS_OFFSETASSERT;
        !           868:        } else {
        !           869:                cp = "Clear";
        !           870:                mode = PPS_CAPTURECLEAR;
        !           871:                mode1 = PPS_OFFSETCLEAR;
        !           872:        }
        !           873:        snprintf(Msg, sizeof(Msg), "Initializing timing to %s.", cp);
        !           874:        oncore_log(instance, LOG_INFO, Msg);
        !           875: 
        !           876:        if (!(mode & cap)) {
        !           877:                snprintf(Msg, sizeof(Msg),
        !           878:                         "Can't set timing to %s, exiting...", cp);
        !           879:                oncore_log(instance, LOG_ERR, Msg);
        !           880:                return(0);
        !           881:        }
        !           882: 
        !           883:        if (!(mode1 & cap)) {
        !           884:                snprintf(Msg, sizeof(Msg),
        !           885:                         "Can't set %s, this will increase jitter.", cp);
        !           886:                oncore_log(instance, LOG_NOTICE, Msg);
        !           887:                mode1 = 0;
        !           888:        }
        !           889: 
        !           890:        /* only set what is legal */
        !           891: 
        !           892:        instance->pps_p.mode = (mode | mode1 | PPS_TSFMT_TSPEC) & cap;
        !           893: 
        !           894:        if (time_pps_setparams(instance->pps_h, &instance->pps_p) < 0) {
        !           895:                oncore_log(instance, LOG_ERR, "ONCORE: time_pps_setparams fails");
        !           896:                return(0);              /* exit, can't do time_pps_setparans on PPS file */
        !           897:        }
        !           898: 
        !           899:        /* If HARDPPS is on, we tell kernel */
        !           900: 
        !           901:        if (instance->hardpps) {
        !           902:                int     i;
        !           903: 
        !           904:                oncore_log(instance, LOG_INFO, "HARDPPS Set.");
        !           905: 
        !           906:                if (instance->assert)
        !           907:                        i = PPS_CAPTUREASSERT;
        !           908:                else
        !           909:                        i = PPS_CAPTURECLEAR;
        !           910: 
        !           911:                /* we know that 'i' is legal from above */
        !           912: 
        !           913:                if (time_pps_kcbind(instance->pps_h, PPS_KC_HARDPPS, i,
        !           914:                    PPS_TSFMT_TSPEC) < 0) {
        !           915:                        msnprintf(Msg, sizeof(Msg), "time_pps_kcbind failed: %m");
        !           916:                        oncore_log(instance, LOG_ERR, Msg);
        !           917:                        oncore_log(instance, LOG_ERR, "HARDPPS failed, abort...");
        !           918:                        return (0);
        !           919:                }
        !           920: 
        !           921:                pps_enable = 1;
        !           922:        }
        !           923:        return(1);
        !           924: }
        !           925: 
        !           926: 
        !           927: 
        !           928: #ifdef ONCORE_SHMEM_STATUS
        !           929: static void
        !           930: oncore_init_shmem(
        !           931:        struct instance *instance
        !           932:        )
        !           933: {
        !           934:        int i, l, n, fd, shmem_old_size, n1;
        !           935:        char Msg[160];
        !           936:        u_char *cp, *cp1, *buf, *shmem_old;
        !           937:        struct msg_desc *mp;
        !           938:        struct stat sbuf;
        !           939:        size_t shmem_length;
        !           940: 
        !           941:        /*
        !           942:        * The first thing we do is see if there is an instance->shmem_fname file (still)
        !           943:        * out there from a previous run.  If so, we copy it in and use it to initialize
        !           944:        * shmem (so we won't lose our almanac if we need it).
        !           945:        */
        !           946: 
        !           947:        shmem_old = 0;
        !           948:        shmem_old_size = 0;
        !           949:        if ((fd = open(instance->shmem_fname, O_RDONLY)) < 0)
        !           950:                oncore_log(instance, LOG_WARNING, "ONCORE: Can't open SHMEM file");
        !           951:        else {
        !           952:                fstat(fd, &sbuf);
        !           953:                shmem_old_size = sbuf.st_size;
        !           954:                if (shmem_old_size != 0) {
        !           955:                        shmem_old = emalloc((unsigned) sbuf.st_size);
        !           956:                        read(fd, shmem_old, shmem_old_size);
        !           957:                }
        !           958:                close(fd);
        !           959:        }
        !           960: 
        !           961:        /* OK, we now create the NEW SHMEM. */
        !           962: 
        !           963:        if ((instance->shmemfd = open(instance->shmem_fname, O_RDWR|O_CREAT|O_TRUNC, 0644)) < 0) {
        !           964:                oncore_log(instance, LOG_WARNING, "ONCORE: Can't open shmem");
        !           965:                if (shmem_old)
        !           966:                        free(shmem_old);
        !           967: 
        !           968:                return;
        !           969:        }
        !           970: 
        !           971:        /* see how big it needs to be */
        !           972: 
        !           973:        n = 1;
        !           974:        for (mp=oncore_messages; mp->flag[0]; mp++) {
        !           975:                mp->shmem = n;
        !           976:                /* Allocate space for multiplexed almanac, and 0D/2D/3D @@Ea records */
        !           977:                if (!strcmp(mp->flag, "Cb")) {
        !           978:                        instance->shmem_Cb = n;
        !           979:                        n += (mp->len + 3) * 34;
        !           980:                }
        !           981:                if (!strcmp(mp->flag, "Ba")) {
        !           982:                        instance->shmem_Ba = n;
        !           983:                        n += (mp->len + 3) * 3;
        !           984:                }
        !           985:                if (!strcmp(mp->flag, "Ea")) {
        !           986:                        instance->shmem_Ea = n;
        !           987:                        n += (mp->len + 3) * 3;
        !           988:                }
        !           989:                if (!strcmp(mp->flag, "Ha")) {
        !           990:                        instance->shmem_Ha = n;
        !           991:                        n += (mp->len + 3) * 3;
        !           992:                }
        !           993:                n += (mp->len + 3);
        !           994:        }
        !           995:        shmem_length = n + 2;
        !           996: 
        !           997:        buf = emalloc(shmem_length);
        !           998:        memset(buf, 0, shmem_length);
        !           999: 
        !          1000:        /* next build the new SHMEM buffer in memory */
        !          1001: 
        !          1002:        for (mp=oncore_messages; mp->flag[0]; mp++) {
        !          1003:                l = mp->shmem;
        !          1004:                buf[l + 0] = mp->len >> 8;
        !          1005:                buf[l + 1] = mp->len & 0xff;
        !          1006:                buf[l + 2] = 0;
        !          1007:                buf[l + 3] = '@';
        !          1008:                buf[l + 4] = '@';
        !          1009:                buf[l + 5] = mp->flag[0];
        !          1010:                buf[l + 6] = mp->flag[1];
        !          1011:                if (!strcmp(mp->flag, "Cb") || !strcmp(mp->flag, "Ba") || !strcmp(mp->flag, "Ea") || !strcmp(mp->flag, "Ha")) {
        !          1012:                        if (!strcmp(mp->flag, "Cb"))
        !          1013:                                n = 35;
        !          1014:                        else
        !          1015:                                n = 4;
        !          1016:                        for (i=1; i<n; i++) {
        !          1017:                                buf[l + i * (mp->len+3) + 0] = mp->len >> 8;
        !          1018:                                buf[l + i * (mp->len+3) + 1] = mp->len & 0xff;
        !          1019:                                buf[l + i * (mp->len+3) + 2] = 0;
        !          1020:                                buf[l + i * (mp->len+3) + 3] = '@';
        !          1021:                                buf[l + i * (mp->len+3) + 4] = '@';
        !          1022:                                buf[l + i * (mp->len+3) + 5] = mp->flag[0];
        !          1023:                                buf[l + i * (mp->len+3) + 6] = mp->flag[1];
        !          1024:                        }
        !          1025:                }
        !          1026:        }
        !          1027: 
        !          1028:        /* we now walk thru the two buffers (shmem_old and buf, soon to become shmem)
        !          1029:         * copying the data in shmem_old to buf.
        !          1030:         * When we are done we write it out and free both buffers.
        !          1031:         * If the structure sizes dont agree, I will not copy.
        !          1032:         * This could be due to an addition/deletion or a problem with the disk file.
        !          1033:         */
        !          1034: 
        !          1035:        if (shmem_old) {
        !          1036:                if (shmem_old_size == shmem_length) {
        !          1037:                        for (cp=buf+4, cp1=shmem_old+4; (n = 256*(*(cp-3)) + *(cp-2));  cp+=(n+3), cp1+=(n+3)) {
        !          1038:                                n1 = 256*(*(cp1-3)) + *(cp1-2);
        !          1039:                                if (n == 0 || n1 != n || strncmp((char *) cp, (char *) cp1, 4))
        !          1040:                                        break;
        !          1041: 
        !          1042:                                memcpy(cp, cp1, (size_t) n);
        !          1043:                        }
        !          1044:                }
        !          1045:                free(shmem_old);
        !          1046:        }
        !          1047: 
        !          1048:        i = write(instance->shmemfd, buf, shmem_length);
        !          1049:        free(buf);
        !          1050: 
        !          1051:        if (i != shmem_length) {
        !          1052:                oncore_log(instance, LOG_ERR, "ONCORE: error writing shmem");
        !          1053:                close(instance->shmemfd);
        !          1054:                return;
        !          1055:        }
        !          1056: 
        !          1057:        instance->shmem = (u_char *) mmap(0, shmem_length,
        !          1058:                PROT_READ | PROT_WRITE,
        !          1059: #ifdef MAP_HASSEMAPHORE
        !          1060:                MAP_HASSEMAPHORE |
        !          1061: #endif
        !          1062:                MAP_SHARED, instance->shmemfd, (off_t)0);
        !          1063: 
        !          1064:        if (instance->shmem == (u_char *)MAP_FAILED) {
        !          1065:                instance->shmem = 0;
        !          1066:                close(instance->shmemfd);
        !          1067:                return;
        !          1068:        }
        !          1069: 
        !          1070:        snprintf(Msg, sizeof(Msg),
        !          1071:                 "SHMEM (size = %ld) is CONFIGURED and available as %s",
        !          1072:                 (u_long) shmem_length, instance->shmem_fname);
        !          1073:        oncore_log(instance, LOG_NOTICE, Msg);
        !          1074: }
        !          1075: #endif /* ONCORE_SHMEM_STATUS */
        !          1076: 
        !          1077: 
        !          1078: 
        !          1079: /*
        !          1080:  * Read Input file if it exists.
        !          1081:  */
        !          1082: 
        !          1083: static void
        !          1084: oncore_read_config(
        !          1085:        struct instance *instance
        !          1086:        )
        !          1087: {
        !          1088: /*
        !          1089:  * First we try to open the configuration file
        !          1090:  *    /etc/ntp.oncore.N
        !          1091:  * where N is the unit number viz 127.127.30.N.
        !          1092:  * If we don't find it we try
        !          1093:  *    /etc/ntp.oncoreN
        !          1094:  * and then
        !          1095:  *    /etc/ntp.oncore
        !          1096:  *
        !          1097:  * If we don't find any then we don't have the cable delay or PPS offset
        !          1098:  * and we choose MODE (4) below.
        !          1099:  *
        !          1100:  * Five Choices for MODE
        !          1101:  *    (0) ONCORE is preinitialized, don't do anything to change it.
        !          1102:  *         nb, DON'T set 0D mode, DON'T set Delay, position...
        !          1103:  *    (1) NO RESET, Read Position, delays from data file, lock it in, go to 0D mode.
        !          1104:  *    (2) NO RESET, Read Delays from data file, do SITE SURVEY to get position,
        !          1105:  *                 lock this in, go to 0D mode.
        !          1106:  *    (3) HARD RESET, Read Position, delays from data file, lock it in, go to 0D mode.
        !          1107:  *    (4) HARD RESET, Read Delays from data file, do SITE SURVEY to get position,
        !          1108:  *                 lock this in, go to 0D mode.
        !          1109:  *     NB. If a POSITION is specified in the config file with mode=(2,4) [SITE SURVEY]
        !          1110:  *        then this position is set as the INITIAL position of the ONCORE.
        !          1111:  *        This can reduce the time to first fix.
        !          1112:  * -------------------------------------------------------------------------------
        !          1113:  * Note that an Oncore UT without a battery backup retains NO information if it is
        !          1114:  *   power cycled, with a Battery Backup it remembers the almanac, etc.
        !          1115:  * For an Oncore VP, there is an eeprom that will contain this data, along with the
        !          1116:  *   option of Battery Backup.
        !          1117:  * So a UT without Battery Backup is equivalent to doing a HARD RESET on each
        !          1118:  *   power cycle, since there is nowhere to store the data.
        !          1119:  * -------------------------------------------------------------------------------
        !          1120:  *
        !          1121:  * If we open one or the other of the files, we read it looking for
        !          1122:  *   MODE, LAT, LON, (HT, HTGPS, HTMSL), DELAY, OFFSET, ASSERT, CLEAR, HARDPPS,
        !          1123:  *   STATUS, POSN3D, POSN2D, CHAN, TRAIM
        !          1124:  * then initialize using method MODE.  For Mode = (1,3) all of (LAT, LON, HT) must
        !          1125:  *   be present or mode reverts to (2,4).
        !          1126:  *
        !          1127:  * Read input file.
        !          1128:  *
        !          1129:  *     # is comment to end of line
        !          1130:  *     = allowed between 1st and 2nd fields.
        !          1131:  *
        !          1132:  *     Expect to see one line with 'MODE' as first field, followed by an integer
        !          1133:  *        in the range 0-4 (default = 4).
        !          1134:  *
        !          1135:  *     Expect to see two lines with 'LONG', 'LAT' followed by 1-3 fields.
        !          1136:  *     All numbers are floating point.
        !          1137:  *             DDD.ddd
        !          1138:  *             DDD  MMM.mmm
        !          1139:  *             DDD  MMM  SSS.sss
        !          1140:  *
        !          1141:  *     Expect to see one line with 'HT' as first field,
        !          1142:  *        followed by 1-2 fields.  First is a number, the second is 'FT' or 'M'
        !          1143:  *        for feet or meters.  HT is the height above the GPS ellipsoid.
        !          1144:  *        If the receiver reports height in both GPS and MSL, then we will report
        !          1145:  *        the difference GPS-MSL on the clockstats file.
        !          1146:  *
        !          1147:  *     There is an optional line, starting with DELAY, followed
        !          1148:  *        by 1 or two fields.  The first is a number (a time) the second is
        !          1149:  *        'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds.
        !          1150:  *         DELAY  is cable delay, typically a few tens of ns.
        !          1151:  *
        !          1152:  *     There is an optional line, starting with OFFSET, followed
        !          1153:  *        by 1 or two fields.  The first is a number (a time) the second is
        !          1154:  *        'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds.
        !          1155:  *        OFFSET is the offset of the PPS pulse from 0. (only fully implemented
        !          1156:  *             with the PPSAPI, we need to be able to tell the Kernel about this
        !          1157:  *             offset if the Kernel PLL is in use, but can only do this presently
        !          1158:  *             when using the PPSAPI interface.  If not using the Kernel PLL,
        !          1159:  *             then there is no problem.
        !          1160:  *
        !          1161:  *     There is an optional line, with either ASSERT or CLEAR on it, which
        !          1162:  *        determine which transition of the PPS signal is used for timing by the
        !          1163:  *        PPSAPI.  If neither is present, then ASSERT is assumed.
        !          1164:  *        ASSERT/CLEAR can also be set with FLAG2 of the ntp.conf input.
        !          1165:  *        For Flag2, ASSERT=0, and hence is default.
        !          1166:  *
        !          1167:  *     There is an optional line, with HARDPPS on it.  Including this line causes
        !          1168:  *        the PPS signal to control the kernel PLL.
        !          1169:  *        HARDPPS can also be set with FLAG3 of the ntp.conf input.
        !          1170:  *        For Flag3, 0 is disabled, and the default.
        !          1171:  *
        !          1172:  *     There are three options that have to do with using the shared memory option.
        !          1173:  *        First, to enable the option there must be a SHMEM line with a file name.
        !          1174:  *        The file name is the file associated with the shared memory.
        !          1175:  *
        !          1176:  *     In shared memory, there is one 'record' for each returned variable.
        !          1177:  *     For the @@Ea data there are three 'records' containing position data.
        !          1178:  *        There will always be data in the record corresponding to the '0D' @@Ea record,
        !          1179:  *        and the user has a choice of filling the '3D' record by specifying POSN3D,
        !          1180:  *        or the '2D' record by specifying POSN2D.  In either case the '2D' or '3D'
        !          1181:  *        record is filled once every 15s.
        !          1182:  *
        !          1183:  *     Two additional variables that can be set are CHAN and TRAIM.  These should be
        !          1184:  *        set correctly by the code examining the @@Cj record, but we bring them out here
        !          1185:  *        to allow the user to override either the # of channels, or the existence of TRAIM.
        !          1186:  *        CHAN expects to be followed by in integer: 6, 8, or 12. TRAIM expects to be
        !          1187:  *        followed by YES or NO.
        !          1188:  *
        !          1189:  *     There is an optional line with MASK on it followed by one integer field in the
        !          1190:  *        range 0 to 89. This sets the satellite mask angle and will determine the minimum
        !          1191:  *        elevation angle for satellites to be tracked by the receiver. The default value
        !          1192:  *        is 10 deg for the VP and 0 deg for all other receivers.
        !          1193:  *
        !          1194:  * So acceptable input would be
        !          1195:  *     # these are my coordinates (RWC)
        !          1196:  *     LON  -106 34.610
        !          1197:  *     LAT    35 08.999
        !          1198:  *     HT      1589    # could equally well say HT 5215 FT
        !          1199:  *     DELAY  60 ns
        !          1200:  */
        !          1201: 
        !          1202:        FILE    *fd;
        !          1203:        char    *cp, *cc, *ca, line[100], units[2], device[64], Msg[160], **cpp;
        !          1204:        char    *dirs[] = { "/etc/ntp", "/etc", 0 };
        !          1205:        int     i, sign, lat_flg, long_flg, ht_flg, mode, mask;
        !          1206:        double  f1, f2, f3;
        !          1207: 
        !          1208:        fd = NULL;      /* just to shutup gcc complaint */
        !          1209:        for (cpp=dirs; *cpp; cpp++) {
        !          1210:                cp = *cpp;
        !          1211:                snprintf(device, sizeof(device), "%s/ntp.oncore.%d",
        !          1212:                         cp, instance->unit);  /* try "ntp.oncore.0 */
        !          1213:                if ((fd=fopen(device, "r")))
        !          1214:                        break;
        !          1215:                snprintf(device, sizeof(device), "%s/ntp.oncore%d",
        !          1216:                         cp, instance->unit);  /* try "ntp.oncore0" */
        !          1217:                if ((fd=fopen(device, "r")))
        !          1218:                        break;
        !          1219:                snprintf(device, sizeof(device), "%s/ntp.oncore", cp);
        !          1220:                if ((fd=fopen(device, "r")))   /* last try "ntp.oncore" */
        !          1221:                        break;
        !          1222:        }
        !          1223: 
        !          1224:        if (!fd) {      /* no inputfile, default to the works ... */
        !          1225:                instance->init_type = 4;
        !          1226:                return;
        !          1227:        }
        !          1228: 
        !          1229:        mode = mask = 0;
        !          1230:        lat_flg = long_flg = ht_flg = 0;
        !          1231:        while (fgets(line, 100, fd)) {
        !          1232: 
        !          1233:                /* Remove comments */
        !          1234:                if ((cp = strchr(line, '#')))
        !          1235:                        *cp = '\0';
        !          1236: 
        !          1237:                /* Remove trailing space */
        !          1238:                for (i = strlen(line);
        !          1239:                     i > 0 && isascii((int)line[i - 1]) && isspace((int)line[i - 1]);
        !          1240:                        )
        !          1241:                        line[--i] = '\0';
        !          1242: 
        !          1243:                /* Remove leading space */
        !          1244:                for (cc = line; *cc && isascii((int)*cc) && isspace((int)*cc); cc++)
        !          1245:                        continue;
        !          1246: 
        !          1247:                /* Stop if nothing left */
        !          1248:                if (!*cc)
        !          1249:                        continue;
        !          1250: 
        !          1251:                /* Uppercase the command and find the arg */
        !          1252:                for (ca = cc; *ca; ca++) {
        !          1253:                        if (isascii((int)*ca)) {
        !          1254:                                if (islower((int)*ca)) {
        !          1255:                                        *ca = toupper(*ca);
        !          1256:                                } else if (isspace((int)*ca) || (*ca == '='))
        !          1257:                                        break;
        !          1258:                        }
        !          1259:                }
        !          1260: 
        !          1261:                /* Remove space (and possible =) leading the arg */
        !          1262:                for (; *ca && isascii((int)*ca) && (isspace((int)*ca) || (*ca == '=')); ca++)
        !          1263:                        continue;
        !          1264: 
        !          1265:                if (!strncmp(cc, "STATUS", (size_t) 6) || !strncmp(cc, "SHMEM", (size_t) 5)) {
        !          1266:                        instance->shmem_fname = estrdup(ca);
        !          1267:                        continue;
        !          1268:                }
        !          1269: 
        !          1270:                /* Uppercase argument as well */
        !          1271:                for (cp = ca; *cp; cp++)
        !          1272:                        if (isascii((int)*cp) && islower((int)*cp))
        !          1273:                                *cp = toupper(*cp);
        !          1274: 
        !          1275:                if (!strncmp(cc, "LAT", (size_t) 3)) {
        !          1276:                        f1 = f2 = f3 = 0;
        !          1277:                        sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3);
        !          1278:                        sign = 1;
        !          1279:                        if (f1 < 0) {
        !          1280:                                f1 = -f1;
        !          1281:                                sign = -1;
        !          1282:                        }
        !          1283:                        instance->ss_lat = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/
        !          1284:                        lat_flg++;
        !          1285:                } else if (!strncmp(cc, "LON", (size_t) 3)) {
        !          1286:                        f1 = f2 = f3 = 0;
        !          1287:                        sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3);
        !          1288:                        sign = 1;
        !          1289:                        if (f1 < 0) {
        !          1290:                                f1 = -f1;
        !          1291:                                sign = -1;
        !          1292:                        }
        !          1293:                        instance->ss_long = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/
        !          1294:                        long_flg++;
        !          1295:                } else if (!strncmp(cc, "HT", (size_t) 2)) {
        !          1296:                        f1 = 0;
        !          1297:                        units[0] = '\0';
        !          1298:                        sscanf(ca, "%lf %1s", &f1, units);
        !          1299:                        if (units[0] == 'F')
        !          1300:                                f1 = 0.3048 * f1;
        !          1301:                        instance->ss_ht = 100 * f1;    /* cm */
        !          1302:                        ht_flg++;
        !          1303:                } else if (!strncmp(cc, "DELAY", (size_t) 5)) {
        !          1304:                        f1 = 0;
        !          1305:                        units[0] = '\0';
        !          1306:                        sscanf(ca, "%lf %1s", &f1, units);
        !          1307:                        if (units[0] == 'N')
        !          1308:                                ;
        !          1309:                        else if (units[0] == 'U')
        !          1310:                                f1 = 1000 * f1;
        !          1311:                        else if (units[0] == 'M')
        !          1312:                                f1 = 1000000 * f1;
        !          1313:                        else
        !          1314:                                f1 = 1000000000 * f1;
        !          1315:                        if (f1 < 0 || f1 > 1.e9)
        !          1316:                                f1 = 0;
        !          1317:                        if (f1 < 0 || f1 > 999999) {
        !          1318:                                snprintf(Msg, sizeof(Msg), 
        !          1319:                                         "PPS Cable delay of %fns out of Range, ignored",
        !          1320:                                         f1);
        !          1321:                                oncore_log(instance, LOG_WARNING, Msg);
        !          1322:                        } else
        !          1323:                                instance->delay = f1;           /* delay in ns */
        !          1324:                } else if (!strncmp(cc, "OFFSET", (size_t) 6)) {
        !          1325:                        f1 = 0;
        !          1326:                        units[0] = '\0';
        !          1327:                        sscanf(ca, "%lf %1s", &f1, units);
        !          1328:                        if (units[0] == 'N')
        !          1329:                                ;
        !          1330:                        else if (units[0] == 'U')
        !          1331:                                f1 = 1000 * f1;
        !          1332:                        else if (units[0] == 'M')
        !          1333:                                f1 = 1000000 * f1;
        !          1334:                        else
        !          1335:                                f1 = 1000000000 * f1;
        !          1336:                        if (f1 < 0 || f1 > 1.e9)
        !          1337:                                f1 = 0;
        !          1338:                        if (f1 < 0 || f1 > 999999999.) {
        !          1339:                                snprintf(Msg, sizeof(Msg),
        !          1340:                                         "PPS Offset of %fns out of Range, ignored",
        !          1341:                                         f1);
        !          1342:                                oncore_log(instance, LOG_WARNING, Msg);
        !          1343:                        } else
        !          1344:                                instance->offset = f1;          /* offset in ns */
        !          1345:                } else if (!strncmp(cc, "MODE", (size_t) 4)) {
        !          1346:                        sscanf(ca, "%d", &mode);
        !          1347:                        if (mode < 0 || mode > 4)
        !          1348:                                mode = 4;
        !          1349:                } else if (!strncmp(cc, "ASSERT", (size_t) 6)) {
        !          1350:                        instance->assert = 1;
        !          1351:                } else if (!strncmp(cc, "CLEAR", (size_t) 5)) {
        !          1352:                        instance->assert = 0;
        !          1353:                } else if (!strncmp(cc, "HARDPPS", (size_t) 7)) {
        !          1354:                        instance->hardpps = 1;
        !          1355:                } else if (!strncmp(cc, "POSN2D", (size_t) 6)) {
        !          1356:                        instance->shmem_Posn = 2;
        !          1357:                } else if (!strncmp(cc, "POSN3D", (size_t) 6)) {
        !          1358:                        instance->shmem_Posn = 3;
        !          1359:                } else if (!strncmp(cc, "CHAN", (size_t) 4)) {
        !          1360:                        sscanf(ca, "%d", &i);
        !          1361:                        if ((i == 6) || (i == 8) || (i == 12))
        !          1362:                                instance->chan_in = i;
        !          1363:                } else if (!strncmp(cc, "TRAIM", (size_t) 5)) {
        !          1364:                        instance->traim_in = 1;         /* so TRAIM alone is YES */
        !          1365:                        if (!strcmp(ca, "NO") || !strcmp(ca, "OFF"))    /* Yes/No, On/Off */
        !          1366:                                instance->traim_in = 0;
        !          1367:                } else if (!strncmp(cc, "MASK", (size_t) 4)) {
        !          1368:                        sscanf(ca, "%d", &mask);
        !          1369:                        if (mask > -1 && mask < 90)
        !          1370:                                instance->Ag = mask;                    /* Satellite mask angle */
        !          1371:                }
        !          1372:        }
        !          1373:        fclose(fd);
        !          1374: 
        !          1375:        /*
        !          1376:         *    OK, have read all of data file, and extracted the good stuff.
        !          1377:         *    If lat/long/ht specified they ALL must be specified for mode = (1,3).
        !          1378:         */
        !          1379: 
        !          1380:        instance->posn_set = 1;
        !          1381:        if (!( lat_flg && long_flg && ht_flg )) {
        !          1382:                snprintf(Msg, sizeof(Msg),
        !          1383:                         "ONCORE: incomplete data on %s", device);
        !          1384:                oncore_log (instance, LOG_WARNING, Msg);
        !          1385:                instance->posn_set = 0;
        !          1386:                if (mode == 1 || mode == 3) {
        !          1387:                        snprintf(Msg, sizeof(Msg),
        !          1388:                                 "Input Mode = %d, but no/incomplete position, mode set to %d",
        !          1389:                                 mode, mode+1);
        !          1390:                        oncore_log(instance, LOG_WARNING, Msg);
        !          1391:                        mode++;
        !          1392:                }
        !          1393:        }
        !          1394:        instance->init_type = mode;
        !          1395: 
        !          1396:        snprintf(Msg, sizeof(Msg), "Input mode = %d", mode);
        !          1397:        oncore_log(instance, LOG_INFO, Msg);
        !          1398: }
        !          1399: 
        !          1400: 
        !          1401: 
        !          1402: /*
        !          1403:  * move data from NTP to buffer (toss the extra in the unlikely case it won't fit)
        !          1404:  */
        !          1405: 
        !          1406: static void
        !          1407: oncore_receive(
        !          1408:        struct recvbuf *rbufp
        !          1409:        )
        !          1410: {
        !          1411:        size_t i;
        !          1412:        u_char *p;
        !          1413:        struct peer *peer;
        !          1414:        struct instance *instance;
        !          1415: 
        !          1416:        peer = (struct peer *)rbufp->recv_srcclock;
        !          1417:        instance = (struct instance *) peer->procptr->unitptr;
        !          1418:        p = (u_char *) &rbufp->recv_space;
        !          1419: 
        !          1420: #ifdef ONCORE_VERBOSE_RECEIVE
        !          1421:        if (debug > 4) {
        !          1422:                int i;
        !          1423:                char    Msg[120], Msg2[10];
        !          1424: 
        !          1425:                snprintf(Msg, sizeof(Msg), ">>> %d bytes available",
        !          1426:                         rbufp->recv_length);
        !          1427:                oncore_log(instance, LOG_DEBUG, Msg);
        !          1428:                strncpy(Msg, ">>>", sizeof(Msg));
        !          1429:                for (i = 0; i < rbufp->recv_length; i++) {
        !          1430:                        snprintf(Msg2, sizeof(Msg2), "%02x ", p[i]);
        !          1431:                        strncat(Msg, Msg2, sizeof(Msg));
        !          1432:                }
        !          1433:                oncore_log(instance, LOG_DEBUG, Msg);
        !          1434: 
        !          1435:                strncpy(Msg, ">>>", sizeof(Msg));
        !          1436:                for (i = 0; i < rbufp->recv_length; i++) {
        !          1437:                        snprintf(Msg2, sizeof(Msg2), "%03o ", p[i]);
        !          1438:                        strncat(Msg, Msg2, sizeof(Msg));
        !          1439:                }
        !          1440:                oncore_log(instance, LOG_DEBUG, Msg);
        !          1441:        }
        !          1442: #endif
        !          1443: 
        !          1444:        i = rbufp->recv_length;
        !          1445:        if (rcvbuf+rcvptr+i > &rcvbuf[sizeof rcvbuf])
        !          1446:                i = sizeof(rcvbuf) - rcvptr;    /* and some char will be lost */
        !          1447:        memcpy(rcvbuf+rcvptr, p, i);
        !          1448:        rcvptr += i;
        !          1449:        oncore_consume(instance);
        !          1450: }
        !          1451: 
        !          1452: 
        !          1453: 
        !          1454: /*
        !          1455:  * Deal with any complete messages
        !          1456:  */
        !          1457: 
        !          1458: static void
        !          1459: oncore_consume(
        !          1460:        struct instance *instance
        !          1461:        )
        !          1462: {
        !          1463:        int i, m;
        !          1464:        unsigned l;
        !          1465: 
        !          1466:        while (rcvptr >= 7) {
        !          1467:                if (rcvbuf[0] != '@' || rcvbuf[1] != '@') {
        !          1468:                        /* We're not in sync, lets try to get there */
        !          1469:                        for (i=1; i < rcvptr-1; i++)
        !          1470:                                if (rcvbuf[i] == '@' && rcvbuf[i+1] == '@')
        !          1471:                                        break;
        !          1472: #ifdef ONCORE_VERBOSE_CONSUME
        !          1473:                        if (debug > 4) {
        !          1474:                                char    Msg[120];
        !          1475: 
        !          1476:                                snprintf(Msg, sizeof(Msg),
        !          1477:                                         ">>> skipping %d chars", i);
        !          1478:                                oncore_log(instance, LOG_DEBUG, Msg);
        !          1479:                        }
        !          1480: #endif
        !          1481:                        if (i != rcvptr)
        !          1482:                                memcpy(rcvbuf, rcvbuf+i, (size_t)(rcvptr-i));
        !          1483:                        rcvptr -= i;
        !          1484:                        continue;
        !          1485:                }
        !          1486: 
        !          1487:                /* Ok, we have a header now */
        !          1488:                l = sizeof(oncore_messages)/sizeof(oncore_messages[0]) -1;
        !          1489:                for(m=0; m<l; m++)
        !          1490:                        if (!strncmp(oncore_messages[m].flag, (char *)(rcvbuf+2), (size_t) 2))
        !          1491:                                break;
        !          1492:                if (m == l) {
        !          1493: #ifdef ONCORE_VERBOSE_CONSUME
        !          1494:                        if (debug > 4) {
        !          1495:                                char    Msg[120];
        !          1496: 
        !          1497:                                snprintf(Msg, sizeof(Msg),
        !          1498:                                         ">>> Unknown MSG, skipping 4 (%c%c)",
        !          1499:                                         rcvbuf[2], rcvbuf[3]);
        !          1500:                                oncore_log(instance, LOG_DEBUG, Msg);
        !          1501:                        }
        !          1502: #endif
        !          1503:                        memcpy(rcvbuf, rcvbuf+4, (size_t) 4);
        !          1504:                        rcvptr -= 4;
        !          1505:                        continue;
        !          1506:                }
        !          1507: 
        !          1508:                l = oncore_messages[m].len;
        !          1509: #ifdef ONCORE_VERBOSE_CONSUME
        !          1510:                if (debug > 3) {
        !          1511:                        char Msg[120];
        !          1512: 
        !          1513:                        snprintf(Msg, sizeof(Msg),
        !          1514:                                 "GOT: %c%c  %d of %d entry %d",
        !          1515:                                 instance->unit, rcvbuf[2], rcvbuf[3],
        !          1516:                                 rcvptr, l, m);
        !          1517:                        oncore_log(instance, LOG_DEBUG, Msg);
        !          1518:                        }
        !          1519: #endif
        !          1520:                /* Got the entire message ? */
        !          1521: 
        !          1522:                if (rcvptr < l)
        !          1523:                        return;
        !          1524: 
        !          1525:                /* are we at the end of message? should be <Cksum><CR><LF> */
        !          1526: 
        !          1527:                if (rcvbuf[l-2] != '\r' || rcvbuf[l-1] != '\n') {
        !          1528: #ifdef ONCORE_VERBOSE_CONSUME
        !          1529:                        if (debug)
        !          1530:                                oncore_log(instance, LOG_DEBUG, "NO <CR><LF> at end of message");
        !          1531: #endif
        !          1532:                } else {        /* check the CheckSum */
        !          1533:                        if (oncore_checksum_ok(rcvbuf, l)) {
        !          1534:                                if (instance->shmem != NULL) {
        !          1535:                                        instance->shmem[oncore_messages[m].shmem + 2]++;
        !          1536:                                        memcpy(instance->shmem + oncore_messages[m].shmem + 3,
        !          1537:                                            rcvbuf, (size_t) l);
        !          1538:                                }
        !          1539:                                oncore_msg_any(instance, rcvbuf, (size_t) (l-3), m);
        !          1540:                                if (oncore_messages[m].handler)
        !          1541:                                        oncore_messages[m].handler(instance, rcvbuf, (size_t) (l-3));
        !          1542:                        }
        !          1543: #ifdef ONCORE_VERBOSE_CONSUME
        !          1544:                        else if (debug) {
        !          1545:                                char    Msg[120], Msg2[10];
        !          1546: 
        !          1547:                                oncore_log(instance, LOG_ERR, "Checksum mismatch!");
        !          1548:                                snprintf(Msg, sizeof(Msg), "@@%c%c ", rcvbuf[2], rcvbuf[3]);
        !          1549:                                for (i = 4; i < l; i++) {
        !          1550:                                        snprintf(Msg2, sizeof(Msg2),
        !          1551:                                                 "%03o ", rcvbuf[i]);
        !          1552:                                        strncat(Msg, Msg2, sizeof(Msg));
        !          1553:                                }
        !          1554:                                oncore_log(instance, LOG_DEBUG, Msg);
        !          1555:                        }
        !          1556: #endif
        !          1557:                }
        !          1558: 
        !          1559:                if (l != rcvptr)
        !          1560:                        memcpy(rcvbuf, rcvbuf+l, (size_t) (rcvptr-l));
        !          1561:                rcvptr -= l;
        !          1562:        }
        !          1563: }
        !          1564: 
        !          1565: 
        !          1566: 
        !          1567: static void
        !          1568: oncore_get_timestamp(
        !          1569:        struct instance *instance,
        !          1570:        long dt1,       /* tick offset THIS time step */
        !          1571:        long dt2        /* tick offset NEXT time step */
        !          1572:        )
        !          1573: {
        !          1574:        int     Rsm;
        !          1575:        u_long  j;
        !          1576:        l_fp ts, ts_tmp;
        !          1577:        double dmy;
        !          1578: #ifdef HAVE_STRUCT_TIMESPEC
        !          1579:        struct timespec *tsp = 0;
        !          1580: #else
        !          1581:        struct timeval  *tsp = 0;
        !          1582: #endif
        !          1583:        int     current_mode;
        !          1584:        pps_params_t current_params;
        !          1585:        struct timespec timeout;
        !          1586:        struct peer *peer;
        !          1587:        pps_info_t pps_i;
        !          1588:        char    Msg[140];
        !          1589: 
        !          1590:        peer = instance->peer;
        !          1591: 
        !          1592: #if 1
        !          1593:        /* If we are in SiteSurvey mode, then we are in 3D mode, and we fall thru.
        !          1594:         * If we have Finished the SiteSurvey, then we fall thru for the 14/15
        !          1595:         *  times we get here in 0D mode (the 1/15 is in 3D for SHMEM).
        !          1596:         * This gives good time, which gets better when the SS is done.
        !          1597:         */
        !          1598: 
        !          1599:        if ((instance->site_survey == ONCORE_SS_DONE) && (instance->mode != MODE_0D)) {
        !          1600: #else
        !          1601:        /* old check, only fall thru for SS_DONE and 0D mode, 2h45m wait for ticks */
        !          1602: 
        !          1603:        if ((instance->site_survey != ONCORE_SS_DONE) || (instance->mode != MODE_0D)) {
        !          1604: #endif
        !          1605:                peer->flags &= ~FLAG_PPS;
        !          1606:                return;
        !          1607:        }
        !          1608: 
        !          1609:        /* Don't do anything without an almanac to define the GPS->UTC delta */
        !          1610: 
        !          1611:        if (instance->rsm.bad_almanac) {
        !          1612:                peer->flags &= ~FLAG_PPS;
        !          1613:                return;
        !          1614:        }
        !          1615: 
        !          1616:        /* Once the Almanac is valid, the M12+T does not produce valid UTC
        !          1617:         * immediately.
        !          1618:         * Wait for UTC offset decode valid, then wait one message more
        !          1619:         * so we are not off by 13 seconds after  reset.
        !          1620:         */
        !          1621: 
        !          1622:        if (instance->count5) {
        !          1623:                instance->count5--;
        !          1624:                peer->flags &= ~FLAG_PPS;
        !          1625:                return;
        !          1626:        }
        !          1627: 
        !          1628:        j = instance->ev_serial;
        !          1629:        timeout.tv_sec = 0;
        !          1630:        timeout.tv_nsec = 0;
        !          1631:        if (time_pps_fetch(instance->pps_h, PPS_TSFMT_TSPEC, &pps_i,
        !          1632:            &timeout) < 0) {
        !          1633:                oncore_log(instance, LOG_ERR, "time_pps_fetch failed");
        !          1634:                peer->flags &= ~FLAG_PPS;
        !          1635:                return;
        !          1636:        }
        !          1637: 
        !          1638:        if (instance->assert) {
        !          1639:                tsp = &pps_i.assert_timestamp;
        !          1640: 
        !          1641: #ifdef ONCORE_VERBOSE_GET_TIMESTAMP
        !          1642:                if (debug > 2) {
        !          1643:                        u_long i;
        !          1644: 
        !          1645:                        i = (u_long) pps_i.assert_sequence;
        !          1646: # ifdef HAVE_STRUCT_TIMESPEC
        !          1647:                        snprintf(Msg, sizeof(Msg),
        !          1648:                                 "serial/j (%lu, %lu) %ld.%09ld", i, j,
        !          1649:                                 (long)tsp->tv_sec, (long)tsp->tv_nsec);
        !          1650: # else
        !          1651:                        snprintf(Msg, sizeof(Msg), 
        !          1652:                                 "serial/j (%lu, %lu) %ld.%06ld", i, j,
        !          1653:                                 (long)tsp->tv_sec, (long)tsp->tv_usec);
        !          1654: # endif
        !          1655:                        oncore_log(instance, LOG_DEBUG, Msg);
        !          1656:                }
        !          1657: #endif
        !          1658: 
        !          1659:                if (pps_i.assert_sequence == j) {
        !          1660:                        oncore_log(instance, LOG_NOTICE, "ONCORE: oncore_get_timestamp, error serial pps");
        !          1661:                        peer->flags &= ~FLAG_PPS;
        !          1662:                        return;
        !          1663:                }
        !          1664: 
        !          1665:                instance->ev_serial = pps_i.assert_sequence;
        !          1666:        } else {
        !          1667:                tsp = &pps_i.clear_timestamp;
        !          1668: 
        !          1669: #if 0
        !          1670:                if (debug > 2) {
        !          1671:                        u_long i;
        !          1672: 
        !          1673:                        i = (u_long) pps_i.clear_sequence;
        !          1674: # ifdef HAVE_STRUCT_TIMESPEC
        !          1675:                        snprintf(Msg, sizeof(Msg),
        !          1676:                                 "serial/j (%lu, %lu) %ld.%09ld", i, j,
        !          1677:                                 (long)tsp->tv_sec, (long)tsp->tv_nsec);
        !          1678: # else
        !          1679:                        snprintf(Msg. sizeof(Msg),
        !          1680:                                 "serial/j (%lu, %lu) %ld.%06ld", i, j,
        !          1681:                                 (long)tsp->tv_sec, (long)tsp->tv_usec);
        !          1682: # endif
        !          1683:                        oncore_log(instance, LOG_DEBUG, Msg);
        !          1684:                }
        !          1685: #endif
        !          1686: 
        !          1687:                if (pps_i.clear_sequence == j) {
        !          1688:                        oncore_log(instance, LOG_ERR, "oncore_get_timestamp, error serial pps");
        !          1689:                        peer->flags &= ~FLAG_PPS;
        !          1690:                        return;
        !          1691:                }
        !          1692:                instance->ev_serial = pps_i.clear_sequence;
        !          1693:        }
        !          1694: 
        !          1695:        /* convert timespec -> ntp l_fp */
        !          1696: 
        !          1697:        dmy = tsp->tv_nsec;
        !          1698:        dmy /= 1e9;
        !          1699:        ts.l_uf = dmy * 4294967296.0;
        !          1700:        ts.l_ui = tsp->tv_sec;
        !          1701: 
        !          1702: #if 0
        !          1703:      alternate code for previous 4 lines is
        !          1704:        dmy = 1.0e-9*tsp->tv_nsec;      /* fractional part */
        !          1705:        DTOLFP(dmy, &ts);
        !          1706:        dmy = tsp->tv_sec;              /* integer part */
        !          1707:        DTOLFP(dmy, &ts_tmp);
        !          1708:        L_ADD(&ts, &ts_tmp);
        !          1709:      or more simply
        !          1710:        dmy = 1.0e-9*tsp->tv_nsec;      /* fractional part */
        !          1711:        DTOLFP(dmy, &ts);
        !          1712:        ts.l_ui = tsp->tv_sec;
        !          1713: #endif /* 0 */
        !          1714: 
        !          1715:        /* now have timestamp in ts */
        !          1716:        /* add in saw_tooth and offset, these will be ZERO if no TRAIM */
        !          1717:        /* they will be IGNORED if the PPSAPI cant do PPS_OFFSET/ASSERT/CLEAR */
        !          1718:        /* we just try to add them in and dont test for that here */
        !          1719: 
        !          1720:        /* saw_tooth not really necessary if using TIMEVAL */
        !          1721:        /* since its only precise to us, but do it anyway. */
        !          1722: 
        !          1723:        /* offset in ns, and is positive (late), we subtract */
        !          1724:        /* to put the PPS time transition back where it belongs */
        !          1725: 
        !          1726:        /* must hand the offset for the NEXT sec off to the Kernel to do */
        !          1727:        /* the addition, so that the Kernel PLL sees the offset too */
        !          1728: 
        !          1729:        if (instance->assert)
        !          1730:                instance->pps_p.assert_offset.tv_nsec = -dt2;
        !          1731:        else
        !          1732:                instance->pps_p.clear_offset.tv_nsec  = -dt2;
        !          1733: 
        !          1734:        /* The following code is necessary, and not just a time_pps_setparams,
        !          1735:         * using the saved instance->pps_p, since some other process on the
        !          1736:         * machine may have diddled with the mode bits (say adding something
        !          1737:         * that it needs).  We take what is there and ADD what we need.
        !          1738:         * [[ The results from the time_pps_getcap is unlikely to change so
        !          1739:         *    we could probably just save it, but I choose to do the call ]]
        !          1740:         * Unfortunately, there is only ONE set of mode bits in the kernel per
        !          1741:         * interface, and not one set for each open handle.
        !          1742:         *
        !          1743:         * There is still a race condition here where we might mess up someone
        !          1744:         * elses mode, but if he is being careful too, he should survive.
        !          1745:         */
        !          1746: 
        !          1747:        if (time_pps_getcap(instance->pps_h, &current_mode) < 0) {
        !          1748:                msnprintf(Msg, sizeof(Msg), "time_pps_getcap failed: %m");
        !          1749:                oncore_log(instance, LOG_ERR, Msg);
        !          1750:                peer->flags &= ~FLAG_PPS;
        !          1751:                return;
        !          1752:        }
        !          1753: 
        !          1754:        if (time_pps_getparams(instance->pps_h, &current_params) < 0) {
        !          1755:                msnprintf(Msg, sizeof(Msg), "time_pps_getparams failed: %m");
        !          1756:                oncore_log(instance, LOG_ERR, Msg);
        !          1757:                peer->flags &= ~FLAG_PPS;
        !          1758:                return;
        !          1759:        }
        !          1760: 
        !          1761:                /* or current and mine */
        !          1762:        current_params.mode |= instance->pps_p.mode;
        !          1763:                /* but only set whats legal */
        !          1764:        current_params.mode &= current_mode;
        !          1765: 
        !          1766:        current_params.assert_offset.tv_sec = 0;
        !          1767:        current_params.assert_offset.tv_nsec = -dt2;
        !          1768:        current_params.clear_offset.tv_sec = 0;
        !          1769:        current_params.clear_offset.tv_nsec = -dt2;
        !          1770: 
        !          1771:        if (time_pps_setparams(instance->pps_h, &current_params))
        !          1772:                oncore_log(instance, LOG_ERR, "ONCORE: Error doing time_pps_setparams");
        !          1773: 
        !          1774:        /* have time from UNIX origin, convert to NTP origin. */
        !          1775: 
        !          1776:        ts.l_ui += JAN_1970;
        !          1777:        instance->pp->lastrec = ts;
        !          1778: 
        !          1779:        /* print out information about this timestamp (long line) */
        !          1780: 
        !          1781:        ts_tmp = ts;
        !          1782:        ts_tmp.l_ui = 0;        /* zero integer part */
        !          1783:        LFPTOD(&ts_tmp, dmy);   /* convert fractional part to a double */
        !          1784:        j = 1.0e9*dmy;          /* then to integer ns */
        !          1785: 
        !          1786:        Rsm = 0;
        !          1787:        if (instance->chan == 6)
        !          1788:                Rsm = instance->BEHa[64];
        !          1789:        else if (instance->chan == 8)
        !          1790:                Rsm = instance->BEHa[72];
        !          1791:        else if (instance->chan == 12)
        !          1792:                Rsm = ((instance->BEHa[129]<<8) | instance->BEHa[130]);
        !          1793: 
        !          1794:        if (instance->chan == 6 || instance->chan == 8) {
        !          1795:                char    f1[5], f2[5], f3[5], f4[5];
        !          1796:                if (instance->traim) {
        !          1797:                        snprintf(f1, sizeof(f1), "%d",
        !          1798:                                 instance->BEHn[21]);
        !          1799:                        snprintf(f2, sizeof(f2), "%d",
        !          1800:                                 instance->BEHn[22]);
        !          1801:                        snprintf(f3, sizeof(f3), "%2d",
        !          1802:                                 instance->BEHn[23] * 256 +
        !          1803:                                     instance->BEHn[24]);
        !          1804:                        snprintf(f4, sizeof(f4), "%3d",
        !          1805:                                 (s_char)instance->BEHn[25]);
        !          1806:                } else {
        !          1807:                        strncpy(f1, "x", sizeof(f1));
        !          1808:                        strncpy(f2, "x", sizeof(f2));
        !          1809:                        strncpy(f3, "xx", sizeof(f3));
        !          1810:                        strncpy(f4, "xxx", sizeof(f4));
        !          1811:                }
        !          1812:                snprintf(Msg, sizeof(Msg),      /* MAX length 128, currently at 127 */
        !          1813:  "%u.%09lu %d %d %2d %2d %2d %2ld rstat   %02x dop %4.1f nsat %2d,%d traim %d,%s,%s sigma %s neg-sawtooth %s sat %d%d%d%d%d%d%d%d",
        !          1814:                    ts.l_ui, j,
        !          1815:                    instance->pp->year, instance->pp->day,
        !          1816:                    instance->pp->hour, instance->pp->minute, instance->pp->second,
        !          1817:                    (long) tsp->tv_sec % 60,
        !          1818:                    Rsm, 0.1*(256*instance->BEHa[35]+instance->BEHa[36]),
        !          1819:                    /*rsat      dop */
        !          1820:                    instance->BEHa[38], instance->BEHa[39], instance->traim, f1, f2,
        !          1821:                    /*  nsat visible,     nsat tracked,     traim,traim,traim */
        !          1822:                    f3, f4,
        !          1823:                    /* sigma neg-sawtooth */
        !          1824:          /*sat*/   instance->BEHa[41], instance->BEHa[45], instance->BEHa[49], instance->BEHa[53],
        !          1825:                    instance->BEHa[57], instance->BEHa[61], instance->BEHa[65], instance->BEHa[69]
        !          1826:                    );                                  /* will be 0 for 6 chan */
        !          1827:        } else if (instance->chan == 12) {
        !          1828:                char    f1[5], f2[5], f3[5], f4[5];
        !          1829:                if (instance->traim) {
        !          1830:                        snprintf(f1, sizeof(f1), "%d",
        !          1831:                                 instance->BEHn[6]);
        !          1832:                        snprintf(f2, sizeof(f2), "%d",
        !          1833:                                 instance->BEHn[7]);
        !          1834:                        snprintf(f3, sizeof(f3), "%d",
        !          1835:                                 instance->BEHn[12] * 256 +
        !          1836:                                     instance->BEHn[13]);
        !          1837:                        snprintf(f4, sizeof(f4), "%3d",
        !          1838:                                 (s_char)instance->BEHn[14]);
        !          1839:                } else {
        !          1840:                        strncpy(f1, "x", sizeof(f1));
        !          1841:                        strncpy(f2, "x", sizeof(f2));
        !          1842:                        strncpy(f3, "xx", sizeof(f3));
        !          1843:                        strncpy(f4, "xxx", sizeof(f4));
        !          1844:                }
        !          1845:                snprintf(Msg, sizeof(Msg),
        !          1846:  "%u.%09lu %d %d %2d %2d %2d %2ld rstat %02x dop %4.1f nsat %2d,%d traim %d,%s,%s sigma %s neg-sawtooth %s sat %d%d%d%d%d%d%d%d%d%d%d%d",
        !          1847:                    ts.l_ui, j,
        !          1848:                    instance->pp->year, instance->pp->day,
        !          1849:                    instance->pp->hour, instance->pp->minute, instance->pp->second,
        !          1850:                    (long) tsp->tv_sec % 60,
        !          1851:                    Rsm, 0.1*(256*instance->BEHa[53]+instance->BEHa[54]),
        !          1852:                    /*rsat      dop */
        !          1853:                    instance->BEHa[55], instance->BEHa[56], instance->traim, f1, f2,
        !          1854:                    /*  nsat visible,     nsat tracked   traim,traim,traim */
        !          1855:                    f3, f4,
        !          1856:                    /* sigma neg-sawtooth */
        !          1857:          /*sat*/   instance->BEHa[58], instance->BEHa[64], instance->BEHa[70], instance->BEHa[76],
        !          1858:                    instance->BEHa[82], instance->BEHa[88], instance->BEHa[94], instance->BEHa[100],
        !          1859:                    instance->BEHa[106], instance->BEHa[112], instance->BEHa[118], instance->BEHa[124]
        !          1860:                    );
        !          1861:        }
        !          1862: 
        !          1863:        /* and some things I dont understand (magic ntp things) */
        !          1864: 
        !          1865:        if (!refclock_process(instance->pp)) {
        !          1866:                refclock_report(instance->peer, CEVNT_BADTIME);
        !          1867:                peer->flags &= ~FLAG_PPS;
        !          1868:                return;
        !          1869:        }
        !          1870: 
        !          1871:        oncore_log(instance, LOG_INFO, Msg);     /* this is long message above */
        !          1872:        instance->pollcnt = 2;
        !          1873: 
        !          1874:        if (instance->polled) {
        !          1875:                instance->polled = 0;
        !          1876:             /* instance->pp->dispersion = instance->pp->skew = 0;      */
        !          1877:                instance->pp->lastref = instance->pp->lastrec;
        !          1878:                refclock_receive(instance->peer);
        !          1879:        }
        !          1880:        peer->flags |= FLAG_PPS;
        !          1881: }
        !          1882: 
        !          1883: 
        !          1884: /*************** oncore_msg_XX routines start here *******************/
        !          1885: 
        !          1886: 
        !          1887: /*
        !          1888:  * print Oncore response message.
        !          1889:  */
        !          1890: 
        !          1891: static void
        !          1892: oncore_msg_any(
        !          1893:        struct instance *instance,
        !          1894:        u_char *buf,
        !          1895:        size_t len,
        !          1896:        int idx
        !          1897:        )
        !          1898: {
        !          1899: #ifdef ONCORE_VERBOSE_MSG_ANY
        !          1900:        int i;
        !          1901:        const char *fmt = oncore_messages[idx].fmt;
        !          1902:        const char *p;
        !          1903:        char *q;
        !          1904:        char *qlim;
        !          1905: #ifdef HAVE_GETCLOCK
        !          1906:        struct timespec ts;
        !          1907: #endif
        !          1908:        struct timeval tv;
        !          1909:        char    Msg[120], Msg2[10];
        !          1910: 
        !          1911:        if (debug > 3) {
        !          1912: # ifdef HAVE_GETCLOCK
        !          1913:                (void) getclock(TIMEOFDAY, &ts);
        !          1914:                tv.tv_sec = ts.tv_sec;
        !          1915:                tv.tv_usec = ts.tv_nsec / 1000;
        !          1916: # else
        !          1917:                GETTIMEOFDAY(&tv, 0);
        !          1918: # endif
        !          1919:                snprintf(Msg, sizeof(Msg), "%ld.%06ld",
        !          1920:                         (long)tv.tv_sec, (long)tv.tv_usec);
        !          1921:                oncore_log(instance, LOG_DEBUG, Msg);
        !          1922: 
        !          1923:                if (!*fmt) {
        !          1924:                        snprintf(Msg, sizeof(Msg), ">>@@%c%c ", buf[2],
        !          1925:                                 buf[3]);
        !          1926:                        for(i = 2; i < len && i < 2400 ; i++) {
        !          1927:                                snprintf(Msg2, sizeof(Msg2), "%02x",
        !          1928:                                         buf[i]);
        !          1929:                                strncpy(Msg, Msg2, sizeof(Msg));
        !          1930: 
        !          1931:                        }
        !          1932:                        oncore_log(instance, LOG_DEBUG, Msg);
        !          1933:                        return;
        !          1934:                } else {
        !          1935:                        strncat(Msg, "##", sizeof(Msg));
        !          1936:                        qlim = Msg + sizeof(Msg) - 3;
        !          1937:                        for (p = fmt, q = Msg + 2; q < qlim && *p; ) {
        !          1938:                                *q++ = *p++;
        !          1939:                                *q++ = '_';
        !          1940:                        }
        !          1941:                        *q = '\0';
        !          1942:                        oncore_log(instance, LOG_DEBUG, Msg);
        !          1943:                        snprintf(Msg, sizeof(Msg), "%c%c", buf[2],
        !          1944:                                 buf[3]);
        !          1945:                        i = 4;
        !          1946:                        for (p = fmt; *p; p++) {
        !          1947:                                snprintf(Msg2, "%02x", buf[i++]);
        !          1948:                                strncat(Msg, Msg2, sizeof(Msg));
        !          1949:                        }
        !          1950:                        oncore_log(instance, LOG_DEBUG, Msg);
        !          1951:                }
        !          1952:        }
        !          1953: #endif
        !          1954: }
        !          1955: 
        !          1956: 
        !          1957: 
        !          1958: /* Latitude, Longitude, Height */
        !          1959: 
        !          1960: static void
        !          1961: oncore_msg_Adef(
        !          1962:        struct instance *instance,
        !          1963:        u_char *buf,
        !          1964:        size_t len
        !          1965:        )
        !          1966: {
        !          1967: }
        !          1968: 
        !          1969: 
        !          1970: 
        !          1971: /* Mask Angle */
        !          1972: 
        !          1973: static void
        !          1974: oncore_msg_Ag(
        !          1975:        struct instance *instance,
        !          1976:        u_char *buf,
        !          1977:        size_t len
        !          1978:        )
        !          1979: {              char  Msg[160], *cp;
        !          1980: 
        !          1981:                cp = "set to";
        !          1982:                if (instance->o_state == ONCORE_RUN)
        !          1983:                        cp = "is";
        !          1984: 
        !          1985:                instance->Ag = buf[4];
        !          1986:                snprintf(Msg, sizeof(Msg),
        !          1987:                         "Satellite mask angle %s %d degrees", cp, 
        !          1988:                         (int)instance->Ag);
        !          1989:                oncore_log(instance, LOG_INFO, Msg);
        !          1990: }
        !          1991: 
        !          1992: 
        !          1993: 
        !          1994: /*
        !          1995:  * get Position hold position
        !          1996:  */
        !          1997: 
        !          1998: static void
        !          1999: oncore_msg_As(
        !          2000:        struct instance *instance,
        !          2001:        u_char *buf,
        !          2002:        size_t len
        !          2003:        )
        !          2004: {
        !          2005:        instance->ss_lat  = buf_w32(&buf[4]);
        !          2006:        instance->ss_long = buf_w32(&buf[8]);
        !          2007:        instance->ss_ht   = buf_w32(&buf[12]);
        !          2008: 
        !          2009:        /* Print out Position */
        !          2010:        oncore_print_posn(instance);
        !          2011: }
        !          2012: 
        !          2013: 
        !          2014: 
        !          2015: /*
        !          2016:  * Try to use Oncore UT+ Auto Survey Feature
        !          2017:  *     If its not there (VP), set flag to do it ourselves.
        !          2018:  */
        !          2019: 
        !          2020: static void
        !          2021: oncore_msg_At(
        !          2022:        struct instance *instance,
        !          2023:        u_char *buf,
        !          2024:        size_t len
        !          2025:        )
        !          2026: {
        !          2027:        instance->saw_At = 1;
        !          2028:        if (instance->site_survey == ONCORE_SS_TESTING) {
        !          2029:                if (buf[4] == 2) {
        !          2030:                        oncore_log(instance, LOG_NOTICE,
        !          2031:                                        "Initiating hardware 3D site survey");
        !          2032: 
        !          2033:                        oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_HW");
        !          2034:                        instance->site_survey = ONCORE_SS_HW;
        !          2035:                }
        !          2036:        }
        !          2037: }
        !          2038: 
        !          2039: 
        !          2040: 
        !          2041: /*
        !          2042:  * get PPS Offset
        !          2043:  * Nb. @@Ay is not supported for early UT (no plus) model
        !          2044:  */
        !          2045: 
        !          2046: static void
        !          2047: oncore_msg_Ay(
        !          2048:        struct instance *instance,
        !          2049:        u_char *buf,
        !          2050:        size_t len
        !          2051:        )
        !          2052: {
        !          2053:        char Msg[120];
        !          2054: 
        !          2055:        if (instance->saw_Ay)
        !          2056:                return;
        !          2057: 
        !          2058:        instance->saw_Ay = 1;
        !          2059: 
        !          2060:        instance->offset = buf_w32(&buf[4]);
        !          2061: 
        !          2062:        snprintf(Msg, sizeof(Msg), "PPS Offset is set to %ld ns",
        !          2063:                 instance->offset);
        !          2064:        oncore_log(instance, LOG_INFO, Msg);
        !          2065: }
        !          2066: 
        !          2067: 
        !          2068: 
        !          2069: /*
        !          2070:  * get Cable Delay
        !          2071:  */
        !          2072: 
        !          2073: static void
        !          2074: oncore_msg_Az(
        !          2075:        struct instance *instance,
        !          2076:        u_char *buf,
        !          2077:        size_t len
        !          2078:        )
        !          2079: {
        !          2080:        char Msg[120];
        !          2081: 
        !          2082:        if (instance->saw_Az)
        !          2083:                return;
        !          2084: 
        !          2085:        instance->saw_Az = 1;
        !          2086: 
        !          2087:        instance->delay = buf_w32(&buf[4]);
        !          2088: 
        !          2089:        snprintf(Msg, sizeof(Msg), "Cable delay is set to %ld ns",
        !          2090:                instance->delay);
        !          2091:        oncore_log(instance, LOG_INFO, Msg);
        !          2092: }
        !          2093: 
        !          2094: 
        !          2095: 
        !          2096: /* Ba, Ea and Ha come here, these contain Position */
        !          2097: 
        !          2098: static void
        !          2099: oncore_msg_BaEaHa(
        !          2100:        struct instance *instance,
        !          2101:        u_char *buf,
        !          2102:        size_t len
        !          2103:        )
        !          2104: {
        !          2105:        const char      *cp;
        !          2106:        char            Msg[160];
        !          2107:        int             mode;
        !          2108: 
        !          2109:        /* OK, we are close to the RUN state now.
        !          2110:         * But we have a few more items to initialize first.
        !          2111:         *
        !          2112:         * At the beginning of this routine there are several 'timers'.
        !          2113:         * We enter this routine 1/sec, and since the upper levels of NTP have usurped
        !          2114:         * the use of timers, we use the 1/sec entry to do things that
        !          2115:         * we would normally do with timers...
        !          2116:         */
        !          2117: 
        !          2118:        if (instance->o_state == ONCORE_CHECK_CHAN) {   /* here while checking for the # chan */
        !          2119:                if (buf[2] == 'B') {            /* 6chan */
        !          2120:                        if (instance->chan_ck < 6) instance->chan_ck = 6;
        !          2121:                } else if (buf[2] == 'E') {     /* 8chan */
        !          2122:                        if (instance->chan_ck < 8) instance->chan_ck = 8;
        !          2123:                } else if (buf[2] == 'H') {     /* 12chan */
        !          2124:                        if (instance->chan_ck < 12) instance->chan_ck = 12;
        !          2125:                }
        !          2126: 
        !          2127:                if (instance->count3++ < 5)
        !          2128:                        return;
        !          2129: 
        !          2130:                instance->count3 = 0;
        !          2131: 
        !          2132:                if (instance->chan_in != -1)    /* set in Input */
        !          2133:                        instance->chan = instance->chan_in;
        !          2134:                else                            /* set from test */
        !          2135:                        instance->chan = instance->chan_ck;
        !          2136: 
        !          2137:                snprintf(Msg, sizeof(Msg), "Input   says chan = %d",
        !          2138:                         instance->chan_in);
        !          2139:                oncore_log(instance, LOG_INFO, Msg);
        !          2140:                snprintf(Msg, sizeof(Msg), "Model # says chan = %d",
        !          2141:                         instance->chan_id);
        !          2142:                oncore_log(instance, LOG_INFO, Msg);
        !          2143:                snprintf(Msg, sizeof(Msg), "Testing says chan = %d",
        !          2144:                         instance->chan_ck);
        !          2145:                oncore_log(instance, LOG_INFO, Msg);
        !          2146:                snprintf(Msg, sizeof(Msg), "Using        chan = %d",
        !          2147:                         instance->chan);
        !          2148:                oncore_log(instance, LOG_INFO, Msg);
        !          2149: 
        !          2150:                instance->o_state = ONCORE_HAVE_CHAN;
        !          2151:                oncore_log(instance, LOG_NOTICE, "state = ONCORE_HAVE_CHAN");
        !          2152: 
        !          2153:                instance->timeout = 4;
        !          2154:                oncore_sendmsg(instance, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
        !          2155:                return;
        !          2156:        }
        !          2157: 
        !          2158:        if (instance->o_state != ONCORE_ALMANAC && instance->o_state != ONCORE_RUN)
        !          2159:                return;
        !          2160: 
        !          2161:        /* PAUSE 5sec - make sure results are stable, before using position */
        !          2162: 
        !          2163:        if (instance->count) {
        !          2164:                if (instance->count++ < 5)
        !          2165:                        return;
        !          2166:                instance->count = 0;
        !          2167:        }
        !          2168: 
        !          2169:        memcpy(instance->BEHa, buf, (size_t) (len+3));  /* Ba, Ea or Ha */
        !          2170: 
        !          2171:        /* check the antenna (did it get unplugged) and almanac (is it ready) for changes. */
        !          2172: 
        !          2173:        oncore_check_almanac(instance);
        !          2174:        oncore_check_antenna(instance);
        !          2175: 
        !          2176:        /* If we are in Almanac mode, waiting for Almanac, we can't do anything till we have it */
        !          2177:        /* When we have an almanac, we will start the Bn/En/@@Hn messages */
        !          2178: 
        !          2179:        if (instance->o_state == ONCORE_ALMANAC)
        !          2180:                if (oncore_wait_almanac(instance))
        !          2181:                        return;
        !          2182: 
        !          2183:        /* do some things once when we get this far in BaEaHa */
        !          2184: 
        !          2185:        if (instance->once) {
        !          2186:                instance->once = 0;
        !          2187:                instance->count2 = 1;
        !          2188: 
        !          2189:                /* Have we seen an @@At (position hold) command response */
        !          2190:                /* if not, message out */
        !          2191: 
        !          2192:                if (instance->chan != 12 && !instance->saw_At) {
        !          2193:                        oncore_log(instance, LOG_NOTICE,
        !          2194:                                "Not Good, no @@At command (no Position Hold), must be a GT/GT+");
        !          2195:                        oncore_sendmsg(instance, oncore_cmd_Av1, sizeof(oncore_cmd_Av1));
        !          2196:                }
        !          2197: 
        !          2198:                /* have an Almanac, can start the SiteSurvey
        !          2199:                 * (actually only need to get past the almanac_load where we diddle with At
        !          2200:                 *  command,- we can't change it after we start the HW_SS below
        !          2201:                 */
        !          2202: 
        !          2203:                mode = instance->init_type;
        !          2204:                switch (mode) {
        !          2205:                case 0: /* NO initialization, don't change anything */
        !          2206:                case 1: /* Use given Position */
        !          2207:                case 3:
        !          2208:                        instance->site_survey = ONCORE_SS_DONE;
        !          2209:                        oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_DONE");
        !          2210:                        break;
        !          2211: 
        !          2212:                case 2:
        !          2213:                case 4: /* Site Survey */
        !          2214:                        oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_TESTING");
        !          2215:                        instance->site_survey = ONCORE_SS_TESTING;
        !          2216:                        instance->count1 = 1;
        !          2217:                        if (instance->chan == 12)
        !          2218:                                oncore_sendmsg(instance, oncore_cmd_Gd3,  sizeof(oncore_cmd_Gd3));  /* M12+T */
        !          2219:                        else
        !          2220:                                oncore_sendmsg(instance, oncore_cmd_At2,  sizeof(oncore_cmd_At2));  /* not GT, arg not VP */
        !          2221:                        break;
        !          2222:                }
        !          2223: 
        !          2224:                /* Read back PPS Offset for Output */
        !          2225:                /* Nb. This will fail silently for early UT (no plus) and M12 models */
        !          2226: 
        !          2227:                oncore_sendmsg(instance, oncore_cmd_Ayx,  sizeof(oncore_cmd_Ayx));
        !          2228: 
        !          2229:                /* Read back Cable Delay for Output */
        !          2230: 
        !          2231:                oncore_sendmsg(instance, oncore_cmd_Azx,  sizeof(oncore_cmd_Azx));
        !          2232: 
        !          2233:                /* Read back Satellite Mask Angle for Output */
        !          2234: 
        !          2235:                oncore_sendmsg(instance, oncore_cmd_Agx,  sizeof(oncore_cmd_Agx));
        !          2236:        }
        !          2237: 
        !          2238: 
        !          2239:        /* Unfortunately, the Gd3 command returns '3' for the M12 v1.3 firmware where it is
        !          2240:         * out-of-range and it should return 0-2. (v1.3 can't do a HW Site Survey)
        !          2241:         * We must do the Gd3, and then wait a cycle or two for things to settle,
        !          2242:         * then check Ha[130]&0x10 to see if a SS is in progress.
        !          2243:         * We will set SW if HW has not been set after an appropriate delay.
        !          2244:         */
        !          2245: 
        !          2246:        if (instance->site_survey == ONCORE_SS_TESTING) {
        !          2247:                if (instance->chan == 12) {
        !          2248:                        if (instance->count1) {
        !          2249:                                if (instance->count1++ > 5 || instance->BEHa[130]&0x10) {
        !          2250:                                        instance->count1 = 0;
        !          2251:                                        if (instance->BEHa[130]&0x10) {
        !          2252:                                                oncore_log(instance, LOG_NOTICE,
        !          2253:                                                                "Initiating hardware 3D site survey");
        !          2254: 
        !          2255:                                                oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_HW");
        !          2256:                                                instance->site_survey = ONCORE_SS_HW;
        !          2257:                                        } else {
        !          2258:                                                oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_SW");
        !          2259:                                                instance->site_survey = ONCORE_SS_SW;
        !          2260:                                        }
        !          2261:                                }
        !          2262:                        }
        !          2263:                } else {
        !          2264:                        if (instance->count1) {
        !          2265:                                if (instance->count1++ > 5) {
        !          2266:                                        instance->count1 = 0;
        !          2267:                                        /*
        !          2268:                                         * For instance->site_survey to still be ONCORE_SS_TESTING, then after a 5sec
        !          2269:                                         * wait after the @@At2/@@Gd3 command we have not changed the state to
        !          2270:                                         * ONCORE_SS_HW.  If the Hardware is capable of doing a Site Survey, then
        !          2271:                                         * the variable would have been changed by now.
        !          2272:                                         * There are three possibilities:
        !          2273:                                         * 6/8chan
        !          2274:                                         *   (a) We did not get a response to the @@At0 or @@At2 commands,
        !          2275:                                         *         and it must be a GT/GT+/SL with no position hold mode.
        !          2276:                                         *         We will have to do it ourselves.
        !          2277:                                         *   (b) We saw the @@At0, @@At2 commands, but @@At2 failed,
        !          2278:                                         *         must be a VP or older UT which doesn't have Site Survey mode.
        !          2279:                                         *         We will have to do it ourselves.
        !          2280:                                         * 12chan
        !          2281:                                         *   (c) We saw the @@Gd command, and saw H[13]*0x10
        !          2282:                                         *         We will have to do it ourselves (done above)
        !          2283:                                         */
        !          2284: 
        !          2285:                                        snprintf(Msg, sizeof(Msg), 
        !          2286:                                                 "Initiating software 3D site survey (%d samples)",
        !          2287:                                                 POS_HOLD_AVERAGE);
        !          2288:                                        oncore_log(instance, LOG_INFO, Msg);
        !          2289: 
        !          2290:                                        oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_SW");
        !          2291:                                        instance->site_survey = ONCORE_SS_SW;
        !          2292: 
        !          2293:                                        instance->ss_lat = instance->ss_long = instance->ss_ht = 0;
        !          2294:                                        if (instance->chan == 12)
        !          2295:                                                oncore_sendmsg(instance, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* disable */
        !          2296:                                        else {
        !          2297:                                                oncore_sendmsg(instance, oncore_cmd_At0, sizeof(oncore_cmd_At0)); /* disable */
        !          2298:                                                oncore_sendmsg(instance, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); /* disable */
        !          2299:                                        }
        !          2300:                                }
        !          2301:                        }
        !          2302:                }
        !          2303:        }
        !          2304: 
        !          2305:        /* check the mode we are in 0/2/3D */
        !          2306: 
        !          2307:        if (instance->chan == 6) {
        !          2308:                if (instance->BEHa[64]&0x8)
        !          2309:                        instance->mode = MODE_0D;
        !          2310:                else if (instance->BEHa[64]&0x10)
        !          2311:                        instance->mode = MODE_2D;
        !          2312:                else if (instance->BEHa[64]&0x20)
        !          2313:                        instance->mode = MODE_3D;
        !          2314:        } else if (instance->chan == 8) {
        !          2315:                if (instance->BEHa[72]&0x8)
        !          2316:                        instance->mode = MODE_0D;
        !          2317:                else if (instance->BEHa[72]&0x10)
        !          2318:                        instance->mode = MODE_2D;
        !          2319:                else if (instance->BEHa[72]&0x20)
        !          2320:                        instance->mode = MODE_3D;
        !          2321:        } else if (instance->chan == 12) {
        !          2322:                int bits;
        !          2323: 
        !          2324:                bits = (instance->BEHa[129]>>5) & 0x7;  /* actually Ha */
        !          2325:                if (bits == 0x4)
        !          2326:                        instance->mode = MODE_0D;
        !          2327:                else if (bits == 0x6)
        !          2328:                        instance->mode = MODE_2D;
        !          2329:                else if (bits == 0x7)
        !          2330:                        instance->mode = MODE_3D;
        !          2331:        }
        !          2332: 
        !          2333:        /* copy the record to the (extra) location in SHMEM */
        !          2334: 
        !          2335:        if (instance->shmem) {
        !          2336:                int     i;
        !          2337:                u_char  *smp;    /* pointer to start of shared mem for Ba/Ea/Ha */
        !          2338: 
        !          2339:                switch(instance->chan) {
        !          2340:                case 6:   smp = &instance->shmem[instance->shmem_Ba]; break;
        !          2341:                case 8:   smp = &instance->shmem[instance->shmem_Ea]; break;
        !          2342:                case 12:  smp = &instance->shmem[instance->shmem_Ha]; break;
        !          2343:                default:  smp = (u_char *) NULL;                      break;
        !          2344:                }
        !          2345: 
        !          2346:                switch (instance->mode) {
        !          2347:                case MODE_0D:   i = 1; break;   /* 0D, Position Hold */
        !          2348:                case MODE_2D:   i = 2; break;   /* 2D, Altitude Hold */
        !          2349:                case MODE_3D:   i = 3; break;   /* 3D fix */
        !          2350:                default:        i = 0; break;
        !          2351:                }
        !          2352: 
        !          2353:                if (i && smp != NULL) {
        !          2354:                        i *= (len+6);
        !          2355:                        smp[i + 2]++;
        !          2356:                        memcpy(&smp[i+3], buf, (size_t) (len+3));
        !          2357:                }
        !          2358:        }
        !          2359: 
        !          2360:        /*
        !          2361:         * check if traim timer active
        !          2362:         * if it hasn't been cleared, then @@Bn/@@En/@@Hn did not respond
        !          2363:         */
        !          2364: 
        !          2365:        if (instance->traim_delay) {
        !          2366:                if (instance->traim_delay++ > 5) {
        !          2367:                        instance->traim = 0;
        !          2368:                        instance->traim_delay = 0;
        !          2369:                        cp = "ONCORE: Did not detect TRAIM response, TRAIM = OFF";
        !          2370:                        oncore_log(instance, LOG_INFO, cp);
        !          2371: 
        !          2372:                        oncore_set_traim(instance);
        !          2373:                } else
        !          2374:                        return;
        !          2375: 
        !          2376:        }
        !          2377: 
        !          2378:        /* by now should have a @@Ba/@@Ea/@@Ha with good data in it */
        !          2379: 
        !          2380:        if (!instance->have_dH && !instance->traim_delay)
        !          2381:                oncore_compute_dH(instance);
        !          2382: 
        !          2383:        /*
        !          2384:         * must be ONCORE_RUN if we are here.
        !          2385:         * Have # chan and TRAIM by now.
        !          2386:         */
        !          2387: 
        !          2388:        instance->pp->year   = buf[6]*256+buf[7];
        !          2389:        instance->pp->day    = ymd2yd(buf[6]*256+buf[7], buf[4], buf[5]);
        !          2390:        instance->pp->hour   = buf[8];
        !          2391:        instance->pp->minute = buf[9];
        !          2392:        instance->pp->second = buf[10];
        !          2393: 
        !          2394:        /*
        !          2395:         * Are we doing a Hardware or Software Site Survey?
        !          2396:         */
        !          2397: 
        !          2398:        if (instance->site_survey == ONCORE_SS_HW || instance->site_survey == ONCORE_SS_SW)
        !          2399:                oncore_ss(instance);
        !          2400: 
        !          2401:        /* see if we ever saw a response from the @@Ayx above */
        !          2402: 
        !          2403:        if (instance->count2) {
        !          2404:                if (instance->count2++ > 5) {   /* this delay to check on @@Ay command */
        !          2405:                        instance->count2 = 0;
        !          2406: 
        !          2407:                        /* Have we seen an Ay (1PPS time offset) command response */
        !          2408:                        /* if not, and non-zero offset, zero the offset, and send message */
        !          2409: 
        !          2410:                        if (!instance->saw_Ay && instance->offset) {
        !          2411:                                oncore_log(instance, LOG_INFO, "No @@Ay command, PPS OFFSET ignored");
        !          2412:                                instance->offset = 0;
        !          2413:                        }
        !          2414:                }
        !          2415:        }
        !          2416: 
        !          2417:        /*
        !          2418:         * Check the leap second status once per day.
        !          2419:         */
        !          2420: 
        !          2421:        oncore_check_leap_sec(instance);
        !          2422: 
        !          2423:        /*
        !          2424:         * if SHMEM active, every 15s, steal one 'tick' to get 2D or 3D posn.
        !          2425:         */
        !          2426: 
        !          2427:        if (instance->shmem && !instance->shmem_bad_Ea && instance->shmem_Posn && (instance->site_survey == ONCORE_SS_DONE))
        !          2428:                oncore_shmem_get_3D(instance);
        !          2429: 
        !          2430:        if (!instance->traim)   /* NO traim, no BnEnHn, go get tick */
        !          2431:                oncore_get_timestamp(instance, instance->offset, instance->offset);
        !          2432: }
        !          2433: 
        !          2434: 
        !          2435: 
        !          2436: /* Almanac Status */
        !          2437: 
        !          2438: static void
        !          2439: oncore_msg_Bd(
        !          2440:        struct instance *instance,
        !          2441:        u_char *buf,
        !          2442:        size_t len
        !          2443:        )
        !          2444: {
        !          2445:        char Msg[160];
        !          2446: 
        !          2447:        snprintf(Msg, sizeof(Msg),
        !          2448:                 "Bd: Almanac %s, week = %d, t = %d, %d SVs: %x",
        !          2449:                 ((buf[4]) ? "LOADED" : "(NONE)"), buf[5], buf[6],
        !          2450:                 buf[7], w32(&buf[8]));
        !          2451:        oncore_log(instance, LOG_NOTICE, Msg);
        !          2452: }
        !          2453: 
        !          2454: 
        !          2455: 
        !          2456: /* get leap-second warning message */
        !          2457: 
        !          2458: /*
        !          2459:  * @@Bj does NOT behave as documented in current Oncore firmware.
        !          2460:  * It turns on the LEAP indicator when the data is set, and does not,
        !          2461:  * as documented, wait until the beginning of the month when the
        !          2462:  * leap second will occur.
        !          2463:  * Since this firmware bug will never be fixed in all the outstanding Oncore receivers
        !          2464:  * @@Bj is only called in June/December.
        !          2465:  */
        !          2466: 
        !          2467: static void
        !          2468: oncore_msg_Bj(
        !          2469:        struct instance *instance,
        !          2470:        u_char *buf,
        !          2471:        size_t len
        !          2472:        )
        !          2473: {
        !          2474:        const char      *cp;
        !          2475: 
        !          2476:        instance->saw_Bj = 1;
        !          2477: 
        !          2478:        switch(buf[4]) {
        !          2479:        case 1:
        !          2480:                instance->pp->leap = LEAP_ADDSECOND;
        !          2481:                cp = "Set pp.leap to LEAP_ADDSECOND";
        !          2482:                break;
        !          2483:        case 2:
        !          2484:                instance->pp->leap = LEAP_DELSECOND;
        !          2485:                cp = "Set pp.leap to LEAP_DELSECOND";
        !          2486:                break;
        !          2487:        case 0:
        !          2488:        default:
        !          2489:                instance->pp->leap = LEAP_NOWARNING;
        !          2490:                cp = "Set pp.leap to LEAP_NOWARNING";
        !          2491:                break;
        !          2492:        }
        !          2493:        oncore_log(instance, LOG_NOTICE, cp);
        !          2494: }
        !          2495: 
        !          2496: 
        !          2497: 
        !          2498: static void
        !          2499: oncore_msg_Bl(
        !          2500:        struct instance *instance,
        !          2501:        u_char *buf,
        !          2502:        size_t  len
        !          2503:        )
        !          2504: {
        !          2505:        int     chan, id, subframe, valid, page, i, j, tow;
        !          2506:        int     day_now, day_lsf;
        !          2507:        char    *cp, Msg[120];
        !          2508:        enum {
        !          2509:                WARN_NOT_YET,
        !          2510:                WARN_0,
        !          2511:                WARN_PLUS,
        !          2512:                WARN_MINUS
        !          2513:        } warn;
        !          2514: 
        !          2515:        day_now = day_lsf = 0;
        !          2516:        cp = NULL;      /* keep gcc happy */
        !          2517: 
        !          2518:        chan = buf[4] & 0377;
        !          2519:        id   = buf[5] & 0377;
        !          2520:        subframe = buf[6] & 017;
        !          2521:        valid = (buf[6] >> 4) & 017;
        !          2522:        page = buf[7];
        !          2523: 
        !          2524:        if ((!instance->Bl.lsf_flg && !instance->Bl.wn_flg) && (subframe == 4 && page == 18 && valid == 10)) {
        !          2525:                instance->Bl.dt_ls  = buf[32];
        !          2526:                instance->Bl.WN_lsf = buf[33];
        !          2527:                instance->Bl.DN_lsf = buf[34];
        !          2528:                instance->Bl.dt_lsf = buf[35];
        !          2529:                instance->Bl.lsf_flg++;
        !          2530:        }
        !          2531:        if ((instance->Bl.lsf_flg && !instance->Bl.wn_flg) && (subframe == 1 && valid == 10)) {
        !          2532:                i = (buf[7+7]<<8) + buf[7+8];
        !          2533:                instance->Bl.WN = i >> 6;
        !          2534:                tow = (buf[7+4]<<16) + (buf[7+5]<<8) + buf[7+6];
        !          2535:                tow >>= 7;
        !          2536:                tow = tow & 0377777;
        !          2537:                tow <<= 2;
        !          2538:                instance->Bl.DN = tow/57600L + 1;
        !          2539:                instance->Bl.wn_flg++;
        !          2540:        }
        !          2541:        if (instance->Bl.wn_flg && instance->Bl.lsf_flg)  {
        !          2542:                instance->Bl.wn_flg = instance->Bl.lsf_flg = 0;
        !          2543:                oncore_cmd_Bl[2] = 0;
        !          2544:                oncore_sendmsg(instance, oncore_cmd_Bl, sizeof oncore_cmd_Bl);
        !          2545:                oncore_cmd_Bl[2] = 1;
        !          2546: 
        !          2547:                i = instance->Bl.WN&01400;
        !          2548:                instance->Bl.WN_lsf |= i;
        !          2549: 
        !          2550:                /* have everything I need, doit */
        !          2551: 
        !          2552:                i = (instance->Bl.WN_lsf - instance->Bl.WN);
        !          2553:                if (i < 0)
        !          2554:                        i += 1024;
        !          2555:                day_now = instance->Bl.DN;
        !          2556:                day_lsf = 7*i + instance->Bl.DN_lsf;
        !          2557: 
        !          2558:                /* ignore if in past or more than a month in future */
        !          2559: 
        !          2560:                warn = WARN_NOT_YET;
        !          2561:                if (day_lsf >= day_now && day_lsf - day_now < 32) {
        !          2562:                        /* if < 28d, doit, if 28-31, ck day-of-month < 20 (not at end of prev month) */
        !          2563:                        if (day_lsf - day_now < 28 ||  instance->BEHa[5] < 20) {
        !          2564:                                i = instance->Bl.dt_lsf - instance->Bl.dt_ls;
        !          2565:                                switch (i) {
        !          2566:                                case -1:
        !          2567:                                        warn = WARN_MINUS;
        !          2568:                                        break;
        !          2569:                                case  0:
        !          2570:                                        warn = WARN_0;
        !          2571:                                        break;
        !          2572:                                case  1:
        !          2573:                                        warn = WARN_PLUS;
        !          2574:                                        break;
        !          2575:                                }
        !          2576:                        }
        !          2577:                }
        !          2578: 
        !          2579:                switch (warn) {
        !          2580:                case WARN_0:
        !          2581:                case WARN_NOT_YET:
        !          2582:                        instance->peer->leap = LEAP_NOWARNING;
        !          2583:                        cp = "Set peer.leap to LEAP_NOWARNING";
        !          2584:                        break;
        !          2585:                case WARN_MINUS:
        !          2586:                        instance->peer->leap = LEAP_DELSECOND;
        !          2587:                        cp = "Set peer.leap to LEAP_DELSECOND";
        !          2588:                        break;
        !          2589:                case WARN_PLUS:
        !          2590:                        instance->peer->leap = LEAP_ADDSECOND;
        !          2591:                        cp = "Set peer.leap to LEAP_ADDSECOND";
        !          2592:                        break;
        !          2593:                }
        !          2594:                oncore_log(instance, LOG_NOTICE, cp);
        !          2595: 
        !          2596:                i = instance->Bl.dt_lsf-instance->Bl.dt_ls;
        !          2597:                if (i) {
        !          2598:                        j = (i >= 0) ? i : -i;          /* abs(i) */
        !          2599:                        snprintf(Msg, sizeof(Msg),
        !          2600:                                 "see Leap_Second (%c%d) in %d days",
        !          2601:                                 ((i >= 0) ? '+' : '-'), j,
        !          2602:                                 day_lsf-day_now);
        !          2603:                        oncore_log(instance, LOG_NOTICE, Msg);
        !          2604:                }
        !          2605:        }
        !          2606:        snprintf(Msg, sizeof(Msg), 
        !          2607:                "dt_ls = %d  dt_lsf = %d  WN = %d  DN = %d  WN_lsf = %d  DNlsf = %d  wn_flg = %d  lsf_flg = %d  Bl_day = %d",
        !          2608:                instance->Bl.dt_ls, instance->Bl.dt_lsf,
        !          2609:                instance->Bl.WN, instance->Bl.DN, 
        !          2610:                instance->Bl.WN_lsf, instance->Bl.DN_lsf,
        !          2611:                instance->Bl.wn_flg, instance->Bl.lsf_flg,
        !          2612:                instance->Bl.Bl_day);
        !          2613:        oncore_log(instance, LOG_INFO, Msg);
        !          2614: }
        !          2615: 
        !          2616: 
        !          2617: static void
        !          2618: oncore_msg_BnEnHn(
        !          2619:        struct instance *instance,
        !          2620:        u_char *buf,
        !          2621:        size_t  len
        !          2622:        )
        !          2623: {
        !          2624:        long    dt1, dt2;
        !          2625: 
        !          2626:        if (instance->o_state != ONCORE_RUN)
        !          2627:                return;
        !          2628: 
        !          2629:        if (instance->traim_delay) {     /* flag that @@Bn/@@En/Hn returned */
        !          2630:                        instance->traim_ck = 1;
        !          2631:                        instance->traim_delay = 0;
        !          2632:                        oncore_log(instance, LOG_NOTICE, "ONCORE: Detected TRAIM, TRAIM = ON");
        !          2633: 
        !          2634:                        oncore_set_traim(instance);
        !          2635:        }
        !          2636: 
        !          2637:        memcpy(instance->BEHn, buf, (size_t) len);      /* Bn or En or Hn */
        !          2638: 
        !          2639:        if (!instance->traim)   /* BnEnHn will be turned off in any case */
        !          2640:                return;
        !          2641: 
        !          2642:        /* If Time RAIM doesn't like it, don't trust it */
        !          2643: 
        !          2644:        if (buf[2] == 'H') {
        !          2645:                if (instance->BEHn[6]) {    /* bad TRAIM */
        !          2646:                        oncore_log(instance, LOG_WARNING, "BAD TRAIM");
        !          2647:                        return;
        !          2648:                }
        !          2649: 
        !          2650:                dt1 = instance->saw_tooth + instance->offset;    /* dt this time step */
        !          2651:                instance->saw_tooth = (s_char) instance->BEHn[14]; /* update for next time Hn[14] */
        !          2652:                dt2 = instance->saw_tooth + instance->offset;    /* dt next time step */
        !          2653:        } else {
        !          2654:                if (instance->BEHn[21]) /* bad TRAIM */
        !          2655:                        return;
        !          2656: 
        !          2657:                dt1 = instance->saw_tooth + instance->offset;    /* dt this time step */
        !          2658:                instance->saw_tooth = (s_char) instance->BEHn[25]; /* update for next time Bn[25], En[25] */
        !          2659:                dt2 = instance->saw_tooth + instance->offset;    /* dt next time step */
        !          2660:        }
        !          2661: 
        !          2662:        oncore_get_timestamp(instance, dt1, dt2);
        !          2663: }
        !          2664: 
        !          2665: 
        !          2666: 
        !          2667: /* Here for @@Ca, @@Fa and @@Ia messages */
        !          2668: 
        !          2669: /* These are Self test Commands for 6, 8, and 12 chan receivers.
        !          2670:  * There are good reasons NOT to do a @@Ca, @@Fa or @@Ia command with the ONCORE.
        !          2671:  * It was found that under some circumstances the following
        !          2672:  * command would fail if issued immediately after the return from the
        !          2673:  * @@Fa, but a 2sec delay seemed to fix things.  Since simply calling
        !          2674:  * sleep(2) is wasteful, and may cause trouble for some OS's, repeating
        !          2675:  * itimer, we set a flag, and test it at the next POLL.  If it hasn't
        !          2676:  * been cleared, we reissue the @@Cj that is issued below.
        !          2677:  * Note that we do a @@Cj at the beginning, and again here.
        !          2678:  * The first is to get the info, the 2nd is just used as a safe command
        !          2679:  * after the @@Fa for all Oncores (and it was in this posn in the
        !          2680:  * original code).
        !          2681:  */
        !          2682: 
        !          2683: static void
        !          2684: oncore_msg_CaFaIa(
        !          2685:        struct instance *instance,
        !          2686:        u_char *buf,
        !          2687:        size_t len
        !          2688:        )
        !          2689: {
        !          2690:        char    Msg[120];
        !          2691:        int     i;
        !          2692: 
        !          2693:        if (instance->o_state == ONCORE_TEST_SENT) {
        !          2694:                enum antenna_state antenna;
        !          2695: 
        !          2696:                instance->timeout = 0;
        !          2697: 
        !          2698: #if ONCORE_VERBOSE_SELF_TEST
        !          2699:                if (debug > 2) {
        !          2700:                        if (buf[2] == 'I')
        !          2701:                                snprintf(Msg, sizeof(Msg),
        !          2702:                                         ">>@@%ca %x %x %x", buf[2],
        !          2703:                                         buf[4], buf[5], buf[6]);
        !          2704:                        else
        !          2705:                                snprintf(Msg, sizeof(Msg),
        !          2706:                                         ">>@@%ca %x %x", buf[2],
        !          2707:                                         buf[4], buf[5]);
        !          2708:                        oncore_log(instance, LOG_DEBUG, Msg);
        !          2709:                }
        !          2710: #endif
        !          2711: 
        !          2712:                antenna = (buf[4] & 0xc0) >> 6;
        !          2713:                buf[4] &= ~0xc0;
        !          2714: 
        !          2715:                i = buf[4] || buf[5];
        !          2716:                if (buf[2] == 'I') i = i || buf[6];
        !          2717:                if (i) {
        !          2718:                        if (buf[2] == 'I')
        !          2719:                                snprintf(Msg, sizeof(Msg), 
        !          2720:                                         "self test failed: result %02x %02x %02x",
        !          2721:                                         buf[4], buf[5], buf[6]);
        !          2722:                        else
        !          2723:                                snprintf(Msg, sizeof(Msg),
        !          2724:                                         "self test failed: result %02x %02x",
        !          2725:                                         buf[4], buf[5]);
        !          2726:                        oncore_log(instance, LOG_ERR, Msg);
        !          2727: 
        !          2728:                        oncore_log(instance, LOG_ERR, 
        !          2729:                                   "ONCORE: self test failed, shutting down driver");
        !          2730: 
        !          2731:                        refclock_report(instance->peer, CEVNT_FAULT);
        !          2732:                        oncore_shutdown(instance->unit, instance->peer);
        !          2733:                        return;
        !          2734:                }
        !          2735: 
        !          2736:                /* report the current antenna state */
        !          2737: 
        !          2738:                oncore_antenna_report(instance, antenna);
        !          2739: 
        !          2740:                instance->o_state = ONCORE_INIT;
        !          2741:                oncore_log(instance, LOG_NOTICE, "state = ONCORE_INIT");
        !          2742: 
        !          2743:                instance->timeout = 4;
        !          2744:                oncore_sendmsg(instance, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
        !          2745:        }
        !          2746: }
        !          2747: 
        !          2748: 
        !          2749: 
        !          2750: /*
        !          2751:  * Demultiplex the almanac into shmem
        !          2752:  */
        !          2753: 
        !          2754: static void
        !          2755: oncore_msg_Cb(
        !          2756:        struct instance *instance,
        !          2757:        u_char *buf,
        !          2758:        size_t len
        !          2759:        )
        !          2760: {
        !          2761:        int i;
        !          2762: 
        !          2763:        if (instance->shmem == NULL)
        !          2764:                return;
        !          2765: 
        !          2766:        if (buf[4] == 5 && buf[5] > 0 && buf[5] < 26)
        !          2767:                i = buf[5];
        !          2768:        else if (buf[4] == 4 && buf[5] <= 5)
        !          2769:                i = buf[5] + 24;
        !          2770:        else if (buf[4] == 4 && buf[5] <= 10)
        !          2771:                i = buf[5] + 23;
        !          2772:        else if (buf[4] == 4 && buf[5] == 25)
        !          2773:                i = 34;
        !          2774:        else {
        !          2775:                oncore_log(instance, LOG_NOTICE, "Cb: Response is NO ALMANAC");
        !          2776:                return;
        !          2777:        }
        !          2778: 
        !          2779:        i *= 36;
        !          2780:        instance->shmem[instance->shmem_Cb + i + 2]++;
        !          2781:        memcpy(instance->shmem + instance->shmem_Cb + i + 3, buf, (size_t) (len + 3));
        !          2782: 
        !          2783: #ifdef ONCORE_VERBOSE_MSG_CB
        !          2784:        {
        !          2785:                char Msg[160];
        !          2786: 
        !          2787:                snprintf(Msg, sizeof(Msg), "See Cb [%d,%d]", buf[4],
        !          2788:                         buf[5]);
        !          2789:                oncore_log(instance, LOG_DEBUG, Msg);
        !          2790:        }
        !          2791: #endif
        !          2792: }
        !          2793: 
        !          2794: 
        !          2795: 
        !          2796: /*
        !          2797:  * Set to Factory Defaults (Reasonable for UT w/ no Battery Backup
        !          2798:  *     not so for VP (eeprom) or any unit with a battery
        !          2799:  */
        !          2800: 
        !          2801: static void
        !          2802: oncore_msg_Cf(
        !          2803:        struct instance *instance,
        !          2804:        u_char *buf,
        !          2805:        size_t len
        !          2806:        )
        !          2807: {
        !          2808:        if (instance->o_state == ONCORE_RESET_SENT) {
        !          2809:                oncore_sendmsg(instance, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Return to  Posn Fix mode */
        !          2810:                                                                                       /* Reset set VP to IDLE */
        !          2811:                instance->o_state = ONCORE_TEST_SENT;
        !          2812:                oncore_log(instance, LOG_NOTICE, "state = ONCORE_TEST_SENT");
        !          2813: 
        !          2814:                oncore_sendmsg(instance, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
        !          2815:        }
        !          2816: }
        !          2817: 
        !          2818: 
        !          2819: 
        !          2820: /*
        !          2821:  * This is the Grand Central Station for the Preliminary Initialization.
        !          2822:  * Once done here we move on to oncore_msg_BaEaHa for final Initialization and Running.
        !          2823:  *
        !          2824:  * We do an @@Cj whenever we need a safe command for all Oncores.
        !          2825:  * The @@Cj gets us back here where we can switch to the next phase of setup.
        !          2826:  *
        !          2827:  * o Once at the very beginning (in start) to get the Model number.
        !          2828:  *   This info is printed, but no longer used.
        !          2829:  * o Again after we have determined the number of Channels in the receiver.
        !          2830:  * o And once later after we have done a reset and test, (which may hang),
        !          2831:  *   as we are about to initialize the Oncore and start it running.
        !          2832:  * o We have one routine below for each case.
        !          2833:  */
        !          2834: 
        !          2835: static void
        !          2836: oncore_msg_Cj(
        !          2837:        struct instance *instance,
        !          2838:        u_char *buf,
        !          2839:        size_t len
        !          2840:        )
        !          2841: {
        !          2842:        int     mode;
        !          2843: 
        !          2844:        memcpy(instance->Cj, buf, len);
        !          2845: 
        !          2846:        instance->timeout = 0;
        !          2847:        if (instance->o_state == ONCORE_CHECK_ID) {
        !          2848:                oncore_msg_Cj_id(instance, buf, len);
        !          2849:                oncore_chan_test(instance);
        !          2850:        } else if (instance->o_state == ONCORE_HAVE_CHAN) {
        !          2851:                mode = instance->init_type;
        !          2852:                if (mode == 3 || mode == 4) {   /* Cf will return here to check for TEST */
        !          2853:                        instance->o_state = ONCORE_RESET_SENT;
        !          2854:                        oncore_log(instance, LOG_NOTICE, "state = ONCORE_RESET_SENT");
        !          2855:                        oncore_sendmsg(instance, oncore_cmd_Cf, sizeof(oncore_cmd_Cf));
        !          2856:                } else {
        !          2857:                        instance->o_state = ONCORE_TEST_SENT;
        !          2858:                        oncore_log(instance, LOG_NOTICE, "state = ONCORE_TEST_SENT");
        !          2859:                }
        !          2860:        }
        !          2861: 
        !          2862:        if (instance->o_state == ONCORE_TEST_SENT) {
        !          2863:                if (instance->chan == 6)
        !          2864:                        oncore_sendmsg(instance, oncore_cmd_Ca, sizeof(oncore_cmd_Ca));
        !          2865:                else if (instance->chan == 8)
        !          2866:                        oncore_sendmsg(instance, oncore_cmd_Fa, sizeof(oncore_cmd_Fa));
        !          2867:                else if (instance->chan == 12)
        !          2868:                        oncore_sendmsg(instance, oncore_cmd_Ia, sizeof(oncore_cmd_Ia));
        !          2869:        } else if (instance->o_state == ONCORE_INIT)
        !          2870:                oncore_msg_Cj_init(instance, buf, len);
        !          2871: }
        !          2872: 
        !          2873: 
        !          2874: 
        !          2875: /* The information on determining a Oncore 'Model', viz VP, UT, etc, from
        !          2876:  *     the Model Number comes from "Richard M. Hambly" <rick@cnssys.com>
        !          2877:  *     and from Motorola.  Until recently Rick was the only source of
        !          2878:  *     this information as Motorola didn't give the information out.
        !          2879:  *
        !          2880:  * Determine the Type from the Model #, this determines #chan and if TRAIM is
        !          2881:  *   available.
        !          2882:  *
        !          2883:  * The Information from this routine is NO LONGER USED.
        !          2884:  * The RESULTS are PRINTED, BUT NOT USED, and the routine COULD BE DELETED
        !          2885:  */
        !          2886: 
        !          2887: static void
        !          2888: oncore_msg_Cj_id(
        !          2889:        struct instance *instance,
        !          2890:        u_char *buf,
        !          2891:        size_t len
        !          2892:        )
        !          2893: {
        !          2894:        char *cp, *cp1, *cp2, Model[21], Msg[160];
        !          2895: 
        !          2896:        /* Write Receiver ID message to clockstats file */
        !          2897: 
        !          2898:        instance->Cj[294] = '\0';
        !          2899:        for (cp=(char *)instance->Cj; cp< (char *) &instance->Cj[294]; ) {
        !          2900:                cp1 = strchr(cp, '\r');
        !          2901:                if (!cp1)
        !          2902:                        cp1 = (char *)&instance->Cj[294];
        !          2903:                *cp1 = '\0';
        !          2904:                oncore_log(instance, LOG_NOTICE, cp);
        !          2905:                *cp1 = '\r';
        !          2906:                cp = cp1+2;
        !          2907:        }
        !          2908: 
        !          2909:        /* next, the Firmware Version and Revision numbers */
        !          2910: 
        !          2911:        instance->version  = atoi((char *) &instance->Cj[83]);
        !          2912:        instance->revision = atoi((char *) &instance->Cj[111]);
        !          2913: 
        !          2914:        /* from model number decide which Oncore this is,
        !          2915:                and then the number of channels */
        !          2916: 
        !          2917:        for (cp= (char *) &instance->Cj[160]; *cp == ' '; cp++)   /* start right after 'Model #' */
        !          2918:                ;
        !          2919:        cp1 = cp;
        !          2920:        cp2 = Model;
        !          2921:        for (; !isspace((int)*cp) && cp-cp1 < 20; cp++, cp2++)
        !          2922:                *cp2 = *cp;
        !          2923:        *cp2 = '\0';
        !          2924: 
        !          2925:        cp = 0;
        !          2926:        if (!strncmp(Model, "PVT6", (size_t) 4)) {
        !          2927:                cp = "PVT6";
        !          2928:                instance->model = ONCORE_PVT6;
        !          2929:        } else if (Model[0] == 'A') {
        !          2930:                cp = "Basic";
        !          2931:                instance->model = ONCORE_BASIC;
        !          2932:        } else if (Model[0] == 'B' || !strncmp(Model, "T8", (size_t) 2)) {
        !          2933:                cp = "VP";
        !          2934:                instance->model = ONCORE_VP;
        !          2935:        } else if (Model[0] == 'P') {
        !          2936:                cp = "M12";
        !          2937:                instance->model = ONCORE_M12;
        !          2938:        } else if (Model[0] == 'R' || Model[0] == 'D' || Model[0] == 'S') {
        !          2939:                if (Model[5] == 'N') {
        !          2940:                        cp = "GT";
        !          2941:                        instance->model = ONCORE_GT;
        !          2942:                } else if ((Model[1] == '3' || Model[1] == '4') && Model[5] == 'G') {
        !          2943:                        cp = "GT+";
        !          2944:                        instance->model = ONCORE_GTPLUS;
        !          2945:                } else if ((Model[1] == '5' && Model[5] == 'U') || (Model[1] == '1' && Model[5] == 'A')) {
        !          2946:                                cp = "UT";
        !          2947:                                instance->model = ONCORE_UT;
        !          2948:                } else if (Model[1] == '5' && Model[5] == 'G') {
        !          2949:                        cp = "UT+";
        !          2950:                        instance->model = ONCORE_UTPLUS;
        !          2951:                } else if (Model[1] == '6' && Model[5] == 'G') {
        !          2952:                        cp = "SL";
        !          2953:                        instance->model = ONCORE_SL;
        !          2954:                } else {
        !          2955:                        cp = "Unknown";
        !          2956:                        instance->model = ONCORE_UNKNOWN;
        !          2957:                }
        !          2958:        } else  {
        !          2959:                cp = "Unknown";
        !          2960:                instance->model = ONCORE_UNKNOWN;
        !          2961:        }
        !          2962: 
        !          2963:        /* use MODEL to set CHAN and TRAIM and possibly zero SHMEM */
        !          2964: 
        !          2965:        snprintf(Msg, sizeof(Msg),
        !          2966:                 "This looks like an Oncore %s with version %d.%d firmware.",
        !          2967:                 cp, instance->version, instance->revision);
        !          2968:        oncore_log(instance, LOG_INFO, Msg);
        !          2969: 
        !          2970:        instance->chan_id = 8;     /* default */
        !          2971:        if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6)
        !          2972:                instance->chan_id = 6;
        !          2973:        else if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || instance->model == ONCORE_UTPLUS)
        !          2974:                instance->chan_id = 8;
        !          2975:        else if (instance->model == ONCORE_M12)
        !          2976:                instance->chan_id = 12;
        !          2977: 
        !          2978:        instance->traim_id = 0;    /* default */
        !          2979:        if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6)
        !          2980:                instance->traim_id = 0;
        !          2981:        else if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || instance->model == ONCORE_UTPLUS)
        !          2982:                instance->traim_id = 1;
        !          2983:        else if (instance->model == ONCORE_M12)
        !          2984:                instance->traim_id = -1;
        !          2985: 
        !          2986:        snprintf(Msg, sizeof(Msg), "Channels = %d, TRAIM = %s",
        !          2987:                 instance->chan_id,
        !          2988:                 ((instance->traim_id < 0)
        !          2989:                      ? "UNKNOWN"
        !          2990:                      : (instance->traim_id > 0)
        !          2991:                            ? "ON"
        !          2992:                            : "OFF"));
        !          2993:        oncore_log(instance, LOG_INFO, Msg);
        !          2994: }
        !          2995: 
        !          2996: 
        !          2997: 
        !          2998: /* OK, know type of Oncore, have possibly reset it, and have tested it.
        !          2999:  * We know the number of channels.
        !          3000:  * We will determine whether we have TRAIM before we actually start.
        !          3001:  * Now initialize.
        !          3002:  */
        !          3003: 
        !          3004: static void
        !          3005: oncore_msg_Cj_init(
        !          3006:        struct instance *instance,
        !          3007:        u_char *buf,
        !          3008:        size_t len
        !          3009:        )
        !          3010: {
        !          3011:        char    Msg[160];
        !          3012:        u_char  Cmd[20];
        !          3013:        int     mode;
        !          3014: 
        !          3015: 
        !          3016:        /* The M12 with 1.3 or 2.0 Firmware, loses track of all Satellites and has to
        !          3017:         * start again if we go from 0D -> 3D, then loses them again when we
        !          3018:         * go from 3D -> 0D.  We do this to get a @@Ea message for SHMEM.
        !          3019:         * For NOW we will turn this aspect of filling SHMEM off for the M12
        !          3020:         */
        !          3021: 
        !          3022:        if (instance->chan == 12) {
        !          3023:                instance->shmem_bad_Ea = 1;
        !          3024:                snprintf(Msg, sizeof(Msg),
        !          3025:                         "*** SHMEM partially enabled for ONCORE M12 s/w v%d.%d ***",
        !          3026:                         instance->version, instance->revision);
        !          3027:                oncore_log(instance, LOG_NOTICE, Msg);
        !          3028:        }
        !          3029: 
        !          3030:        oncore_sendmsg(instance, oncore_cmd_Cg, sizeof(oncore_cmd_Cg)); /* Return to  Posn Fix mode */
        !          3031:        oncore_sendmsg(instance, oncore_cmd_Bb, sizeof(oncore_cmd_Bb)); /* turn on for shmem (6/8/12) */
        !          3032:        oncore_sendmsg(instance, oncore_cmd_Ek, sizeof(oncore_cmd_Ek)); /* turn off (VP) */
        !          3033:        oncore_sendmsg(instance, oncore_cmd_Aw, sizeof(oncore_cmd_Aw)); /* UTC time (6/8/12) */
        !          3034:        oncore_sendmsg(instance, oncore_cmd_AB, sizeof(oncore_cmd_AB)); /* Appl type static (VP) */
        !          3035:        oncore_sendmsg(instance, oncore_cmd_Be, sizeof(oncore_cmd_Be)); /* Tell us the Almanac for shmem (6/8/12) */
        !          3036:        oncore_sendmsg(instance, oncore_cmd_Bd, sizeof(oncore_cmd_Bd)); /* Tell us when Almanac changes */
        !          3037: 
        !          3038:        mode = instance->init_type;
        !          3039: 
        !          3040:        /* If there is Position input in the Config file
        !          3041:         * and mode = (1,3) set it as posn hold posn, goto 0D mode.
        !          3042:         *  or mode = (2,4) set it as INITIAL position, and do Site Survey.
        !          3043:         */
        !          3044: 
        !          3045:        if (instance->posn_set) {
        !          3046:                oncore_log(instance, LOG_INFO, "Setting Posn from input data");
        !          3047:                oncore_set_posn(instance);      /* this should print posn indirectly thru the As cmd */
        !          3048:        } else  /* must issue an @@At here to check on 6/8 Position Hold, set_posn would have */
        !          3049:                if (instance->chan != 12)
        !          3050:                        oncore_sendmsg(instance, oncore_cmd_Atx, sizeof(oncore_cmd_Atx));
        !          3051: 
        !          3052:        if (mode != 0) {
        !          3053:                        /* cable delay in ns */
        !          3054:                memcpy(Cmd, oncore_cmd_Az, (size_t) sizeof(oncore_cmd_Az));
        !          3055:                w32_buf(&Cmd[-2+4], instance->delay);
        !          3056:                oncore_sendmsg(instance, Cmd,  sizeof(oncore_cmd_Az));  /* 6,8,12 */
        !          3057: 
        !          3058:                        /* PPS offset in ns */
        !          3059:                if (instance->offset) {
        !          3060:                        memcpy(Cmd, oncore_cmd_Ay, (size_t) sizeof(oncore_cmd_Ay));     /* some have it, some don't */
        !          3061:                        w32_buf(&Cmd[-2+4], instance->offset);                  /* will check for hw response */
        !          3062:                        oncore_sendmsg(instance, Cmd,  sizeof(oncore_cmd_Ay));
        !          3063:                }
        !          3064: 
        !          3065:                /* Satellite mask angle */
        !          3066: 
        !          3067:                if (instance->Ag != 0xff) {     /* will have 0xff in it if not set by user */
        !          3068:                        memcpy(Cmd, oncore_cmd_Ag, (size_t) sizeof(oncore_cmd_Ag));
        !          3069:                        Cmd[-2+4] = instance->Ag;
        !          3070:                        oncore_sendmsg(instance, Cmd,  sizeof(oncore_cmd_Ag));
        !          3071:                }
        !          3072:        }
        !          3073: 
        !          3074:        /* 6, 8 12 chan - Position/Status/Data Output Message, 1/s
        !          3075:         * now we're really running
        !          3076:         * these were ALL started in the chan test,
        !          3077:         * However, if we had mode=3,4 then commands got turned off, so we turn
        !          3078:         * them on again here just in case
        !          3079:         */
        !          3080: 
        !          3081:        if (instance->chan == 6) { /* start 6chan, kill 8,12chan commands, possibly testing VP in 6chan mode */
        !          3082:                oncore_sendmsg(instance, oncore_cmd_Ea0, sizeof(oncore_cmd_Ea0));
        !          3083:                oncore_sendmsg(instance, oncore_cmd_En0, sizeof(oncore_cmd_En0));
        !          3084:                oncore_sendmsg(instance, oncore_cmd_Ha0, sizeof(oncore_cmd_Ha0));
        !          3085:                oncore_sendmsg(instance, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0));
        !          3086:                oncore_sendmsg(instance, oncore_cmd_Ba, sizeof(oncore_cmd_Ba ));
        !          3087:        } else if (instance->chan == 8) {  /* start 8chan, kill 6,12chan commands */
        !          3088:                oncore_sendmsg(instance, oncore_cmd_Ba0, sizeof(oncore_cmd_Ba0));
        !          3089:                oncore_sendmsg(instance, oncore_cmd_Bn0, sizeof(oncore_cmd_Bn0));
        !          3090:                oncore_sendmsg(instance, oncore_cmd_Ha0, sizeof(oncore_cmd_Ha0));
        !          3091:                oncore_sendmsg(instance, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0));
        !          3092:                oncore_sendmsg(instance, oncore_cmd_Ea, sizeof(oncore_cmd_Ea ));
        !          3093:        } else if (instance->chan == 12){  /* start 12chan, kill 6,12chan commands */
        !          3094:                oncore_sendmsg(instance, oncore_cmd_Ba0, sizeof(oncore_cmd_Ba0));
        !          3095:                oncore_sendmsg(instance, oncore_cmd_Bn0, sizeof(oncore_cmd_Bn0));
        !          3096:                oncore_sendmsg(instance, oncore_cmd_Ea0, sizeof(oncore_cmd_Ea0));
        !          3097:                oncore_sendmsg(instance, oncore_cmd_En0, sizeof(oncore_cmd_En0));
        !          3098:                oncore_sendmsg(instance, oncore_cmd_Ha, sizeof(oncore_cmd_Ha ));
        !          3099:        }
        !          3100: 
        !          3101:        instance->count = 1;
        !          3102:        instance->o_state = ONCORE_ALMANAC;
        !          3103:        oncore_log(instance, LOG_NOTICE, "state = ONCORE_ALMANAC");
        !          3104: }
        !          3105: 
        !          3106: 
        !          3107: 
        !          3108: /* 12chan position */
        !          3109: 
        !          3110: static void
        !          3111: oncore_msg_Ga(
        !          3112:        struct instance *instance,
        !          3113:        u_char *buf,
        !          3114:        size_t len
        !          3115:        )
        !          3116: {
        !          3117:        char Msg[160];
        !          3118:        long lat, lon, ht;
        !          3119:        double Lat, Lon, Ht;
        !          3120: 
        !          3121: 
        !          3122:        lat = buf_w32(&buf[4]);
        !          3123:        lon = buf_w32(&buf[8]);
        !          3124:        ht  = buf_w32(&buf[12]);  /* GPS ellipsoid */
        !          3125: 
        !          3126:        Lat = lat;
        !          3127:        Lon = lon;
        !          3128:        Ht  = ht;
        !          3129: 
        !          3130:        Lat /= 3600000;
        !          3131:        Lon /= 3600000;
        !          3132:        Ht  /= 100;
        !          3133: 
        !          3134: 
        !          3135:        snprintf(Msg, sizeof(Msg),
        !          3136:                 "Ga Posn Lat = %.7f, Lon = %.7f, Ht  = %.2f", Lat,
        !          3137:                 Lon, Ht);
        !          3138:        oncore_log(instance, LOG_NOTICE, Msg);
        !          3139: 
        !          3140:        instance->ss_lat  = lat;
        !          3141:        instance->ss_long = lon;
        !          3142:        instance->ss_ht   = ht;
        !          3143: 
        !          3144:        oncore_print_posn(instance);
        !          3145: }
        !          3146: 
        !          3147: 
        !          3148: 
        !          3149: /* 12 chan time/date */
        !          3150: 
        !          3151: static void
        !          3152: oncore_msg_Gb(
        !          3153:        struct instance *instance,
        !          3154:        u_char *buf,
        !          3155:        size_t len
        !          3156:        )
        !          3157: {
        !          3158:        char    Msg[160], *gmts;
        !          3159:        int     mo, d, y, h, m, s, gmth, gmtm;
        !          3160: 
        !          3161:        mo = buf[4];
        !          3162:        d  = buf[5];
        !          3163:        y  = 256*buf[6]+buf[7];
        !          3164: 
        !          3165:        h  = buf[8];
        !          3166:        m  = buf[9];
        !          3167:        s  = buf[10];
        !          3168: 
        !          3169:        gmts = ((buf[11] == 0) ? "+" : "-");
        !          3170:        gmth = buf[12];
        !          3171:        gmtm = buf[13];
        !          3172: 
        !          3173:        snprintf(Msg, sizeof(Msg),
        !          3174:                 "Date/Time set to: %d%s%d %2d:%02d:%02d GMT (GMT offset is %s%02d:%02d)",
        !          3175:                 d, Month[mo-1], y, h, m, s, gmts, gmth, gmtm);
        !          3176:        oncore_log(instance, LOG_NOTICE, Msg);
        !          3177: }
        !          3178: 
        !          3179: 
        !          3180: 
        !          3181: /* Leap Second for M12, gives all info from satellite message */
        !          3182: /* also in UT v3.0 */
        !          3183: 
        !          3184: static void
        !          3185: oncore_msg_Gj(
        !          3186:        struct instance *instance,
        !          3187:        u_char *buf,
        !          3188:        size_t len
        !          3189:        )
        !          3190: {
        !          3191:        int dt;
        !          3192:        char Msg[160], *cp;
        !          3193: 
        !          3194:        instance->saw_Gj = 1; /* flag, saw_Gj, dont need to try Bj in check_leap */
        !          3195: 
        !          3196:        /* print the message to verify whats there */
        !          3197: 
        !          3198:        dt = buf[5] - buf[4];
        !          3199: 
        !          3200:        snprintf(Msg, sizeof(Msg),
        !          3201:                 "Leap Sec Msg: %d %d %d %d %d %d %d %d %d %d", buf[4],
        !          3202:                 buf[5], 256 * buf[6] + buf[7], buf[8], buf[9], buf[10],
        !          3203:                 (buf[14] + 256 *
        !          3204:                     (buf[13] + 256 * (buf[12] + 256 * buf[11]))),
        !          3205:                 buf[15], buf[16], buf[17]);
        !          3206:        oncore_log(instance, LOG_INFO, Msg);
        !          3207: 
        !          3208:        if (dt) {
        !          3209:                snprintf(Msg, sizeof(Msg),
        !          3210:                         "Leap second (%d) scheduled for %d%s%d at %d:%d:%d",
        !          3211:                         dt, buf[9], Month[buf[8] - 1], 
        !          3212:                         256 * buf[6] + buf[7], buf[15], buf[16],
        !          3213:                         buf[17]);
        !          3214:                oncore_log(instance, LOG_NOTICE, Msg);
        !          3215:        }
        !          3216: 
        !          3217:        /* Only raise warning within a month of the leap second */
        !          3218: 
        !          3219:        instance->pp->leap = LEAP_NOWARNING;
        !          3220:        cp = "Set pp.leap to LEAP_NOWARNING";
        !          3221: 
        !          3222:        if (buf[6] == instance->BEHa[6] && buf[7] == instance->BEHa[7] && /* year */
        !          3223:            buf[8] == instance->BEHa[4]) {      /* month */
        !          3224:                if (dt) {
        !          3225:                        if (dt < 0) {
        !          3226:                                instance->pp->leap = LEAP_DELSECOND;
        !          3227:                                cp = "Set pp.leap to LEAP_DELSECOND";
        !          3228:                        } else {
        !          3229:                                instance->pp->leap = LEAP_ADDSECOND;
        !          3230:                                cp = "Set pp.leap to LEAP_ADDSECOND";
        !          3231:                        }
        !          3232:                }
        !          3233:        }
        !          3234:        oncore_log(instance, LOG_INFO, cp);
        !          3235: }
        !          3236: 
        !          3237: 
        !          3238: 
        !          3239: /* Power on failure */
        !          3240: 
        !          3241: static void
        !          3242: oncore_msg_Sz(
        !          3243:        struct instance *instance,
        !          3244:        u_char *buf,
        !          3245:        size_t len
        !          3246:        )
        !          3247: {
        !          3248:        if (instance && instance->peer) {
        !          3249:                oncore_log(instance, LOG_ERR, "Oncore: System Failure at Power On");
        !          3250:                oncore_shutdown(instance->unit, instance->peer);
        !          3251:        }
        !          3252: }
        !          3253: 
        !          3254: /************** Small Subroutines ***************/
        !          3255: 
        !          3256: 
        !          3257: static void
        !          3258: oncore_antenna_report(
        !          3259:        struct instance *instance,
        !          3260:        enum antenna_state new_state)
        !          3261: {
        !          3262:        char *cp;
        !          3263: 
        !          3264:        if (instance->ant_state == new_state)
        !          3265:                return;
        !          3266: 
        !          3267:        switch (new_state) {
        !          3268:        case ONCORE_ANTENNA_OK: cp = "GPS antenna: OK";                   break;
        !          3269:        case ONCORE_ANTENNA_OC: cp = "GPS antenna: short (overcurrent)";  break;
        !          3270:        case ONCORE_ANTENNA_UC: cp = "GPS antenna: open (not connected)"; break;
        !          3271:        case ONCORE_ANTENNA_NV: cp = "GPS antenna: short (no voltage)";   break;
        !          3272:        default:                cp = "GPS antenna: ?";                    break;
        !          3273:        }
        !          3274: 
        !          3275:        instance->ant_state = new_state;
        !          3276:        oncore_log(instance, LOG_NOTICE, cp);
        !          3277: }
        !          3278: 
        !          3279: 
        !          3280: 
        !          3281: static void
        !          3282: oncore_chan_test(
        !          3283:        struct instance *instance
        !          3284:        )
        !          3285: {
        !          3286:        /* subroutine oncore_Cj_id has determined the number of channels from the
        !          3287:         * model number of the attached oncore.  This is not always correct since
        !          3288:         * the oncore could have non-standard firmware.  Here we check (independently) by
        !          3289:         * trying a 6, 8, and 12 chan command, and see which responds.
        !          3290:         * Caution: more than one CAN respond.
        !          3291:         *
        !          3292:         * This #chan is used by the code rather than that calculated from the model number.
        !          3293:         */
        !          3294: 
        !          3295:        instance->o_state = ONCORE_CHECK_CHAN;
        !          3296:        oncore_log(instance, LOG_NOTICE, "state = ONCORE_CHECK_CHAN");
        !          3297: 
        !          3298:        instance->count3 = 1;
        !          3299:        oncore_sendmsg(instance, oncore_cmd_Ba, sizeof(oncore_cmd_Ba));
        !          3300:        oncore_sendmsg(instance, oncore_cmd_Ea, sizeof(oncore_cmd_Ea));
        !          3301:        oncore_sendmsg(instance, oncore_cmd_Ha, sizeof(oncore_cmd_Ha));
        !          3302: }
        !          3303: 
        !          3304: 
        !          3305: 
        !          3306: /* check for a GOOD Almanac, have we got one yet? */
        !          3307: 
        !          3308: static void
        !          3309: oncore_check_almanac(
        !          3310:        struct instance *instance
        !          3311:        )
        !          3312: {
        !          3313:        if (instance->chan == 6) {
        !          3314:                instance->rsm.bad_almanac = instance->BEHa[64]&0x1;
        !          3315:                instance->rsm.bad_fix     = instance->BEHa[64]&0x52;
        !          3316:        } else if (instance->chan == 8) {
        !          3317:                instance->rsm.bad_almanac = instance->BEHa[72]&0x1;
        !          3318:                instance->rsm.bad_fix     = instance->BEHa[72]&0x52;
        !          3319:        } else if (instance->chan == 12) {
        !          3320:                int bits1, bits2, bits3;
        !          3321: 
        !          3322:                bits1 = (instance->BEHa[129]>>5) & 0x7;         /* actually Ha */
        !          3323:                bits2 = instance->BEHa[130];
        !          3324:                instance->rsm.bad_almanac = (bits2 & 0x80);
        !          3325:                instance->rsm.bad_fix     = (bits2 & 0x8) || (bits1 == 0x2);
        !          3326:                                          /* too few sat     Bad Geom     */
        !          3327: 
        !          3328:                bits3 = instance->BEHa[141];    /* UTC parameters */
        !          3329:                if (!instance->count5_set && (bits3 & 0xC0)) {
        !          3330:                        instance->count5 = 2;
        !          3331:                        instance->count5_set = 1;
        !          3332:                }
        !          3333: #ifdef ONCORE_VERBOSE_CHECK_ALMANAC
        !          3334:                {
        !          3335:                        char Msg[160];
        !          3336: 
        !          3337:                        snprintf(Msg, sizeof(Msg),
        !          3338:                                 "DEBUG BITS: (%x %x), (%x %x %x),  %x %x %x %x %x",
        !          3339:                                 instance->BEHa[129],
        !          3340:                                 instance->BEHa[130], bits1, bits2,
        !          3341:                                 bits3, instance->mode == MODE_0D,
        !          3342:                                 instance->mode == MODE_2D, 
        !          3343:                                 instance->mode == MODE_3D,
        !          3344:                                 instance->rsm.bad_almanac,
        !          3345:                                 instance->rsm.bad_fix);
        !          3346:                        oncore_log(instance, LOG_DEBUG, Msg);
        !          3347:                }
        !          3348: #endif
        !          3349:        }
        !          3350: }
        !          3351: 
        !          3352: 
        !          3353: 
        !          3354: /* check the antenna for changes (did it get unplugged?) */
        !          3355: 
        !          3356: static void
        !          3357: oncore_check_antenna(
        !          3358:        struct instance *instance
        !          3359:        )
        !          3360: {
        !          3361:        enum antenna_state antenna;             /* antenna state */
        !          3362: 
        !          3363:        antenna = instance->ant_state;
        !          3364:        if (instance->chan == 12)
        !          3365:                antenna = (instance->BEHa[130] & 0x6 ) >> 1;
        !          3366:        else
        !          3367:                antenna = (instance->BEHa[37] & 0xc0) >> 6;  /* prob unset 6, set GT, UT unset VP */
        !          3368: 
        !          3369:        oncore_antenna_report (instance, antenna);
        !          3370: }
        !          3371: 
        !          3372: 
        !          3373: 
        !          3374: /*
        !          3375:  * Check the leap second status once per day.
        !          3376:  *
        !          3377:  * Note that the ONCORE firmware for the Bj command is wrong at
        !          3378:  * least in the VP.
        !          3379:  * It starts advertising a LEAP SECOND as soon as the GPS satellite
        !          3380:  * data message (page 18, subframe 4) is updated to a date in the
        !          3381:  * future, and does not wait for the month that it will occur.
        !          3382:  * The event will usually be advertised several months in advance.
        !          3383:  * Since there is a one bit flag, there is no way to tell if it is
        !          3384:  * this month, or when...
        !          3385:  *
        !          3386:  * As such, we have the workaround below, of only checking for leap
        !          3387:  * seconds with the Bj command in June/December.
        !          3388:  *
        !          3389:  * The Gj command gives more information, and we can tell in which
        !          3390:  * month to apply the correction.
        !          3391:  *
        !          3392:  * Note that with the VP we COULD read the raw data message, and
        !          3393:  * interpret it ourselves, but since this is specific to this receiver
        !          3394:  * only, and the above workaround is adequate, we don't bother.
        !          3395:  */
        !          3396: 
        !          3397: static void
        !          3398: oncore_check_leap_sec(
        !          3399:        struct instance *instance
        !          3400:        )
        !          3401: {
        !          3402:        oncore_cmd_Bl[2] = 1;                           /* just to be sure */
        !          3403:        if (instance->Bj_day != instance->BEHa[5]) {    /* do this 1/day */
        !          3404:                instance->Bj_day = instance->BEHa[5];
        !          3405: 
        !          3406:                if (instance->saw_Gj < 0) {     /* -1 DONT have Gj use Bj */
        !          3407:                        if ((instance->BEHa[4] == 6) || (instance->BEHa[4] == 12))
        !          3408:                                oncore_sendmsg(instance, oncore_cmd_Bj, sizeof(oncore_cmd_Bj));
        !          3409:                                oncore_sendmsg(instance, oncore_cmd_Bl, sizeof(oncore_cmd_Bl));
        !          3410:                        return;
        !          3411:                }
        !          3412: 
        !          3413:                if (instance->saw_Gj == 0)      /* 0 is dont know if we have Gj */
        !          3414:                        instance->count4 = 1;
        !          3415: 
        !          3416:                oncore_sendmsg(instance, oncore_cmd_Gj, sizeof(oncore_cmd_Gj));
        !          3417:                return;
        !          3418:        }
        !          3419: 
        !          3420:        /* Gj works for some 6/8 chan UT and the M12      */
        !          3421:        /* if no response from Gj in 5 sec, we try Bj     */
        !          3422:        /* which isnt implemented in all the GT/UT either */
        !          3423: 
        !          3424:        if (instance->count4) {         /* delay, waiting for Gj response */
        !          3425:                if (instance->saw_Gj == 1)
        !          3426:                        instance->count4 = 0;
        !          3427:                else if (instance->count4++ > 5) {      /* delay, waiting for Gj response */
        !          3428:                        instance->saw_Gj = -1;          /* didnt see it, will use Bj */
        !          3429:                        instance->count4 = 0;
        !          3430:                        if ((instance->BEHa[4] == 6) || (instance->BEHa[4] == 12))
        !          3431:                                oncore_sendmsg(instance, oncore_cmd_Bj, sizeof(oncore_cmd_Bj));
        !          3432:                                oncore_sendmsg(instance, oncore_cmd_Bl, sizeof(oncore_cmd_Bl));
        !          3433:                }
        !          3434:        }
        !          3435: }
        !          3436: 
        !          3437: 
        !          3438: 
        !          3439: /* check the message checksum,
        !          3440:  *  buf points to START of message ( @@ )
        !          3441:  *  len is length WITH CR/LF.
        !          3442:  */
        !          3443: 
        !          3444: static int
        !          3445: oncore_checksum_ok(
        !          3446:        u_char *buf,
        !          3447:        int     len
        !          3448:        )
        !          3449: {
        !          3450:        int     i, j;
        !          3451: 
        !          3452:        j = 0;
        !          3453:        for (i = 2; i < len-3; i++)
        !          3454:                j ^= buf[i];
        !          3455: 
        !          3456:        return(j == buf[len-3]);
        !          3457: }
        !          3458: 
        !          3459: 
        !          3460: 
        !          3461: static void
        !          3462: oncore_compute_dH(
        !          3463:        struct instance *instance
        !          3464:        )
        !          3465: {
        !          3466:        int GPS, MSL;
        !          3467:        char    Msg[160];
        !          3468: 
        !          3469:        /* Here calculate dH = GPS - MSL for output message */
        !          3470:        /* also set Altitude Hold mode if GT */
        !          3471: 
        !          3472:        instance->have_dH = 1;
        !          3473:        if (instance->chan == 12) {
        !          3474:                GPS = buf_w32(&instance->BEHa[39]);
        !          3475:                MSL = buf_w32(&instance->BEHa[43]);
        !          3476:        } else {
        !          3477:                GPS = buf_w32(&instance->BEHa[23]);
        !          3478:                MSL = buf_w32(&instance->BEHa[27]);
        !          3479:        }
        !          3480:        instance->dH = GPS - MSL;
        !          3481:        instance->dH /= 100.;
        !          3482: 
        !          3483:        /* if MSL is not set, the calculation is meaningless */
        !          3484: 
        !          3485:        if (MSL) {      /* not set ! */
        !          3486:                snprintf(Msg, sizeof(Msg), "dH = (GPS - MSL) = %.2fm",
        !          3487:                         instance->dH);
        !          3488:                oncore_log(instance, LOG_INFO, Msg);
        !          3489:        }
        !          3490: }
        !          3491: 
        !          3492: 
        !          3493: 
        !          3494: /*
        !          3495:  * try loading Almanac from shmem (where it was copied from shmem_old
        !          3496:  */
        !          3497: 
        !          3498: static void
        !          3499: oncore_load_almanac(
        !          3500:        struct instance *instance
        !          3501:        )
        !          3502: {
        !          3503:        u_char  *cp, Cmd[20];
        !          3504:        int     n;
        !          3505:        struct timeval tv;
        !          3506:        struct tm *tm;
        !          3507: 
        !          3508:        if (!instance->shmem)
        !          3509:                return;
        !          3510: 
        !          3511: #ifndef ONCORE_VERBOSE_LOAD_ALMANAC
        !          3512:        for (cp = instance->shmem + 4; (n = 256 * (*(cp-3)) + *(cp-2));
        !          3513:             cp += (n + 3)) {
        !          3514:                if (!strncmp((char *) cp, "@@Cb", 4) &&
        !          3515:                    oncore_checksum_ok(cp, 33) &&
        !          3516:                    (*(cp+4) == 4 || *(cp+4) == 5)) {
        !          3517:                        write(instance->ttyfd, cp, n);
        !          3518:                        oncore_print_Cb(instance, cp);
        !          3519:                }
        !          3520:        }
        !          3521: #else  /* ONCORE_VERBOSE_LOAD_ALMANAC follows */
        !          3522:        for (cp = instance->shmem + 4; (n = 256 * (*(cp-3)) + *(cp-2));
        !          3523:             cp += (n+3)) {
        !          3524:                char Msg[160];
        !          3525: 
        !          3526:                snprintf(Msg, sizeof(Msg), "See %c%c%c%c %d", *(cp),
        !          3527:                         *(cp+1), *(cp+2), *(cp+3), *(cp+4));
        !          3528:                oncore_log(instance, LOG_DEBUG, Msg);
        !          3529: 
        !          3530:                if (!strncmp(cp, "@@Cb", 4)) {
        !          3531:                        oncore_print_Cb(instance, cp);
        !          3532:                        if (oncore_checksum_ok(cp, 33)) {
        !          3533:                                if (*(cp+4) == 4 || *(cp+4) == 5) {
        !          3534:                                        oncore_log(instance, LOG_DEBUG, "GOOD SF");
        !          3535:                                        write(instance->ttyfd, cp, n);
        !          3536:                                } else
        !          3537:                                        oncore_log(instance, LOG_DEBUG, "BAD SF");
        !          3538:                        } else
        !          3539:                                oncore_log(instance, LOG_DEBUG, "BAD CHECKSUM");
        !          3540:                }
        !          3541:        }
        !          3542: #endif
        !          3543: 
        !          3544:        /* Must load position and time or the Almanac doesn't do us any good */
        !          3545: 
        !          3546:        if (!instance->posn_set) {      /* if we input a posn use it, else from SHMEM */
        !          3547:                oncore_log(instance, LOG_NOTICE, "Loading Posn from SHMEM");
        !          3548:                for (cp=instance->shmem+4; (n = 256*(*(cp-3)) + *(cp-2));  cp+=(n+3)) {
        !          3549:                        if ((instance->chan == 6  && (!strncmp((char *) cp, "@@Ba", 4) && oncore_checksum_ok(cp,  68))) ||
        !          3550:                            (instance->chan == 8  && (!strncmp((char *) cp, "@@Ea", 4) && oncore_checksum_ok(cp,  76))) ||
        !          3551:                            (instance->chan == 12 && (!strncmp((char *) cp, "@@Ha", 4) && oncore_checksum_ok(cp, 154)))) {
        !          3552:                                int ii, jj, kk;
        !          3553: 
        !          3554:                                instance->posn_set = 1;
        !          3555:                                ii = buf_w32(cp + 15);
        !          3556:                                jj = buf_w32(cp + 19);
        !          3557:                                kk = buf_w32(cp + 23);
        !          3558: #ifdef ONCORE_VERBOSE_LOAD_ALMANAC
        !          3559:                                {
        !          3560:                                        char Msg[160];
        !          3561:                                        snprintf(Msg, sizeof(Msg),
        !          3562:                                                 "SHMEM posn = %ld (%d, %d, %d)",
        !          3563:                                                 (long)(cp-instance->shmem),
        !          3564:                                                 ii, jj, kk);
        !          3565:                                        oncore_log(instance, LOG_DEBUG, Msg);
        !          3566:                                }
        !          3567: #endif
        !          3568:                                if (ii != 0 || jj != 0 || kk != 0) { /* phk asked for this test */
        !          3569:                                        instance->ss_lat  = ii;
        !          3570:                                        instance->ss_long = jj;
        !          3571:                                        instance->ss_ht   = kk;
        !          3572:                                }
        !          3573:                        }
        !          3574:                }
        !          3575:        }
        !          3576:        oncore_set_posn(instance);
        !          3577: 
        !          3578:        /* and set time to time from Computer clock */
        !          3579: 
        !          3580:        GETTIMEOFDAY(&tv, 0);
        !          3581:        tm = gmtime((const time_t *) &tv.tv_sec);
        !          3582: 
        !          3583: #ifdef ONCORE_VERBOSE_LOAD_ALMANAC
        !          3584:        {
        !          3585:                char Msg[160];
        !          3586:                snprintf(Msg, sizeof(Msg), "DATE %d %d %d, %d %d %d",
        !          3587:                         1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
        !          3588:                         tm->tm_hour, tm->tm_min, tm->tm_sec);
        !          3589:                oncore_log(instance, LOG_DEBUG, Msg);
        !          3590:        }
        !          3591: #endif
        !          3592:        if (instance->chan == 12) {
        !          3593:                memcpy(Cmd, oncore_cmd_Gb, (size_t) sizeof(oncore_cmd_Gb));
        !          3594:                Cmd[-2+4]  = tm->tm_mon + 1;
        !          3595:                Cmd[-2+5]  = tm->tm_mday;
        !          3596:                Cmd[-2+6]  = (1900+tm->tm_year)/256;
        !          3597:                Cmd[-2+7]  = (1900+tm->tm_year)%256;
        !          3598:                Cmd[-2+8]  = tm->tm_hour;
        !          3599:                Cmd[-2+9]  = tm->tm_min;
        !          3600:                Cmd[-2+10] = tm->tm_sec;
        !          3601:                Cmd[-2+11] = 0;
        !          3602:                Cmd[-2+12] = 0;
        !          3603:                Cmd[-2+13] = 0;
        !          3604:                oncore_sendmsg(instance, Cmd,  sizeof(oncore_cmd_Gb));
        !          3605:        } else {
        !          3606:                /* First set GMT offset to zero */
        !          3607: 
        !          3608:                oncore_sendmsg(instance, oncore_cmd_Ab, sizeof(oncore_cmd_Ab));
        !          3609: 
        !          3610:                memcpy(Cmd, oncore_cmd_Ac, (size_t) sizeof(oncore_cmd_Ac));
        !          3611:                Cmd[-2+4] = tm->tm_mon + 1;
        !          3612:                Cmd[-2+5] = tm->tm_mday;
        !          3613:                Cmd[-2+6] = (1900+tm->tm_year)/256;
        !          3614:                Cmd[-2+7] = (1900+tm->tm_year)%256;
        !          3615:                oncore_sendmsg(instance, Cmd,  sizeof(oncore_cmd_Ac));
        !          3616: 
        !          3617:                memcpy(Cmd, oncore_cmd_Aa, (size_t) sizeof(oncore_cmd_Aa));
        !          3618:                Cmd[-2+4] = tm->tm_hour;
        !          3619:                Cmd[-2+5] = tm->tm_min;
        !          3620:                Cmd[-2+6] = tm->tm_sec;
        !          3621:                oncore_sendmsg(instance, Cmd,  sizeof(oncore_cmd_Aa));
        !          3622:        }
        !          3623: 
        !          3624:        oncore_log(instance, LOG_INFO, "Setting Posn and Time after Loading Almanac");
        !          3625: }
        !          3626: 
        !          3627: 
        !          3628: 
        !          3629: /* Almanac data input */
        !          3630: 
        !          3631: static void
        !          3632: oncore_print_Cb(
        !          3633:        struct instance *instance,
        !          3634:        u_char *cp
        !          3635:        )
        !          3636: {
        !          3637: #ifdef ONCORE_VERBOSE_CB
        !          3638:        int     ii;
        !          3639:        char    Msg[160], Msg2[10];
        !          3640: 
        !          3641:        snprintf(Msg, sizeof(Msg), "DEBUG: See: %c%c%c%c", *(cp),
        !          3642:                 *(cp+1), *(cp+2), *(cp+3));
        !          3643:        oncore_log(instance, LOG_DEBUG, Msg);
        !          3644:        snprintf(Msg, sizeof(Msg), "DEBUG: Cb: [%d,%d]", *(cp+4),
        !          3645:                *(cp+5));
        !          3646:        for(ii = 0; ii < 33; ii++) {
        !          3647:                snprintf(Msg2, sizeof(Msg2), " %d", *(cp+ii));
        !          3648:                strncat(Msg, Msg2, sizeof(Msg));
        !          3649:        }
        !          3650:        oncore_log(instance, LOG_DEBUG, Msg);
        !          3651: 
        !          3652:        snprintf(Msg, sizeof(Msg), "Debug: Cb: [%d,%d]", *(cp+4),
        !          3653:                 *(cp+5));
        !          3654:        oncore_log(instance, LOG_DEBUG, Msg);
        !          3655: #endif
        !          3656: }
        !          3657: 
        !          3658: 
        !          3659: #if 0
        !          3660: static void
        !          3661: oncore_print_array(
        !          3662:        u_char *cp,
        !          3663:        int     n
        !          3664:        )
        !          3665: {
        !          3666:        int     jj, i, j, nn;
        !          3667: 
        !          3668:        nn = 0;
        !          3669:        printf("\nTOP\n");
        !          3670:        jj = n/16;
        !          3671:        for (j=0; j<jj; j++) {
        !          3672:                printf("%4d: ", nn);
        !          3673:                nn += 16;
        !          3674:                for (i=0; i<16; i++)
        !          3675:                        printf(" %o", *cp++);
        !          3676:                printf("\n");
        !          3677:        }
        !          3678: }
        !          3679: #endif
        !          3680: 
        !          3681: 
        !          3682: static void
        !          3683: oncore_print_posn(
        !          3684:        struct instance *instance
        !          3685:        )
        !          3686: {
        !          3687:        char Msg[120], ew, ns;
        !          3688:        double xd, xm, xs, yd, ym, ys, hm, hft;
        !          3689:        int idx, idy, is, imx, imy;
        !          3690:        long lat, lon;
        !          3691: 
        !          3692:        oncore_log(instance, LOG_INFO, "Posn:");
        !          3693:        ew = 'E';
        !          3694:        lon = instance->ss_long;
        !          3695:        if (lon < 0) {
        !          3696:                ew = 'W';
        !          3697:                lon = -lon;
        !          3698:        }
        !          3699: 
        !          3700:        ns = 'N';
        !          3701:        lat = instance->ss_lat;
        !          3702:        if (lat < 0) {
        !          3703:                ns = 'S';
        !          3704:                lat = -lat;
        !          3705:        }
        !          3706: 
        !          3707:        hm = instance->ss_ht/100.;
        !          3708:        hft= hm/0.3048;
        !          3709: 
        !          3710:        xd = lat/3600000.;      /* lat, lon in int msec arc, ht in cm. */
        !          3711:        yd = lon/3600000.;
        !          3712:        snprintf(Msg, sizeof(Msg),
        !          3713:                 "Lat = %c %11.7fdeg,    Long = %c %11.7fdeg,    Alt = %5.2fm (%5.2fft) GPS",
        !          3714:                 ns, xd, ew, yd, hm, hft);
        !          3715:        oncore_log(instance, LOG_INFO, Msg);
        !          3716: 
        !          3717:        idx = xd;
        !          3718:        idy = yd;
        !          3719:        imx = lat%3600000;
        !          3720:        imy = lon%3600000;
        !          3721:        xm = imx/60000.;
        !          3722:        ym = imy/60000.;
        !          3723:        snprintf(Msg, sizeof(Msg),
        !          3724:            "Lat = %c %3ddeg %7.4fm,   Long = %c %3ddeg %8.5fm,  Alt = %7.2fm (%7.2fft) GPS", ns, idx, xm, ew, idy, ym, hm, hft);
        !          3725:        oncore_log(instance, LOG_INFO, Msg);
        !          3726: 
        !          3727:        imx = xm;
        !          3728:        imy = ym;
        !          3729:        is  = lat%60000;
        !          3730:        xs  = is/1000.;
        !          3731:        is  = lon%60000;
        !          3732:        ys  = is/1000.;
        !          3733:        snprintf(Msg, sizeof(Msg),
        !          3734:                 "Lat = %c %3ddeg %2dm %5.2fs, Long = %c %3ddeg %2dm %5.2fs, Alt = %7.2fm (%7.2fft) GPS",
        !          3735:                 ns, idx, imx, xs, ew, idy, imy, ys, hm, hft);
        !          3736:        oncore_log(instance, LOG_INFO, Msg);
        !          3737: }
        !          3738: 
        !          3739: 
        !          3740: 
        !          3741: /*
        !          3742:  * write message to Oncore.
        !          3743:  */
        !          3744: 
        !          3745: static void
        !          3746: oncore_sendmsg(
        !          3747:        struct  instance *instance,
        !          3748:        u_char *ptr,
        !          3749:        size_t len
        !          3750:        )
        !          3751: {
        !          3752:        int     fd;
        !          3753:        u_char cs = 0;
        !          3754: 
        !          3755:        fd = instance->ttyfd;
        !          3756: #ifdef ONCORE_VERBOSE_SENDMSG
        !          3757:        if (debug > 4) {
        !          3758:                char    Msg[120];
        !          3759: 
        !          3760:                snprintf(Msg, sizeof(Msg), "ONCORE: Send @@%c%c %d",
        !          3761:                         ptr[0], ptr[1], (int)len);
        !          3762:                oncore_log(instance, LOG_DEBUG, Msg);
        !          3763:        }
        !          3764: #endif
        !          3765:        write(fd, "@@", (size_t) 2);
        !          3766:        write(fd, ptr, len);
        !          3767:        while (len--)
        !          3768:                cs ^= *ptr++;
        !          3769:        write(fd, &cs, (size_t) 1);
        !          3770:        write(fd, "\r\n", (size_t) 2);
        !          3771: }
        !          3772: 
        !          3773: 
        !          3774: 
        !          3775: static void
        !          3776: oncore_set_posn(
        !          3777:        struct instance *instance
        !          3778:        )
        !          3779: {
        !          3780:        int     mode;
        !          3781:        u_char    Cmd[20];
        !          3782: 
        !          3783:        /* Turn OFF position hold, it needs to be off to set position (for some units),
        !          3784:           will get set ON in @@Ea later */
        !          3785: 
        !          3786:        if (instance->chan == 12)
        !          3787:                oncore_sendmsg(instance, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0)); /* (12) */
        !          3788:        else {
        !          3789:                oncore_sendmsg(instance, oncore_cmd_At0, sizeof(oncore_cmd_At0)); /* (6/8) */
        !          3790:                oncore_sendmsg(instance, oncore_cmd_Av0, sizeof(oncore_cmd_Av0)); /* (6/8) */
        !          3791:        }
        !          3792: 
        !          3793:        mode = instance->init_type;
        !          3794: 
        !          3795:        if (mode != 0) {        /* first set posn hold position */
        !          3796:                memcpy(Cmd, oncore_cmd_As, (size_t) sizeof(oncore_cmd_As));     /* don't modify static variables */
        !          3797:                w32_buf(&Cmd[-2+4],  (int) instance->ss_lat);
        !          3798:                w32_buf(&Cmd[-2+8],  (int) instance->ss_long);
        !          3799:                w32_buf(&Cmd[-2+12], (int) instance->ss_ht);
        !          3800:                Cmd[-2+16] = 0;
        !          3801:                oncore_sendmsg(instance, Cmd,  sizeof(oncore_cmd_As));  /* posn hold 3D posn (6/8/12) */
        !          3802: 
        !          3803:                memcpy(Cmd, oncore_cmd_Au, (size_t) sizeof(oncore_cmd_Au));
        !          3804:                w32_buf(&Cmd[-2+4], (int) instance->ss_ht);
        !          3805:                Cmd[-2+8] = 0;
        !          3806:                oncore_sendmsg(instance, Cmd,  sizeof(oncore_cmd_Au));  /* altitude hold (6/8/12 not UT, M12T) */
        !          3807: 
        !          3808:                /* next set current position */
        !          3809: 
        !          3810:                if (instance->chan == 12) {
        !          3811:                        memcpy(Cmd, oncore_cmd_Ga, (size_t) sizeof(oncore_cmd_Ga));
        !          3812:                        w32_buf(&Cmd[-2+4], (int) instance->ss_lat);
        !          3813:                        w32_buf(&Cmd[-2+8], (int) instance->ss_long);
        !          3814:                        w32_buf(&Cmd[-2+12],(int) instance->ss_ht);
        !          3815:                        Cmd[-2+16] = 0;
        !          3816:                        oncore_sendmsg(instance, Cmd,  sizeof(oncore_cmd_Ga));            /* 3d posn (12) */
        !          3817:                } else {
        !          3818:                        memcpy(Cmd, oncore_cmd_Ad, (size_t) sizeof(oncore_cmd_Ad));
        !          3819:                        w32_buf(&Cmd[-2+4], (int) instance->ss_lat);
        !          3820:                        oncore_sendmsg(instance, Cmd,  sizeof(oncore_cmd_Ad));  /* lat (6/8) */
        !          3821: 
        !          3822:                        memcpy(Cmd, oncore_cmd_Ae, (size_t) sizeof(oncore_cmd_Ae));
        !          3823:                        w32_buf(&Cmd[-2+4], (int) instance->ss_long);
        !          3824:                        oncore_sendmsg(instance, Cmd,  sizeof(oncore_cmd_Ae));  /* long (6/8) */
        !          3825: 
        !          3826:                        memcpy(Cmd, oncore_cmd_Af, (size_t) sizeof(oncore_cmd_Af));
        !          3827:                        w32_buf(&Cmd[-2+4], (int) instance->ss_ht);
        !          3828:                        Cmd[-2+8] = 0;
        !          3829:                        oncore_sendmsg(instance, Cmd,  sizeof(oncore_cmd_Af));  /* ht (6/8) */
        !          3830:                }
        !          3831: 
        !          3832:                /* Finally, turn on position hold */
        !          3833: 
        !          3834:                if (instance->chan == 12)
        !          3835:                        oncore_sendmsg(instance, oncore_cmd_Gd1,  sizeof(oncore_cmd_Gd1));
        !          3836:                else
        !          3837:                        oncore_sendmsg(instance, oncore_cmd_At1,  sizeof(oncore_cmd_At1));
        !          3838:        }
        !          3839: }
        !          3840: 
        !          3841: 
        !          3842: 
        !          3843: static void
        !          3844: oncore_set_traim(
        !          3845:        struct instance *instance
        !          3846:        )
        !          3847: {
        !          3848:        char    Msg[160];
        !          3849: 
        !          3850:        if (instance->traim_in != -1)   /* set in Input */
        !          3851:                instance->traim = instance->traim_in;
        !          3852:        else
        !          3853:                instance->traim = instance->traim_ck;
        !          3854: 
        !          3855:        snprintf(Msg, sizeof(Msg), "Input   says TRAIM = %d",
        !          3856:                 instance->traim_in);
        !          3857:        oncore_log(instance, LOG_INFO, Msg);
        !          3858:        snprintf(Msg, sizeof(Msg), "Model # says TRAIM = %d",
        !          3859:                 instance->traim_id);
        !          3860:        oncore_log(instance, LOG_INFO, Msg);
        !          3861:        snprintf(Msg, sizeof(Msg), "Testing says TRAIM = %d",
        !          3862:                 instance->traim_ck);
        !          3863:        oncore_log(instance, LOG_INFO, Msg);
        !          3864:        snprintf(Msg, sizeof(Msg), "Using        TRAIM = %d",
        !          3865:                 instance->traim);
        !          3866:        oncore_log(instance, LOG_INFO, Msg);
        !          3867: 
        !          3868:        if (instance->traim_ck == 1 && instance->traim == 0) {
        !          3869:                /* if it should be off, and I turned it on during testing,
        !          3870:                   then turn it off again */
        !          3871:                if (instance->chan == 6)
        !          3872:                        oncore_sendmsg(instance, oncore_cmd_Bnx, sizeof(oncore_cmd_Bnx));
        !          3873:                else if (instance->chan == 8)
        !          3874:                        oncore_sendmsg(instance, oncore_cmd_Enx, sizeof(oncore_cmd_Enx));
        !          3875:                else    /* chan == 12 */
        !          3876:                        oncore_sendmsg(instance, oncore_cmd_Ge0, sizeof(oncore_cmd_Ge0));
        !          3877:                        oncore_sendmsg(instance, oncore_cmd_Hn0, sizeof(oncore_cmd_Hn0));
        !          3878:        }
        !          3879: }
        !          3880: 
        !          3881: 
        !          3882: 
        !          3883: /*
        !          3884:  * if SHMEM active, every 15s, steal one 'tick' to get 2D or 3D posn.
        !          3885:  */
        !          3886: 
        !          3887: static void
        !          3888: oncore_shmem_get_3D(
        !          3889:        struct instance *instance
        !          3890:        )
        !          3891: {
        !          3892:        if (instance->pp->second%15 == 3) {     /* start the sequence */                        /* by changing mode */
        !          3893:                instance->shmem_reset = 1;
        !          3894:                if (instance->chan == 12) {
        !          3895:                        if (instance->shmem_Posn == 2)
        !          3896:                                oncore_sendmsg(instance, oncore_cmd_Gd2,  sizeof(oncore_cmd_Gd2));  /* 2D */
        !          3897:                        else
        !          3898:                                oncore_sendmsg(instance, oncore_cmd_Gd0,  sizeof(oncore_cmd_Gd0));  /* 3D */
        !          3899:                } else {
        !          3900:                        if (instance->saw_At) {                 /* out of 0D -> 3D mode */
        !          3901:                                oncore_sendmsg(instance, oncore_cmd_At0, sizeof(oncore_cmd_At0));
        !          3902:                                if (instance->shmem_Posn == 2)  /* 3D -> 2D mode */
        !          3903:                                        oncore_sendmsg(instance, oncore_cmd_Av1, sizeof(oncore_cmd_Av1));
        !          3904:                        } else
        !          3905:                                oncore_sendmsg(instance, oncore_cmd_Av0, sizeof(oncore_cmd_Av0));
        !          3906:                }
        !          3907:        } else if (instance->shmem_reset || (instance->mode != MODE_0D)) {
        !          3908:                instance->shmem_reset = 0;
        !          3909:                if (instance->chan == 12)
        !          3910:                        oncore_sendmsg(instance, oncore_cmd_Gd1,  sizeof(oncore_cmd_Gd1));      /* 0D */
        !          3911:                else {
        !          3912:                        if (instance->saw_At) {
        !          3913:                                if (instance->mode == MODE_2D)  /* 2D -> 3D or 0D mode */
        !          3914:                                        oncore_sendmsg(instance, oncore_cmd_Av0, sizeof(oncore_cmd_Av0));
        !          3915:                                oncore_sendmsg(instance, oncore_cmd_At1,  sizeof(oncore_cmd_At1)); /* to 0D mode */
        !          3916:                        } else
        !          3917:                                oncore_sendmsg(instance, oncore_cmd_Av1,  sizeof(oncore_cmd_Av1));
        !          3918:                }
        !          3919:        }
        !          3920: }
        !          3921: 
        !          3922: 
        !          3923: 
        !          3924: /*
        !          3925:  * Here we do the Software SiteSurvey.
        !          3926:  * We have to average our own position for the Position Hold Mode
        !          3927:  *   We use Heights from the GPS ellipsoid.
        !          3928:  * We check for the END of either HW or SW SiteSurvey.
        !          3929:  */
        !          3930: 
        !          3931: static void
        !          3932: oncore_ss(
        !          3933:        struct instance *instance
        !          3934:        )
        !          3935: {
        !          3936:        char    Msg[160];
        !          3937:        double  lat, lon, ht;
        !          3938: 
        !          3939: 
        !          3940:        if (instance->site_survey == ONCORE_SS_HW) {
        !          3941:                /*
        !          3942:                 * Check to see if Hardware SiteSurvey has Finished.
        !          3943:                 */
        !          3944: 
        !          3945:                if ((instance->chan == 8  && !(instance->BEHa[37]  & 0x20)) ||
        !          3946:                    (instance->chan == 12 && !(instance->BEHa[130] & 0x10))) {
        !          3947:                        oncore_log(instance, LOG_INFO, "Now in 0D mode");
        !          3948: 
        !          3949:                        if (instance->chan == 12)
        !          3950:                                oncore_sendmsg(instance, oncore_cmd_Gax, sizeof(oncore_cmd_Gax));
        !          3951:                        else
        !          3952:                                oncore_sendmsg(instance, oncore_cmd_Asx, sizeof(oncore_cmd_Asx));
        !          3953: 
        !          3954:                        oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_DONE");
        !          3955:                        instance->site_survey = ONCORE_SS_DONE;
        !          3956:                }
        !          3957:        } else {
        !          3958:                /*
        !          3959:                 * Must be a Software Site Survey.
        !          3960:                 */
        !          3961: 
        !          3962:                if (instance->rsm.bad_fix)      /* Not if poor geometry or less than 3 sats */
        !          3963:                        return;
        !          3964: 
        !          3965:                if (instance->mode != MODE_3D)  /* Use only 3D Fixes */
        !          3966:                        return;
        !          3967: 
        !          3968:                instance->ss_lat  += buf_w32(&instance->BEHa[15]);
        !          3969:                instance->ss_long += buf_w32(&instance->BEHa[19]);
        !          3970:                instance->ss_ht   += buf_w32(&instance->BEHa[23]);  /* GPS ellipsoid */
        !          3971:                instance->ss_count++;
        !          3972: 
        !          3973:                if (instance->ss_count != POS_HOLD_AVERAGE)
        !          3974:                        return;
        !          3975: 
        !          3976:                instance->ss_lat  /= POS_HOLD_AVERAGE;
        !          3977:                instance->ss_long /= POS_HOLD_AVERAGE;
        !          3978:                instance->ss_ht   /= POS_HOLD_AVERAGE;
        !          3979: 
        !          3980:                snprintf(Msg, sizeof(Msg),
        !          3981:                         "Surveyed posn: lat %.3f (mas) long %.3f (mas) ht %.3f (cm)",
        !          3982:                         instance->ss_lat, instance->ss_long,
        !          3983:                         instance->ss_ht);
        !          3984:                oncore_log(instance, LOG_NOTICE, Msg);
        !          3985:                lat = instance->ss_lat/3600000.;
        !          3986:                lon = instance->ss_long/3600000.;
        !          3987:                ht  = instance->ss_ht/100;
        !          3988:                snprintf(Msg, sizeof(Msg),
        !          3989:                         "Surveyed posn: lat %.7f (deg) long %.7f (deg) ht %.2f (m)",
        !          3990:                         lat, lon, ht);
        !          3991:                oncore_log(instance, LOG_NOTICE, Msg);
        !          3992: 
        !          3993:                oncore_set_posn(instance);
        !          3994: 
        !          3995:                oncore_log(instance, LOG_INFO, "Now in 0D mode");
        !          3996: 
        !          3997:                oncore_log(instance, LOG_NOTICE, "SSstate = ONCORE_SS_DONE");
        !          3998:                instance->site_survey = ONCORE_SS_DONE;
        !          3999:        }
        !          4000: }
        !          4001: 
        !          4002: 
        !          4003: 
        !          4004: static int
        !          4005: oncore_wait_almanac(
        !          4006:        struct instance *instance
        !          4007:        )
        !          4008: {
        !          4009:        if (instance->rsm.bad_almanac) {
        !          4010:                instance->counta++;
        !          4011:                if (instance->counta%5 == 0)
        !          4012:                        oncore_log(instance, LOG_INFO, "Waiting for Almanac");
        !          4013: 
        !          4014:                /*
        !          4015:                 * If we get here (first time) then we don't have an almanac in memory.
        !          4016:                 * Check if we have a SHMEM, and if so try to load whatever is there.
        !          4017:                 */
        !          4018: 
        !          4019:                if (!instance->almanac_from_shmem) {
        !          4020:                        instance->almanac_from_shmem = 1;
        !          4021:                        oncore_load_almanac(instance);
        !          4022:                }
        !          4023:                return(1);
        !          4024:        } else {  /* Here we have the Almanac, we will be starting the @@Bn/@@En/@@Hn
        !          4025:                     commands, and can finally check for TRAIM.  Again, we set a delay
        !          4026:                     (5sec) and wait for things to settle down */
        !          4027: 
        !          4028:                if (instance->chan == 6)
        !          4029:                        oncore_sendmsg(instance, oncore_cmd_Bn, sizeof(oncore_cmd_Bn));
        !          4030:                else if (instance->chan == 8)
        !          4031:                        oncore_sendmsg(instance, oncore_cmd_En, sizeof(oncore_cmd_En));
        !          4032:                else if (instance->chan == 12) {
        !          4033:                        oncore_sendmsg(instance, oncore_cmd_Gc, sizeof(oncore_cmd_Gc)); /* 1PPS on, continuous */
        !          4034:                        oncore_sendmsg(instance, oncore_cmd_Ge, sizeof(oncore_cmd_Ge)); /* TRAIM on */
        !          4035:                        oncore_sendmsg(instance, oncore_cmd_Hn, sizeof(oncore_cmd_Hn)); /* TRAIM status 1/s */
        !          4036:                }
        !          4037:                instance->traim_delay = 1;
        !          4038: 
        !          4039:                oncore_log(instance, LOG_NOTICE, "Have now loaded an ALMANAC");
        !          4040: 
        !          4041:                instance->o_state = ONCORE_RUN;
        !          4042:                oncore_log(instance, LOG_NOTICE, "state = ONCORE_RUN");
        !          4043:        }
        !          4044:        return(0);
        !          4045: }
        !          4046: 
        !          4047: 
        !          4048: 
        !          4049: static void
        !          4050: oncore_log (
        !          4051:        struct instance *instance,
        !          4052:        int     log_level,
        !          4053:        const char *msg
        !          4054:        )
        !          4055: {
        !          4056:        int i;
        !          4057:        char    Msg[200];
        !          4058: 
        !          4059:        snprintf(Msg, sizeof(Msg), "ONCORE[%d]: %s", instance->unit,
        !          4060:                 msg);
        !          4061:        syslog(log_level, Msg);
        !          4062: 
        !          4063:        i = strlen(msg);
        !          4064: 
        !          4065:        if (i > 127) {
        !          4066:                snprintf(Msg, sizeof(Msg),
        !          4067:                         "Internal Error: max error msg length exceeded in clockstats file (%d)",
        !          4068:                         i);
        !          4069:                record_clock_stats(&(instance->peer->srcadr), Msg);
        !          4070:                record_clock_stats(&(instance->peer->srcadr), "Start of message was");
        !          4071:                strncpy(Msg, msg, 120);
        !          4072:                record_clock_stats(&(instance->peer->srcadr), Msg);
        !          4073:        } else {        /* now put ONCORE[n]: ahead of message if it will fit */
        !          4074:                if (i < 110) {
        !          4075:                        snprintf(Msg, sizeof(Msg), "ONCORE[%d]: %s",
        !          4076:                                 instance->unit, msg);
        !          4077:                        record_clock_stats(&(instance->peer->srcadr), Msg);
        !          4078:                } else
        !          4079:                        record_clock_stats(&(instance->peer->srcadr), msg);
        !          4080:        }
        !          4081: 
        !          4082: #ifdef ONCORE_VERBOSE_ONCORE_LOG
        !          4083:        instance->max_len = max(i, instance->max_len);
        !          4084:        instance->max_count++;
        !          4085:        if (instance->max_count % 100 == 0) {
        !          4086:                snprintf(Msg, sizeof(Msg),
        !          4087:                         "Max Message Length so far is %d",
        !          4088:                         instance->max_len);
        !          4089:                oncore_log(instance, LOG_INFO, Msg);
        !          4090:        }
        !          4091: #endif
        !          4092: }
        !          4093: 
        !          4094: #else
        !          4095: int refclock_oncore_bs;
        !          4096: #endif /* REFCLOCK && CLOCK_ONCORE */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>