]> git.ipfire.org Git - thirdparty/ntp.git/commitdiff
Added RIPE NCC trimble driver
authorHarlan Stenn <stenn@ntp.org>
Fri, 28 Jun 2002 05:25:19 +0000 (01:25 -0400)
committerHarlan Stenn <stenn@ntp.org>
Fri, 28 Jun 2002 05:25:19 +0000 (01:25 -0400)
From: Mark Santcroos <marks@ripe.net>

bk: 3d1bf33fjbFJ80L4ltfJVG4weMzu2Q

configure.in
html/driver43.html [new file with mode: 0644]
html/driver43_1.gif [new file with mode: 0644]
html/driver43_2.jpg [new file with mode: 0644]
include/ntp.h
libntp/clocktypes.c
ntpd/Makefile.am
ntpd/ntp_control.c
ntpd/refclock_conf.c
ntpd/refclock_ripencc.c [new file with mode: 0644]

index 190e35ad40976296298c8e126a3ea5110ca0c260..d6599b1f02d402a89d31252b4321713e872c006c 100644 (file)
@@ -2007,6 +2007,16 @@ if test "$ntp_ok" = "yes"; then
 fi
 AC_MSG_RESULT($ntp_ok)
 
+AC_MSG_CHECKING(RIPENCC specific Trimble driver)
+AC_ARG_ENABLE(RIPENCC,
+    AC_HELP_STRING([--enable-RIPENCC], [+ RIPENCC specific Trimble driver]),
+    [ntp_ok=$enableval], [ntp_ok=$ntp_eac])
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    AC_DEFINE(CLOCK_RIPENCC, ,[RIPE NCC Trimble clock])
+fi
+AC_MSG_RESULT($ntp_ok)
+
 AC_MSG_CHECKING(Spectracom 8170/Netclock/2 WWVB receiver)
 AC_ARG_ENABLE(SPECTRACOM,
     AC_HELP_STRING([--enable-SPECTRACOM], [+ Spectracom 8170/Netclock/2 WWVB receiver]),
diff --git a/html/driver43.html b/html/driver43.html
new file mode 100644 (file)
index 0000000..fc994ef
--- /dev/null
@@ -0,0 +1,109 @@
+<html>
+<head>
+<title>RIPE NCC interface for Trimble Palisade</title>
+</head>
+<body>
+<h3>RIPE NCC interface for Trimble Palisade</h3>
+
+<hr>
+
+<img src="pic/driver43_2.jpg" alt="Trimble Acutime 2000" align="right">
+
+<h4>Synopsis</h4>
+
+Address: 127.127.43.<i>u</i> <br>
+Reference ID: <tt>RIPENCC</tt> <br>
+Driver ID: <tt>RIPENCC</tt> 
+
+<h4>Description</h4>
+
+<p> This is a special driver developed to be used in conjuction with the 
+RIPE NCC clock card in the RIPE NCC Test Traffic Measurements project.
+</p>
+
+<h4>Why this driver?</h4>
+
+<p>
+The reason why we created a seperated driver for an antenna for which
+already a (vendor supplied) driver exist is a design decision.
+To be more specific, the standard Trimble interface uses a 12 pin
+connector. The cable sold by Trimble to connect to this wire is a very
+thick cable. Certainly not something you wish to run for several 100
+meters through your building. And if you wanted to run it for 100 meters,
+you always would have to really run the cable, and didn't have the option
+to use existing wiring.<br>
+This is where we wanted more flexibility. We wanted to be able to use
+existing wiring in buildings. That leaded us to CAT-5(UTP) which only
+gives us 8 wires. Therefor we decided to redesing the use of the Trimble
+antenna. The Trimble supports two modes: EVENT driver and PPS mode. The
+default is to use the EVENT mode which needs all 12 wires. We only use the
+PPS timestamps for which we have enough with 8 wires. For our purposes
+this is more than fine.
+</p>
+
+More information about the project can be found on the <a href="http://www.ripe.net/test-traffic" TARGET=_new>Test Traffic Measurements</a> website.
+
+<img src="pic/driver43_1.gif" alt="RIPE NCC clock card" align="right">
+<h4> RIPE NCC clock card</h4>
+
+<p>The card is very a simple PCI card. The only feature on the bus it uses
+is the power supply. It uses this power supply to power the Trimble GPS
+antenna.</p>
+
+<p>The card basicly just is a RS422 to RS232 converter. It gets the
+Trimble's RS422 signal on a RJ45 connector and transforms that to RS232 on a 
+DIN9 connector. This connector should be loopbacked on the back of the
+machine to the serial port. As said, the card doesn't do any PCI data
+transfers.</p>
+
+<p>The schematics of the interface card is available here: <a
+href="http://www.ripe.net/ripencc/mem-services/ttm/Documents/gps_interface_schematic.pdf">gps_interface_schematic.pdf</a>.
+You are free to create this card yourself as long as you give some credit
+or reference to us. Note that we don't sell these cards on a commercial 
+basis, but for interested parties we do have some spares to share.<p>
+
+
+<h4>Monitor Data</h4>
+
+In the <tt>filegen clockstats</tt> file the following (example) data is 
+collected:
+<pre>
+52445 41931.275 127.127.40.0 U1 20.6.2002 11:38:51 13 11
+52445 41931.395 127.127.40.0 C1 20062002 113851 6  364785 110.2 450 6.7 13 5222.374737 N 0453.268013 E 48  7 11 0 1 -14 20 0 -25
+52445 41931.465 127.127.40.0 S1 07 1 1 02 59.3 291.5 39.3
+52445 41931.485 127.127.40.0 S1 11 2 1 02 59.9 138.0 60.2
+52445 41931.525 127.127.40.0 S1 01 4 1 02 48.4 185.7 28.3
+52445 41931.555 127.127.40.0 S1 14 5 2 02 32.7  41.0 15.4
+52445 41931.585 127.127.40.0 S1 20 6 1 02 59.9 256.6 78.0
+52445 41931.615 127.127.40.0 S1 25 8 2 00  0.0  86.6 20.1
+</pre>
+This is in the form of:
+<pre>
+All output lines consist of a prefix and a message, the prefix is:
+[days since epoch] [sec.ms since start of day] [peer address] 
+
+And all individual messages:
+
+*Primary UTC time packet:
+U1 [date] [time] [trackstat] [utcflags]
+
+*Comprehensive time packet:
+C1 [date] [time] [mode] [bias] [biasunc] [rate] [rateunc] [utcoff] [latitude] [longtitude] [alt] [vis sat](x8)
+
+*Tracking status packet:
+S1 [prn] [channel] [aqflag] [ephstat] [snr] [azinuth] [elevation]
+</pre>
+
+<h4>Additional Information</h4>
+
+<a href="refclock.htm">Reference Clock Drivers</a>
+
+
+<hr>
+<a href="index.htm"><img align="left" src="pic/home.gif" alt=
+"Home"></a>
+
+<address><a href="mailto:marks@ripe.net">Mark Santcroos
+&lt;marks@ripe.net&gt;</a></address>
+</body>
+</html>
diff --git a/html/driver43_1.gif b/html/driver43_1.gif
new file mode 100644 (file)
index 0000000..f1ff7c7
Binary files /dev/null and b/html/driver43_1.gif differ
diff --git a/html/driver43_2.jpg b/html/driver43_2.jpg
new file mode 100644 (file)
index 0000000..c53639c
Binary files /dev/null and b/html/driver43_2.jpg differ
index 2f07a5a6e1eed2e81af5d10c0a521dc554b9ca2d..353c1f394160555fc2f680d87f36d56cbf7cb1d7 100644 (file)
@@ -460,7 +460,8 @@ struct peer {
 #define REFCLK_JJY             40      /* JJY receiver  */
 #define        REFCLK_TT560            41      /* TrueTime 560 IRIG-B decoder */
 #define REFCLK_ZYFER           42      /* Zyfer GPStarplus receiver  */
-#define REFCLK_MAX             42      /* Grow as needed... */
+#define REFCLK_RIPENCC         43      /* RIPE NCC Trimble driver */
+#define REFCLK_MAX             43      /* Grow as needed... */
 
 /*
  * We tell reference clocks from real peers by giving the reference
index e5434378586ee3342d2ce4432d70bef885d23d56..4e425c544b436d5ec248121f4a6f9f75e9ef8cf1 100644 (file)
@@ -96,6 +96,8 @@ struct clktype clktypes[] = {
          "TT_IRIG"},
        { REFCLK_ZYFER, "Zyfer GPStarplus receiver (42)",
          "GPS_ZYFER" },
+       { REFCLK_RIPENCC,       "RIPE NCC Trimble driver (43)",
+         "GPS_RIPENCC" },
        { -1,                   "", "" }
 };
 
index 0c1d4c1aecc9e726645a7c2ff89aa59fd6f62f60..b057cae89397c42586f09571777143232da4363c 100644 (file)
@@ -37,7 +37,7 @@ ntpd_SOURCES = cmd_args.c jupiter.h map_vme.c ntp_config.c ntp_control.c \
        refclock_pcf.c refclock_pst.c refclock_ptbacts.c refclock_shm.c \
        refclock_tpro.c refclock_trak.c refclock_true.c refclock_tt560.c \
        refclock_ulink.c refclock_usno.c refclock_wwv.c refclock_wwvb.c \
-       refclock_zyfer.c
+       refclock_zyfer.c refclock_ripencc.c
 
 $(PROGRAMS): $(LDADD)
 
index 11686beb708c3e861d53cb06451b5b7ac7830f43..f1e943c30d8b71c88c1acaaf6683a78da16e2d81 100644 (file)
@@ -398,6 +398,7 @@ static u_char clocktypes[] = {
        CTL_SST_TS_LF,          /* REFCLK_JJY (40) */
        CTL_SST_TS_UHF,         /* REFCLK_TT560 (41) */
        CTL_SST_TS_UHF,         /* REFCLK_ZYFER (42) */
+       CTL_SST_TS_UHF,         /* REFCLK_RIPENCC (43) */
 };
 
 
index 478019f0cf43b4534d79bf292da29338bf395ec0..62949b0a4868a57c25ddee719f6e9bafe84109c8 100644 (file)
@@ -258,6 +258,12 @@ extern     struct refclock refclock_zyfer;
 #define        refclock_zyfer refclock_none
 #endif
 
+#ifdef CLOCK_RIPENCC
+extern struct refclock refclock_ripencc;
+#else
+#define refclock_ripencc refclock_none
+#endif
+
 /*
  * Order is clock_start(), clock_shutdown(), clock_poll(),
  * clock_control(), clock_init(), clock_buginfo, clock_flags;
@@ -307,7 +313,8 @@ struct refclock *refclock_conf[] = {
        &refclock_hopfpci,      /* 39 REFCLK_HOPF_PCI */
        &refclock_jjy,          /* 40 REFCLK_JJY */
        &refclock_tt560,        /* 41 REFCLK_TT560 */
-       &refclock_zyfer         /* 42 REFCLK_ZYFER */
+       &refclock_zyfer,        /* 42 REFCLK_ZYFER */
+       &refclock_ripencc       /* 43 REFCLK_RIPENCC */
 };
 
 u_char num_refclock_conf = sizeof(refclock_conf)/sizeof(struct refclock *);
diff --git a/ntpd/refclock_ripencc.c b/ntpd/refclock_ripencc.c
new file mode 100644 (file)
index 0000000..f18270e
--- /dev/null
@@ -0,0 +1,4872 @@
+/*
+ * $Id: refclock_ripencc.c,v 1.13 2002/06/18 14:20:55 marks Exp marks $
+ *
+ * Copyright (c) 2002  RIPE NCC
+ *
+ * All Rights Reserved
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of the author not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ *
+ * THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
+ * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ *
+ * This driver was developed for use with the RIPE NCC TTM project.
+ *
+ *
+ * The initial driver was developed by Daniel Karrenberg <dfk@ripe.net> 
+ * using the code made available by Trimble. This was for xntpd-3.x.x
+ *
+ * Rewrite of the driver for ntpd-4.x.x by Mark Santcroos <marks@ripe.net>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#if defined(REFCLOCK) && defined(CLOCK_RIPENCC)
+
+#include "ntp_stdlib.h"
+#include "ntpd.h"
+#include "ntp_refclock.h"
+#include "ntp_unixtime.h"
+#include "ntp_io.h"
+
+#ifdef HAVE_TIMEPPS_H
+# include <timepps.h>
+#else /* HAVE_TIMEPPS_H */
+# ifdef HAVE_SYS_TIMEPPS_H
+#  include <sys/timepps.h>
+# endif /* HAVE_SYS_TIMEPPS_H */
+#endif /* HAVE_TIMEPPS_H */
+
+/*
+ * Definitions
+ */
+
+/* we are on little endian */
+#define BYTESWAP
+
+/* 
+ * DEBUG statements: uncomment if necessary
+ */
+/* #define DEBUG_NCC */ /* general debug statements */
+/* #define DEBUG_PPS */ /* debug pps */
+/* #define DEBUG_RAW */ /* print raw packets */
+
+#define TRIMBLE_OUTPUT_FUNC
+#define TSIP_VERNUM "7.12a"
+
+#ifndef FALSE
+#define FALSE  (0)
+#define TRUE   (!FALSE)
+#endif /* FALSE */
+
+#define GPS_PI         (3.1415926535898)
+#define GPS_C          (299792458.)
+#define        D2R             (GPS_PI/180.0)
+#define        R2D             (180.0/GPS_PI)
+#define WEEK   (604800.)
+#define MAXCHAN  (8)
+
+/* control characters for TSIP packets */
+#define DLE    (0x10)
+#define ETX    (0x03)
+
+#define MAX_RPTBUF (256)
+
+/* values of TSIPPKT.status */
+#define TSIP_PARSED_EMPTY      0
+#define TSIP_PARSED_FULL       1
+#define TSIP_PARSED_DLE_1      2
+#define TSIP_PARSED_DATA       3
+#define TSIP_PARSED_DLE_2      4
+
+#define UTCF_UTC_AVAIL  (unsigned char) (1)             /* UTC available */
+#define UTCF_LEAP_SCHD  (unsigned char) (1<<4)  /* Leap scheduled */
+#define UTCF_LEAP_PNDG  (unsigned char) (1<<5)  /* Leap pending, will occur at end of day */
+
+#define DEVICE  "/dev/gps%d"   /* name of radio device */
+#define PRECISION       (-9)    /* precision assumed (about 2 ms) */
+#define PPS_PRECISION   (-20)  /* precision assumed (about 1 us) */
+#define REFID           "GPS\0" /* reference id */
+#define REFID_LEN      4
+#define DESCRIPTION     "RIPE NCC GPS (Palisade)"      /* Description */
+#define SPEED232        B9600   /* 9600 baud */
+
+#define NSAMPLES        3       /* stages of median filter */
+
+/* Structures */
+
+/* TSIP packets have the following structure, whether report or command. */
+typedef struct {
+       short 
+               counter,        /* counter */
+               len;            /* size of buf; < MAX_RPTBUF unsigned chars */
+       unsigned char
+               status,         /* TSIP packet format/parse status */
+               code,           /* TSIP code */
+               buf[MAX_RPTBUF];/* report or command string */
+} TSIPPKT;
+
+/* TSIP binary data structures */
+typedef struct {
+       unsigned char
+               t_oa_raw, SV_health;
+       float
+               e, t_oa, i_0, OMEGADOT, sqrt_A,
+               OMEGA_0, omega, M_0, a_f0, a_f1,
+               Axis, n, OMEGA_n, ODOT_n, t_zc;
+       short
+               weeknum, wn_oa;
+} ALM_INFO;
+
+typedef struct {     /*  Almanac health page (25) parameters  */
+       unsigned char
+               WN_a, SV_health[32], t_oa;
+} ALH_PARMS;
+
+typedef struct {     /*  Universal Coordinated Time (UTC) parms */
+       double
+               A_0;
+       float
+               A_1;
+       short
+               delta_t_LS;
+       float
+               t_ot;
+       short
+               WN_t, WN_LSF, DN, delta_t_LSF;
+} UTC_INFO;
+
+typedef struct {      /*  Ionospheric info (float)  */
+       float
+               alpha_0, alpha_1, alpha_2, alpha_3,
+               beta_0, beta_1, beta_2, beta_3;
+} ION_INFO;
+
+typedef struct {      /*  Subframe 1 info (float)  */
+       short
+               weeknum;
+       unsigned char
+               codeL2, L2Pdata, SVacc_raw, SV_health;
+       short
+               IODC;
+       float
+               T_GD, t_oc, a_f2, a_f1, a_f0, SVacc;
+} EPHEM_CLOCK;
+
+typedef        struct {     /*  Ephemeris info (float)  */
+       unsigned char
+               IODE, fit_interval;
+       float
+               C_rs, delta_n;
+       double
+               M_0;
+       float
+               C_uc;
+       double
+               e;
+       float
+               C_us;
+       double
+               sqrt_A;
+       float
+               t_oe, C_ic;
+       double
+               OMEGA_0;
+       float
+               C_is;
+       double
+               i_0;
+       float
+               C_rc;
+       double
+               omega;
+       float
+               OMEGADOT, IDOT;
+       double
+               Axis, n, r1me2, OMEGA_n, ODOT_n;
+} EPHEM_ORBIT;
+
+typedef struct {     /* Navigation data structure */
+       short
+               sv_number;     /* SV number (0 = no entry) */
+       float
+               t_ephem;       /* time of ephemeris collection */
+       EPHEM_CLOCK
+               ephclk;        /* subframe 1 data */
+       EPHEM_ORBIT
+               ephorb;        /* ephemeris data */
+} NAV_INFO;
+
+typedef struct {
+       unsigned char
+               bSubcode,
+               operating_mode,
+               dgps_mode,
+               dyn_code,
+               trackmode;
+       float
+               elev_mask,
+               cno_mask,
+               dop_mask,
+               dop_switch;
+       unsigned char
+               dgps_age_limit;
+} TSIP_RCVR_CFG;
+
+
+#ifdef TRIMBLE_OUTPUT_FUNC
+static char
+       *dayname[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"},
+       old_baudnum[] = {0, 1, 4, 5, 6, 8, 9, 11, 28, 12},
+        *st_baud_text_app [] = {"", "", "  300", "  600", " 1200", " 2400", 
+               " 4800", " 9600", "19200", "38400"},
+       *old_parity_text[] = {"EVEN", "ODD", "", "", "NONE"},
+       *parity_text [] = {"NONE", "ODD", "EVEN"},
+       *old_input_ch[] = { "TSIP", "RTCM (6 of 8 bits)"},
+       *old_output_ch[] = { "TSIP", "No output", "", "", "", "NMEA 0183"},
+       *protocols_in_text[] = { "", "TSIP", "", ""},
+       *protocols_out_text[] = { "", "TSIP", "NMEA"},
+       *rcvr_port_text [] = { "Port A      ", "Port B      ", "Current Port"},
+       *dyn_text [] = {"Unchanged", "Land", "Sea", "Air", "Static"},
+       *NavModeText0xBB[] = {"automatic", "time only (0-D)", "", "2-D",
+               "3-D", "", "", "OverDetermined Time"},
+       *PPSTimeBaseText[] = {"GPS", "UTC", "USER"},
+       *PPSPolarityText[] = {"Positive", "Negative"},
+       *MaskText[] = { "Almanac  ", "Ephemeris", "UTC      ", "Iono     ",
+               "GPS Msg  ", "Alm Hlth ", "Time Fix ", "SV Select",
+               "Ext Event", "Pos Fix  ", "Raw Meas "};
+
+#endif /* TRIMBLE_OUTPUT_FUNC */
+
+/*
+ * Unit control structure
+ */
+struct ripencc_unit {                   
+        int unit;                       /* unit number */
+        int     pollcnt;                /* poll message counter */
+        int     polled;                 /* Hand in a sample? */
+        char leapdelta;                 /* delta of next leap event */
+        unsigned char utcflags;         /* delta of next leap event */
+        l_fp    tstamp;                 /* timestamp of last poll */
+        
+        struct timespec ts;             /* last timestamp */
+        pps_params_t pps_params;        /* pps parameters */
+        pps_info_t pps_info;            /* last pps data */
+        pps_handle_t handle;            /* pps handlebars */
+
+};
+
+
+/*******************        PROTOYPES            *****************/
+
+/*  prototypes for report parsing primitives */
+short rpt_0x3D (TSIPPKT *rpt, unsigned char *tx_baud_index,
+       unsigned char *rx_baud_index, unsigned char *char_format_index,
+       unsigned char *stop_bits, unsigned char *tx_mode_index,
+       unsigned char *rx_mode_index);
+short rpt_0x40 (TSIPPKT *rpt, unsigned char *sv_prn, short *week_num,
+       float *t_zc, float *eccentricity, float *t_oa, float *i_0,
+       float *OMEGA_dot, float *sqrt_A, float *OMEGA_0, float *omega,
+       float *M_0);
+short rpt_0x41 (TSIPPKT *rpt, float *time_of_week, float *UTC_offset,
+       short *week_num);
+short rpt_0x42 (TSIPPKT *rpt, float ECEF_pos[3], float *time_of_fix);
+short rpt_0x43 (TSIPPKT *rpt, float ECEF_vel[3], float *freq_offset,
+       float *time_of_fix);
+short rpt_0x45 (TSIPPKT *rpt, unsigned char *major_nav_version,
+       unsigned char *minor_nav_version, unsigned char *nav_day,
+       unsigned char *nav_month, unsigned char *nav_year,
+       unsigned char *major_dsp_version, unsigned char *minor_dsp_version,
+       unsigned char *dsp_day, unsigned char *dsp_month,
+       unsigned char *dsp_year);
+short rpt_0x46 (TSIPPKT *rpt, unsigned char *status1, unsigned char *status2);
+short rpt_0x47 (TSIPPKT *rpt, unsigned char *nsvs, unsigned char *sv_prn,
+       float *snr);
+short rpt_0x48 (TSIPPKT *rpt, unsigned char *message);
+short rpt_0x49 (TSIPPKT *rpt, unsigned char *sv_health);
+short rpt_0x4A (TSIPPKT *rpt, float *lat, float *lon, float *alt,
+       float *clock_bias, float *time_of_fix);
+short rpt_0x4A_2 (TSIPPKT *rpt, float *alt, float *dummy,
+       unsigned char *alt_flag);
+short rpt_0x4B (TSIPPKT *rpt, unsigned char *machine_id,
+       unsigned char *status3, unsigned char *status4);
+short rpt_0x4C (TSIPPKT *rpt, unsigned char *dyn_code, float *el_mask,
+       float *snr_mask, float *dop_mask, float *dop_switch);
+short rpt_0x4D (TSIPPKT *rpt, float *osc_offset);
+short rpt_0x4E (TSIPPKT *rpt, unsigned char *response);
+short rpt_0x4F (TSIPPKT *rpt, double *a0, float *a1, float *time_of_data,
+       short *dt_ls, short *wn_t, short *wn_lsf, short *dn, short *dt_lsf);
+short rpt_0x54 (TSIPPKT *rpt, float *clock_bias, float *freq_offset,
+       float *time_of_fix);
+short rpt_0x55 (TSIPPKT *rpt, unsigned char *pos_code, unsigned char *vel_code,
+       unsigned char *time_code, unsigned char *aux_code);
+short rpt_0x56 (TSIPPKT *rpt, float vel_ENU[3], float *freq_offset,
+       float *time_of_fix);
+short rpt_0x57 (TSIPPKT *rpt, unsigned char *source_code,
+       unsigned char *diag_code, short *week_num, float *time_of_fix);
+short rpt_0x58 (TSIPPKT *rpt, unsigned char *op_code, unsigned char *data_type,
+       unsigned char *sv_prn, unsigned char *data_length,
+       unsigned char *data_packet);
+short rpt_0x59 (TSIPPKT *rpt, unsigned char *code_type,
+       unsigned char status_code[32]);
+short rpt_0x5A (TSIPPKT *rpt, unsigned char *sv_prn, float *sample_length,
+       float *signal_level, float *code_phase, float *Doppler,
+       double *time_of_fix);
+short rpt_0x5B (TSIPPKT *rpt, unsigned char *sv_prn, unsigned char *sv_health,
+       unsigned char *sv_iode, unsigned char *fit_interval_flag,
+       float *time_of_collection, float *time_of_eph, float *sv_accy);
+short rpt_0x5C (TSIPPKT *rpt, unsigned char *sv_prn, unsigned char *slot,
+       unsigned char *chan, unsigned char *acq_flag, unsigned char *eph_flag,
+       float *signal_level, float *time_of_last_msmt, float *elev,
+       float *azim, unsigned char *old_msmt_flag,
+       unsigned char *integer_msec_flag, unsigned char *bad_data_flag,
+       unsigned char *data_collect_flag);
+short rpt_0x6D (TSIPPKT *rpt, unsigned char *manual_mode, unsigned char *nsvs,
+       unsigned char *ndim, unsigned char sv_prn[], float *pdop,
+       float *hdop, float *vdop, float *tdop);
+short rpt_0x82 (TSIPPKT *rpt, unsigned char *diff_mode);
+short rpt_0x83 (TSIPPKT *rpt, double ECEF_pos[3], double *clock_bias,
+       float *time_of_fix);
+short rpt_0x84 (TSIPPKT *rpt, double *lat, double *lon, double *alt,
+       double *clock_bias, float *time_of_fix);
+short rpt_Paly0xBB(TSIPPKT *rpt, TSIP_RCVR_CFG *TsipxBB);
+short rpt_0xBC   (TSIPPKT *rpt, unsigned char *port_num,
+       unsigned char *in_baud, unsigned char *out_baud,
+       unsigned char *data_bits, unsigned char *parity,
+       unsigned char *stop_bits, unsigned char *flow_control,
+       unsigned char *protocols_in, unsigned char *protocols_out,
+       unsigned char *reserved);
+
+/* prototypes for superpacket parsers */
+
+short rpt_0x8F0B (TSIPPKT *rpt, unsigned short *event, double *tow,
+   unsigned char *date, unsigned char *month, short *year,
+   unsigned char *dim_mode, short *utc_offset, double *bias, double *drift,
+   float *bias_unc, float *dr_unc, double *lat, double *lon, double *alt,
+   char sv_id[8]);
+short rpt_0x8F14 (TSIPPKT *rpt, short *datum_idx, double datum_coeffs[5]);
+short rpt_0x8F15 (TSIPPKT *rpt, short *datum_idx, double datum_coeffs[5]);
+short rpt_0x8F20 (TSIPPKT *rpt, unsigned char *info, double *lat,
+       double *lon, double *alt, double vel_enu[], double *time_of_fix,
+       short *week_num, unsigned char *nsvs, unsigned char sv_prn[], 
+       short sv_IODC[], short *datum_index);
+short rpt_0x8F41 (TSIPPKT *rpt, unsigned char *bSearchRange,
+       unsigned char *bBoardOptions, unsigned long *iiSerialNumber,
+       unsigned char *bBuildYear, unsigned char *bBuildMonth,
+       unsigned char *bBuildDay, unsigned char *bBuildHour,
+       float *fOscOffset, unsigned short *iTestCodeId);
+short rpt_0x8F42 (TSIPPKT *rpt, unsigned char *bProdOptionsPre,
+       unsigned char *bProdNumberExt, unsigned short *iCaseSerialNumberPre,
+       unsigned long *iiCaseSerialNumber, unsigned long *iiProdNumber,
+       unsigned short *iPremiumOptions, unsigned short *iMachineID,
+       unsigned short *iKey);
+short rpt_0x8F45 (TSIPPKT *rpt, unsigned char *bSegMask);
+short rpt_0x8F4A_16 (TSIPPKT *rpt, unsigned char *pps_enabled,
+       unsigned char *pps_timebase, unsigned char *pos_polarity,
+       double *pps_offset, float *bias_unc_threshold);
+short rpt_0x8F4B (TSIPPKT *rpt, unsigned long *decorr_max);
+short rpt_0x8F4D (TSIPPKT *rpt, unsigned long *event_mask);
+short rpt_0x8FA5 (TSIPPKT *rpt, unsigned char *spktmask);
+short rpt_0x8FAD (TSIPPKT *rpt, unsigned short *COUNT, double *FracSec,
+    unsigned char *Hour, unsigned char *Minute, unsigned char *Second,
+    unsigned char *Day, unsigned char *Month, unsigned short *Year,
+    unsigned char *Status, unsigned char *Flags);
+
+/**/
+/* prototypes for command-encode primitives with suffix convention:  */
+/* c = clear, s = set, q = query, e = enable, d = disable            */
+void cmd_0x1F  (TSIPPKT *cmd);
+void cmd_0x26  (TSIPPKT *cmd);
+void cmd_0x2F  (TSIPPKT *cmd);
+void cmd_0x35s (TSIPPKT *cmd, unsigned char pos_code, unsigned char vel_code,
+       unsigned char time_code, unsigned char opts_code);
+void cmd_0x3C  (TSIPPKT *cmd, unsigned char sv_prn);
+void cmd_0x3Ds (TSIPPKT *cmd, unsigned char baud_out, unsigned char baud_inp,
+       unsigned char char_code, unsigned char stopbitcode,
+       unsigned char output_mode, unsigned char input_mode);
+void cmd_0xBBq (TSIPPKT *cmd, unsigned char subcode) ;
+
+/* prototypes 8E commands */
+void cmd_0x8E0Bq (TSIPPKT *cmd);
+void cmd_0x8E41q (TSIPPKT *cmd);
+void cmd_0x8E42q (TSIPPKT *cmd);
+void cmd_0x8E4Aq (TSIPPKT *cmd);
+void cmd_0x8E4As (TSIPPKT *cmd, unsigned char PPSOnOff, unsigned char TimeBase,
+       unsigned char Polarity, double PPSOffset, float Uncertainty);
+void cmd_0x8E4Bq (TSIPPKT *cmd);
+void cmd_0x8E4Ds (TSIPPKT *cmd, unsigned long AutoOutputMask);
+void cmd_0x8EADq (TSIPPKT *cmd);
+
+/* header/source border XXXXXXXXXXXXXXXXXXXXXXXXXX */
+
+/* Trimble parse functions */
+static         int     parse0x8FAD     P((TSIPPKT *, struct peer *));
+static         int     parse0x8F0B     P((TSIPPKT *, struct peer *));
+#ifdef TRIMBLE_OUTPUT_FUNC
+static         int     parseany        P((TSIPPKT *, struct peer *));
+static         void    TranslateTSIPReportToText       P((TSIPPKT *, char *));
+#endif /* TRIMBLE_OUTPUT_FUNC */
+static         int     parse0x5C       P((TSIPPKT *, struct peer *));
+static         int     parse0x4F       P((TSIPPKT *, struct peer *));
+static void    tsip_input_proc P((TSIPPKT *, int));
+
+/* Trimble helper functions */
+static void    bPutFloat       P((float *, unsigned char *));
+static void    bPutDouble      P((double *, unsigned char *));
+static void    bPutULong       P((unsigned long *, unsigned char *));
+static int     print_msg_table_header  P((int rptcode, char *HdrStr, int force));
+static char *  show_time       P((float time_of_week));
+
+/* RIPE NCC functions */
+static void    ripencc_control P((int, struct refclockstat *, struct
+                               refclockstat *, struct peer *));
+static int     ripencc_ppsapi  P((struct peer *, int, int));
+static int     ripencc_get_pps_ts      P((struct ripencc_unit *, l_fp *));
+static int     ripencc_start   P((int, struct peer *));
+static         void    ripencc_shutdown        P((int, struct peer *));
+static         void    ripencc_poll    P((int, struct peer *));
+static         void    ripencc_send    P((struct peer *, TSIPPKT spt));
+static         void    ripencc_receive P((struct recvbuf *));
+
+/* fill in reflock structure for our clock */
+struct refclock refclock_ripencc = {
+       ripencc_start,          /* start up driver */
+       ripencc_shutdown,       /* shut down driver */
+       ripencc_poll,           /* transmit poll message */
+       ripencc_control,        /* control function */
+       noentry,                /* initialize driver */
+       noentry,                /* debug info */
+       NOFLAGS                 /* clock flags */
+};
+
+/*
+ *  Tables to compute the ddd of year form icky dd/mm timecode. Viva la
+ *  leap.
+ */
+static int day1tab[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+static int day2tab[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+extern int pps_hardpps;
+extern int pps_assert;
+
+/*
+ * ripencc_start - open the GPS devices and initialize data for processing
+ */
+static int
+ripencc_start(int unit, struct peer *peer)
+{
+       register struct ripencc_unit *up;
+       struct refclockproc *pp;
+       char device[40];
+       int fd;
+       struct termios tio;
+       TSIPPKT spt;
+
+       /*
+        * Open serial port
+        */
+       (void)snprintf(device, sizeof(device), DEVICE, unit);
+       if (!(fd = refclock_open(device, SPEED232, LDISC_RAW)))
+               return (0);
+
+       /* from refclock_palisade.c */
+       if (tcgetattr(fd, &tio) < 0) {
+               msyslog(LOG_ERR, "Palisade(%d) tcgetattr(fd, &tio): %m",unit);
+               return (0);
+       }
+
+       /*
+        * set flags
+        */
+       tio.c_cflag |= (PARENB|PARODD);
+       tio.c_iflag &= ~ICRNL;
+       if (tcsetattr(fd, TCSANOW, &tio) == -1) {
+               msyslog(LOG_ERR, "Palisade(%d) tcsetattr(fd, &tio): %m",unit);
+               return (0);
+       }
+
+       /*
+        * Allocate and initialize unit structure
+        */
+       if (!(up = (struct ripencc_unit *) 
+                               emalloc(sizeof(struct ripencc_unit)))) {
+               (void) close(fd);
+               return (0);
+       }
+       memset((char *)up, 0, sizeof(struct ripencc_unit));
+       pp = peer->procptr;
+       pp->io.clock_recv = ripencc_receive;
+       pp->io.srcclock = (caddr_t)peer;
+       pp->io.datalen = 0;
+       pp->io.fd = fd;
+       if (!io_addclock(&pp->io)) {
+               (void) close(fd);
+               free(up);
+               return (0);
+       }
+       pp->unitptr = (caddr_t)up;
+
+       /*
+        * Initialize miscellaneous variables
+        */
+       peer->precision = PRECISION;
+       pp->clockdesc = DESCRIPTION;
+       memcpy((char *)&pp->refid, REFID, REFID_LEN);
+       up->pollcnt = 2;
+       up->unit = unit;
+       up->leapdelta = 0;
+       up->utcflags = 0;
+
+       /*
+        * Initialize the Clock
+        */
+
+       /* query software versions */
+       cmd_0x1F(&spt);                 
+       ripencc_send(peer, spt);          
+
+       /* query receiver health */
+       cmd_0x26(&spt);                 
+       ripencc_send(peer, spt);
+
+       /* query serial numbers */      
+       cmd_0x8E42q(&spt);              
+       ripencc_send(peer, spt);  
+       
+       /* query manuf params */
+       cmd_0x8E41q(&spt);              
+       ripencc_send(peer, spt); 
+
+       /* i/o opts */ /* trimble manual page A30 */
+       cmd_0x35s(&spt, 
+               0x1C,   /* position */
+               0x00,   /* velocity */
+               0x05,   /* timing */
+               0x0a);  /* auxilary */
+       ripencc_send(peer, spt);
+       
+       /* turn off port A */
+       cmd_0x3Ds (&spt,
+               0x0B, /* baud_out */
+               0x0B, /* baud_inp */
+               0x07, /* char_code */
+               0x07, /* stopbitcode */
+               0x01, /* output_mode */
+               0x00); /* input_mode */
+       ripencc_send(peer, spt);
+
+       /* set i/o options */
+       cmd_0x8E4As (&spt,
+               0x01,           /* PPS on */
+               0x01,           /* Timebase UTC */
+               0x00,           /* polarity positive */
+               0.,             /* 100 ft. cable XXX make flag */
+               1e-6 * GPS_C);  /* turn of biasuncert. > (1us) */
+       ripencc_send(peer,spt);
+
+       /* all outomatic packet output off */
+       cmd_0x8E4Ds(&spt,
+               0x00000000); /* AutoOutputMask */
+       ripencc_send(peer, spt);
+
+       cmd_0xBBq (&spt,
+               0x00); /* query primary configuration */
+       ripencc_send(peer,spt);
+
+
+       /* query PPS parameters */
+       cmd_0x8E4Aq (&spt); /* query PPS params */
+       ripencc_send(peer,spt);
+
+       /* query survey limit */
+       cmd_0x8E4Bq (&spt); /* query survey limit */
+       ripencc_send(peer,spt);
+
+#ifdef DEBUG_NCC
+       if (debug)
+               printf("ripencc_start: success\n");
+#endif /* DEBUG_NCC */
+
+       /*
+        * Start the PPSAPI interface if it is there. Default to use
+        * the assert edge and do not enable the kernel hardpps.
+        */
+       if (time_pps_create(fd, &up->handle) < 0) {
+               up->handle = 0;
+               msyslog(LOG_ERR, "refclock_ripencc: time_pps_create failed: %m");
+               return (1);
+       }
+
+       return(ripencc_ppsapi(peer, pps_assert, pps_hardpps));
+}
+
+/*
+ * ripencc_control - fudge control
+ */
+static void
+ripencc_control(
+       int unit,               /* unit (not used) */
+       struct refclockstat *in, /* input parameters (not used) */
+       struct refclockstat *out, /* output parameters (not used) */
+       struct peer *peer       /* peer structure pointer */
+       )
+{
+       struct refclockproc *pp;
+
+#ifdef DEBUG_NCC
+       msyslog(LOG_INFO,"%s()",__FUNCTION__);
+#endif /* DEBUG_NCC */
+
+       pp = peer->procptr;
+       ripencc_ppsapi(peer, pp->sloppyclockflag & CLK_FLAG2,
+           pp->sloppyclockflag & CLK_FLAG3);
+}
+
+
+/*
+ * Initialize PPSAPI
+ */
+int
+ripencc_ppsapi(
+       struct peer *peer,      /* peer structure pointer */
+       int enb_clear,          /* clear enable */
+       int enb_hardpps         /* hardpps enable */
+       )
+{
+       struct refclockproc *pp;
+       struct ripencc_unit *up;
+       int capability;
+
+       pp = peer->procptr;
+       up = (struct ripencc_unit *)pp->unitptr;
+       if (time_pps_getcap(up->handle, &capability) < 0) {
+               msyslog(LOG_ERR,
+                   "refclock_ripencc: time_pps_getcap failed: %m");
+               return (0);
+       }
+       memset(&up->pps_params, 0, sizeof(pps_params_t));
+       if (enb_clear)
+               up->pps_params.mode = capability & PPS_CAPTURECLEAR;
+       else
+               up->pps_params.mode = capability & PPS_CAPTUREASSERT;
+       if (!up->pps_params.mode) {
+               msyslog(LOG_ERR,
+                   "refclock_ripencc: invalid capture edge %d",
+                   !enb_clear);
+               return (0);
+       }
+       up->pps_params.mode |= PPS_TSFMT_TSPEC;
+       if (time_pps_setparams(up->handle, &up->pps_params) < 0) {
+               msyslog(LOG_ERR,
+                   "refclock_ripencc: time_pps_setparams failed: %m");
+               return (0);
+       }
+       if (enb_hardpps) {
+               if (time_pps_kcbind(up->handle, PPS_KC_HARDPPS,
+                                   up->pps_params.mode & ~PPS_TSFMT_TSPEC,
+                                   PPS_TSFMT_TSPEC) < 0) {
+                       msyslog(LOG_ERR,
+                           "refclock_ripencc: time_pps_kcbind failed: %m");
+                       return (0);
+               }
+               pps_enable = 1;
+       }
+       peer->precision = PPS_PRECISION;
+
+#if DEBUG_NCC
+       if (debug) {
+               time_pps_getparams(up->handle, &up->pps_params);
+               printf(
+                   "refclock_ripencc: capability 0x%x version %d mode 0x%x kern %d\n",
+                   capability, up->pps_params.api_version,
+                   up->pps_params.mode, enb_hardpps);
+       }
+#endif /* DEBUG_NCC */
+
+       return (1);
+}
+
+/*
+ * This function is called every 64 seconds from ripencc_receive
+ * It will fetch the pps time 
+ *
+ * Return 0 on failure and 1 on success.
+ */
+static int
+ripencc_get_pps_ts(
+       struct ripencc_unit *up,
+       l_fp *tsptr
+       )
+{
+       pps_info_t pps_info;
+       struct timespec timeout, ts;
+       double dtemp;
+       l_fp tstmp;
+
+#ifdef DEBUG_PPS
+       msyslog(LOG_INFO,"ripencc_get_pps_ts\n");
+#endif /* DEBUG_PPS */
+
+
+       /*
+        * Convert the timespec nanoseconds field to ntp l_fp units.
+        */ 
+       if (up->handle == 0)
+               return (0);
+       timeout.tv_sec = 0;
+       timeout.tv_nsec = 0;
+       memcpy(&pps_info, &up->pps_info, sizeof(pps_info_t));
+       if (time_pps_fetch(up->handle, PPS_TSFMT_TSPEC, &up->pps_info,
+           &timeout) < 0)
+               return (0);
+       if (up->pps_params.mode & PPS_CAPTUREASSERT) {
+               if (pps_info.assert_sequence ==
+                   up->pps_info.assert_sequence)
+                       return (0);
+               ts = up->pps_info.assert_timestamp;
+       } else if (up->pps_params.mode & PPS_CAPTURECLEAR) {
+               if (pps_info.clear_sequence ==
+                   up->pps_info.clear_sequence)
+                       return (0);
+               ts = up->pps_info.clear_timestamp;
+       } else {
+               return (0);
+       }
+       if ((up->ts.tv_sec == ts.tv_sec) && (up->ts.tv_nsec == ts.tv_nsec))
+               return (0);
+       up->ts = ts;
+
+       tstmp.l_ui = ts.tv_sec + JAN_1970;
+       dtemp = ts.tv_nsec * FRAC / 1e9;
+       tstmp.l_uf = (u_int32)dtemp;
+
+#ifdef DEBUG_PPS
+       msyslog(LOG_INFO,"ts.tv_sec: %d\n",(int)ts.tv_sec);
+       msyslog(LOG_INFO,"ts.tv_nsec: %ld\n",ts.tv_nsec);
+#endif /* DEBUG_PPS */
+
+       *tsptr = tstmp;
+       return (1);
+}
+
+/*
+ * ripencc_shutdown - shut down a GPS clock
+ */
+static void
+ripencc_shutdown(int unit, struct peer *peer)
+{
+       register struct ripencc_unit *up;
+       struct refclockproc *pp;
+
+       pp = peer->procptr;
+       up = (struct ripencc_unit *)pp->unitptr;
+
+       if (up->handle != 0)
+               time_pps_destroy(up->handle);
+
+       io_closeclock(&pp->io);
+
+       free(up);
+}
+
+/*
+ * ripencc_poll - called by the transmit procedure
+ */
+static void
+ripencc_poll(int unit, struct peer *peer)
+{
+       register struct ripencc_unit *up;
+       struct refclockproc *pp;
+       TSIPPKT spt;
+
+#ifdef DEBUG_NCC
+       if (debug)
+               fprintf(stderr, "ripencc_poll(%d)\n", unit);
+#endif /* DEBUG_NCC */
+       pp = peer->procptr;
+       up = (struct ripencc_unit *)pp->unitptr;
+       if (up->pollcnt == 0)
+               refclock_report(peer, CEVNT_TIMEOUT);
+       else
+               up->pollcnt--;
+
+       pp->polls++;
+       up->polled = 1;
+
+       /* poll for UTC superpacket */
+       cmd_0x8EADq (&spt);
+       ripencc_send(peer,spt);
+}
+
+/*
+ * ripencc_send - send message to clock
+ * use the structures being created by the trimble functions!
+ * makes the code more readable/clean
+ */
+static void
+ripencc_send(struct peer *peer, TSIPPKT spt)
+{
+       unsigned char *ip, *op;
+       unsigned char obuf[512];
+
+#ifdef DEBUG_RAW
+       {
+               register struct ripencc_unit *up;
+               register struct refclockproc *pp;       
+
+               pp = peer->procptr;
+               up = (struct ripencc_unit *)pp->unitptr;
+               if (debug)
+                       printf("ripencc_send(%d, %02X)\n", up->unit, cmd);
+       }
+#endif /* DEBUG_RAW */
+
+       ip = spt.buf;
+       op = obuf;
+
+       *op++ = 0x10;
+       *op++ = spt.code;
+
+       while (spt.len--) {
+               if (op-obuf > sizeof(obuf)-5) {
+                       msyslog(LOG_ERR, "ripencc_send obuf overflow!");
+                       refclock_report(peer, CEVNT_FAULT);
+                       return;
+               }
+                       
+               if (*ip == 0x10)  /* byte stuffing */
+                       *op++ = 0x10;
+               *op++ = *ip++;
+       }
+       
+       *op++ = 0x10;
+       *op++ = 0x03;
+
+#ifdef DEBUG_RAW
+       if (debug) { /* print raw packet */
+               unsigned char *cp;
+               int i;
+
+               printf("ripencc_send: len %d\n", op-obuf);
+               for (i=1, cp=obuf; cp<op; i++, cp++) {
+                       printf(" %02X", *cp);
+                       if (i%10 == 0) 
+                               printf("\n");
+               }
+               printf("\n");
+       }
+#endif /* DEBUG_RAW */
+
+       if (write(peer->procptr->io.fd, obuf, op-obuf) == -1) {
+                       refclock_report(peer, CEVNT_FAULT);
+       }
+}
+
+/*
+ * ripencc_receive()
+ *
+ * called when a packet is received on the serial port
+ * takes care of further processing
+ *
+ */
+static void
+ripencc_receive(struct recvbuf *rbufp)
+{
+       register struct ripencc_unit *up;
+       register struct refclockproc *pp;       
+       struct peer *peer;
+       static TSIPPKT rpt; /* structure for current incoming TSIP report  */ 
+       TSIPPKT spt; /* send packet */
+       int ns_since_pps;                       
+       int i;
+       char *cp;
+       /* Use these variables to hold data until we decide its worth keeping */
+       char    rd_lastcode[BMAX];
+       l_fp    rd_tmp;
+       u_short rd_lencode;
+
+       /* msyslog(LOG_INFO, "%s",__FUNCTION__); */
+
+       /*
+        * Initialize pointers and read the timecode and timestamp
+        */
+       peer = (struct peer *)rbufp->recv_srcclock;
+       pp = peer->procptr;
+       up = (struct ripencc_unit *)pp->unitptr;
+       rd_lencode = refclock_gtlin(rbufp, rd_lastcode, BMAX, &rd_tmp);
+
+#ifdef DEBUG_RAW
+       if (debug)
+               fprintf(stderr, "ripencc_receive(%d)\n", up->unit);
+#endif /* DEBUG_RAW */
+
+#ifdef DEBUG_RAW
+       if (debug) { /* print raw packet */
+               int i;
+               unsigned char *cp;
+
+               printf("ripencc_receive: len %d\n", rbufp->recv_length);
+               for (i=1, cp=(char*)&rbufp->recv_space; i <= rbufp->recv_length; i++, cp++) {
+                       printf(" %02X", *cp);
+                       if (i%10 == 0) 
+                               printf("\n");
+               }
+               printf("\n");
+       }
+#endif /* DEBUG_RAW */
+
+       cp = (char*) &rbufp->recv_space;
+       i=rbufp->recv_length;
+
+       while (i--) { /* loop over received chars */
+
+               tsip_input_proc(&rpt, (unsigned char) *cp++);
+
+               if (rpt.status != TSIP_PARSED_FULL)
+                       continue;
+
+               switch (rpt.code) {
+
+               case 0x8F:      /* superpacket */
+
+                       switch (rpt.buf[0]) {
+
+                       case 0xAD:      /* UTC Time */
+                               /*
+                                * When polling on port B the timecode 
+                                * is the time of the previous PPS.
+                                * If we completed receiving the packet 
+                                * less than 150ms after the turn of the second, 
+                                * it may have the code of the previous second.
+                                * We do not trust that and simply poll again
+                                * without even parsing it.
+                                *
+                                * More elegant would be to re-schedule the poll,
+                                * but I do not know (yet) how to do that cleanly.
+                                *
+                                */
+                               /* BLA ns_since_pps = ncc_tstmp(rbufp, &trtmp); */
+/*   if (up->polled && ns_since_pps > -1 && ns_since_pps < 150) { */
+
+                               ns_since_pps=200;
+                               if (up->polled && ns_since_pps < 150) {
+                                       msyslog(LOG_INFO, "%s(): up->polled",__FUNCTION__);
+                                       ripencc_poll(up->unit, peer);
+                                       break;
+                               }
+
+                               /*
+                                * Parse primary utc time packet
+                                * and fill refclock structure 
+                                * from results. 
+                                */
+                               if (parse0x8FAD(&rpt, peer) < 0) {
+                                               msyslog(LOG_INFO, "%s(): parse0x8FAD < 0",__FUNCTION__);
+                                               refclock_report(peer, CEVNT_BADREPLY);
+                                               break;
+                               }
+                               /*
+                                * If the PPSAPI is working, rather use its 
+                                * timestamps.
+                                * assume that the PPS occurs on the second 
+                                * so blow any msec
+                                */
+                               if (ripencc_get_pps_ts(up, &rd_tmp) == 1) {
+                                       pp->lastrec = up->tstamp = rd_tmp;
+                                       pp->msec = 0;
+                               }
+                               else
+                                       msyslog(LOG_INFO, "%s(): ripencc_get_pps_ts returns failure\n",__FUNCTION__);
+
+
+                               if (!up->polled) { 
+                                       msyslog(LOG_INFO, "%s(): unrequested packet\n",__FUNCTION__);
+                                       /* unrequested packet */
+                                       break;
+                               }
+
+                               /* we have been polled ! */
+                               up->polled = 0;
+                               up->pollcnt = 2;
+
+                               /* poll for next packet */
+                               cmd_0x8E0Bq(&spt);
+                               ripencc_send(peer,spt);
+                               
+                               if (ns_since_pps < 0) { /* no PPS */
+                                       msyslog(LOG_INFO, "%s(): ns_since_pps < 0",__FUNCTION__);
+                                       refclock_report(peer, CEVNT_BADTIME);
+                                       break;
+                               }
+
+                               /*
+                                * Process the new sample in the median filter and determine the
+                                * reference clock offset and dispersion. 
+                                */
+                               if (!refclock_process(pp)) {
+                                       msyslog(LOG_INFO, "%s(): !refclock_process",__FUNCTION__);
+                                       refclock_report(peer, CEVNT_BADTIME);
+                                       break;
+                               }
+
+                               refclock_receive(peer);
+                               break;
+                       
+                       case 0x0B: /* comprehensive time packet */
+                               parse0x8F0B(&rpt, peer);
+                               break;
+
+                       default: /* other superpackets */
+#ifdef DEBUG_NCC
+                               msyslog(LOG_INFO, "%s(): calling parseany",__FUNCTION__);
+#endif /* DEBUG_NCC */
+#ifdef TRIMBLE_OUTPUT_FUNC
+                               parseany(&rpt, peer);
+#endif /* TRIMBLE_OUTPUT_FUNC */
+                               break;
+                       }
+                       break;
+
+               case 0x4F:      /* UTC parameters, for leap info */
+                       parse0x4F(&rpt, peer);
+                       break;
+
+               case 0x5C:      /* sat tracking data */
+                       parse0x5C(&rpt, peer);
+                       break;
+
+               default: /* other packets */
+#ifdef TRIMBLE_OUTPUT_FUNC
+                       parseany(&rpt, peer);
+#endif /* TRIMBLE_OUTPUT_FUNC */
+                       break;
+               }
+               rpt.status = TSIP_PARSED_EMPTY;
+       }
+}
+
+/* 
+ * All trimble functions that are directly referenced from driver code
+ * (so not from parseany)
+ */
+
+void cmd_0x1F (TSIPPKT *cmd)
+/* request software versions */
+{
+       cmd->len = 0;
+       cmd->code = 0x1F;
+}
+
+void cmd_0x26 (TSIPPKT *cmd)
+/* request receiver health */
+{
+       cmd->len = 0;
+       cmd->code = 0x26;
+}
+
+
+
+
+void cmd_0x2F (TSIPPKT *cmd)
+/* request UTC params */
+{
+       cmd->len = 0;
+       cmd->code = 0x2F;
+}
+
+void cmd_0x35s  (TSIPPKT *cmd, unsigned char pos_code, unsigned char vel_code,
+       unsigned char time_code, unsigned char opts_code)
+/* set serial I/O options */
+{
+       cmd->buf[0] = pos_code;
+       cmd->buf[1] = vel_code;
+       cmd->buf[2] = time_code;
+       cmd->buf[3] = opts_code;
+       cmd->len = 4;
+       cmd->code = 0x35;
+}
+void cmd_0x3C  (TSIPPKT *cmd, unsigned char sv_prn)
+/* request tracking status */
+{
+       cmd->buf[0] = sv_prn;
+       cmd->len = 1;
+       cmd->code = 0x3C;
+}
+
+
+void cmd_0x3Ds (TSIPPKT *cmd,
+       unsigned char baud_out, unsigned char baud_inp,
+   unsigned char char_code, unsigned char stopbitcode,
+   unsigned char output_mode, unsigned char input_mode)
+/* set Channel A configuration for dual-port operation */
+{
+       cmd->buf[0] = baud_out;         /* XMT baud rate */
+       cmd->buf[1] = baud_inp;         /* RCV baud rate */
+       cmd->buf[2] = char_code;           /* parity and #bits per byte */
+       cmd->buf[3] = stopbitcode;      /* number of stop bits code */
+       cmd->buf[4] = output_mode;      /* Ch. A transmission mode */
+       cmd->buf[5] = input_mode;       /* Ch. A reception mode */
+       cmd->len = 6;
+       cmd->code = 0x3D;
+}
+
+
+/* query primary configuration */
+void cmd_0xBBq (TSIPPKT *cmd,
+       unsigned char subcode)
+{
+
+       cmd->len = 1;
+       cmd->code = 0xBB;
+       cmd->buf[0] = subcode;
+}
+
+
+/**** Superpackets ****/
+void cmd_0x8E0Bq (TSIPPKT *cmd)
+/* 8E-0B to query 8F-0B controls */
+{
+
+       cmd->len = 1;
+       cmd->code = 0x8E;
+       cmd->buf[0] = 0x0B;
+}
+
+
+void cmd_0x8E41q (TSIPPKT *cmd)
+/* 8F-41 to query board serial number */
+{
+
+       cmd->len = 1;
+       cmd->code = 0x8E;
+       cmd->buf[0] = 0x41;
+}
+
+
+void cmd_0x8E42q (TSIPPKT *cmd)
+/* 8F-42 to query product serial number */
+{
+
+       cmd->len = 1;
+       cmd->code = 0x8E;
+       cmd->buf[0] = 0x42;
+}
+void cmd_0x8E4Aq (TSIPPKT *cmd)
+/* 8F-4A to query PPS parameters */
+{
+       cmd->len = 1;
+       cmd->code = 0x8E;
+       cmd->buf[0] = 0x4A;
+}
+
+
+/* set i/o options */
+void cmd_0x8E4As (TSIPPKT *cmd,
+       unsigned char PPSOnOff,
+       unsigned char TimeBase,
+       unsigned char Polarity,
+   double PPSOffset,
+   float Uncertainty)
+{
+       cmd->len = 16;
+       cmd->code = 0x8E;
+       cmd->buf[0] = 0x4A;
+       cmd->buf[1] = PPSOnOff;
+       cmd->buf[2] = TimeBase;
+       cmd->buf[3] = Polarity;
+       bPutDouble (&PPSOffset, &cmd->buf[4]);
+       bPutFloat (&Uncertainty, &cmd->buf[12]);
+}
+void cmd_0x8E4Bq (TSIPPKT *cmd)
+/* 8F-4B query survey limit */
+{
+       cmd->len = 1;
+       cmd->code = 0x8E;
+       cmd->buf[0] = 0x4B;
+}
+
+
+/* poll for UTC superpacket */
+void cmd_0x8EADq (TSIPPKT *cmd)
+/* 8E-AD to query 8F-AD controls */
+{
+       cmd->len = 1;
+       cmd->code = 0x8E;
+       cmd->buf[0] = 0xAD;
+}
+
+/* all outomatic packet output off */
+void cmd_0x8E4Ds (TSIPPKT *cmd,
+       unsigned long AutoOutputMask)
+{
+       cmd->len = 5;
+       cmd->code = 0x8E;
+       cmd->buf[0] = 0x4D;
+       bPutULong (&AutoOutputMask, &cmd->buf[1]);
+}
+
+
+
+
+/* for DOS machines, reverse order of bytes as they come through the
+ * serial port. */
+#ifdef BYTESWAP
+static short bGetShort (unsigned char *bp)
+{
+       short outval;
+   unsigned char *optr;
+
+   optr = (unsigned char*)&outval + 1;
+   *optr-- = *bp++;
+   *optr = *bp;
+       return outval;
+}
+
+#ifdef TRIMBLE_OUTPUT_FUNC
+static unsigned short bGetUShort (unsigned char *bp)
+{
+       unsigned short outval;
+   unsigned char *optr;
+
+   optr = (unsigned char*)&outval + 1;
+   *optr-- = *bp++;
+   *optr = *bp;
+       return outval;
+}
+
+static long bGetLong (unsigned char *bp)
+{
+       long outval;
+   unsigned char *optr;
+
+   optr = (unsigned char*)&outval + 3;
+   *optr-- = *bp++;
+   *optr-- = *bp++;
+   *optr-- = *bp++;
+   *optr = *bp;
+       return outval;
+}
+
+static unsigned long bGetULong (unsigned char *bp)
+{
+       unsigned long outval;
+   unsigned char *optr;
+
+   optr = (unsigned char*)&outval + 3;
+   *optr-- = *bp++;
+   *optr-- = *bp++;
+   *optr-- = *bp++;
+   *optr = *bp;
+       return outval;
+}
+#endif /* TRIMBLE_OUTPUT_FUNC */
+
+static float bGetSingle (unsigned char *bp)
+{
+       float outval;
+   unsigned char *optr;
+
+   optr = (unsigned char*)&outval + 3;
+   *optr-- = *bp++;
+   *optr-- = *bp++;
+   *optr-- = *bp++;
+   *optr = *bp;
+       return outval;
+}
+
+static double bGetDouble (unsigned char *bp)
+{
+       double outval;
+   unsigned char *optr;
+
+   optr = (unsigned char*)&outval + 7;
+   *optr-- = *bp++;
+   *optr-- = *bp++;
+   *optr-- = *bp++;
+   *optr-- = *bp++;
+   *optr-- = *bp++;
+   *optr-- = *bp++;
+   *optr-- = *bp++;
+   *optr = *bp;
+       return outval;
+}
+
+#else /* not BYTESWAP */
+
+#define bGetShort(bp)  (*(short*)(bp))
+#define bGetLong(bp)   (*(long*)(bp))
+#define bGetULong(bp)  (*(unsigned long*)(bp))
+#define bGetSingle(bp)         (*(float*)(bp))
+#define bGetDouble(bp) (*(double*)(bp))
+
+#endif /* BYTESWAP */
+/*
+ * Byte-reversal is necessary for little-endian (Intel-based) machines.
+ * TSIP streams are Big-endian (Motorola-based).
+ */
+#ifdef BYTESWAP
+
+void
+bPutFloat (float *in, unsigned char *out)
+{
+       unsigned char *inptr;
+
+   inptr = (unsigned char*)in + 3;
+   *out++ = *inptr--;
+   *out++ = *inptr--;
+   *out++ = *inptr--;
+   *out = *inptr;
+}
+
+static void
+bPutULong (unsigned long *in, unsigned char *out)
+{
+       unsigned char *inptr;
+
+   inptr = (unsigned char*)in + 3;
+   *out++ = *inptr--;
+   *out++ = *inptr--;
+   *out++ = *inptr--;
+   *out = *inptr;
+}
+
+static void
+bPutDouble (double *in, unsigned char *out)
+{
+       unsigned char *inptr;
+
+   inptr = (unsigned char*)in + 7;
+   *out++ = *inptr--;
+   *out++ = *inptr--;
+   *out++ = *inptr--;
+   *out++ = *inptr--;
+   *out++ = *inptr--;
+   *out++ = *inptr--;
+   *out++ = *inptr--;
+   *out = *inptr;
+}
+
+#else  /* not BYTESWAP */
+
+void bPutShort (short a, unsigned char *cmdbuf) {*(short*) cmdbuf = a;}
+void bPutULong (long a, unsigned char *cmdbuf)         {*(long*) cmdbuf = a;}
+void bPutFloat (float a, unsigned char *cmdbuf) {*(float*) cmdbuf = a;}
+void bPutDouble (double a, unsigned char *cmdbuf){*(double*) cmdbuf = a;}
+
+#endif /* BYTESWAP */
+
+/*
+ * Parse primary utc time packet
+ * and fill refclock structure 
+ * from results. 
+ *
+ * 0 = success
+ * -1 = errors
+ */
+
+static int
+parse0x8FAD(rpt, peer)
+       TSIPPKT *rpt;
+       struct peer *peer;      
+{
+       register struct refclockproc *pp;       
+       register struct ripencc_unit *up;
+
+       unsigned day, month, year;      /* data derived from received timecode */
+       unsigned hour, minute, second;
+       unsigned char trackstat, utcflags;
+
+       static char logbuf[1024];       /* logging string buffer */
+       int i;
+       unsigned char *buf;
+               
+       buf = rpt->buf;
+       pp = peer->procptr;
+
+       if (rpt->len != 22) 
+               return (-1);
+       
+       if (bGetShort(&buf[1]) != 0) {
+#ifdef DEBUG_NCC
+               if (debug) 
+                       printf("parse0x8FAD: event count != 0\n");
+#endif /* DEBUG_NCC */
+               return(-1);
+       }
+
+
+       if (bGetDouble(&buf[3]) != 0.0) {
+#ifdef DEBUG_NCC
+               if (debug) 
+                       printf("parse0x8FAD: fracsecs != 0\n");
+#endif /* DEBUG_NCC */
+               return(-1);
+       }
+
+       hour = (unsigned int) buf[11];
+       minute = (unsigned int) buf[12];
+       second = (unsigned int) buf[13];
+       day =           (unsigned int) buf[14];
+       month =         (unsigned int) buf[15];
+       year =          bGetShort(&buf[16]);
+       trackstat = buf[18];
+       utcflags = buf[19];
+
+
+       sprintf(logbuf, "U1 %d.%d.%d %02d:%02d:%02d %d %02x",
+               day, month, year, hour, minute, second, trackstat, utcflags);
+
+#ifdef DEBUG_NCC
+       if (debug) 
+               puts(logbuf);
+#endif /* DEBUG_NCC */
+
+       record_clock_stats(&peer->srcadr, logbuf);
+
+       if (!utcflags & UTCF_UTC_AVAIL)
+               return(-1);
+
+       /* poll for UTC parameters once and then if UTC flag changed */
+       up = (struct ripencc_unit *) pp->unitptr;
+       if (utcflags != up->utcflags) {
+               TSIPPKT spt; /* local structure for send packet */
+               cmd_0x2F (&spt); /* request UTC params */
+               ripencc_send(peer,spt);
+               up->utcflags = utcflags;
+       }
+       
+       /*
+        * If we hit the leap second, we choose to skip this sample
+        * rather than rely on other code to be perfectly correct.
+        * No offense, just defense ;-).
+        */
+       if (second == 60)
+               return(-1);
+
+       /* now check and convert the time we received */
+
+       pp->year = year;
+       if (month < 1 || month > 12 || day < 1 || day > 31) 
+               return(-1);
+
+       if (pp->year % 4) {
+               if (day > day1tab[month - 1]) 
+                       return(-1);
+               for (i = 0; i < month - 1; i++)
+                       day += day1tab[i];
+       } else {
+               if (day > day2tab[month - 1]) 
+                       return(-1);
+               for (i = 0; i < month - 1; i++)
+                       day += day2tab[i];
+       }
+       pp->day = day;
+       pp->hour = hour;
+       pp->minute = minute;
+       pp-> second = second;
+       pp->msec = 0;
+
+       if ((utcflags&UTCF_LEAP_PNDG) && up->leapdelta != 0) 
+               pp-> leap = (up->leapdelta > 0 ? LEAP_ADDSECOND : LEAP_DELSECOND); 
+       else
+               pp-> leap = LEAP_NOWARNING;  
+
+       return (0);
+}
+
+/*
+ * Parse comprehensive time packet 
+ *
+ * 0 = success
+ * -1 = errors
+ */
+
+int parse0x8F0B(rpt, peer)
+       TSIPPKT *rpt;
+       struct peer *peer;      
+{
+       register struct refclockproc *pp;       
+
+       unsigned day, month, year;      /* data derived from received timecode */
+       unsigned hour, minute, second;
+       unsigned utcoff;
+       unsigned char mode;
+       double  bias, rate;
+       float biasunc, rateunc;
+       double lat, lon, alt;
+       short lat_deg, lon_deg;
+       float lat_min, lon_min;
+       unsigned char north_south, east_west;
+       char sv[9];
+
+       static char logbuf[1024];       /* logging string buffer */
+       unsigned char b;
+       int i;
+       unsigned char *buf;
+       double tow;
+               
+       buf = rpt->buf;
+       pp = peer->procptr;
+
+       if (rpt->len != 74) 
+               return (-1);
+       
+       if (bGetShort(&buf[1]) != 0)
+               return(-1);;
+
+       tow =  bGetDouble(&buf[3]);
+
+       if (tow == -1.0) {
+               return(-1);
+       }
+       else if ((tow >= 604800.0) || (tow < 0.0)) {
+               return(-1);
+       }
+       else
+       {
+               if (tow < 604799.9) tow = tow + .00000001;
+               second = (unsigned int) fmod(tow, 60.);
+               minute =  (unsigned int) fmod(tow/60., 60.);
+               hour = (unsigned int )fmod(tow / 3600., 24.);
+       } 
+
+
+       day =           (unsigned int) buf[11];
+       month =         (unsigned int) buf[12];
+       year =          bGetShort(&buf[13]);
+       mode =          buf[15];
+       utcoff =        bGetShort(&buf[16]);
+       bias =          bGetDouble(&buf[18]) / GPS_C * 1e9;     /* ns */
+       rate =          bGetDouble(&buf[26]) / GPS_C * 1e9;     /* ppb */ 
+       biasunc =       bGetSingle(&buf[34]) / GPS_C * 1e9;     /* ns */
+       rateunc =       bGetSingle(&buf[38]) / GPS_C * 1e9;     /* ppb */
+       lat =           bGetDouble(&buf[42]) * R2D;
+       lon =           bGetDouble(&buf[50]) * R2D;
+       alt =           bGetDouble(&buf[58]);
+
+       if (lat < 0.0) {
+               north_south = 'S';
+               lat = -lat;
+       }
+       else {
+               north_south = 'N';
+       }
+       lat_deg = (short)lat;
+       lat_min = (lat - lat_deg) * 60.0;
+
+       if (lon < 0.0) {
+               east_west = 'W';
+               lon = -lon;
+       }
+       else {
+               east_west = 'E';
+       }
+
+       lon_deg = (short)lon;
+       lon_min = (lon - lon_deg) * 60.0;
+
+       for (i=0; i<8; i++) {
+               sv[i] = buf[i + 66];
+               if (sv[i]) {
+                       TSIPPKT spt; /* local structure for sendpacket */
+                       b = (unsigned char) (sv[i]<0 ? -sv[i] : sv[i]);
+                       /* request tracking status */
+                       cmd_0x3C  (&spt, b);
+                       ripencc_send(peer,spt);
+               }
+       }
+
+
+       sprintf(logbuf, "C1 %02d%02d%04d %02d%02d%02d %d %7.0f %.1f %.0f %.1f %d %02d%09.6f %c %02d%09.6f %c %.0f  %d %d %d %d %d %d %d %d",
+               day, month, year, hour, minute, second, mode, bias, biasunc, rate, rateunc, utcoff,
+               lat_deg, lat_min, north_south, lon_deg, lon_min, east_west, alt,
+               sv[0], sv[1], sv[2], sv[3], sv[4], sv[5], sv[6], sv[7]);
+
+#ifdef DEBUG_NCC
+       if (debug) 
+               puts(logbuf);
+#endif /* DEBUG_NCC */
+
+       record_clock_stats(&peer->srcadr, logbuf);
+
+       return (0);
+}
+
+#ifdef TRIMBLE_OUTPUT_FUNC
+/* 
+ * Parse any packet using Trimble machinery
+ */
+int parseany(rpt, peer)        
+       TSIPPKT *rpt;
+       struct peer *peer;      
+{
+       static char logbuf[1024];       /* logging string buffer */
+
+       TranslateTSIPReportToText (rpt, logbuf);        /* anything else */
+#ifdef DEBUG_NCC
+       if (debug) 
+               puts(&logbuf[1]);
+#endif /* DEBUG_NCC */
+       record_clock_stats(&peer->srcadr, &logbuf[1]);
+       return(0);
+}
+#endif /* TRIMBLE_OUTPUT_FUNC */
+
+
+/*
+ * Parse UTC Parameter Packet
+ * 
+ * See the IDE for documentation!
+ *
+ * 0 = success
+ * -1 = errors
+ */
+
+int parse0x4F(rpt, peer)
+       TSIPPKT *rpt;
+       struct peer *peer;      
+{
+       register struct ripencc_unit *up;
+
+       double a0;
+       float a1, tot;
+       int dt_ls, wn_t, wn_lsf, dn, dt_lsf;
+
+       static char logbuf[1024];       /* logging string buffer */
+       unsigned char *buf;
+               
+       buf = rpt->buf;
+       
+       if (rpt->len != 26) 
+               return (-1);
+       a0 = bGetDouble (buf);
+       a1 = bGetSingle (&buf[8]);
+       dt_ls = bGetShort (&buf[12]);
+       tot = bGetSingle (&buf[14]);
+       wn_t = bGetShort (&buf[18]);
+       wn_lsf = bGetShort (&buf[20]);
+       dn = bGetShort (&buf[22]);
+       dt_lsf = bGetShort (&buf[24]);
+
+       sprintf(logbuf, "L1 %d %d %d %g %g %g %d %d %d",
+               dt_lsf - dt_ls, dt_ls, dt_lsf, a0, a1, tot, wn_t, wn_lsf, dn); 
+
+#ifdef DEBUG_NCC
+       if (debug) 
+               puts(logbuf);
+#endif /* DEBUG_NCC */
+
+       record_clock_stats(&peer->srcadr, logbuf);
+
+       up = (struct ripencc_unit *) peer->procptr->unitptr;
+       up->leapdelta = dt_lsf - dt_ls;
+
+       return (0);
+}
+
+/*
+ * Parse Tracking Status packet
+ *
+ * 0 = success
+ * -1 = errors
+ */
+
+int parse0x5C(rpt, peer)
+       TSIPPKT *rpt;
+       struct peer *peer;      
+{
+       unsigned char prn, channel, aqflag, ephstat;
+       float snr, azinuth, elevation;
+
+       static char logbuf[1024];       /* logging string buffer */
+       unsigned char *buf;
+               
+       buf = rpt->buf;
+       
+       if (rpt->len != 24) 
+               return(-1);
+
+       prn = buf[0];
+       channel = (unsigned char)(buf[1] >> 3);
+       if (channel == 0x10) 
+               channel = 2;
+       else 
+               channel++;
+       aqflag = buf[2];
+       ephstat = buf[3];
+       snr = bGetSingle(&buf[4]);
+       elevation = bGetSingle(&buf[12]) * R2D;
+       azinuth = bGetSingle(&buf[16]) * R2D;
+
+       sprintf(logbuf, "S1 %02d %d %d %02x %4.1f %5.1f %4.1f",
+               prn, channel, aqflag, ephstat, snr, azinuth, elevation);
+
+#ifdef DEBUG_NCC
+       if (debug) 
+               puts(logbuf);
+#endif /* DEBUG_NCC */
+
+       record_clock_stats(&peer->srcadr, logbuf);
+
+       return (0);
+}
+
+/******* Code below is from Trimble Tsipchat *************/
+
+/*
+ * *************************************************************************
+ *
+ * Trimble Navigation, Ltd.
+ * OEM Products Development Group
+ * P.O. Box 3642
+ * 645 North Mary Avenue
+ * Sunnyvale, California 94088-3642
+ *
+ * Corporate Headquarter:
+ *    Telephone:  (408) 481-8000
+ *    Fax:        (408) 481-6005
+ *
+ * Technical Support Center:
+ *    Telephone:  (800) 767-4822       (U.S. and Canada)
+ *                (408) 481-6940    (outside U.S. and Canada)
+ *    Fax:        (408) 481-6020
+ *    BBS:        (408) 481-7800
+ *    e-mail:     trimble_support@trimble.com
+ *             ftp://ftp.trimble.com/pub/sct/embedded/bin
+ *
+ * *************************************************************************
+ *
+ * -------  BYTE-SWAPPING  -------
+ * TSIP is big-endian (Motorola) protocol.  To use on little-endian (Intel)
+ * systems, the bytes of all multi-byte types (shorts, floats, doubles, etc.)
+ * must be reversed.  This is controlled by the MACRO BYTESWAP; if defined, it
+ * assumes little-endian protocol.
+ * --------------------------------
+ *
+ * T_PARSER.C and T_PARSER.H contains primitive functions that interpret
+ * reports received from the receiver.  A second source file pair,
+ * T_FORMAT.C and T_FORMAT.H, contin the matching TSIP command formatters.
+ *
+ * The module is in very portable, basic C language.  It can be used as is, or
+ * with minimal changes if a TSIP communications application is needed separate
+ * from TSIPCHAT. The construction of most argument lists avoid the use of
+ * structures, but the developer is encouraged to reconstruct them using such
+ * definitions to meet project requirements.  Declarations of T_PARSER.C
+ * functions are included in T_PARSER.H to provide prototyping definitions.
+ *
+ * There are two types of functions: a serial input processing routine,
+ *                            tsip_input_proc()
+ * which assembles incoming bytes into a TSIPPKT structure, and the
+ * report parsers, rpt_0x??().
+ *
+ * 1) The function tsip_input_proc() accumulates bytes from the receiver,
+ * strips control bytes (DLE), and checks if the report end sequence (DLE ETX)
+ * has been received.  rpt.status is defined as TSIP_PARSED_FULL (== 1)
+ * if a complete packet is available.
+ *
+ * 2) The functions rpt_0x??() are report string interpreters patterned after
+ * the document called "Trimble Standard Interface Protocol".  It should be
+ * noted that if the report buffer is sent into the receiver with the wrong
+ * length (byte count), the rpt_0x??() returns the Boolean equivalence for
+ * TRUE.
+ *
+ * *************************************************************************
+ *
+ */
+
+
+/**/
+static void tsip_input_proc (
+       TSIPPKT *rpt,
+       int inbyte)
+/* reads bytes until serial buffer is empty or a complete report
+ * has been received; end of report is signified by DLE ETX.
+ */
+{
+       unsigned char newbyte;
+
+       if (inbyte < 0 || inbyte > 0xFF) return;
+
+       newbyte = (unsigned char)(inbyte);
+       switch (rpt->status)
+       {
+       case TSIP_PARSED_DLE_1:
+               switch (newbyte)
+               {
+               case 0:
+               case ETX:
+       /* illegal TSIP IDs */
+         rpt->len = 0;
+                       rpt->status = TSIP_PARSED_EMPTY;
+                       break;
+               case DLE:
+       /* try normal message start again */
+                       rpt->len = 0;
+                       rpt->status = TSIP_PARSED_DLE_1;
+                       break;
+               default:
+       /* legal TSIP ID; start message */
+                       rpt->code = newbyte;
+         rpt->len = 0;
+                       rpt->status = TSIP_PARSED_DATA;
+                       break;
+               }
+               break;
+       case TSIP_PARSED_DATA:
+               switch (newbyte) {
+               case DLE:
+       /* expect DLE or ETX next */
+                       rpt->status = TSIP_PARSED_DLE_2;
+                       break;
+               default:
+       /* normal data byte  */
+                       rpt->buf[rpt->len] = newbyte;
+                       rpt->len++;
+         /* no change in rpt->status */
+                       break;
+               }
+               break;
+       case TSIP_PARSED_DLE_2:
+               switch (newbyte) {
+               case DLE:
+       /* normal data byte */
+                       rpt->buf[rpt->len] = newbyte;
+                       rpt->len++;
+                       rpt->status = TSIP_PARSED_DATA;
+                       break;
+               case ETX:
+                       /* end of message; return TRUE here. */
+                       rpt->status = TSIP_PARSED_FULL;
+                       break;
+               default:
+                       /* error: treat as TSIP_PARSED_DLE_1; start new report packet */
+                       rpt->code = newbyte;
+         rpt->len = 0;
+                       rpt->status = TSIP_PARSED_DATA;
+               }
+               break;
+       case TSIP_PARSED_FULL:
+       case TSIP_PARSED_EMPTY:
+       default:
+               switch (newbyte) {
+               case DLE:
+       /* normal message start */
+                       rpt->len = 0;
+                       rpt->status = TSIP_PARSED_DLE_1;
+                       break;
+               default:
+                       /* error: ignore newbyte */
+                       rpt->len = 0;
+                       rpt->status = TSIP_PARSED_EMPTY;
+               }
+               break;
+       }
+       if (rpt->len > MAX_RPTBUF) {
+               /* error: start new report packet */
+               rpt->status = TSIP_PARSED_EMPTY;
+               rpt->len = 0;
+       }
+}
+
+#ifdef TRIMBLE_OUTPUT_FUNC
+
+/**/
+short rpt_0x3D (TSIPPKT *rpt,
+       unsigned char *tx_baud_index,
+       unsigned char *rx_baud_index,
+       unsigned char *char_format_index,
+       unsigned char *stop_bits,
+       unsigned char *tx_mode_index,
+       unsigned char *rx_mode_index)
+/* Channel A configuration for dual port operation */
+{
+       unsigned char *buf;
+       buf = rpt->buf;
+
+       if (rpt->len != 6) return TRUE;
+       *tx_baud_index = buf[0];
+       *rx_baud_index = buf[1];
+       *char_format_index = buf[2];
+       *stop_bits = (unsigned char)((buf[3] == 0x07) ? 1 : 2);
+       *tx_mode_index = buf[4];
+       *rx_mode_index = buf[5];
+       return FALSE;
+}
+
+/**/
+short rpt_0x40 (TSIPPKT *rpt,
+       unsigned char *sv_prn,
+       short *week_num,
+       float *t_zc,
+       float *eccentricity,
+       float *t_oa,
+       float *i_0,
+       float *OMEGA_dot,
+       float *sqrt_A,
+       float *OMEGA_0,
+       float *omega,
+       float *M_0)
+/* almanac data for specified satellite */
+{
+       unsigned char *buf;
+       buf = rpt->buf;
+
+       if (rpt->len != 39) return TRUE;
+       *sv_prn = buf[0];
+       *t_zc = bGetSingle (&buf[1]);
+       *week_num = bGetShort (&buf[5]);
+       *eccentricity = bGetSingle (&buf[7]);
+       *t_oa = bGetSingle (&buf[11]);
+       *i_0 = bGetSingle (&buf[15]);
+       *OMEGA_dot = bGetSingle (&buf[19]);
+       *sqrt_A = bGetSingle (&buf[23]);
+       *OMEGA_0 = bGetSingle (&buf[27]);
+       *omega = bGetSingle (&buf[31]);
+       *M_0 = bGetSingle (&buf[35]);
+       return FALSE;
+}
+
+short rpt_0x41 (TSIPPKT *rpt,
+       float *time_of_week,
+       float *UTC_offset,
+       short *week_num)
+/* GPS time */
+{
+       unsigned char *buf;
+       buf = rpt->buf;
+       
+       if (rpt->len != 10) return TRUE;
+       *time_of_week = bGetSingle (buf);
+       *week_num = bGetShort (&buf[4]);
+       *UTC_offset = bGetSingle (&buf[6]);
+       return FALSE;
+}
+
+short rpt_0x42 (TSIPPKT *rpt,
+       float pos_ECEF[3],
+       float *time_of_fix)
+/* position in ECEF, single precision */
+{
+       unsigned char *buf;
+       buf = rpt->buf;
+       
+       if (rpt->len != 16) return TRUE;
+       pos_ECEF[0] = bGetSingle (buf);
+       pos_ECEF[1]= bGetSingle (&buf[4]);
+       pos_ECEF[2]= bGetSingle (&buf[8]);
+       *time_of_fix = bGetSingle (&buf[12]);
+       return FALSE;
+}
+
+short rpt_0x43 (TSIPPKT *rpt,
+       float ECEF_vel[3],
+       float *freq_offset,
+       float *time_of_fix)
+/* velocity in ECEF, single precision */
+{
+       unsigned char *buf;
+       buf = rpt->buf;
+
+       if (rpt->len != 20) return TRUE;
+       ECEF_vel[0] = bGetSingle (buf);
+       ECEF_vel[1] = bGetSingle (&buf[4]);
+       ECEF_vel[2] = bGetSingle (&buf[8]);
+       *freq_offset = bGetSingle (&buf[12]);
+       *time_of_fix = bGetSingle (&buf[16]);
+       return FALSE;
+}
+
+short rpt_0x45 (TSIPPKT *rpt,
+       unsigned char *major_nav_version,
+       unsigned char *minor_nav_version,
+       unsigned char *nav_day,
+       unsigned char *nav_month,
+       unsigned char *nav_year,
+       unsigned char *major_dsp_version,
+       unsigned char *minor_dsp_version,
+       unsigned char *dsp_day,
+       unsigned char *dsp_month,
+       unsigned char *dsp_year)
+/* software versions */        
+{
+       unsigned char *buf;
+       buf = rpt->buf;
+
+       if (rpt->len != 10) return TRUE;
+       *major_nav_version = buf[0];
+       *minor_nav_version = buf[1];
+       *nav_day = buf[2];
+       *nav_month = buf[3];
+       *nav_year = buf[4];
+       *major_dsp_version = buf[5];
+       *minor_dsp_version = buf[6];
+       *dsp_day = buf[7];
+       *dsp_month = buf[8];
+       *dsp_year = buf[9];
+       return FALSE;
+}
+
+short rpt_0x46 (TSIPPKT *rpt,
+       unsigned char *status1,
+       unsigned char *status2)
+/* receiver health and status */
+{
+       unsigned char *buf;
+       buf = rpt->buf;
+
+       if (rpt->len != 2) return TRUE;
+       *status1 = buf[0];
+       *status2 = buf[1];
+       return FALSE;
+}
+
+short rpt_0x47 (TSIPPKT *rpt,
+       unsigned char *nsvs, unsigned char *sv_prn,
+       float *snr)
+/* signal levels for all satellites tracked */
+{
+       short isv;
+       unsigned char *buf;
+       buf = rpt->buf;
+
+       if (rpt->len != 1 + 5*buf[0]) return TRUE;
+       *nsvs = buf[0];
+       for (isv = 0; isv < (*nsvs); isv++) {
+               sv_prn[isv] = buf[5*isv + 1];
+               snr[isv] = bGetSingle (&buf[5*isv + 2]);
+       }
+       return FALSE;
+}
+
+short rpt_0x48 (TSIPPKT *rpt,
+       unsigned char *message)
+/* GPS system message */
+{
+       unsigned char *buf;
+       buf = rpt->buf;
+
+       if (rpt->len != 22) return TRUE;
+       memcpy (message, buf, 22);
+       message[22] = 0;
+       return FALSE;
+}
+
+short rpt_0x49 (TSIPPKT *rpt,
+       unsigned char *sv_health)
+/* health for all satellites from almanac health page */
+{
+       short i;
+       unsigned char *buf;
+       buf = rpt->buf;
+
+       if (rpt->len != 32) return TRUE;
+       for (i = 0; i < 32; i++) sv_health [i]= buf[i];
+       return FALSE;
+}
+
+short rpt_0x4A (TSIPPKT *rpt,
+       float *lat,
+       float *lon,
+       float *alt,
+       float *clock_bias,
+       float *time_of_fix)
+/* position in lat-lon-alt, single precision */
+{
+       unsigned char *buf;
+       buf = rpt->buf;
+
+       if (rpt->len != 20) return TRUE;
+       *lat = bGetSingle (buf);
+       *lon = bGetSingle (&buf[4]);
+       *alt = bGetSingle (&buf[8]);
+       *clock_bias = bGetSingle (&buf[12]);
+       *time_of_fix = bGetSingle (&buf[16]);
+       return FALSE;
+}
+
+short rpt_0x4A_2 (TSIPPKT *rpt,
+       float *alt, float *dummy , unsigned char *alt_flag)
+/* reference altitude parameters */
+{
+       unsigned char *buf;
+
+       buf = rpt->buf;
+
+       if (rpt->len != 9) return TRUE;
+       *alt = bGetSingle (buf);
+       *dummy = bGetSingle (&buf[4]);
+       *alt_flag = buf[8];
+       return FALSE;
+}
+
+short rpt_0x4B (TSIPPKT *rpt,
+       unsigned char *machine_id,
+       unsigned char *status3,
+       unsigned char *status4)
+/* machine ID code, status */
+{
+       unsigned char *buf;
+       buf = rpt->buf;
+
+       if (rpt->len != 3) return TRUE;
+       *machine_id = buf[0];
+       *status3 = buf[1];
+       *status4 = buf[2];
+       return FALSE;
+}
+
+short rpt_0x4C (TSIPPKT *rpt,
+       unsigned char *dyn_code,
+       float *el_mask,
+       float *snr_mask,
+       float *dop_mask,
+       float *dop_switch)
+/* operating parameters and masks */
+{
+       unsigned char *buf;
+       buf = rpt->buf;
+
+       if (rpt->len != 17) return TRUE;
+       *dyn_code = buf[0];
+       *el_mask = bGetSingle (&buf[1]);
+       *snr_mask = bGetSingle (&buf[5]);
+       *dop_mask = bGetSingle (&buf[9]);
+       *dop_switch = bGetSingle (&buf[13]);
+       return FALSE;
+}
+
+short rpt_0x4D (TSIPPKT *rpt,
+       float *osc_offset)
+/* oscillator offset */
+{
+       unsigned char *buf;
+       buf = rpt->buf;
+
+       if (rpt->len != 4) return TRUE;
+       *osc_offset = bGetSingle (buf);
+       return FALSE;
+}
+
+short rpt_0x4E (TSIPPKT *rpt,
+       unsigned char *response)
+/* yes/no response to command to set GPS time */
+{
+       unsigned char *buf;
+       buf = rpt->buf;
+
+       if (rpt->len != 1) return TRUE;
+       *response = buf[0];
+       return FALSE;
+}
+
+short rpt_0x4F (TSIPPKT *rpt,
+       double *a0,
+       float *a1,
+       float *time_of_data,
+       short *dt_ls,
+       short *wn_t,
+       short *wn_lsf,
+       short *dn,
+       short *dt_lsf)
+/* UTC data */
+{
+       unsigned char *buf;
+       buf = rpt->buf;
+
+       if (rpt->len != 26) return TRUE;
+       *a0 = bGetDouble (buf);
+       *a1 = bGetSingle (&buf[8]);
+       *dt_ls = bGetShort (&buf[12]);
+       *time_of_data = bGetSingle (&buf[14]);
+       *wn_t = bGetShort (&buf[18]);
+       *wn_lsf = bGetShort (&buf[20]);
+       *dn = bGetShort (&buf[22]);
+       *dt_lsf = bGetShort (&buf[24]);
+       return FALSE;
+}
+
+/**/
+short rpt_0x54 (TSIPPKT *rpt,
+       float *clock_bias,
+   float *freq_offset,
+   float *time_of_fix)
+/* clock offset and frequency offset in 1-SV (0-D) mode */
+{
+       unsigned char *buf;
+       buf = rpt->buf;
+
+       if (rpt->len != 12) return TRUE;
+       *clock_bias = bGetSingle (buf);
+       *freq_offset = bGetSingle (&buf[4]);
+       *time_of_fix = bGetSingle (&buf[8]);
+       return FALSE;
+}
+
+short rpt_0x55 (TSIPPKT *rpt,
+       unsigned char *pos_code,
+       unsigned char *vel_code,
+       unsigned char *time_code,
+       unsigned char *aux_code)
+/* I/O serial options */
+{
+       unsigned char *buf;
+       buf = rpt->buf;
+       
+       if (rpt->len != 4) return TRUE;
+       *pos_code = buf[0];
+       *vel_code = buf[1];
+       *time_code = buf[2];
+       *aux_code = buf[3];
+       return FALSE;
+}
+
+short rpt_0x56 (TSIPPKT *rpt,
+       float vel_ENU[3], float *freq_offset, float *time_of_fix)
+/* velocity in east-north-up coordinates */    
+{
+       unsigned char *buf;
+       buf = rpt->buf;
+       
+       if (rpt->len != 20) return TRUE;
+       /* east */
+       vel_ENU[0] = bGetSingle (buf);
+       /* north */
+       vel_ENU[1] = bGetSingle (&buf[4]);
+       /* up */
+       vel_ENU[2] = bGetSingle (&buf[8]);
+       *freq_offset = bGetSingle (&buf[12]);
+       *time_of_fix = bGetSingle (&buf[16]);
+       return FALSE;
+}
+
+short rpt_0x57 (TSIPPKT *rpt,
+       unsigned char *source_code, unsigned char *diag_code,
+       short *week_num,
+       float *time_of_fix)
+/* info about last computed fix */
+{
+       unsigned char *buf;
+       buf = rpt->buf;
+       
+       if (rpt->len != 8) return TRUE;
+       *source_code = buf[0];
+       *diag_code = buf[1];
+       *time_of_fix = bGetSingle (&buf[2]);
+       *week_num = bGetShort (&buf[6]);
+       return FALSE;
+}
+
+short rpt_0x58 (TSIPPKT *rpt,
+       unsigned char *op_code, unsigned char *data_type, unsigned char *sv_prn,
+       unsigned char *data_length, unsigned char *data_packet)
+/* GPS system data or acknowledgment of GPS system data load */
+{
+       unsigned char *buf, *buf4;
+       short dl;
+       ALM_INFO* alminfo;
+       ION_INFO* ioninfo;
+       UTC_INFO* utcinfo;
+       NAV_INFO* navinfo;
+
+       buf = rpt->buf;
+
+       if (buf[0] == 2) {
+               if (rpt->len < 4) return TRUE;
+               if (rpt->len != 4+buf[3]) return TRUE;
+       }
+       else if (rpt->len != 3) {
+               return TRUE;
+       }
+       *op_code = buf[0];
+       *data_type = buf[1];
+       *sv_prn = buf[2];
+       if (*op_code == 2) {
+               dl = buf[3];
+               *data_length = (unsigned char)dl;
+               buf4 = &buf[4];
+               switch (*data_type) {
+               case 2:
+                       /* Almanac */
+                       if (*data_length != sizeof (ALM_INFO)) return TRUE;
+                       alminfo = (ALM_INFO*)data_packet;
+                       alminfo->t_oa_raw  = buf4[0];
+                       alminfo->SV_health = buf4[1];
+                       alminfo->e         = bGetSingle(&buf4[2]);
+                       alminfo->t_oa      = bGetSingle(&buf4[6]);
+                       alminfo->i_0       = bGetSingle(&buf4[10]);
+                       alminfo->OMEGADOT  = bGetSingle(&buf4[14]);
+                       alminfo->sqrt_A    = bGetSingle(&buf4[18]);
+                       alminfo->OMEGA_0   = bGetSingle(&buf4[22]);
+                       alminfo->omega     = bGetSingle(&buf4[26]);
+                       alminfo->M_0       = bGetSingle(&buf4[30]);
+                       alminfo->a_f0      = bGetSingle(&buf4[34]);
+                       alminfo->a_f1      = bGetSingle(&buf4[38]);
+                       alminfo->Axis      = bGetSingle(&buf4[42]);
+                       alminfo->n         = bGetSingle(&buf4[46]);
+                       alminfo->OMEGA_n   = bGetSingle(&buf4[50]);
+                       alminfo->ODOT_n    = bGetSingle(&buf4[54]);
+                       alminfo->t_zc      = bGetSingle(&buf4[58]);
+                       alminfo->weeknum   = bGetShort(&buf4[62]);
+                       alminfo->wn_oa     = bGetShort(&buf4[64]);
+                       break;
+
+               case 3:
+                       /* Almanac health page */
+                       if (*data_length != sizeof (ALH_PARMS) + 3) return TRUE;
+
+                       /* this record is returned raw */
+                       memcpy (data_packet, buf4, dl);
+                       break;
+
+               case 4:
+                       /* Ionosphere */
+                       if (*data_length != sizeof (ION_INFO) + 8) return TRUE;
+                       ioninfo = (ION_INFO*)data_packet;
+                       ioninfo->alpha_0   = bGetSingle (&buf4[8]);
+                       ioninfo->alpha_1   = bGetSingle (&buf4[12]);
+                       ioninfo->alpha_2   = bGetSingle (&buf4[16]);
+                       ioninfo->alpha_3   = bGetSingle (&buf4[20]);
+                       ioninfo->beta_0    = bGetSingle (&buf4[24]);
+                       ioninfo->beta_1    = bGetSingle (&buf4[28]);
+                       ioninfo->beta_2    = bGetSingle (&buf4[32]);
+                       ioninfo->beta_3    = bGetSingle (&buf4[36]);
+                       break;
+
+               case 5:
+                       /* UTC */
+                       if (*data_length != sizeof (UTC_INFO) + 13) return TRUE;
+                       utcinfo = (UTC_INFO*)data_packet;
+                       utcinfo->A_0       = bGetDouble (&buf4[13]);
+                       utcinfo->A_1       = bGetSingle (&buf4[21]);
+                       utcinfo->delta_t_LS = bGetShort (&buf4[25]);
+                       utcinfo->t_ot      = bGetSingle(&buf4[27]);
+                       utcinfo->WN_t      = bGetShort (&buf4[31]);
+                       utcinfo->WN_LSF    = bGetShort (&buf4[33]);
+                       utcinfo->DN        = bGetShort (&buf4[35]);
+                       utcinfo->delta_t_LSF = bGetShort (&buf4[37]);
+                       break;
+
+               case 6:
+                       /* Ephemeris */
+                       if (*data_length != sizeof (NAV_INFO) - 1) return TRUE;
+
+                       navinfo = (NAV_INFO*)data_packet;
+
+                       navinfo->sv_number = buf4[0];
+                       navinfo->t_ephem = bGetSingle (&buf4[1]);
+                       navinfo->ephclk.weeknum = bGetShort (&buf4[5]);
+
+                       navinfo->ephclk.codeL2 = buf4[7];
+                       navinfo->ephclk.L2Pdata = buf4[8];
+                       navinfo->ephclk.SVacc_raw = buf4[9];
+                       navinfo->ephclk.SV_health = buf4[10];
+                       navinfo->ephclk.IODC = bGetShort (&buf4[11]);
+                       navinfo->ephclk.T_GD = bGetSingle (&buf4[13]);
+                       navinfo->ephclk.t_oc = bGetSingle (&buf4[17]);
+                       navinfo->ephclk.a_f2 = bGetSingle (&buf4[21]);
+                       navinfo->ephclk.a_f1 = bGetSingle (&buf4[25]);
+                       navinfo->ephclk.a_f0 = bGetSingle (&buf4[29]);
+                       navinfo->ephclk.SVacc = bGetSingle (&buf4[33]);
+
+                       navinfo->ephorb.IODE = buf4[37];
+                       navinfo->ephorb.fit_interval = buf4[38];
+                       navinfo->ephorb.C_rs = bGetSingle (&buf4[39]);
+                       navinfo->ephorb.delta_n = bGetSingle (&buf4[43]);
+                       navinfo->ephorb.M_0 = bGetDouble (&buf4[47]);
+                       navinfo->ephorb.C_uc = bGetSingle (&buf4[55]);
+                       navinfo->ephorb.e = bGetDouble (&buf4[59]);
+                       navinfo->ephorb.C_us = bGetSingle (&buf4[67]);
+                       navinfo->ephorb.sqrt_A = bGetDouble (&buf4[71]);
+                       navinfo->ephorb.t_oe = bGetSingle (&buf4[79]);
+                       navinfo->ephorb.C_ic = bGetSingle (&buf4[83]);
+                       navinfo->ephorb.OMEGA_0 = bGetDouble (&buf4[87]);
+                       navinfo->ephorb.C_is = bGetSingle (&buf4[95]);
+                       navinfo->ephorb.i_0 = bGetDouble (&buf4[99]);
+                       navinfo->ephorb.C_rc = bGetSingle (&buf4[107]);
+                       navinfo->ephorb.omega = bGetDouble (&buf4[111]);
+                       navinfo->ephorb.OMEGADOT=bGetSingle (&buf4[119]);
+                       navinfo->ephorb.IDOT = bGetSingle (&buf4[123]);
+                       navinfo->ephorb.Axis = bGetDouble (&buf4[127]);
+                       navinfo->ephorb.n = bGetDouble (&buf4[135]);
+                       navinfo->ephorb.r1me2 = bGetDouble (&buf4[143]);
+                       navinfo->ephorb.OMEGA_n=bGetDouble (&buf4[151]);
+                       navinfo->ephorb.ODOT_n = bGetDouble (&buf4[159]);
+                       break;
+               }
+       }
+       return FALSE;
+}
+
+short rpt_0x59 (TSIPPKT *rpt,
+       unsigned char *code_type,
+       unsigned char status_code[32])
+/* satellite enable/disable or health heed/ignore list */      
+{
+       short iprn;
+       unsigned char *buf;
+       buf = rpt->buf;
+       
+       if (rpt->len != 33) return TRUE;
+       *code_type = buf[0];
+       for (iprn = 0; iprn < 32; iprn++)
+               status_code[iprn] = buf[iprn + 1];
+       return FALSE;
+}
+
+short rpt_0x5A (TSIPPKT *rpt,
+       unsigned char *sv_prn,
+       float *sample_length,
+       float *signal_level,
+       float *code_phase,
+       float *Doppler,
+       double *time_of_fix)
+/* raw measurement data - code phase/Doppler */
+{
+       unsigned char *buf;
+       buf = rpt->buf;
+
+       if (rpt->len != 25) return TRUE;
+       *sv_prn = buf[0];
+       *sample_length = bGetSingle (&buf[1]);
+       *signal_level = bGetSingle (&buf[5]);
+       *code_phase = bGetSingle (&buf[9]);
+       *Doppler = bGetSingle (&buf[13]);
+       *time_of_fix = bGetDouble (&buf[17]);
+       return FALSE;
+}
+
+short rpt_0x5B (TSIPPKT *rpt,
+       unsigned char *sv_prn,
+       unsigned char *sv_health,
+       unsigned char *sv_iode,
+       unsigned char *fit_interval_flag,
+       float *time_of_collection,
+       float *time_of_eph,
+       float *sv_accy)
+/* satellite ephorb status */  
+{
+       unsigned char *buf;
+       buf = rpt->buf;
+       
+       if (rpt->len != 16) return TRUE;
+       *sv_prn = buf[0];
+       *time_of_collection = bGetSingle (&buf[1]);
+       *sv_health = buf[5];
+       *sv_iode = buf[6];
+       *time_of_eph = bGetSingle (&buf[7]);
+       *fit_interval_flag = buf[11];
+       *sv_accy = bGetSingle (&buf[12]);
+       return FALSE;
+}
+
+short rpt_0x5C (TSIPPKT *rpt,
+       unsigned char *sv_prn,
+       unsigned char *slot,
+       unsigned char *chan,
+       unsigned char *acq_flag,
+       unsigned char *eph_flag,
+       float *signal_level,
+       float *time_of_last_msmt,
+       float *elev,
+       float *azim,
+       unsigned char *old_msmt_flag,
+       unsigned char *integer_msec_flag,
+       unsigned char *bad_data_flag,
+       unsigned char *data_collect_flag)
+/* satellite tracking status */
+{
+       unsigned char *buf;
+       buf = rpt->buf;
+       
+       if (rpt->len != 24) return TRUE;
+       *sv_prn = buf[0];
+       *slot = (unsigned char)((buf[1] & 0x07) + 1);
+       *chan = (unsigned char)(buf[1] >> 3);
+       if (*chan == 0x10) *chan = 2;
+       else (*chan)++;
+       *acq_flag = buf[2];
+       *eph_flag = buf[3];
+       *signal_level = bGetSingle (&buf[4]);
+       *time_of_last_msmt = bGetSingle (&buf[8]);
+       *elev = bGetSingle (&buf[12]);
+       *azim = bGetSingle (&buf[16]);
+       *old_msmt_flag = buf[20];
+       *integer_msec_flag = buf[21];
+       *bad_data_flag = buf[22];
+       *data_collect_flag = buf[23];
+       return FALSE;
+}
+
+/**/
+short rpt_0x6D (TSIPPKT *rpt,
+       unsigned char *manual_mode,
+       unsigned char *nsvs,
+       unsigned char *ndim,
+       unsigned char sv_prn[],
+       float *pdop,
+       float *hdop,
+       float *vdop,
+       float *tdop)
+/* over-determined satellite selection for position fixes, PDOP, fix mode */
+{
+       short islot;
+       unsigned char *buf;
+       buf = rpt->buf;
+
+       *nsvs = (unsigned char)((buf[0] & 0xF0) >> 4);
+       if ((*nsvs)>8) return TRUE;
+       if (rpt->len != 17 + (*nsvs) ) return TRUE;
+
+       *manual_mode = (unsigned char)(buf[0] & 0x08);
+       *ndim  = (unsigned char)((buf[0] & 0x07));
+       *pdop = bGetSingle (&buf[1]);
+       *hdop = bGetSingle (&buf[5]);
+       *vdop = bGetSingle (&buf[9]);
+       *tdop = bGetSingle (&buf[13]);
+       for (islot = 0; islot < (*nsvs); islot++)
+               sv_prn[islot] = buf[islot + 17];
+       return FALSE;
+}
+
+/**/
+short rpt_0x82 (TSIPPKT *rpt,
+       unsigned char *diff_mode)
+/* differential fix mode */
+{
+       unsigned char *buf;
+       buf = rpt->buf;
+
+       if (rpt->len != 1) return TRUE;
+       *diff_mode = buf[0];
+       return FALSE;
+}
+
+short rpt_0x83 (TSIPPKT *rpt,
+       double ECEF_pos[3],
+       double *clock_bias,
+       float *time_of_fix)
+/* position, ECEF double precision */
+{
+       unsigned char *buf;
+       buf = rpt->buf;
+
+       if (rpt->len != 36) return TRUE;
+       ECEF_pos[0] = bGetDouble (buf);
+       ECEF_pos[1] = bGetDouble (&buf[8]);
+       ECEF_pos[2] = bGetDouble (&buf[16]);
+       *clock_bias  = bGetDouble (&buf[24]);
+       *time_of_fix = bGetSingle (&buf[32]);
+       return FALSE;
+}
+
+short rpt_0x84 (TSIPPKT *rpt,
+       double *lat,
+       double *lon,
+       double *alt,
+       double *clock_bias,
+       float *time_of_fix)
+/* position, lat-lon-alt double precision */   
+{
+       unsigned char *buf;
+       buf = rpt->buf;
+
+       if (rpt->len != 36) return TRUE;
+       *lat = bGetDouble (buf);
+       *lon = bGetDouble (&buf[8]);
+       *alt = bGetDouble (&buf[16]);
+       *clock_bias = bGetDouble (&buf[24]);
+       *time_of_fix = bGetSingle (&buf[32]);
+       return FALSE;
+}
+
+short rpt_Paly0xBB(TSIPPKT *rpt,
+       TSIP_RCVR_CFG *TsipxBB)
+{
+
+       unsigned char *buf;
+       buf = rpt->buf;
+
+       /* Palisade is inconsistent with other TSIP, which has a kength of 40 */
+       /* if (rpt->len != 40) return TRUE; */
+       if (rpt->len != 43) return TRUE;
+
+       TsipxBB->bSubcode               =       buf[0];
+       TsipxBB->operating_mode =       buf[1]  ;
+       TsipxBB->dyn_code                       =       buf[3]  ;
+       TsipxBB->elev_mask              =  bGetSingle (&buf[5]);
+       TsipxBB->cno_mask                       =       bGetSingle (&buf[9]);
+       TsipxBB->dop_mask               =  bGetSingle (&buf[13]);
+       TsipxBB->dop_switch     =  bGetSingle (&buf[17]);
+       return FALSE;
+}
+
+short rpt_0xBC (TSIPPKT *rpt,
+       unsigned char *port_num,
+   unsigned char *in_baud,
+       unsigned char *out_baud,
+   unsigned char *data_bits,
+       unsigned char *parity,
+   unsigned char *stop_bits,
+   unsigned char *flow_control,
+       unsigned char *protocols_in,
+   unsigned char *protocols_out,
+   unsigned char *reserved)
+/* Receiver serial port configuration */
+{
+       unsigned char *buf;
+       buf = rpt->buf;
+
+       if (rpt->len != 10) return TRUE;
+       *port_num = buf[0];
+       *in_baud = buf[1];
+       *out_baud = buf[2];
+       *data_bits = buf[3];
+       *parity = buf[4];
+       *stop_bits = buf[5];
+       *flow_control = buf[6];
+       *protocols_in = buf[7];
+       *protocols_out = buf[8];
+       *reserved = buf[9];
+
+       return FALSE;
+}
+
+/**** Superpackets ****/
+
+short rpt_0x8F0B(TSIPPKT *rpt,
+                 unsigned short *event,
+                 double *tow,
+                 unsigned char *date,
+                 unsigned char *month,
+                 short *year,
+                 unsigned char *dim_mode,
+                 short *utc_offset,
+                 double *bias,
+                 double *drift,
+                 float *bias_unc,
+                 float *dr_unc,
+                 double *lat,
+                 double *lon,
+                 double *alt,
+                 char sv_id[8])
+{
+       short local_index;
+       unsigned char *buf;
+
+       buf = rpt->buf;
+       if (rpt->len != 74) return TRUE;
+       *event = bGetShort(&buf[1]);
+       *tow = bGetDouble(&buf[3]);
+       *date = buf[11];
+       *month = buf[12];
+       *year = bGetShort(&buf[13]);
+       *dim_mode = buf[15];
+       *utc_offset = bGetShort(&buf[16]);
+       *bias = bGetDouble(&buf[18]);
+       *drift = bGetDouble(&buf[26]);
+       *bias_unc = bGetSingle(&buf[34]);
+       *dr_unc = bGetSingle(&buf[38]);
+       *lat = bGetDouble(&buf[42]);
+       *lon = bGetDouble(&buf[50]);
+       *alt = bGetDouble(&buf[58]);
+
+       for (local_index=0; local_index<8; local_index++) sv_id[local_index] = buf[local_index + 66];
+       return FALSE;
+}
+
+short rpt_0x8F14 (TSIPPKT *rpt,
+       short *datum_idx,
+       double datum_coeffs[5])
+/*  datum index and coefficients  */
+{
+       unsigned char *buf;
+       buf = rpt->buf;
+
+       if (rpt->len != 43) return TRUE;
+       *datum_idx = bGetShort(&buf[1]);
+       datum_coeffs[0] = bGetDouble (&buf[3]);
+       datum_coeffs[1] = bGetDouble (&buf[11]);
+       datum_coeffs[2] = bGetDouble (&buf[19]);
+       datum_coeffs[3] = bGetDouble (&buf[27]);
+       datum_coeffs[4] = bGetDouble (&buf[35]);
+       return FALSE;
+}
+
+
+short rpt_0x8F15 (TSIPPKT *rpt,
+       short *datum_idx,
+       double datum_coeffs[5])
+/*  datum index and coefficients  */
+{
+       unsigned char *buf;
+       buf = rpt->buf;
+
+       if (rpt->len != 43) return TRUE;
+       *datum_idx = bGetShort(&buf[1]);
+       datum_coeffs[0] = bGetDouble (&buf[3]);
+       datum_coeffs[1] = bGetDouble (&buf[11]);
+       datum_coeffs[2] = bGetDouble (&buf[19]);
+       datum_coeffs[3] = bGetDouble (&buf[27]);
+       datum_coeffs[4] = bGetDouble (&buf[35]);
+       return FALSE;
+}
+
+
+#define MAX_LONG  (2147483648.)   /* 2**31 */
+
+short rpt_0x8F20 (TSIPPKT *rpt,
+       unsigned char *info,
+       double *lat,
+       double *lon,
+       double *alt,
+       double vel_enu[],
+       double *time_of_fix,
+       short *week_num,
+       unsigned char *nsvs,
+       unsigned char sv_prn[],
+       short sv_IODC[],
+       short *datum_index)
+{
+       short
+               isv;
+       unsigned char
+               *buf, prnx, iode;
+       unsigned long
+               ulongtemp;
+       long
+               longtemp;
+       double
+               vel_scale;
+
+       buf = rpt->buf;
+
+       if (rpt->len != 56) return TRUE;
+
+       vel_scale = (buf[24]&1)? 0.020 : 0.005;
+       vel_enu[0] = bGetShort (buf+2)*vel_scale;
+       vel_enu[1] = bGetShort (buf+4)*vel_scale;
+       vel_enu[2] = bGetShort (buf+6)*vel_scale;
+
+       *time_of_fix = bGetULong (buf+8)*.001;
+
+       longtemp = bGetLong (buf+12);
+       *lat = longtemp*(GPS_PI/MAX_LONG);
+
+       ulongtemp = bGetULong (buf+16);
+       *lon = ulongtemp*(GPS_PI/MAX_LONG);
+       if (*lon > GPS_PI) *lon -= 2.0*GPS_PI;
+
+       *alt = bGetLong (buf+20)*.001;
+       /* 25 blank; 29 = UTC */
+       (*datum_index) = (short)((short)buf[26]-1);
+       *info = buf[27];
+       *nsvs = buf[28];
+       *week_num = bGetShort (&buf[30]);
+       for (isv = 0; isv < 8; isv++) {
+               prnx = buf[32+2*isv];
+               sv_prn[isv] = (unsigned char)(prnx&0x3F);
+      iode = buf[33+2*isv];
+               sv_IODC[isv] = (short)(iode | ((prnx>>6)<<8));
+       }
+       return FALSE;
+}
+
+short rpt_0x8F41 (TSIPPKT *rpt,
+       unsigned char *bSearchRange,
+       unsigned char *bBoardOptions,
+       unsigned long *iiSerialNumber,
+       unsigned char *bBuildYear,
+       unsigned char *bBuildMonth,
+       unsigned char *bBuildDay,
+       unsigned char *bBuildHour,
+       float *fOscOffset,
+       unsigned short *iTestCodeId)
+{
+       if(rpt->len != 17) return FALSE;
+       *bSearchRange = rpt->buf[1];
+       *bBoardOptions = rpt->buf[2];
+       *iiSerialNumber = bGetLong(&rpt->buf[3]);
+       *bBuildYear = rpt->buf[7];
+       *bBuildMonth = rpt->buf[8];
+       *bBuildDay = rpt->buf[9];
+       *bBuildHour =   rpt->buf[10];
+       *fOscOffset = bGetSingle(&rpt->buf[11]);
+       *iTestCodeId = bGetShort(&rpt->buf[15]);
+/*     Tsipx8E41Data = *Tsipx8E41; */
+       return TRUE;
+}
+
+short rpt_0x8F42 (TSIPPKT *rpt,
+       unsigned char *bProdOptionsPre,
+       unsigned char *bProdNumberExt,
+       unsigned short *iCaseSerialNumberPre,
+       unsigned long *iiCaseSerialNumber,
+       unsigned long *iiProdNumber,
+       unsigned short *iPremiumOptions,
+       unsigned short *iMachineID,
+       unsigned short *iKey)
+{
+       if(rpt->len != 19) return FALSE;
+       *bProdOptionsPre = rpt->buf[1];
+       *bProdNumberExt = rpt->buf[2];
+       *iCaseSerialNumberPre = bGetShort(&rpt->buf[3]);
+       *iiCaseSerialNumber = bGetLong(&rpt->buf[5]);
+       *iiProdNumber = bGetLong(&rpt->buf[9]);
+       *iPremiumOptions = bGetShort(&rpt->buf[13]);
+       *iMachineID = bGetShort(&rpt->buf[15]);
+       *iKey = bGetShort(&rpt->buf[17]);
+       return TRUE;
+}
+
+short rpt_0x8F45(TSIPPKT *rpt,
+   unsigned char *bSegMask)
+{
+       if(rpt->len != 2) return FALSE;
+       *bSegMask = rpt->buf[1];
+       return TRUE;
+}
+
+short rpt_0x8F4A_16(TSIPPKT *rpt,
+       unsigned char *pps_enabled,
+   unsigned char *pps_timebase,
+   unsigned char *pos_polarity,
+   double *pps_offset,
+   float *bias_unc_threshold)
+/* Stinger PPS definition */
+{
+       unsigned char
+       *buf;
+
+   buf = rpt->buf;
+   if (rpt->len != 16) return TRUE;
+   *pps_enabled = buf[1];
+   *pps_timebase = buf[2];
+   *pos_polarity = buf[3];
+   *pps_offset = bGetDouble(&buf[4]);
+   *bias_unc_threshold = bGetSingle(&buf[12]);
+       return FALSE;
+}
+
+short rpt_0x8F4B(TSIPPKT *rpt,
+                 unsigned long *decorr_max)
+{
+       unsigned char
+       *buf;
+
+   buf = rpt->buf;
+   if (rpt->len != 5) return TRUE;
+   *decorr_max = bGetLong(&buf[1]);
+   return FALSE;
+}
+
+short rpt_0x8F4D(TSIPPKT *rpt,
+       unsigned long *event_mask)
+{
+       unsigned char
+       *buf;
+
+   buf = rpt->buf;
+   if (rpt->len != 5) return TRUE;
+   *event_mask = bGetULong (&buf[1]);
+   return FALSE;
+}
+
+short rpt_0x8FA5(TSIPPKT *rpt,
+       unsigned char *spktmask)
+{
+       unsigned char
+       *buf;
+
+   buf = rpt->buf;
+   if (rpt->len != 5) return TRUE;
+   spktmask[0] = buf[1];
+   spktmask[1] = buf[2];
+   spktmask[2] = buf[3];
+   spktmask[3] = buf[4];
+   return FALSE;
+}
+
+short rpt_0x8FAD (TSIPPKT *rpt,
+    unsigned short *COUNT,
+    double *FracSec,
+    unsigned char *Hour,
+    unsigned char *Minute,
+    unsigned char *Second,
+    unsigned char *Day,
+    unsigned char *Month,
+    unsigned short *Year,
+    unsigned char *Status,
+    unsigned char *Flags)
+{
+
+       if (rpt->len != 22) return TRUE;
+
+    *COUNT = bGetUShort(&rpt->buf[1]);
+    *FracSec = bGetDouble(&rpt->buf[3]);
+    *Hour = rpt->buf[11];
+    *Minute = rpt->buf[12];
+    *Second = rpt->buf[13];
+    *Day = rpt->buf[14];
+    *Month = rpt->buf[15];
+    *Year = bGetUShort(&rpt->buf[16]);
+    *Status = rpt->buf[18];
+    *Flags = rpt->buf[19];
+    return FALSE;
+}
+
+
+/*
+ * *************************************************************************
+ *
+ * Trimble Navigation, Ltd.
+ * OEM Products Development Group
+ * P.O. Box 3642
+ * 645 North Mary Avenue
+ * Sunnyvale, California 94088-3642
+ *
+ * Corporate Headquarter:
+ *    Telephone:  (408) 481-8000
+ *    Fax:        (408) 481-6005
+ *
+ * Technical Support Center:
+ *    Telephone:  (800) 767-4822       (U.S. and Canada)
+ *                (408) 481-6940    (outside U.S. and Canada)
+ *    Fax:        (408) 481-6020
+ *    BBS:        (408) 481-7800
+ *    e-mail:     trimble_support@trimble.com
+ *             ftp://ftp.trimble.com/pub/sct/embedded/bin
+ *
+ * *************************************************************************
+ *
+ * T_REPORT.C consists of a primary function TranslateTSIPReportToText()
+ * called by main().
+ *
+ * This function takes a character buffer that has been received as a report
+ * from a TSIP device and interprets it.  The character buffer has been
+ * assembled using tsip_input_proc() in T_PARSER.C.
+ *
+ * A large case statement directs processing to one of many mid-level
+ * functions.  The mid-level functions specific to the current report
+ * code passes the report buffer to the appropriate report decoder
+ * rpt_0x?? () in T_PARSER.C, which converts the byte stream in rpt.buf
+ * to data values approporaite for use.
+ *
+ * *************************************************************************
+ *
+ */
+
+
+#define GOOD_PARSE 0
+#define BADID_PARSE 1
+#define BADLEN_PARSE 2
+#define BADDATA_PARSE 3
+
+#define B_TSIP 0x02
+#define B_NMEA 0x04
+
+
+/* pbuf is the pointer to the current location of the text output */
+static char
+       *pbuf;
+
+/* keep track of whether the message has been successfully parsed */
+static short
+       parsed;
+
+
+/* convert time of week into day-hour-minute-second and print */
+char* show_time (float time_of_week)
+{
+       short   days, hours, minutes;
+       float seconds;
+       double tow = 0;
+   static char timestring [80];
+
+       if (time_of_week == -1.0)
+   {
+               sprintf(timestring, "   <No time yet>   ");
+       }
+       else if ((time_of_week >= 604800.0) || (time_of_week < 0.0))
+   {
+               sprintf(timestring, "     <Bad time>     ");
+       }
+   else
+   {
+               if (time_of_week < 604799.9) 
+                       tow = time_of_week + .00000001;
+               seconds = (float)fmod(tow, 60.);
+               minutes =  (short) fmod(tow/60., 60.);
+               hours = (short)fmod(tow / 3600., 24.);
+               days = (short)(tow / 86400.0);
+               sprintf(timestring, " %s %02d:%02d:%05.2f   ",
+               dayname[days], hours, minutes, seconds);
+   }
+   return timestring;
+}
+
+/**/
+/* 0x3D */
+static void rpt_chan_A_config (TSIPPKT *rpt)
+{
+       unsigned char
+               tx_baud_index, rx_baud_index,
+               char_format_index, stop_bits,
+      tx_mode_index, rx_mode_index,
+      databits, parity;
+       int
+               i, nbaud;
+
+       /* unload rptbuf */
+       if (rpt_0x3D (rpt,
+               &tx_baud_index, &rx_baud_index, &char_format_index,
+               &stop_bits, &tx_mode_index, &rx_mode_index)) {
+               parsed = BADLEN_PARSE;
+               return;
+       }
+
+       pbuf += sprintf(pbuf, "\nChannel A Configuration");
+
+   nbaud = sizeof(old_baudnum);
+
+       for (i = 0; i < nbaud; ++i) if (tx_baud_index == old_baudnum[i]) break;
+       pbuf += sprintf(pbuf, "\n   Transmit speed: %s at %s",
+               old_output_ch[tx_mode_index], st_baud_text_app[i]);
+
+       for (i = 0; i < nbaud; ++i) if (rx_baud_index == old_baudnum[i]) break;
+       pbuf += sprintf(pbuf, "\n   Receive speed: %s at %s",
+               old_input_ch[rx_mode_index], st_baud_text_app[i]);
+
+       databits = (unsigned char)((char_format_index & 0x03) + 5);
+
+       parity = (unsigned char)(char_format_index >> 2);
+       if (parity > 4) parity = 2;
+
+       pbuf += sprintf(pbuf, "\n   Character format (bits/char, parity, stop bits): %d-%s-%d",
+               databits, old_parity_text[parity], stop_bits);
+}
+
+/**/
+/* 0x40 */
+static void rpt_almanac_data_page (TSIPPKT *rpt)
+{
+       unsigned char
+               sv_prn;
+       short
+               week_num;
+       float
+               t_zc,
+               eccentricity,
+               t_oa,
+               i_0,
+               OMEGA_dot,
+               sqrt_A,
+               OMEGA_0,
+               omega,
+               M_0;
+
+       /* unload rptbuf */
+       if (rpt_0x40 (rpt,
+               &sv_prn, &week_num, &t_zc, &eccentricity, &t_oa,
+               &i_0, &OMEGA_dot, &sqrt_A, &OMEGA_0, &omega, &M_0)) {
+               parsed = BADLEN_PARSE;
+               return;
+       }
+
+       pbuf += sprintf(pbuf, "\nAlmanac for SV %02d", sv_prn);
+       pbuf += sprintf(pbuf, "\n       Captured:%15.0f %s",
+       t_zc, show_time (t_zc));
+       pbuf += sprintf(pbuf, "\n           week:%15d", week_num);
+       pbuf += sprintf(pbuf, "\n   Eccentricity:%15g", eccentricity);
+       pbuf += sprintf(pbuf, "\n           T_oa:%15.0f %s",
+       t_oa, show_time (t_oa));
+       pbuf += sprintf(pbuf, "\n            i 0:%15g", i_0);
+       pbuf += sprintf(pbuf, "\n      OMEGA dot:%15g", OMEGA_dot);
+       pbuf += sprintf(pbuf, "\n         sqrt A:%15g", sqrt_A);
+       pbuf += sprintf(pbuf, "\n        OMEGA 0:%15g", OMEGA_0);
+       pbuf += sprintf(pbuf, "\n          omega:%15g", omega);
+       pbuf += sprintf(pbuf, "\n            M 0:%15g", M_0);
+}
+
+/* 0x41 */
+static void rpt_GPS_time (TSIPPKT *rpt)
+{
+       float
+               time_of_week, UTC_offset;
+       short
+               week_num;
+
+       /* unload rptbuf */
+       if (rpt_0x41 (rpt, &time_of_week, &UTC_offset, &week_num)) {
+               parsed = BADLEN_PARSE;
+               return;
+       }
+
+       pbuf += sprintf(pbuf, "\nGPS time:%s GPS week: %d   UTC offset %.1f",
+       show_time(time_of_week), week_num, UTC_offset);
+
+}
+
+/* 0x42 */
+static void rpt_single_ECEF_position (TSIPPKT *rpt)
+{
+       float
+               ECEF_pos[3], time_of_fix;
+
+       /* unload rptbuf */
+       if (rpt_0x42 (rpt, ECEF_pos, &time_of_fix)) {
+               parsed = BADLEN_PARSE;
+               return;
+       }
+
+       pbuf += sprintf(pbuf, "\nSXYZ:  %15.0f  %15.0f  %15.0f    %s",
+               ECEF_pos[0], ECEF_pos[1], ECEF_pos[2],
+      show_time(time_of_fix));
+}
+
+/* 0x43 */
+static void rpt_single_ECEF_velocity (TSIPPKT *rpt)
+{
+
+       float
+               ECEF_vel[3], freq_offset, time_of_fix;
+
+       /* unload rptbuf */
+       if (rpt_0x43 (rpt, ECEF_vel, &freq_offset, &time_of_fix)) {
+               parsed = BADLEN_PARSE;
+               return;
+       }
+
+       pbuf += sprintf(pbuf, "\nVelECEF: %11.3f  %11.3f  %11.3f  %12.3f%s",
+               ECEF_vel[0], ECEF_vel[1], ECEF_vel[2], freq_offset,
+      show_time(time_of_fix));
+}
+
+/*  0x45  */
+static void rpt_SW_version (TSIPPKT *rpt) {
+       unsigned char
+               major_nav_version, minor_nav_version,
+               nav_day, nav_month, nav_year,
+               major_dsp_version, minor_dsp_version,
+               dsp_day, dsp_month, dsp_year;
+
+       /* unload rptbuf */
+       if (rpt_0x45 (rpt,
+               &major_nav_version, &minor_nav_version,
+               &nav_day, &nav_month, &nav_year,
+               &major_dsp_version, &minor_dsp_version,
+               &dsp_day, &dsp_month, &dsp_year)) {
+               parsed = BADLEN_PARSE;
+               return;
+       }
+
+       pbuf += sprintf(pbuf,
+"\nFW Versions:  Nav Proc %2d.%02d  %2d/%2d/%2d  Sig Proc %2d.%02d  %2d/%2d/%2d",
+               major_nav_version, minor_nav_version, nav_day, nav_month, nav_year,
+               major_dsp_version, minor_dsp_version, dsp_day, dsp_month, dsp_year);
+}
+
+/* 0x46 */
+static void rpt_rcvr_health (TSIPPKT *rpt)
+{
+       unsigned char
+               status1, status2;
+       static char
+               *sc_text[] = {
+                       "Doing position fixes",
+                       "Don't have GPS time yet",
+                       "Waiting for almanac collection",
+                       "DOP too high          ",
+                       "No satellites available",
+                       "Only 1 satellite available",
+                       "Only 2 satellites available",
+                       "Only 3 satellites available",
+                       "No satellites usable   ",
+                       "Only 1 satellite usable",
+                       "Only 2 satellites usable",
+                       "Only 3 satellites usable",
+                       "Chosen satellite unusable"};
+
+
+       /* unload rptbuf */
+       if (rpt_0x46 (rpt, &status1, &status2))
+       {
+               parsed = BADLEN_PARSE;
+               return;
+       }
+
+       pbuf += sprintf(pbuf, "\nRcvr status1: %s (%02Xh); ",
+       sc_text[rpt->buf[0]], status1);
+
+       pbuf += sprintf(pbuf, "status2: %s, %s (%02Xh)",
+               (status2 & 0x01)?"No BBRAM":"BBRAM OK",
+               (status2 & 0x10)?"No Ant":"Ant OK",
+      status2);
+}
+
+/* 0x47 */
+static void rpt_SNR_all_SVs (TSIPPKT *rpt)
+{
+       unsigned char
+               nsvs, sv_prn[12];
+       short
+               isv;
+       float
+               snr[12];
+
+       /* unload rptbuf */
+       if (rpt_0x47 (rpt, &nsvs, sv_prn, snr))
+   {
+               parsed = BADLEN_PARSE;
+               return;
+       }
+
+       pbuf += sprintf(pbuf, "\nSNR for satellites: %d", nsvs);
+       for (isv = 0; isv < nsvs; isv++)
+   {
+               pbuf += sprintf(pbuf, "\n    SV %02d   %6.2f",
+       sv_prn[isv], snr[isv]);
+       }
+}
+
+/* 0x48 */
+static void rpt_GPS_system_message (TSIPPKT *rpt)
+{
+       unsigned char
+               message[23];
+
+       /* unload rptbuf */
+       if (rpt_0x48 (rpt, message))
+   {
+               parsed = BADLEN_PARSE;
+               return;
+       }
+
+       pbuf += sprintf(pbuf, "\nGPS message: %s", message);
+}
+
+/* 0x49 */
+static void rpt_almanac_health_page (TSIPPKT *rpt)
+{
+       short
+               iprn;
+       unsigned char
+               sv_health [32];
+
+       /* unload rptbuf */
+       if (rpt_0x49 (rpt, sv_health))
+   {
+               parsed = BADLEN_PARSE;
+               return;
+       }
+
+       pbuf += sprintf(pbuf, "\nAlmanac health page:");
+       for (iprn = 0; iprn < 32; iprn++)
+   {
+               if (!(iprn%5)) *pbuf++ = '\n';
+               pbuf += sprintf(pbuf, "    SV%02d  %2X",
+       (iprn+1) , sv_health[iprn]);
+       }
+}
+
+/* 0x4A */
+static void rpt_single_lla_position (TSIPPKT *rpt) {
+       short
+               lat_deg, lon_deg;
+       float
+               lat, lon,
+               alt, clock_bias, time_of_fix;
+       double lat_min, lon_min;
+       unsigned char
+               north_south, east_west;
+
+       if (rpt_0x4A (rpt,
+               &lat, &lon, &alt, &clock_bias, &time_of_fix))
+   {
+               parsed = BADLEN_PARSE;
+               return;
+       }
+
+       /* convert from radians to degrees */
+       lat *= (float)R2D;
+       north_south = 'N';
+       if (lat < 0.0)
+   {
+               north_south = 'S';
+               lat = -lat;
+       }
+       lat_deg = (short)lat;
+       lat_min = (lat - lat_deg) * 60.0;
+
+       lon *= (float)R2D;
+       east_west = 'E';
+       if (lon < 0.0)
+   {
+               east_west = 'W';
+               lon = -lon;
+       }
+       lon_deg = (short)lon;
+       lon_min = (lon - lon_deg) * 60.0;
+
+       pbuf += sprintf(pbuf, "\nSLLA: %4d: %06.3f  %c%5d:%06.3f  %c%10.2f  %12.2f%s",
+               lat_deg, lat_min, north_south,
+               lon_deg, lon_min, east_west,
+               alt, clock_bias,
+               show_time(time_of_fix));
+}
+
+/* 0x4A */
+static void rpt_ref_alt (TSIPPKT *rpt) {
+
+       float
+               alt, dummy;
+       unsigned char
+               alt_flag;
+
+       if (rpt_0x4A_2 (rpt,
+               &alt, &dummy, &alt_flag))
+   {
+               parsed = BADLEN_PARSE;
+               return;
+       }
+
+       pbuf += sprintf(pbuf, "\nReference Alt:   %.1f m;    %s",
+       alt, alt_flag?"ON":"OFF");
+}
+
+/* 0x4B */
+static void rpt_rcvr_id_and_status (TSIPPKT *rpt)
+{
+
+       unsigned char
+               machine_id, status3, status4;
+
+       /* unload rptbuf */
+       if (rpt_0x4B (rpt, &machine_id, &status3, &status4))
+   {
+               parsed = BADLEN_PARSE;
+               return;
+       }
+
+       pbuf += sprintf(pbuf, "\nRcvr Machine ID: %d; Status3 = %s, %s (%02Xh)",
+       machine_id,
+               (status3 & 0x02)?"No RTC":"RTC OK",
+               (status3 & 0x08)?"No Alm":"Alm OK",
+               status3);
+}
+
+/* 0x4C */
+static void rpt_operating_parameters (TSIPPKT *rpt)
+{
+       unsigned char
+               dyn_code;
+       float
+               el_mask, snr_mask, dop_mask, dop_switch;
+
+       /* unload rptbuf */
+       if (rpt_0x4C (rpt, &dyn_code, &el_mask,
+               &snr_mask, &dop_mask, &dop_switch))
+   {
+               parsed = BADLEN_PARSE;
+               return;
+       }
+
+       pbuf += sprintf(pbuf, "\nOperating Parameters:");
+       pbuf += sprintf(pbuf, "\n     Dynamics code = %d %s",
+       dyn_code, dyn_text[dyn_code]);
+       pbuf += sprintf(pbuf, "\n     Elevation mask = %.2fø", el_mask * R2D);
+       pbuf += sprintf(pbuf, "\n     SNR mask = %.2f", snr_mask);
+       pbuf += sprintf(pbuf, "\n     DOP mask = %.2f", dop_mask);
+       pbuf += sprintf(pbuf, "\n     DOP switch = %.2f", dop_switch);
+}
+
+/* 0x4D */
+static void rpt_oscillator_offset (TSIPPKT *rpt)
+{
+       float
+               osc_offset;
+
+       /* unload rptbuf */
+       if (rpt_0x4D (rpt, &osc_offset))
+   {
+               parsed = BADLEN_PARSE;
+               return;
+       }
+
+       pbuf += sprintf(pbuf, "\nOscillator offset: %.2f Hz = %.3f PPM",
+       osc_offset, osc_offset/1575.42);
+}
+
+/* 0x4E */
+static void rpt_GPS_time_set_response (TSIPPKT *rpt)
+{
+
+       unsigned char
+               response;
+
+       /* unload rptbuf */
+       if (rpt_0x4E (rpt, &response))
+   {
+               parsed = BADLEN_PARSE;
+               return;
+       }
+
+       switch (response)
+   {
+       case 'Y':
+               pbuf += sprintf(pbuf, "\nTime set accepted");
+               break;
+
+       case 'N':
+               pbuf += sprintf(pbuf, "\nTime set rejected or not required");
+               break;
+
+       default:
+               parsed = BADDATA_PARSE;
+       }
+}
+
+/* 0x4F */
+static void rpt_UTC_offset (TSIPPKT *rpt)
+{
+       double
+               a0;
+       float
+               a1, time_of_data;
+       short
+               dt_ls, wn_t, wn_lsf, dn, dt_lsf;
+
+       /* unload rptbuf */
+       if (rpt_0x4F (rpt, &a0, &a1, &time_of_data,
+               &dt_ls, &wn_t, &wn_lsf, &dn, &dt_lsf)) {
+               parsed = BADLEN_PARSE;
+               return;
+       }
+
+       pbuf += sprintf(pbuf, "\nUTC Correction Data");
+       pbuf += sprintf(pbuf, "\n   A_0         = %g  ", a0);
+       pbuf += sprintf(pbuf, "\n   A_1         = %g  ", a1);
+       pbuf += sprintf(pbuf, "\n   delta_t_LS  = %d  ", dt_ls);
+       pbuf += sprintf(pbuf, "\n   t_ot        = %.0f  ", time_of_data);
+       pbuf += sprintf(pbuf, "\n   WN_t        = %d  ", wn_t );
+       pbuf += sprintf(pbuf, "\n   WN_LSF      = %d  ", wn_lsf );
+       pbuf += sprintf(pbuf, "\n   DN          = %d  ", dn );
+       pbuf += sprintf(pbuf, "\n   delta_t_LSF = %d  ", dt_lsf );
+}
+
+/**/
+/* 0x54 */
+static void rpt_1SV_bias (TSIPPKT *rpt)
+{
+       float
+               clock_bias, freq_offset, time_of_fix;
+
+       /* unload rptbuf */
+       if (rpt_0x54 (rpt, &clock_bias, &freq_offset, &time_of_fix)) {
+               parsed = BADLEN_PARSE;
+               return;
+       }
+
+       pbuf += sprintf (pbuf, "\nTime Fix   Clock Bias: %6.2f m  Freq Bias: %6.2f m/s%s",
+               clock_bias, freq_offset, show_time (time_of_fix));
+}
+
+/* 0x55 */
+static void rpt_io_opt (TSIPPKT *rpt)
+{
+       unsigned char
+               pos_code, vel_code, time_code, aux_code;
+
+       /* unload rptbuf */
+       if (rpt_0x55 (rpt,
+               &pos_code, &vel_code, &time_code, &aux_code)) {
+               parsed = BADLEN_PARSE;
+               return;
+       }
+       /* rptbuf unloaded */
+
+       pbuf += sprintf(pbuf, "\nI/O Options: %2X %2X %2X %2X",
+               pos_code, vel_code, time_code, aux_code);
+
+       if (pos_code & 0x01) {
+               pbuf += sprintf(pbuf, "\n    ECEF XYZ position output");
+       }
+
+       if (pos_code & 0x02) {
+               pbuf += sprintf(pbuf, "\n    LLA position output");
+       }
+
+       pbuf += sprintf(pbuf, (pos_code & 0x04)?
+               "\n    MSL altitude output (Geoid height) ":
+               "\n    WGS-84 altitude output");
+
+       pbuf += sprintf(pbuf, (pos_code & 0x08)?
+               "\n    MSL altitude input":
+      "\n    WGS-84 altitude input");
+
+       pbuf += sprintf(pbuf, (pos_code & 0x10)?
+               "\n    Double precision":
+      "\n    Single precision");
+
+       if (pos_code & 0x20) {
+               pbuf += sprintf(pbuf, "\n    All Enabled Superpackets");
+       }
+
+       if (vel_code & 0x01) {
+               pbuf += sprintf(pbuf, "\n    ECEF XYZ velocity output");
+       }
+
+       if (vel_code & 0x02) {
+               pbuf += sprintf(pbuf, "\n    ENU velocity output");
+       }
+
+       pbuf += sprintf(pbuf, (time_code & 0x01)?
+                 "\n    Time tags in UTC":
+        "\n    Time tags in GPS time");
+
+       if (time_code & 0x02) {
+               pbuf += sprintf(pbuf, "\n    Fixes delayed to integer seconds");
+       }
+
+       if (time_code & 0x04) {
+               pbuf += sprintf(pbuf, "\n    Fixes sent only on request");
+       }
+
+       if (time_code & 0x08) {
+               pbuf += sprintf(pbuf, "\n    Synchronized measurements");
+       }
+
+       if (time_code & 0x10) {
+               pbuf += sprintf(pbuf, "\n    Minimize measurement propagation");
+       }
+
+   pbuf += sprintf(pbuf, (time_code & 0x20) ?
+               "\n    PPS output at all times" :
+       "\n    PPS output during fixes");
+
+       if (aux_code & 0x01) {
+               pbuf += sprintf(pbuf, "\n    Raw measurement output");
+       }
+
+       if (aux_code & 0x02) {
+               pbuf += sprintf(pbuf, "\n    Code-phase smoothed before output");
+       }
+
+       if (aux_code & 0x04) {
+               pbuf += sprintf(pbuf, "\n    Additional fix status");
+       }
+
+       pbuf += sprintf(pbuf, (aux_code & 0x08)?
+       "\n    Signal Strength Output as dBHz" :
+       "\n    Signal Strength Output as AMU");
+}
+
+/* 0x56 */
+static void rpt_ENU_velocity (TSIPPKT *rpt)
+{
+       float
+               vel_ENU[3], freq_offset, time_of_fix;
+
+       /* unload rptbuf */
+       if (rpt_0x56 (rpt, vel_ENU, &freq_offset, &time_of_fix)) {
+               parsed = BADLEN_PARSE;
+               return;
+       }
+
+       pbuf += sprintf(pbuf, "\nVel ENU: %11.3f  %11.3f  %11.3f  %12.3f%s",
+               vel_ENU[0], vel_ENU[1], vel_ENU[2], freq_offset,
+      show_time (time_of_fix));
+}
+
+/* 0x57 */
+static void rpt_last_fix_info (TSIPPKT *rpt)
+{
+       unsigned char
+               source_code, diag_code;
+       short
+               week_num;
+       float
+               time_of_fix;
+
+       /* unload rptbuf */
+       if (rpt_0x57 (rpt, &source_code, &diag_code, &week_num, &time_of_fix)) {
+               parsed = BADLEN_PARSE;
+               return;
+       }
+
+       pbuf += sprintf(pbuf, "\n source code %d;   diag code: %2Xh",
+       source_code, diag_code);
+       pbuf += sprintf(pbuf, "\n    Time of last fix:%s", show_time(time_of_fix));
+       pbuf += sprintf(pbuf, "\n    Week of last fix: %d", week_num);
+}
+
+/* 0x58 */
+static void rpt_GPS_system_data (TSIPPKT *rpt)
+{
+       unsigned char
+       iprn,
+               op_code, data_type, sv_prn,
+               data_length, data_packet[250];
+       ALM_INFO
+               *almanac;
+       ALH_PARMS
+               *almh;
+       UTC_INFO
+               *utc;
+       ION_INFO
+               *ionosphere;
+       EPHEM_CLOCK
+               *cdata;
+       EPHEM_ORBIT
+               *edata;
+       NAV_INFO
+               *nav_data;
+       unsigned char
+               curr_t_oa;
+       unsigned short
+               curr_wn_oa;
+       static char
+               *datname[] =
+               {"", "", "Almanac Orbit",
+               "Health Page & Ref Time", "Ionosphere", "UTC ",
+               "Ephemeris"};
+
+       /* unload rptbuf */
+       if (rpt_0x58 (rpt, &op_code, &data_type, &sv_prn,
+               &data_length, data_packet))
+   {
+               parsed = BADLEN_PARSE;
+               return;
+       }
+
+       pbuf += sprintf(pbuf, "\nSystem data [%d]:  %s  SV%02d",
+               data_type, datname[data_type], sv_prn);
+       switch (op_code)
+       {
+       case 1:
+               pbuf += sprintf(pbuf, "  Acknowledgment");
+               break;
+       case 2:
+               pbuf += sprintf(pbuf, "  length = %d bytes", data_length);
+               switch (data_type) {
+               case 2:
+                       /* Almanac */
+                       if (sv_prn == 0 || sv_prn > 32) {
+                               pbuf += sprintf(pbuf, "  Binary PRN invalid");
+                               return;
+                       }
+                       almanac = (ALM_INFO*)data_packet;
+                       pbuf += sprintf(pbuf, "\n   t_oa_raw = % -12d    SV_hlth  = % -12d  ",
+               almanac->t_oa_raw , almanac->SV_health );
+                       pbuf += sprintf(pbuf, "\n   e        = % -12g    t_oa     = % -12g  ",
+               almanac->e        , almanac->t_oa     );
+                       pbuf += sprintf(pbuf, "\n   i_0      = % -12g    OMEGADOT = % -12g  ",
+               almanac->i_0      , almanac->OMEGADOT );
+                       pbuf += sprintf(pbuf, "\n   sqrt_A   = % -12g    OMEGA_0  = % -12g  ",
+               almanac->sqrt_A   , almanac->OMEGA_0  );
+                       pbuf += sprintf(pbuf, "\n   omega    = % -12g    M_0      = % -12g  ",
+               almanac->omega    , almanac->M_0      );
+                       pbuf += sprintf(pbuf, "\n   a_f0     = % -12g    a_f1     = % -12g  ",
+               almanac->a_f0     , almanac->a_f1     );
+                       pbuf += sprintf(pbuf, "\n   Axis     = % -12g    n        = % -12g  ",
+               almanac->Axis     , almanac->n        );
+                       pbuf += sprintf(pbuf, "\n   OMEGA_n  = % -12g    ODOT_n   = % -12g  ",
+               almanac->OMEGA_n  , almanac->ODOT_n   );
+                       pbuf += sprintf(pbuf, "\n   t_zc     = % -12g    weeknum  = % -12d  ",
+               almanac->t_zc     , almanac->weeknum  );
+                       pbuf += sprintf(pbuf, "\n   wn_oa    = % -12d", almanac->wn_oa    );
+                       break;
+
+               case 3:
+                       /* Almanac health page */
+                       almh = (ALH_PARMS*)data_packet;
+                       pbuf += sprintf(pbuf, "\n   t_oa = %d, wn_oa&0xFF = %d  ",
+               almh->t_oa, almh->WN_a);
+                       pbuf += sprintf(pbuf, "\nAlmanac health page:");
+                       for (iprn = 0; iprn < 32; iprn++) {
+                               if (!(iprn%5)) *pbuf++ = '\n';
+                               pbuf += sprintf(pbuf, "    SV%02d  %2X",
+               (iprn+1) , almh->SV_health[iprn]);
+                       }
+                       curr_t_oa = data_packet[34];
+                       curr_wn_oa = (unsigned short)((data_packet[35]<<8) + data_packet[36]);
+                       pbuf += sprintf(pbuf, "\n   current t_oa = %d, wn_oa = %d  ",
+               curr_t_oa, curr_wn_oa);
+                       break;
+
+               case 4:
+                       /* Ionosphere */
+                       ionosphere = (ION_INFO*)data_packet;
+                       pbuf += sprintf(pbuf, "\n   alpha_0 = % -12g  alpha_1 = % -12g ",
+                ionosphere->alpha_0, ionosphere->alpha_1);
+                       pbuf += sprintf(pbuf, "\n   alpha_2 = % -12g  alpha_3 = % -12g ",
+                ionosphere->alpha_2, ionosphere->alpha_3);
+                       pbuf += sprintf(pbuf, "\n   beta_0  = % -12g  beta_1  = % -12g  ",
+                ionosphere->beta_0, ionosphere->beta_1);
+                       pbuf += sprintf(pbuf, "\n   beta_2  = % -12g  beta_3  = % -12g  ",
+                ionosphere->beta_2, ionosphere->beta_3);
+                       break;
+
+               case 5:
+                       /* UTC */
+                       utc = (UTC_INFO*)data_packet;
+                       pbuf += sprintf(pbuf, "\n   A_0         = %g  ", utc->A_0);
+                       pbuf += sprintf(pbuf, "\n   A_1         = %g  ", utc->A_1);
+                       pbuf += sprintf(pbuf, "\n   delta_t_LS  = %d  ", utc->delta_t_LS);
+                       pbuf += sprintf(pbuf, "\n   t_ot        = %.0f  ", utc->t_ot );
+                       pbuf += sprintf(pbuf, "\n   WN_t        = %d  ", utc->WN_t );
+                       pbuf += sprintf(pbuf, "\n   WN_LSF      = %d  ", utc->WN_LSF );
+                       pbuf += sprintf(pbuf, "\n   DN          = %d  ", utc->DN );
+                       pbuf += sprintf(pbuf, "\n   delta_t_LSF = %d  ", utc->delta_t_LSF );
+                       break;
+
+               case 6: /* Ephemeris */
+                       if (sv_prn == 0 || sv_prn > 32) {
+                               pbuf += sprintf(pbuf, "  Binary PRN invalid");
+                               return;
+                       }
+                       nav_data = (NAV_INFO*)data_packet;
+
+                       pbuf += sprintf(pbuf, "\n     SV_PRN = % -12d .  t_ephem = % -12g . ",
+               nav_data->sv_number , nav_data->t_ephem );
+                       cdata = &(nav_data->ephclk);
+                       pbuf += sprintf(pbuf,
+               "\n    weeknum = % -12d .   codeL2 = % -12d .  L2Pdata = % -12d",
+               cdata->weeknum , cdata->codeL2 , cdata->L2Pdata );
+                       pbuf += sprintf(pbuf,
+               "\n  SVacc_raw = % -12d .SV_health = % -12d .     IODC = % -12d",
+               cdata->SVacc_raw, cdata->SV_health, cdata->IODC );
+                       pbuf += sprintf(pbuf,
+               "\n       T_GD = % -12g .     t_oc = % -12g .     a_f2 = % -12g",
+               cdata->T_GD, cdata->t_oc, cdata->a_f2 );
+                       pbuf += sprintf(pbuf,
+               "\n       a_f1 = % -12g .     a_f0 = % -12g .    SVacc = % -12g",
+               cdata->a_f1, cdata->a_f0, cdata->SVacc );
+                       edata = &(nav_data->ephorb);
+                       pbuf += sprintf(pbuf,
+                "\n       IODE = % -12d .fit_intvl = % -12d .     C_rs = % -12g",
+                edata->IODE, edata->fit_interval, edata->C_rs );
+                       pbuf += sprintf(pbuf,
+               "\n    delta_n = % -12g .      M_0 = % -12g .     C_uc = % -12g",
+               edata->delta_n, edata->M_0, edata->C_uc );
+                       pbuf += sprintf(pbuf,
+               "\n        ecc = % -12g .     C_us = % -12g .   sqrt_A = % -12g",
+                edata->e, edata->C_us, edata->sqrt_A );
+                       pbuf += sprintf(pbuf,
+               "\n       t_oe = % -12g .     C_ic = % -12g .  OMEGA_0 = % -12g",
+            edata->t_oe, edata->C_ic, edata->OMEGA_0 );
+                       pbuf += sprintf(pbuf,
+                "\n       C_is = % -12g .      i_0 = % -12g .     C_rc = % -12g",
+                edata->C_is, edata->i_0, edata->C_rc );
+                       pbuf += sprintf(pbuf,
+                "\n      omega = % -12g . OMEGADOT = % -12g .     IDOT = % -12g",
+               edata->omega, edata->OMEGADOT, edata->IDOT );
+                       pbuf += sprintf(pbuf,
+             "\n       Axis = % -12g .        n = % -12g .    r1me2 = % -12g",
+                edata->Axis, edata->n, edata->r1me2 );
+                       pbuf += sprintf(pbuf,
+          "\n    OMEGA_n = % -12g .   ODOT_n = % -12g",
+                edata->OMEGA_n, edata->ODOT_n );
+                       break;
+               }
+       }
+}
+
+
+/* 0x59: */
+static void rpt_SVs_enabled (TSIPPKT *rpt)
+{
+       unsigned char
+       numsvs,
+               code_type,
+      status_code[32];
+       short
+               iprn;
+
+       /* unload rptbuf */
+       if (rpt_0x59 (rpt, &code_type, status_code))
+   {
+               parsed = BADLEN_PARSE;
+               return;
+       }
+   switch (code_type)
+   {
+   case 3: pbuf += sprintf(pbuf, "\nSVs Disabled:\n"); break;
+   case 6: pbuf += sprintf(pbuf, "\nSVs with Health Ignored:\n"); break;
+   default: return;
+   }
+   numsvs = 0;
+       for (iprn=0; iprn<32; iprn++)
+   {
+       if (status_code[iprn])
+      {
+               pbuf += sprintf(pbuf, " %02d", iprn+1);
+          numsvs++;
+      }
+   }
+   if (numsvs == 0) pbuf += sprintf(pbuf, "None");
+}
+
+
+/* 0x5A */
+static void rpt_raw_msmt (TSIPPKT *rpt)
+{
+       unsigned char
+               sv_prn;
+       float
+               sample_length, signal_level, code_phase, Doppler;
+       double
+               time_of_fix;
+
+       /* unload rptbuf */
+       if (rpt_0x5A (rpt, &sv_prn, &sample_length, &signal_level,
+               &code_phase, &Doppler, &time_of_fix))
+   {
+               parsed = BADLEN_PARSE;
+               return;
+       }
+
+       pbuf += sprintf(pbuf, "\n   %02d %5.0f %7.1f %10.2f %10.2f %12.3f %s",
+               sv_prn, sample_length, signal_level, code_phase, Doppler, time_of_fix,
+               show_time ((float)time_of_fix));
+}
+
+/* 0x5B */
+static void rpt_SV_ephemeris_status (TSIPPKT *rpt)
+{
+       unsigned char
+               sv_prn, sv_health, sv_iode, fit_interval_flag;
+       float
+               time_of_collection, time_of_eph, sv_accy;
+
+       /* unload rptbuf */
+       if (rpt_0x5B (rpt, &sv_prn, &sv_health, &sv_iode, &fit_interval_flag,
+               &time_of_collection, &time_of_eph, &sv_accy))
+   {
+               parsed = BADLEN_PARSE;
+               return;
+       }
+
+       pbuf += sprintf(pbuf, "\n  SV%02d  %s   %2Xh     %2Xh ",
+       sv_prn, show_time (time_of_collection), sv_health, sv_iode);
+       /* note: cannot use show_time twice in same call */
+       pbuf += sprintf(pbuf, "%s   %1d   %4.1f",
+      show_time (time_of_eph), fit_interval_flag, sv_accy);
+}
+
+/* 0x5C */
+static void rpt_SV_tracking_status (TSIPPKT *rpt)
+{
+       unsigned char
+               sv_prn, chan, slot, acq_flag, eph_flag,
+               old_msmt_flag, integer_msec_flag, bad_data_flag,
+               data_collect_flag;
+       float
+               signal_level, time_of_last_msmt,
+               elev, azim;
+
+       /* unload rptbuf */
+       if (rpt_0x5C (rpt,
+               &sv_prn, &slot, &chan, &acq_flag, &eph_flag,
+               &signal_level, &time_of_last_msmt, &elev, &azim,
+               &old_msmt_flag, &integer_msec_flag, &bad_data_flag,
+               &data_collect_flag))
+   {
+               parsed = BADLEN_PARSE;
+               return;
+       }
+
+       pbuf += sprintf(pbuf,
+"\n SV%2d  %1d   %1d   %1d   %4.1f  %s  %5.1f  %5.1f",
+               sv_prn, chan,
+      acq_flag, eph_flag, signal_level,
+      show_time(time_of_last_msmt),
+               elev*R2D, azim*R2D);
+}
+
+/**/
+/* 0x6D */
+static void rpt_allSV_selection (TSIPPKT *rpt)
+{
+       unsigned char
+               manual_mode, nsvs, sv_prn[8], ndim;
+       short
+               islot;
+       float
+               pdop, hdop, vdop, tdop;
+
+       /* unload rptbuf */
+       if (rpt_0x6D (rpt,
+               &manual_mode, &nsvs, &ndim, sv_prn,
+               &pdop, &hdop, &vdop, &tdop))
+   {
+               parsed = BADLEN_PARSE;
+               return;
+       }
+
+       switch (ndim)
+   {
+   case 0:
+               pbuf += sprintf(pbuf, "\nMode: Searching, %d-SV:", nsvs);
+      break;
+   case 1:
+               pbuf += sprintf(pbuf, "\nMode: One-SV Timing:");
+      break;
+   case 3: case 4:
+               pbuf += sprintf(pbuf, "\nMode: %c-%dD, %d-SV:",
+                       manual_mode ? 'M' : 'A', ndim - 1,  nsvs);
+      break;
+       case 5:
+               pbuf += sprintf(pbuf, "\nMode: Timing, %d-SV:", nsvs);
+      break;
+   default:
+               pbuf += sprintf(pbuf, "\nMode: Unknown = %d:", ndim);
+      break;
+   }
+
+       for (islot = 0; islot < nsvs; islot++)
+   {
+               if (sv_prn[islot]) pbuf += sprintf(pbuf, " %02d", sv_prn[islot]);
+       }
+   if (ndim == 3 || ndim == 4)
+   {
+               pbuf += sprintf(pbuf, ";  DOPs: P %.1f H %.1f V %.1f T %.1f",
+                       pdop, hdop, vdop, tdop);
+   }
+}
+
+/**/
+/* 0x82 */
+static void rpt_DGPS_position_mode (TSIPPKT *rpt)
+{
+       unsigned char
+               diff_mode;
+
+       /* unload rptbuf */
+       if (rpt_0x82 (rpt, &diff_mode)) {
+               parsed = BADLEN_PARSE;
+               return;
+       }
+
+       pbuf += sprintf(pbuf, "\nFix is%s DGPS-corrected (%s mode)  (%d)",
+       (diff_mode&1) ? "" : " not",
+       (diff_mode&2) ? "auto" : "manual",
+      diff_mode);
+}
+
+/* 0x83 */
+static void rpt_double_ECEF_position (TSIPPKT *rpt)
+{
+
+       double
+               ECEF_pos[3], clock_bias;
+       float
+               time_of_fix;
+
+       /* unload rptbuf */
+       if (rpt_0x83 (rpt, ECEF_pos, &clock_bias, &time_of_fix))
+   {
+               parsed = BADLEN_PARSE;
+               return;
+       }
+
+       pbuf += sprintf(pbuf, "\nDXYZ:%12.2f  %13.2f  %13.2f %12.2f%s",
+               ECEF_pos[0], ECEF_pos[1], ECEF_pos[2], clock_bias,
+               show_time(time_of_fix));
+}
+
+/* 0x84 */
+static void rpt_double_lla_position (TSIPPKT *rpt)
+{
+       short
+               lat_deg, lon_deg;
+       double
+               lat, lon, lat_min, lon_min,
+               alt, clock_bias;
+       float
+               time_of_fix;
+       unsigned char
+               north_south, east_west;
+
+       /* unload rptbuf */
+       if (rpt_0x84 (rpt,
+               &lat, &lon, &alt, &clock_bias, &time_of_fix))
+   {
+               parsed = BADLEN_PARSE;
+               return;
+       }
+
+       lat *= R2D;
+       lon *= R2D;
+       if (lat < 0.0) {
+               north_south = 'S';
+               lat = -lat;
+       } else {
+               north_south = 'N';
+       }
+       lat_deg = (short)lat;
+       lat_min = (lat - lat_deg) * 60.0;
+
+       if (lon < 0.0) {
+               east_west = 'W';
+               lon = -lon;
+       } else {
+               east_west = 'E';
+       }
+       lon_deg = (short)lon;
+       lon_min = (lon - lon_deg) * 60.0;
+       pbuf += sprintf(pbuf, "\nDLLA: %2d:%08.5f %c; %3d:%08.5f %c; %10.2f %12.2f%s",
+               lat_deg, lat_min, north_south,
+               lon_deg, lon_min, east_west,
+               alt, clock_bias,
+               show_time(time_of_fix));
+}
+
+/* 0xBB */
+static void rpt_complete_rcvr_config (TSIPPKT *rpt)
+{
+       TSIP_RCVR_CFG TsipxBB ;
+       /* unload rptbuf */
+       if (rpt_Paly0xBB (rpt, &TsipxBB))
+       {
+               parsed = BADLEN_PARSE;
+               return;
+       }
+
+       pbuf += sprintf(pbuf, "\n   operating mode:      %s",
+               NavModeText0xBB[TsipxBB.operating_mode]);
+       pbuf += sprintf(pbuf, "\n   dynamics:            %s",
+               dyn_text[TsipxBB.dyn_code]);
+       pbuf += sprintf(pbuf, "\n   elev angle mask:     %g deg",
+               TsipxBB.elev_mask * R2D);
+       pbuf += sprintf(pbuf, "\n   SNR mask:            %g AMU",
+               TsipxBB.cno_mask);
+       pbuf += sprintf(pbuf, "\n   DOP mask:            %g",
+               TsipxBB.dop_mask);
+       pbuf += sprintf(pbuf, "\n   DOP switch:          %g",
+               TsipxBB.dop_switch);
+       return ;
+}
+
+/* 0xBC */
+static void rpt_rcvr_serial_port_config (TSIPPKT *rpt)
+{
+       unsigned char
+               port_num, in_baud, out_baud, data_bits, parity, stop_bits, flow_control,
+               protocols_in, protocols_out, reserved;
+       unsigned char known;
+
+       /* unload rptbuf */
+       if (rpt_0xBC (rpt, &port_num, &in_baud, &out_baud, &data_bits, &parity,
+                       &stop_bits, &flow_control, &protocols_in, &protocols_out, &reserved)) {
+               parsed = BADLEN_PARSE;
+               return;
+       }
+       /* rptbuf unloaded */
+
+       pbuf += sprintf(pbuf, "\n   RECEIVER serial port %s config:",
+               rcvr_port_text[port_num]);
+
+       pbuf += sprintf(pbuf, "\n             I/O Baud %s/%s, %d - %s - %d",
+               st_baud_text_app[in_baud],
+               st_baud_text_app[out_baud],
+               data_bits+5,
+               parity_text[parity],
+               stop_bits=1);
+       pbuf += sprintf(pbuf, "\n             Input protocols: ");
+       known = FALSE;
+       if (protocols_in&B_TSIP)
+   {
+               pbuf += sprintf(pbuf, "%s ", protocols_in_text[1]);
+               known = TRUE;
+       }
+       if (known == FALSE) pbuf += sprintf(pbuf, "No known");
+
+       pbuf += sprintf(pbuf, "\n             Output protocols: ");
+       known = FALSE;
+       if (protocols_out&B_TSIP)
+   {
+               pbuf += sprintf(pbuf, "%s ", protocols_out_text[1]);
+               known = TRUE;
+       }
+       if (protocols_out&B_NMEA)
+   {
+               pbuf += sprintf(pbuf, "%s ", protocols_out_text[2]);
+               known = TRUE;
+       }
+       if (known == FALSE) pbuf += sprintf(pbuf, "No known");
+       reserved = reserved;
+
+ }
+
+/* 0x8F */
+/* 8F0B */
+static void rpt_8F0B(TSIPPKT *rpt)
+{
+       const char
+       *oprtng_dim[7] = {
+       "horizontal (2-D)",
+         "full position (3-D)",
+         "single satellite (0-D)",
+         "automatic",
+         "N/A",
+         "N/A",
+         "overdetermined clock"};
+   char
+       sv_id[8];
+   unsigned char
+       month,
+      date,
+      dim_mode,
+      north_south,
+      east_west;
+   unsigned short
+       event;
+   short
+       utc_offset,
+      year,
+      local_index;
+       short
+       lat_deg,
+      lon_deg;
+   float
+       bias_unc,
+      dr_unc;
+   double
+       tow,
+      bias,
+      drift,
+      lat,
+      lon,
+      alt,
+      lat_min,
+      lon_min;
+   int
+       numfix,
+      numnotfix;
+
+       if (rpt_0x8F0B(rpt,
+       &event,
+      &tow,
+      &date,
+      &month,
+      &year,
+      &dim_mode,
+      &utc_offset,
+      &bias,
+      &drift,
+      &bias_unc,
+      &dr_unc,
+      &lat,
+      &lon,
+      &alt,
+      sv_id))
+   {
+               parsed = BADLEN_PARSE;
+               return;
+       }
+
+       if (event == 0)
+   {
+       pbuf += sprintf(pbuf, "\nNew partial+full meas");
+       }
+   else
+   {
+               pbuf += sprintf(pbuf, "\nEvent count: %5d", event);
+   }
+
+       pbuf += sprintf(pbuf, "\nGPS time  : %s %2d/%2d/%2d (DMY)",
+       show_time(tow), date, month, year);
+       pbuf += sprintf(pbuf, "\nMode      : %s", oprtng_dim[dim_mode]);
+       pbuf += sprintf(pbuf, "\nUTC offset: %2d", utc_offset);
+       pbuf += sprintf(pbuf, "\nClock Bias: %6.2f m", bias);
+       pbuf += sprintf(pbuf, "\nFreq bias : %6.2f m/s", drift);
+       pbuf += sprintf(pbuf, "\nBias unc  : %6.2f m", bias_unc);
+       pbuf += sprintf(pbuf, "\nFreq unc  : %6.2f m/s", dr_unc);
+
+       lat *= R2D; /* convert from radians to degrees */
+       lon *= R2D;
+       if (lat < 0.0)
+   {
+               north_south = 'S';
+               lat = -lat;
+       }
+   else
+   {
+               north_south = 'N';
+       }
+
+       lat_deg = (short)lat;
+       lat_min = (lat - lat_deg) * 60.0;
+       if (lon < 0.0)
+   {
+               east_west = 'W';
+               lon = -lon;
+       }
+   else
+   {
+               east_west = 'E';
+       }
+
+       lon_deg = (short)lon;
+       lon_min = (lon - lon_deg) * 60.0;
+       pbuf += sprintf(pbuf, "\nPosition  :");
+       pbuf += sprintf(pbuf, " %4d %6.3f %c", lat_deg, lat_min, north_south);
+       pbuf += sprintf(pbuf, " %5d %6.3f %c", lon_deg, lon_min, east_west);
+       pbuf += sprintf(pbuf, " %10.2f", alt);
+
+   numfix = numnotfix = 0;
+       for (local_index=0; local_index<8; local_index++)
+   {
+               if (sv_id[local_index] < 0) numnotfix++;
+               if (sv_id[local_index] > 0) numfix++;
+   }
+   if (numfix > 0)
+   {
+               pbuf += sprintf(pbuf, "\nSVs used in fix  : ");
+               for (local_index=0; local_index<8; local_index++)
+          {
+                       if (sv_id[local_index] > 0)
+       {
+               pbuf += sprintf(pbuf, "%2d ", sv_id[local_index]);
+             }
+       }
+   }
+   if (numnotfix > 0)
+   {
+               pbuf += sprintf(pbuf, "\nOther SVs tracked: ");
+               for (local_index=0; local_index<8; local_index++)
+          {
+                       if (sv_id[local_index] < 0)
+       {
+               pbuf += sprintf(pbuf, "%2d ", sv_id[local_index]);
+             }
+       }
+   }
+}
+
+/* 0x8F14 */
+static void rpt_8F14 (TSIPPKT *rpt)
+/* Datum parameters */
+{
+       double
+               datum_coeffs[5];
+       short
+               datum_idx;
+
+       /* unload rptbuf */
+       if (rpt_0x8F14 (rpt, &datum_idx, datum_coeffs))
+   {
+               parsed = BADLEN_PARSE;
+               return;
+       }
+
+       if (datum_idx == -1)
+   {
+       pbuf += sprintf(pbuf, "\nUser-Entered Datum:");
+               pbuf += sprintf(pbuf, "\n   dx        = %6.1f", datum_coeffs[0]);
+               pbuf += sprintf(pbuf, "\n   dy        = %6.1f", datum_coeffs[1]);
+               pbuf += sprintf(pbuf, "\n   dz        = %6.1f", datum_coeffs[2]);
+               pbuf += sprintf(pbuf, "\n   a-axis    = %10.3f", datum_coeffs[3]);
+               pbuf += sprintf(pbuf, "\n   e-squared = %16.14f", datum_coeffs[4]);
+   }
+   else if (datum_idx == 0)
+   {
+       pbuf += sprintf(pbuf, "\nWGS-84 datum, Index 0 ");
+   }
+   else
+   {
+       pbuf += sprintf(pbuf, "\nStandard Datum, Index %3d ", datum_idx);
+   }
+}
+
+/* 0x8F15 */
+static void rpt_8F15 (TSIPPKT *rpt)
+/* Datum parameters */
+{
+       double
+               datum_coeffs[5];
+       short
+               datum_idx;
+
+       /* unload rptbuf */
+       if (rpt_0x8F15 (rpt, &datum_idx, datum_coeffs)) {
+               parsed = BADLEN_PARSE;
+               return;
+       }
+
+       if (datum_idx == -1)
+   {
+       pbuf += sprintf(pbuf, "\nUser-Entered Datum:");
+               pbuf += sprintf(pbuf, "\n   dx        = %6.1f", datum_coeffs[0]);
+               pbuf += sprintf(pbuf, "\n   dy        = %6.1f", datum_coeffs[1]);
+               pbuf += sprintf(pbuf, "\n   dz        = %6.1f", datum_coeffs[2]);
+               pbuf += sprintf(pbuf, "\n   a-axis    = %10.3f", datum_coeffs[3]);
+               pbuf += sprintf(pbuf, "\n   e-squared = %16.14f", datum_coeffs[4]);
+   }
+   else if (datum_idx == 0)
+   {
+       pbuf += sprintf(pbuf, "\nWGS-84 datum, Index 0 ");
+   }
+   else
+   {
+       pbuf += sprintf(pbuf, "\nStandard Datum, Index %3d ", datum_idx);
+   }
+}
+
+/* 0x8F20 */
+#define INFO_DGPS       0x02
+#define INFO_2D         0x04
+#define INFO_ALTSET     0x08
+#define INFO_FILTERED   0x10
+static void rpt_8F20 (TSIPPKT *rpt)
+{
+       unsigned char
+               info, nsvs, sv_prn[32];
+       short
+               week_num, datum_index, sv_IODC[32];
+       double
+               lat, lon, alt, time_of_fix;
+       double
+               londeg, latdeg, vel[3];
+       short
+               isv;
+   char
+       datum_string[20];
+
+       /* unload rptbuf */
+       if (rpt_0x8F20 (rpt,
+               &info, &lat, &lon, &alt, vel,
+               &time_of_fix,
+               &week_num, &nsvs, sv_prn, sv_IODC, &datum_index))
+       {
+               parsed = BADLEN_PARSE;
+               return;
+       }
+       pbuf += sprintf(pbuf,
+       "\nFix at: %04d:%3s:%02d:%02d:%06.3f GPS (=UTC+%2ds)  FixType: %s%s%s",
+       week_num,
+               dayname[(short)(time_of_fix/86400.0)],
+               (short)fmod(time_of_fix/3600., 24.),
+               (short)fmod(time_of_fix/60., 60.),
+               fmod(time_of_fix, 60.),
+      (char)rpt->buf[29],              /* UTC offset */
+               (info & INFO_DGPS)?"Diff":"",
+               (info & INFO_2D)?"2D":"3D",
+               (info & INFO_FILTERED)?"-Filtrd":"");
+
+   if (datum_index > 0)
+   {
+               sprintf(datum_string, "Datum%3d", datum_index);
+   }
+   else if (datum_index)
+   {
+               sprintf(datum_string, "Unknown ");
+   }
+   else
+   {
+               sprintf(datum_string, "WGS-84");
+   }
+
+       /* convert from radians to degrees */
+       latdeg = R2D * fabs(lat);
+       londeg = R2D * fabs(lon);
+       pbuf += sprintf(pbuf,
+       "\n   Pos: %4d:%09.6f %c %5d:%09.6f %c %10.2f m HAE (%s)",
+               (short)latdeg, fmod (latdeg, 1.)*60.0,
+               (lat<0.0)?'S':'N',
+               (short)londeg, fmod (londeg, 1.)*60.0,
+               (lon<0.0)?'W':'E',
+               alt,
+      datum_string);
+       pbuf += sprintf(pbuf,
+       "\n   Vel:    %9.3f E       %9.3f N      %9.3f U   (m/sec)",
+               vel[0], vel[1], vel[2]);
+
+       pbuf += sprintf(pbuf,
+       "\n   SVs: ");
+       for (isv = 0; isv < nsvs; isv++) {
+               pbuf += sprintf(pbuf, " %02d", sv_prn[isv]);
+       }
+       pbuf += sprintf(pbuf, "     (IODEs:");
+       for (isv = 0; isv < nsvs; isv++) {
+               pbuf += sprintf(pbuf, " %02X", sv_IODC[isv]&0xFF);
+       }
+       pbuf += sprintf(pbuf, ")");
+}
+
+/* 0x8F41 */
+static void rpt_8F41(TSIPPKT *rpt)
+{
+       unsigned char
+       bSearchRange,
+               bBoardOptions,
+               bBuildYear,
+               bBuildMonth,
+               bBuildDay,
+               bBuildHour;
+       float
+       fOscOffset;
+       unsigned short
+       iTestCodeId;
+       unsigned long
+               iiSerialNumber;
+
+   if (!rpt_0x8F41(rpt,
+               &bSearchRange,
+               &bBoardOptions,
+               &iiSerialNumber,
+               &bBuildYear,
+               &bBuildMonth,
+               &bBuildDay,
+               &bBuildHour,
+               &fOscOffset,
+               &iTestCodeId))
+   {
+               parsed = BADLEN_PARSE;
+      return;
+   }
+
+   pbuf += sprintf(pbuf, "\n  search range:          %d",
+       bSearchRange);
+   pbuf += sprintf(pbuf, "\n  board options:         %d",
+      bBoardOptions);
+   pbuf += sprintf(pbuf, "\n  board serial #:        %ld",
+      iiSerialNumber);
+   pbuf += sprintf(pbuf, "\n  build date/hour:       %02d/%02d/%02d %02d:00",
+       bBuildDay, bBuildMonth, bBuildYear, bBuildHour);
+   pbuf += sprintf(pbuf, "\n  osc offset:            %.3f PPM (%.0f Hz)",
+       fOscOffset/1575.42, fOscOffset);
+   pbuf += sprintf(pbuf, "\n  test code:             %d",
+       iTestCodeId);
+}
+
+/* 0x8F42 */
+static void rpt_8F42(TSIPPKT *rpt)
+{
+       unsigned char
+       bProdOptionsPre,
+      bProdNumberExt;
+       unsigned short
+       iCaseSerialNumberPre,
+      iPremiumOptions,
+      iMachineID,
+      iKey;
+       unsigned long
+       iiCaseSerialNumber,
+               iiProdNumber;
+
+   if (!rpt_0x8F42(rpt,
+               &bProdOptionsPre,
+               &bProdNumberExt,
+               &iCaseSerialNumberPre,
+               &iiCaseSerialNumber,
+               &iiProdNumber,
+               &iPremiumOptions,
+               &iMachineID,
+               &iKey))
+   {
+               parsed = BADLEN_PARSE;
+      return;
+   }
+
+       pbuf += sprintf(pbuf, "\nProduct ID 8F42");
+   pbuf += sprintf(pbuf, "\n   extension:            %d", bProdNumberExt);
+   pbuf += sprintf(pbuf, "\n   case serial # prefix: %d", iCaseSerialNumberPre);
+   pbuf += sprintf(pbuf, "\n   case serial #:        %ld", iiCaseSerialNumber);
+   pbuf += sprintf(pbuf, "\n   prod. #:              %ld", iiProdNumber);
+       pbuf += sprintf(pbuf, "\n   premium options:      %Xh", iPremiumOptions);
+   pbuf += sprintf(pbuf, "\n   machine ID:           %d", iMachineID);
+   pbuf += sprintf(pbuf, "\n   key:                  %Xh", iKey);
+}
+
+/* 0x8F45 */
+static void rpt_8F45(TSIPPKT *rpt)
+{
+   unsigned char bSegMask;
+
+   if (!rpt_0x8F45(rpt,
+       &bSegMask))
+   {
+               parsed = BADLEN_PARSE;
+               return;
+       }
+       pbuf += sprintf(pbuf, "\nCleared Segment Mask: %Xh", bSegMask);
+}
+
+static void rpt_8F4A(TSIPPKT *rpt)
+/* Stinger PPS def */
+{
+       unsigned char
+       pps_enabled,
+      pps_timebase,
+      pps_polarity;
+   float
+       bias_unc_threshold;
+   double
+       pps_offset;
+
+       if (rpt_0x8F4A_16 (rpt,
+       &pps_enabled,
+      &pps_timebase,
+      &pps_polarity,
+      &pps_offset,
+      &bias_unc_threshold))
+   {
+       parsed = BADLEN_PARSE;
+          return;
+   }
+
+       pbuf += sprintf(pbuf, "\nPPS is         %s",    pps_enabled?"enabled":"disabled");
+   pbuf += sprintf(pbuf, "\n   timebase:   %s", PPSTimeBaseText[pps_timebase]);
+   pbuf += sprintf(pbuf, "\n   polarity:   %s", PPSPolarityText[pps_polarity]);
+   pbuf += sprintf(pbuf, "\n   offset:     %.1f ns, ", pps_offset*1.e9);
+   pbuf += sprintf(pbuf, "\n   biasunc:    %.1f ns", bias_unc_threshold/GPS_C*1.e9);
+}
+
+static void rpt_8F4B(TSIPPKT *rpt)
+/* fast-SA decorrolation time for self-survey */
+{
+       unsigned long
+       decorr_max;
+
+   if (rpt_0x8F4B(rpt, &decorr_max))
+   {
+               parsed = BADLEN_PARSE;
+      return;
+   }
+
+   pbuf += sprintf(pbuf,
+       "\nMax # of position fixes for self-survey : %ld",
+      decorr_max);
+}
+
+static void rpt_8F4D(TSIPPKT *rpt)
+{
+       static char
+       *linestart;
+       unsigned long
+       OutputMask;
+   static unsigned long
+       MaskBit[] = {
+       0x00000001, 0x00000002, 0x00000004, 0x00000008, 0x00000010, 0x00000020,
+       0x00000100L, 0x00000800L, 0x00001000L,
+         0x40000000L, 0x80000000L};
+   int
+       ichoice,
+       numchoices;
+
+   if (rpt_0x8F4D(rpt, &OutputMask))
+   {
+               parsed = BADLEN_PARSE;
+      return;
+   }
+
+   pbuf += sprintf(pbuf, "\nAuto-Report Mask: %02X %02X %02X %02X",
+       (unsigned char)(OutputMask>>24),
+       (unsigned char)(OutputMask>>16),
+       (unsigned char)(OutputMask>>8),
+       (unsigned char)OutputMask);
+
+   numchoices = sizeof(MaskText)/sizeof(char*);
+   pbuf += sprintf(pbuf, "\nAuto-Reports scheduled for Output:");
+   linestart = pbuf;
+   for (ichoice=0; ichoice<numchoices; ichoice++)
+   {
+       if (OutputMask&MaskBit[ichoice])
+      {
+               pbuf += sprintf(pbuf, "%s %s",
+               (pbuf==linestart)?"\n     ":",",
+          MaskText[ichoice]);
+                       if (pbuf-linestart > 60) linestart = pbuf;
+      }
+   }
+
+   pbuf += sprintf(pbuf, "\nAuto-Reports NOT scheduled for Output:");
+   linestart = pbuf;
+   for (ichoice=0; ichoice<numchoices; ichoice++)
+   {
+       if (OutputMask&MaskBit[ichoice]) continue;
+               pbuf += sprintf(pbuf, "%s %s",
+               (pbuf==linestart)?"\n     ":",",
+         MaskText[ichoice]);
+               if (pbuf-linestart > 60) linestart = pbuf;
+   }
+}
+
+static void rpt_8FA5(TSIPPKT *rpt)
+{
+       unsigned char
+       spktmask[4];
+
+   if (rpt_0x8FA5(rpt, spktmask))
+   {
+               parsed = BADLEN_PARSE;
+      return;
+   }
+
+   pbuf += sprintf(pbuf, "\nSuperpacket auto-output mask: %02X %02X %02X %02X",
+       spktmask[0], spktmask[1], spktmask[2], spktmask[3]);
+
+   if (spktmask[0]&0x01) pbuf+= sprintf (pbuf, "\n    PPS   8F-0B");
+   if (spktmask[0]&0x02) pbuf+= sprintf (pbuf, "\n    Event 8F-0B");
+   if (spktmask[0]&0x10) pbuf+= sprintf (pbuf, "\n    PPS   8F-AD");
+   if (spktmask[0]&0x20) pbuf+= sprintf (pbuf, "\n    Event 8F-AD");
+   if (spktmask[2]&0x01) pbuf+= sprintf (pbuf, "\n    ppos Fix 8F-20");
+}
+
+static void rpt_8FAD (TSIPPKT *rpt)
+{
+   unsigned short
+       Count,
+       Year;
+   double
+       FracSec;
+   unsigned char
+       Hour,
+       Minute,
+       Second,
+       Day,
+       Month,
+       Status,
+       Flags;
+       static char* Status8FADText[] = {
+      "CODE_DOING_FIXES",
+      "CODE_GOOD_1_SV",
+      "CODE_APPX_1SV",
+      "CODE_NEED_TIME",
+      "CODE_NEED_INITIALIZATION",
+      "CODE_PDOP_HIGH",
+      "CODE_BAD_1SV",
+      "CODE_0SVS",
+      "CODE_1SV",
+      "CODE_2SVS",
+      "CODE_3SVS",
+      "CODE_NO_INTEGRITY",
+      "CODE_DCORR_GEN",
+      "CODE_OVERDET_CLK",
+      "Invalid Status"},
+       *LeapStatusText[] = {
+       " UTC Avail", " ", " ", " ",
+      " Scheduled", " Pending", " Warning", " In Progress"};
+    int i;
+
+       if (rpt_0x8FAD (rpt,
+       &Count,
+       &FracSec,
+       &Hour,
+       &Minute,
+       &Second,
+       &Day,
+       &Month,
+       &Year,
+       &Status,
+       &Flags))
+   {
+               parsed = BADLEN_PARSE;
+               return;
+   }
+
+       pbuf += sprintf(pbuf,    "\n8FAD   Count: %d   Status: %s",
+       Count, Status8FADText[Status]);
+
+       pbuf += sprintf(pbuf, "\n   Leap Flags:");
+   if (Flags)
+   {
+       for (i=0; i<8; i++)
+      {
+       if (Flags&(1<<i)) pbuf += sprintf(pbuf, LeapStatusText[i]);
+      }
+   }
+   else
+   {
+       pbuf += sprintf(pbuf, "  UTC info not available");
+   }
+
+       pbuf += sprintf(pbuf,     "\n      %02d/%02d/%04d (DMY)  %02d:%02d:%02d.%09ld UTC",
+               Day, Month, Year, Hour, Minute, Second, (long)(FracSec*1.e9));
+}
+
+
+int print_msg_table_header (int rptcode, char *HdrStr, int force)
+{
+       /* force header is to help auto-output function */
+       /* last_rptcode is to determine whether to print a header */
+       /* for the first occurence of a series of reports */
+       static int
+               last_rptcode = 0;
+   int
+       numchars;
+
+   numchars = 0;
+       if (force || rptcode!=last_rptcode)
+   {
+               /* supply a header in console output */
+       switch (rptcode)
+               {
+               case 0x5A:
+                       numchars = sprintf(HdrStr, "\nRaw Measurement Data");
+                       numchars += sprintf(HdrStr+numchars,
+               "\n   SV  Sample   SNR  Code Phase   Doppler    Seconds     Time of Meas");
+                       break;
+
+               case 0x5B:
+                       numchars = sprintf(HdrStr, "\nEphemeris Status");
+                       numchars += sprintf(HdrStr+numchars,
+                               "\n    SV     Time collected     Health  IODE        t oe         Fit   URA");
+                       break;
+
+               case 0x5C:
+                       numchars = sprintf(HdrStr, "\nTracking Info");
+                       numchars += sprintf(HdrStr+numchars,
+               "\n   SV  C Acq Eph   SNR     Time of Meas       Elev  Azim   ");
+                       break;
+
+      }
+       }
+       last_rptcode = rptcode;
+   return (short)numchars;
+}
+
+static void unknown_rpt (TSIPPKT *rpt)
+{
+       int i;
+
+       /* app-specific rpt packets */
+       if (parsed == BADLEN_PARSE)
+   {
+               pbuf += sprintf(pbuf, "\nTSIP report packet ID %2Xh, length %d: Bad length",
+       rpt->code, rpt->len);
+   }
+       if (parsed == BADID_PARSE)
+   {
+               pbuf += sprintf(pbuf,
+       "\nTSIP report packet ID %2Xh, length %d: translation not supported",
+               rpt->code, rpt->len);
+   }
+
+       if (parsed == BADDATA_PARSE)
+   {
+               pbuf += sprintf(pbuf,
+       "\nTSIP report packet ID %2Xh, length %d: data content incorrect",
+               rpt->code, rpt->len);
+   }
+
+       for (i = 0; i < rpt->len; i++) {
+               if ((i % 20) == 0) *pbuf++ = '\n';
+               pbuf += sprintf(pbuf, " %02X", rpt->buf[i]);
+       }
+}
+/**/
+/*
+** main subroutine, called from ProcessInputBytesWhileWaitingForKBHit()
+*/
+void TranslateTSIPReportToText (TSIPPKT *rpt, char *TextOutputBuffer)
+{
+
+       /* pbuf is the pointer to the current location of the text output */
+       pbuf = TextOutputBuffer;
+
+   /* keep track of whether the message has been successfully parsed */
+       parsed = GOOD_PARSE;
+
+       /* print a header if this is the first of a series of messages */
+       pbuf += print_msg_table_header (rpt->code, pbuf, FALSE);
+
+   /* process incoming TSIP report according to code */
+       switch (rpt->code)
+   {
+       case 0x3D: rpt_chan_A_config (rpt); break;
+       case 0x40: rpt_almanac_data_page (rpt); break;
+       case 0x41: rpt_GPS_time (rpt); break;
+       case 0x42: rpt_single_ECEF_position (rpt); break;
+       case 0x43: rpt_single_ECEF_velocity (rpt); break;
+       case 0x45: rpt_SW_version (rpt); break;
+       case 0x46: rpt_rcvr_health (rpt); break;
+       case 0x47: rpt_SNR_all_SVs (rpt); break;
+       case 0x48: rpt_GPS_system_message (rpt); break;
+       case 0x49: rpt_almanac_health_page (rpt); break;
+       case 0x4A: switch (rpt->len) {
+       /*
+      ** special case (=slip-up) in the TSIP protocol;
+      ** parsing method depends on length
+      */
+       case 20: rpt_single_lla_position (rpt); break;
+      case  9: rpt_ref_alt (rpt); break;
+               } break;
+       case 0x4B: rpt_rcvr_id_and_status (rpt);break;
+       case 0x4C: rpt_operating_parameters (rpt); break;
+       case 0x4D: rpt_oscillator_offset (rpt); break;
+       case 0x4E: rpt_GPS_time_set_response (rpt); break;
+       case 0x4F: rpt_UTC_offset (rpt); break;
+   case 0x54: rpt_1SV_bias (rpt); break;
+       case 0x55: rpt_io_opt (rpt); break;
+       case 0x56: rpt_ENU_velocity (rpt); break;
+       case 0x57: rpt_last_fix_info (rpt); break;
+       case 0x58: rpt_GPS_system_data (rpt); break;
+       case 0x59: rpt_SVs_enabled (rpt); break;
+       case 0x5A: rpt_raw_msmt (rpt); break;
+       case 0x5B: rpt_SV_ephemeris_status (rpt); break;
+       case 0x5C: rpt_SV_tracking_status (rpt); break;
+       case 0x6D: rpt_allSV_selection (rpt); break;
+       case 0x82: rpt_DGPS_position_mode (rpt); break;
+       case 0x83: rpt_double_ECEF_position (rpt); break;
+       case 0x84: rpt_double_lla_position (rpt); break;
+       case 0xBB: rpt_complete_rcvr_config (rpt); break;
+       case 0xBC: rpt_rcvr_serial_port_config (rpt); break;
+
+       case 0x8F: switch (rpt->buf[0])
+       {
+      /* superpackets; parsed according to subcodes */
+      case 0x0B: rpt_8F0B(rpt); break;
+      case 0x14: rpt_8F14(rpt); break;
+      case 0x15: rpt_8F15(rpt); break;
+               case 0x20: rpt_8F20(rpt); break;
+      case 0x41: rpt_8F41(rpt); break;
+      case 0x42: rpt_8F42(rpt); break;
+      case 0x45: rpt_8F45(rpt); break;
+      case 0x4A: rpt_8F4A(rpt); break;
+      case 0x4B: rpt_8F4B(rpt); break;
+      case 0x4D: rpt_8F4D(rpt); break;
+      case 0xA5: rpt_8FA5(rpt); break;
+          case 0xAD: rpt_8FAD(rpt); break;
+               default: parsed = BADID_PARSE; break;
+               }
+               break;
+
+       default: parsed = BADID_PARSE; break;
+       }
+
+       if (parsed != GOOD_PARSE)
+       {
+          /*
+       **The message has TSIP structure (DLEs, etc.)
+          ** but could not be parsed by above routines
+       */
+               unknown_rpt (rpt);
+       }
+
+   /* close TextOutputBuffer */
+   pbuf = '\0';
+}
+
+#endif /* TRIMBLE_OUTPUT_FUNC */
+
+#else  /* defined(REFCLOCK) && defined(CLOCK_RIPENCC) */
+int refclock_ripencc_bs;
+#endif /* defined(REFCLOCK) && defined(CLOCK_RIPENCC) */
+