1106424Sroberto/*
2106424Sroberto * $Id: refclock_ripencc.c,v 1.13 2002/06/18 14:20:55 marks Exp marks $
3106424Sroberto *
4106424Sroberto * Copyright (c) 2002  RIPE NCC
5106424Sroberto *
6106424Sroberto * All Rights Reserved
7106424Sroberto *
8106424Sroberto * Permission to use, copy, modify, and distribute this software and its
9106424Sroberto * documentation for any purpose and without fee is hereby granted,
10106424Sroberto * provided that the above copyright notice appear in all copies and that
11106424Sroberto * both that copyright notice and this permission notice appear in
12106424Sroberto * supporting documentation, and that the name of the author not be
13106424Sroberto * used in advertising or publicity pertaining to distribution of the
14106424Sroberto * software without specific, written prior permission.
15106424Sroberto *
16106424Sroberto * THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
17106424Sroberto * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
18106424Sroberto * AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
19106424Sroberto * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
20106424Sroberto * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
21106424Sroberto * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22106424Sroberto *
23106424Sroberto *
24106424Sroberto *
25106424Sroberto * This driver was developed for use with the RIPE NCC TTM project.
26106424Sroberto *
27106424Sroberto *
28106424Sroberto * The initial driver was developed by Daniel Karrenberg <dfk@ripe.net>
29106424Sroberto * using the code made available by Trimble. This was for xntpd-3.x.x
30106424Sroberto *
31106424Sroberto * Rewrite of the driver for ntpd-4.x.x by Mark Santcroos <marks@ripe.net>
32106424Sroberto *
33106424Sroberto */
34106424Sroberto
35106424Sroberto#ifdef HAVE_CONFIG_H
36106424Sroberto#include <config.h>
37106424Sroberto#endif /* HAVE_CONFIG_H */
38106424Sroberto
39106424Sroberto#if defined(REFCLOCK) && defined(CLOCK_RIPENCC)
40106424Sroberto
41106424Sroberto#include "ntp_stdlib.h"
42106424Sroberto#include "ntpd.h"
43106424Sroberto#include "ntp_refclock.h"
44106424Sroberto#include "ntp_unixtime.h"
45106424Sroberto#include "ntp_io.h"
46106424Sroberto
47182007Sroberto#ifdef HAVE_PPSAPI
48182007Sroberto# include "ppsapi_timepps.h"
49182007Sroberto#endif
50106424Sroberto
51106424Sroberto/*
52106424Sroberto * Definitions
53106424Sroberto */
54106424Sroberto
55106424Sroberto/* we are on little endian */
56106424Sroberto#define BYTESWAP
57106424Sroberto
58106424Sroberto/*
59106424Sroberto * DEBUG statements: uncomment if necessary
60106424Sroberto */
61106424Sroberto/* #define DEBUG_NCC */ /* general debug statements */
62106424Sroberto/* #define DEBUG_PPS */ /* debug pps */
63106424Sroberto/* #define DEBUG_RAW */ /* print raw packets */
64106424Sroberto
65106424Sroberto#define TRIMBLE_OUTPUT_FUNC
66106424Sroberto#define TSIP_VERNUM "7.12a"
67106424Sroberto
68106424Sroberto#ifndef FALSE
69106424Sroberto#define FALSE 	(0)
70106424Sroberto#define TRUE 	(!FALSE)
71106424Sroberto#endif /* FALSE */
72106424Sroberto
73106424Sroberto#define GPS_PI 	(3.1415926535898)
74106424Sroberto#define GPS_C 		(299792458.)
75106424Sroberto#define	D2R		(GPS_PI/180.0)
76106424Sroberto#define	R2D		(180.0/GPS_PI)
77106424Sroberto#define WEEK 	(604800.)
78106424Sroberto#define MAXCHAN  (8)
79106424Sroberto
80106424Sroberto/* control characters for TSIP packets */
81106424Sroberto#define DLE 	(0x10)
82106424Sroberto#define ETX 	(0x03)
83106424Sroberto
84106424Sroberto#define MAX_RPTBUF (256)
85106424Sroberto
86106424Sroberto/* values of TSIPPKT.status */
87106424Sroberto#define TSIP_PARSED_EMPTY 	0
88106424Sroberto#define TSIP_PARSED_FULL 	1
89106424Sroberto#define TSIP_PARSED_DLE_1 	2
90106424Sroberto#define TSIP_PARSED_DATA 	3
91106424Sroberto#define TSIP_PARSED_DLE_2 	4
92106424Sroberto
93285612Sdelphij#define UTCF_UTC_AVAIL  (unsigned char) (1)     /* UTC available */
94106424Sroberto#define UTCF_LEAP_SCHD  (unsigned char) (1<<4)  /* Leap scheduled */
95106424Sroberto#define UTCF_LEAP_PNDG  (unsigned char) (1<<5)  /* Leap pending, will occur at end of day */
96106424Sroberto
97106424Sroberto#define DEVICE  "/dev/gps%d"	/* name of radio device */
98106424Sroberto#define PRECISION       (-9)    /* precision assumed (about 2 ms) */
99106424Sroberto#define PPS_PRECISION   (-20)	/* precision assumed (about 1 us) */
100106424Sroberto#define REFID           "GPS\0" /* reference id */
101106424Sroberto#define REFID_LEN	4
102106424Sroberto#define DESCRIPTION     "RIPE NCC GPS (Palisade)"	/* Description */
103106424Sroberto#define SPEED232        B9600   /* 9600 baud */
104106424Sroberto
105106424Sroberto#define NSAMPLES        3       /* stages of median filter */
106106424Sroberto
107106424Sroberto/* Structures */
108106424Sroberto
109106424Sroberto/* TSIP packets have the following structure, whether report or command. */
110106424Srobertotypedef struct {
111106424Sroberto	short
112285612Sdelphij	    counter,		/* counter */
113285612Sdelphij	    len;		/* size of buf; < MAX_RPTBUF unsigned chars */
114106424Sroberto	unsigned char
115285612Sdelphij	    status,		/* TSIP packet format/parse status */
116285612Sdelphij	    code,		/* TSIP code */
117285612Sdelphij	    buf[MAX_RPTBUF];	/* report or command string */
118106424Sroberto} TSIPPKT;
119106424Sroberto
120106424Sroberto/* TSIP binary data structures */
121106424Srobertotypedef struct {
122106424Sroberto	unsigned char
123285612Sdelphij	    t_oa_raw, SV_health;
124106424Sroberto	float
125285612Sdelphij	    e, t_oa, i_0, OMEGADOT, sqrt_A,
126285612Sdelphij	    OMEGA_0, omega, M_0, a_f0, a_f1,
127285612Sdelphij	    Axis, n, OMEGA_n, ODOT_n, t_zc;
128106424Sroberto	short
129285612Sdelphij	    weeknum, wn_oa;
130106424Sroberto} ALM_INFO;
131106424Sroberto
132285612Sdelphijtypedef struct {		/*  Almanac health page (25) parameters  */
133106424Sroberto	unsigned char
134285612Sdelphij	    WN_a, SV_health[32], t_oa;
135106424Sroberto} ALH_PARMS;
136106424Sroberto
137285612Sdelphijtypedef struct {		/*  Universal Coordinated Time (UTC) parms */
138106424Sroberto	double
139285612Sdelphij	    A_0;
140106424Sroberto	float
141285612Sdelphij	    A_1;
142106424Sroberto	short
143285612Sdelphij	    delta_t_LS;
144106424Sroberto	float
145285612Sdelphij	    t_ot;
146106424Sroberto	short
147285612Sdelphij	    WN_t, WN_LSF, DN, delta_t_LSF;
148106424Sroberto} UTC_INFO;
149106424Sroberto
150285612Sdelphijtypedef struct {		/*  Ionospheric info (float)  */
151106424Sroberto	float
152285612Sdelphij	    alpha_0, alpha_1, alpha_2, alpha_3,
153285612Sdelphij	    beta_0, beta_1, beta_2, beta_3;
154106424Sroberto} ION_INFO;
155106424Sroberto
156285612Sdelphijtypedef struct {		/*  Subframe 1 info (float)  */
157106424Sroberto	short
158285612Sdelphij	    weeknum;
159106424Sroberto	unsigned char
160285612Sdelphij	    codeL2, L2Pdata, SVacc_raw, SV_health;
161106424Sroberto	short
162285612Sdelphij	    IODC;
163106424Sroberto	float
164285612Sdelphij	    T_GD, t_oc, a_f2, a_f1, a_f0, SVacc;
165106424Sroberto} EPHEM_CLOCK;
166106424Sroberto
167285612Sdelphijtypedef	struct {		/*  Ephemeris info (float)  */
168106424Sroberto	unsigned char
169285612Sdelphij	    IODE, fit_interval;
170106424Sroberto	float
171285612Sdelphij	    C_rs, delta_n;
172106424Sroberto	double
173285612Sdelphij	    M_0;
174106424Sroberto	float
175285612Sdelphij	    C_uc;
176106424Sroberto	double
177285612Sdelphij	    e;
178106424Sroberto	float
179285612Sdelphij	    C_us;
180106424Sroberto	double
181285612Sdelphij	    sqrt_A;
182106424Sroberto	float
183285612Sdelphij	    t_oe, C_ic;
184106424Sroberto	double
185285612Sdelphij	    OMEGA_0;
186106424Sroberto	float
187285612Sdelphij	    C_is;
188106424Sroberto	double
189285612Sdelphij	    i_0;
190106424Sroberto	float
191285612Sdelphij	    C_rc;
192106424Sroberto	double
193285612Sdelphij	    omega;
194106424Sroberto	float
195285612Sdelphij	    OMEGADOT, IDOT;
196106424Sroberto	double
197285612Sdelphij	    Axis, n, r1me2, OMEGA_n, ODOT_n;
198106424Sroberto} EPHEM_ORBIT;
199106424Sroberto
200285612Sdelphijtypedef struct {		/* Navigation data structure */
201106424Sroberto	short
202285612Sdelphij	    sv_number;		/* SV number (0 = no entry) */
203106424Sroberto	float
204285612Sdelphij	    t_ephem;		/* time of ephemeris collection */
205106424Sroberto	EPHEM_CLOCK
206285612Sdelphij	    ephclk;		/* subframe 1 data */
207106424Sroberto	EPHEM_ORBIT
208285612Sdelphij	    ephorb;		/* ephemeris data */
209106424Sroberto} NAV_INFO;
210106424Sroberto
211106424Srobertotypedef struct {
212106424Sroberto	unsigned char
213285612Sdelphij	    bSubcode,
214285612Sdelphij	    operating_mode,
215285612Sdelphij	    dgps_mode,
216285612Sdelphij	    dyn_code,
217285612Sdelphij	    trackmode;
218106424Sroberto	float
219285612Sdelphij	    elev_mask,
220285612Sdelphij	    cno_mask,
221285612Sdelphij	    dop_mask,
222285612Sdelphij	    dop_switch;
223106424Sroberto	unsigned char
224285612Sdelphij	    dgps_age_limit;
225106424Sroberto} TSIP_RCVR_CFG;
226106424Sroberto
227106424Sroberto
228106424Sroberto#ifdef TRIMBLE_OUTPUT_FUNC
229106424Srobertostatic char
230285612Sdelphij        *dayname[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"},
231106424Sroberto	old_baudnum[] = {0, 1, 4, 5, 6, 8, 9, 11, 28, 12},
232106424Sroberto        *st_baud_text_app [] = {"", "", "  300", "  600", " 1200", " 2400",
233285612Sdelphij				" 4800", " 9600", "19200", "38400"},
234106424Sroberto	*old_parity_text[] = {"EVEN", "ODD", "", "", "NONE"},
235106424Sroberto	*parity_text [] = {"NONE", "ODD", "EVEN"},
236106424Sroberto	*old_input_ch[] = { "TSIP", "RTCM (6 of 8 bits)"},
237106424Sroberto	*old_output_ch[] = { "TSIP", "No output", "", "", "", "NMEA 0183"},
238106424Sroberto	*protocols_in_text[] = { "", "TSIP", "", ""},
239106424Sroberto	*protocols_out_text[] =	{ "", "TSIP", "NMEA"},
240106424Sroberto	*rcvr_port_text [] = { "Port A      ", "Port B      ", "Current Port"},
241106424Sroberto	*dyn_text [] = {"Unchanged", "Land", "Sea", "Air", "Static"},
242106424Sroberto	*NavModeText0xBB[] = {"automatic", "time only (0-D)", "", "2-D",
243285612Sdelphij			      "3-D", "", "", "OverDetermined Time"},
244106424Sroberto	*PPSTimeBaseText[] = {"GPS", "UTC", "USER"},
245106424Sroberto	*PPSPolarityText[] = {"Positive", "Negative"},
246106424Sroberto  	*MaskText[] = { "Almanac  ", "Ephemeris", "UTC      ", "Iono     ",
247285612Sdelphij			"GPS Msg  ", "Alm Hlth ", "Time Fix ", "SV Select",
248285612Sdelphij			"Ext Event", "Pos Fix  ", "Raw Meas "};
249106424Sroberto
250106424Sroberto#endif /* TRIMBLE_OUTPUT_FUNC */
251106424Sroberto
252106424Sroberto/*
253106424Sroberto * Unit control structure
254106424Sroberto */
255106424Srobertostruct ripencc_unit {
256106424Sroberto        int unit;                       /* unit number */
257106424Sroberto        int     pollcnt;                /* poll message counter */
258106424Sroberto        int     polled;                 /* Hand in a sample? */
259106424Sroberto        char leapdelta;                 /* delta of next leap event */
260106424Sroberto        unsigned char utcflags;         /* delta of next leap event */
261106424Sroberto        l_fp    tstamp;                 /* timestamp of last poll */
262106424Sroberto
263106424Sroberto        struct timespec ts;             /* last timestamp */
264106424Sroberto        pps_params_t pps_params;        /* pps parameters */
265106424Sroberto        pps_info_t pps_info;            /* last pps data */
266106424Sroberto        pps_handle_t handle;            /* pps handlebars */
267106424Sroberto
268106424Sroberto};
269106424Sroberto
270106424Sroberto
271106424Sroberto/*******************        PROTOYPES            *****************/
272106424Sroberto
273106424Sroberto/*  prototypes for report parsing primitives */
274106424Srobertoshort rpt_0x3D (TSIPPKT *rpt, unsigned char *tx_baud_index,
275285612Sdelphij		unsigned char *rx_baud_index, unsigned char *char_format_index,
276285612Sdelphij		unsigned char *stop_bits, unsigned char *tx_mode_index,
277285612Sdelphij		unsigned char *rx_mode_index);
278106424Srobertoshort rpt_0x40 (TSIPPKT *rpt, unsigned char *sv_prn, short *week_num,
279285612Sdelphij		float *t_zc, float *eccentricity, float *t_oa, float *i_0,
280285612Sdelphij		float *OMEGA_dot, float *sqrt_A, float *OMEGA_0, float *omega,
281285612Sdelphij		float *M_0);
282106424Srobertoshort rpt_0x41 (TSIPPKT *rpt, float *time_of_week, float *UTC_offset,
283285612Sdelphij		short *week_num);
284106424Srobertoshort rpt_0x42 (TSIPPKT *rpt, float ECEF_pos[3], float *time_of_fix);
285106424Srobertoshort rpt_0x43 (TSIPPKT *rpt, float ECEF_vel[3], float *freq_offset,
286285612Sdelphij		float *time_of_fix);
287106424Srobertoshort rpt_0x45 (TSIPPKT *rpt, unsigned char *major_nav_version,
288285612Sdelphij		unsigned char *minor_nav_version, unsigned char *nav_day,
289285612Sdelphij		unsigned char *nav_month, unsigned char *nav_year,
290285612Sdelphij		unsigned char *major_dsp_version, unsigned char *minor_dsp_version,
291285612Sdelphij		unsigned char *dsp_day, unsigned char *dsp_month,
292285612Sdelphij		unsigned char *dsp_year);
293106424Srobertoshort rpt_0x46 (TSIPPKT *rpt, unsigned char *status1, unsigned char *status2);
294106424Srobertoshort rpt_0x47 (TSIPPKT *rpt, unsigned char *nsvs, unsigned char *sv_prn,
295285612Sdelphij		float *snr);
296106424Srobertoshort rpt_0x48 (TSIPPKT *rpt, unsigned char *message);
297106424Srobertoshort rpt_0x49 (TSIPPKT *rpt, unsigned char *sv_health);
298106424Srobertoshort rpt_0x4A (TSIPPKT *rpt, float *lat, float *lon, float *alt,
299285612Sdelphij		float *clock_bias, float *time_of_fix);
300106424Srobertoshort rpt_0x4A_2 (TSIPPKT *rpt, float *alt, float *dummy,
301285612Sdelphij		  unsigned char *alt_flag);
302106424Srobertoshort rpt_0x4B (TSIPPKT *rpt, unsigned char *machine_id,
303285612Sdelphij		unsigned char *status3, unsigned char *status4);
304106424Srobertoshort rpt_0x4C (TSIPPKT *rpt, unsigned char *dyn_code, float *el_mask,
305285612Sdelphij		float *snr_mask, float *dop_mask, float *dop_switch);
306106424Srobertoshort rpt_0x4D (TSIPPKT *rpt, float *osc_offset);
307106424Srobertoshort rpt_0x4E (TSIPPKT *rpt, unsigned char *response);
308106424Srobertoshort rpt_0x4F (TSIPPKT *rpt, double *a0, float *a1, float *time_of_data,
309285612Sdelphij		short *dt_ls, short *wn_t, short *wn_lsf, short *dn, short *dt_lsf);
310106424Srobertoshort rpt_0x54 (TSIPPKT *rpt, float *clock_bias, float *freq_offset,
311285612Sdelphij		float *time_of_fix);
312106424Srobertoshort rpt_0x55 (TSIPPKT *rpt, unsigned char *pos_code, unsigned char *vel_code,
313285612Sdelphij		unsigned char *time_code, unsigned char *aux_code);
314106424Srobertoshort rpt_0x56 (TSIPPKT *rpt, float vel_ENU[3], float *freq_offset,
315285612Sdelphij		float *time_of_fix);
316106424Srobertoshort rpt_0x57 (TSIPPKT *rpt, unsigned char *source_code,
317285612Sdelphij		unsigned char *diag_code, short *week_num, float *time_of_fix);
318106424Srobertoshort rpt_0x58 (TSIPPKT *rpt, unsigned char *op_code, unsigned char *data_type,
319285612Sdelphij		unsigned char *sv_prn, unsigned char *data_length,
320285612Sdelphij		unsigned char *data_packet);
321106424Srobertoshort rpt_0x59 (TSIPPKT *rpt, unsigned char *code_type,
322285612Sdelphij		unsigned char status_code[32]);
323106424Srobertoshort rpt_0x5A (TSIPPKT *rpt, unsigned char *sv_prn, float *sample_length,
324285612Sdelphij		float *signal_level, float *code_phase, float *Doppler,
325285612Sdelphij		double *time_of_fix);
326106424Srobertoshort rpt_0x5B (TSIPPKT *rpt, unsigned char *sv_prn, unsigned char *sv_health,
327285612Sdelphij		unsigned char *sv_iode, unsigned char *fit_interval_flag,
328285612Sdelphij		float *time_of_collection, float *time_of_eph, float *sv_accy);
329106424Srobertoshort rpt_0x5C (TSIPPKT *rpt, unsigned char *sv_prn, unsigned char *slot,
330285612Sdelphij		unsigned char *chan, unsigned char *acq_flag, unsigned char *eph_flag,
331285612Sdelphij		float *signal_level, float *time_of_last_msmt, float *elev,
332285612Sdelphij		float *azim, unsigned char *old_msmt_flag,
333285612Sdelphij		unsigned char *integer_msec_flag, unsigned char *bad_data_flag,
334285612Sdelphij		unsigned char *data_collect_flag);
335106424Srobertoshort rpt_0x6D (TSIPPKT *rpt, unsigned char *manual_mode, unsigned char *nsvs,
336285612Sdelphij		unsigned char *ndim, unsigned char sv_prn[], float *pdop,
337285612Sdelphij		float *hdop, float *vdop, float *tdop);
338106424Srobertoshort rpt_0x82 (TSIPPKT *rpt, unsigned char *diff_mode);
339106424Srobertoshort rpt_0x83 (TSIPPKT *rpt, double ECEF_pos[3], double *clock_bias,
340285612Sdelphij		float *time_of_fix);
341106424Srobertoshort rpt_0x84 (TSIPPKT *rpt, double *lat, double *lon, double *alt,
342285612Sdelphij		double *clock_bias, float *time_of_fix);
343106424Srobertoshort rpt_Paly0xBB(TSIPPKT *rpt, TSIP_RCVR_CFG *TsipxBB);
344106424Srobertoshort rpt_0xBC   (TSIPPKT *rpt, unsigned char *port_num,
345285612Sdelphij		  unsigned char *in_baud, unsigned char *out_baud,
346285612Sdelphij		  unsigned char *data_bits, unsigned char *parity,
347285612Sdelphij		  unsigned char *stop_bits, unsigned char *flow_control,
348285612Sdelphij		  unsigned char *protocols_in, unsigned char *protocols_out,
349285612Sdelphij		  unsigned char *reserved);
350106424Sroberto
351106424Sroberto/* prototypes for superpacket parsers */
352106424Sroberto
353106424Srobertoshort rpt_0x8F0B (TSIPPKT *rpt, unsigned short *event, double *tow,
354285612Sdelphij		  unsigned char *date, unsigned char *month, short *year,
355285612Sdelphij		  unsigned char *dim_mode, short *utc_offset, double *bias, double *drift,
356285612Sdelphij		  float *bias_unc, float *dr_unc, double *lat, double *lon, double *alt,
357285612Sdelphij		  char sv_id[8]);
358106424Srobertoshort rpt_0x8F14 (TSIPPKT *rpt, short *datum_idx, double datum_coeffs[5]);
359106424Srobertoshort rpt_0x8F15 (TSIPPKT *rpt, short *datum_idx, double datum_coeffs[5]);
360106424Srobertoshort rpt_0x8F20 (TSIPPKT *rpt, unsigned char *info, double *lat,
361285612Sdelphij		  double *lon, double *alt, double vel_enu[], double *time_of_fix,
362285612Sdelphij		  short *week_num, unsigned char *nsvs, unsigned char sv_prn[],
363285612Sdelphij		  short sv_IODC[], short *datum_index);
364106424Srobertoshort rpt_0x8F41 (TSIPPKT *rpt, unsigned char *bSearchRange,
365285612Sdelphij		  unsigned char *bBoardOptions, unsigned long *iiSerialNumber,
366285612Sdelphij		  unsigned char *bBuildYear, unsigned char *bBuildMonth,
367285612Sdelphij		  unsigned char *bBuildDay, unsigned char *bBuildHour,
368285612Sdelphij		  float *fOscOffset, unsigned short *iTestCodeId);
369106424Srobertoshort rpt_0x8F42 (TSIPPKT *rpt, unsigned char *bProdOptionsPre,
370285612Sdelphij		  unsigned char *bProdNumberExt, unsigned short *iCaseSerialNumberPre,
371285612Sdelphij		  unsigned long *iiCaseSerialNumber, unsigned long *iiProdNumber,
372285612Sdelphij		  unsigned short *iPremiumOptions, unsigned short *iMachineID,
373285612Sdelphij		  unsigned short *iKey);
374106424Srobertoshort rpt_0x8F45 (TSIPPKT *rpt, unsigned char *bSegMask);
375106424Srobertoshort rpt_0x8F4A_16 (TSIPPKT *rpt, unsigned char *pps_enabled,
376285612Sdelphij		     unsigned char *pps_timebase, unsigned char *pos_polarity,
377285612Sdelphij		     double *pps_offset, float *bias_unc_threshold);
378106424Srobertoshort rpt_0x8F4B (TSIPPKT *rpt, unsigned long *decorr_max);
379106424Srobertoshort rpt_0x8F4D (TSIPPKT *rpt, unsigned long *event_mask);
380106424Srobertoshort rpt_0x8FA5 (TSIPPKT *rpt, unsigned char *spktmask);
381106424Srobertoshort rpt_0x8FAD (TSIPPKT *rpt, unsigned short *COUNT, double *FracSec,
382285612Sdelphij		  unsigned char *Hour, unsigned char *Minute, unsigned char *Second,
383285612Sdelphij		  unsigned char *Day, unsigned char *Month, unsigned short *Year,
384285612Sdelphij		  unsigned char *Status, unsigned char *Flags);
385106424Sroberto
386106424Sroberto/**/
387106424Sroberto/* prototypes for command-encode primitives with suffix convention:  */
388106424Sroberto/* c = clear, s = set, q = query, e = enable, d = disable            */
389106424Srobertovoid cmd_0x1F  (TSIPPKT *cmd);
390106424Srobertovoid cmd_0x26  (TSIPPKT *cmd);
391106424Srobertovoid cmd_0x2F  (TSIPPKT *cmd);
392106424Srobertovoid cmd_0x35s (TSIPPKT *cmd, unsigned char pos_code, unsigned char vel_code,
393285612Sdelphij		unsigned char time_code, unsigned char opts_code);
394106424Srobertovoid cmd_0x3C  (TSIPPKT *cmd, unsigned char sv_prn);
395106424Srobertovoid cmd_0x3Ds (TSIPPKT *cmd, unsigned char baud_out, unsigned char baud_inp,
396285612Sdelphij		unsigned char char_code, unsigned char stopbitcode,
397285612Sdelphij		unsigned char output_mode, unsigned char input_mode);
398106424Srobertovoid cmd_0xBBq (TSIPPKT *cmd, unsigned char subcode) ;
399106424Sroberto
400106424Sroberto/* prototypes 8E commands */
401106424Srobertovoid cmd_0x8E0Bq (TSIPPKT *cmd);
402106424Srobertovoid cmd_0x8E41q (TSIPPKT *cmd);
403106424Srobertovoid cmd_0x8E42q (TSIPPKT *cmd);
404106424Srobertovoid cmd_0x8E4Aq (TSIPPKT *cmd);
405106424Srobertovoid cmd_0x8E4As (TSIPPKT *cmd, unsigned char PPSOnOff, unsigned char TimeBase,
406285612Sdelphij		  unsigned char Polarity, double PPSOffset, float Uncertainty);
407106424Srobertovoid cmd_0x8E4Bq (TSIPPKT *cmd);
408106424Srobertovoid cmd_0x8E4Ds (TSIPPKT *cmd, unsigned long AutoOutputMask);
409106424Srobertovoid cmd_0x8EADq (TSIPPKT *cmd);
410106424Sroberto
411106424Sroberto/* header/source border XXXXXXXXXXXXXXXXXXXXXXXXXX */
412106424Sroberto
413106424Sroberto/* Trimble parse functions */
414285612Sdelphijstatic 	int	parse0x8FAD	(TSIPPKT *, struct peer *);
415285612Sdelphijstatic 	int	parse0x8F0B	(TSIPPKT *, struct peer *);
416106424Sroberto#ifdef TRIMBLE_OUTPUT_FUNC
417285612Sdelphijstatic 	int	parseany	(TSIPPKT *, struct peer *);
418285612Sdelphijstatic 	void	TranslateTSIPReportToText	(TSIPPKT *, char *);
419106424Sroberto#endif /* TRIMBLE_OUTPUT_FUNC */
420285612Sdelphijstatic 	int	parse0x5C	(TSIPPKT *, struct peer *);
421285612Sdelphijstatic 	int	parse0x4F	(TSIPPKT *, struct peer *);
422285612Sdelphijstatic	void	tsip_input_proc	(TSIPPKT *, int);
423106424Sroberto
424106424Sroberto/* Trimble helper functions */
425285612Sdelphijstatic	void	bPutFloat 	(float *, unsigned char *);
426285612Sdelphijstatic	void	bPutDouble 	(double *, unsigned char *);
427285612Sdelphijstatic	void	bPutULong 	(unsigned long *, unsigned char *);
428285612Sdelphijstatic	int	print_msg_table_header	(int rptcode, char *HdrStr, int force);
429285612Sdelphijstatic	char *	show_time	(float time_of_week);
430106424Sroberto
431106424Sroberto/* RIPE NCC functions */
432285612Sdelphijstatic	void	ripencc_control	(int, const struct refclockstat *,
433285612Sdelphij				 struct refclockstat *, struct peer *);
434285612Sdelphijstatic	int	ripencc_ppsapi	(struct peer *, int, int);
435285612Sdelphijstatic	int	ripencc_get_pps_ts	(struct ripencc_unit *, l_fp *);
436285612Sdelphijstatic	int	ripencc_start	(int, struct peer *);
437285612Sdelphijstatic 	void	ripencc_shutdown	(int, struct peer *);
438285612Sdelphijstatic 	void	ripencc_poll	(int, struct peer *);
439285612Sdelphijstatic 	void	ripencc_send	(struct peer *, TSIPPKT spt);
440285612Sdelphijstatic 	void	ripencc_receive	(struct recvbuf *);
441106424Sroberto
442106424Sroberto/* fill in reflock structure for our clock */
443106424Srobertostruct refclock refclock_ripencc = {
444106424Sroberto	ripencc_start,		/* start up driver */
445106424Sroberto	ripencc_shutdown,	/* shut down driver */
446106424Sroberto	ripencc_poll,		/* transmit poll message */
447106424Sroberto	ripencc_control,	/* control function */
448106424Sroberto	noentry,		/* initialize driver */
449106424Sroberto	noentry,		/* debug info */
450106424Sroberto	NOFLAGS			/* clock flags */
451106424Sroberto};
452106424Sroberto
453106424Sroberto/*
454106424Sroberto *  Tables to compute the ddd of year form icky dd/mm timecode. Viva la
455106424Sroberto *  leap.
456106424Sroberto */
457106424Srobertostatic int day1tab[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
458106424Srobertostatic int day2tab[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
459106424Sroberto
460106424Sroberto
461106424Sroberto/*
462106424Sroberto * ripencc_start - open the GPS devices and initialize data for processing
463106424Sroberto */
464106424Srobertostatic int
465106424Srobertoripencc_start(int unit, struct peer *peer)
466106424Sroberto{
467106424Sroberto	register struct ripencc_unit *up;
468106424Sroberto	struct refclockproc *pp;
469106424Sroberto	char device[40];
470106424Sroberto	int fd;
471106424Sroberto	struct termios tio;
472106424Sroberto	TSIPPKT spt;
473106424Sroberto
474285612Sdelphij	pp = peer->procptr;
475285612Sdelphij
476106424Sroberto	/*
477106424Sroberto	 * Open serial port
478106424Sroberto	 */
479106424Sroberto	(void)snprintf(device, sizeof(device), DEVICE, unit);
480285612Sdelphij	fd = refclock_open(device, SPEED232, LDISC_RAW);
481285612Sdelphij	if (fd <= 0) {
482285612Sdelphij		pp->io.fd = -1;
483106424Sroberto		return (0);
484285612Sdelphij	}
485106424Sroberto
486285612Sdelphij	pp->io.fd = fd;
487285612Sdelphij
488106424Sroberto	/* from refclock_palisade.c */
489106424Sroberto	if (tcgetattr(fd, &tio) < 0) {
490106424Sroberto		msyslog(LOG_ERR, "Palisade(%d) tcgetattr(fd, &tio): %m",unit);
491106424Sroberto		return (0);
492106424Sroberto	}
493106424Sroberto
494106424Sroberto	/*
495106424Sroberto	 * set flags
496106424Sroberto	 */
497106424Sroberto	tio.c_cflag |= (PARENB|PARODD);
498106424Sroberto	tio.c_iflag &= ~ICRNL;
499106424Sroberto	if (tcsetattr(fd, TCSANOW, &tio) == -1) {
500106424Sroberto		msyslog(LOG_ERR, "Palisade(%d) tcsetattr(fd, &tio): %m",unit);
501106424Sroberto		return (0);
502106424Sroberto	}
503106424Sroberto
504106424Sroberto	/*
505106424Sroberto	 * Allocate and initialize unit structure
506106424Sroberto	 */
507285612Sdelphij	up = emalloc_zero(sizeof(*up));
508285612Sdelphij
509106424Sroberto	pp->io.clock_recv = ripencc_receive;
510285612Sdelphij	pp->io.srcclock = peer;
511106424Sroberto	pp->io.datalen = 0;
512106424Sroberto	if (!io_addclock(&pp->io)) {
513285612Sdelphij		pp->io.fd = -1;
514285612Sdelphij		close(fd);
515106424Sroberto		free(up);
516106424Sroberto		return (0);
517106424Sroberto	}
518285612Sdelphij	pp->unitptr = up;
519106424Sroberto
520106424Sroberto	/*
521106424Sroberto	 * Initialize miscellaneous variables
522106424Sroberto	 */
523106424Sroberto	peer->precision = PRECISION;
524106424Sroberto	pp->clockdesc = DESCRIPTION;
525106424Sroberto	memcpy((char *)&pp->refid, REFID, REFID_LEN);
526106424Sroberto	up->pollcnt = 2;
527106424Sroberto	up->unit = unit;
528106424Sroberto	up->leapdelta = 0;
529106424Sroberto	up->utcflags = 0;
530106424Sroberto
531106424Sroberto	/*
532106424Sroberto	 * Initialize the Clock
533106424Sroberto	 */
534106424Sroberto
535106424Sroberto	/* query software versions */
536106424Sroberto	cmd_0x1F(&spt);
537106424Sroberto	ripencc_send(peer, spt);
538106424Sroberto
539106424Sroberto	/* query receiver health */
540106424Sroberto	cmd_0x26(&spt);
541106424Sroberto	ripencc_send(peer, spt);
542106424Sroberto
543106424Sroberto	/* query serial numbers */
544106424Sroberto	cmd_0x8E42q(&spt);
545106424Sroberto	ripencc_send(peer, spt);
546106424Sroberto
547106424Sroberto	/* query manuf params */
548106424Sroberto	cmd_0x8E41q(&spt);
549106424Sroberto	ripencc_send(peer, spt);
550106424Sroberto
551106424Sroberto	/* i/o opts */ /* trimble manual page A30 */
552106424Sroberto	cmd_0x35s(&spt,
553285612Sdelphij		  0x1C, 	/* position */
554285612Sdelphij		  0x00, 	/* velocity */
555285612Sdelphij		  0x05, 	/* timing */
556285612Sdelphij		  0x0a); 	/* auxilary */
557106424Sroberto	ripencc_send(peer, spt);
558106424Sroberto
559106424Sroberto	/* turn off port A */
560106424Sroberto	cmd_0x3Ds (&spt,
561285612Sdelphij		   0x0B,	/* baud_out */
562285612Sdelphij		   0x0B,	/* baud_inp */
563285612Sdelphij		   0x07,	/* char_code */
564285612Sdelphij		   0x07,	/* stopbitcode */
565285612Sdelphij		   0x01,	/* output_mode */
566285612Sdelphij		   0x00);	/* input_mode */
567106424Sroberto	ripencc_send(peer, spt);
568106424Sroberto
569106424Sroberto	/* set i/o options */
570106424Sroberto	cmd_0x8E4As (&spt,
571285612Sdelphij		     0x01,	/* PPS on */
572285612Sdelphij		     0x01,	/* Timebase UTC */
573285612Sdelphij		     0x00,	/* polarity positive */
574285612Sdelphij		     0.,	/* 100 ft. cable XXX make flag */
575285612Sdelphij		     1e-6 * GPS_C); 	/* turn of biasuncert. > (1us) */
576106424Sroberto	ripencc_send(peer,spt);
577106424Sroberto
578106424Sroberto	/* all outomatic packet output off */
579106424Sroberto	cmd_0x8E4Ds(&spt,
580285612Sdelphij		    0x00000000); /* AutoOutputMask */
581106424Sroberto	ripencc_send(peer, spt);
582106424Sroberto
583106424Sroberto	cmd_0xBBq (&spt,
584285612Sdelphij		   0x00);	/* query primary configuration */
585106424Sroberto	ripencc_send(peer,spt);
586106424Sroberto
587106424Sroberto
588106424Sroberto	/* query PPS parameters */
589285612Sdelphij	cmd_0x8E4Aq (&spt);	/* query PPS params */
590106424Sroberto	ripencc_send(peer,spt);
591106424Sroberto
592106424Sroberto	/* query survey limit */
593285612Sdelphij	cmd_0x8E4Bq (&spt);	/* query survey limit */
594106424Sroberto	ripencc_send(peer,spt);
595106424Sroberto
596106424Sroberto#ifdef DEBUG_NCC
597106424Sroberto	if (debug)
598106424Sroberto		printf("ripencc_start: success\n");
599106424Sroberto#endif /* DEBUG_NCC */
600106424Sroberto
601106424Sroberto	/*
602106424Sroberto	 * Start the PPSAPI interface if it is there. Default to use
603106424Sroberto	 * the assert edge and do not enable the kernel hardpps.
604106424Sroberto	 */
605106424Sroberto	if (time_pps_create(fd, &up->handle) < 0) {
606106424Sroberto		up->handle = 0;
607106424Sroberto		msyslog(LOG_ERR, "refclock_ripencc: time_pps_create failed: %m");
608106424Sroberto		return (1);
609106424Sroberto	}
610106424Sroberto
611132451Sroberto	return(ripencc_ppsapi(peer, 0, 0));
612106424Sroberto}
613106424Sroberto
614106424Sroberto/*
615106424Sroberto * ripencc_control - fudge control
616106424Sroberto */
617106424Srobertostatic void
618106424Srobertoripencc_control(
619106424Sroberto	int unit,		/* unit (not used) */
620285612Sdelphij	const struct refclockstat *in, /* input parameters (not used) */
621106424Sroberto	struct refclockstat *out, /* output parameters (not used) */
622106424Sroberto	struct peer *peer	/* peer structure pointer */
623106424Sroberto	)
624106424Sroberto{
625106424Sroberto	struct refclockproc *pp;
626106424Sroberto
627106424Sroberto#ifdef DEBUG_NCC
628106424Sroberto	msyslog(LOG_INFO,"%s()",__FUNCTION__);
629106424Sroberto#endif /* DEBUG_NCC */
630106424Sroberto
631106424Sroberto	pp = peer->procptr;
632106424Sroberto	ripencc_ppsapi(peer, pp->sloppyclockflag & CLK_FLAG2,
633285612Sdelphij		       pp->sloppyclockflag & CLK_FLAG3);
634106424Sroberto}
635106424Sroberto
636106424Sroberto
637106424Sroberto/*
638106424Sroberto * Initialize PPSAPI
639106424Sroberto */
640106424Srobertoint
641106424Srobertoripencc_ppsapi(
642106424Sroberto	struct peer *peer,	/* peer structure pointer */
643106424Sroberto	int enb_clear,		/* clear enable */
644106424Sroberto	int enb_hardpps		/* hardpps enable */
645106424Sroberto	)
646106424Sroberto{
647106424Sroberto	struct refclockproc *pp;
648106424Sroberto	struct ripencc_unit *up;
649106424Sroberto	int capability;
650106424Sroberto
651106424Sroberto	pp = peer->procptr;
652285612Sdelphij	up = pp->unitptr;
653106424Sroberto	if (time_pps_getcap(up->handle, &capability) < 0) {
654106424Sroberto		msyslog(LOG_ERR,
655285612Sdelphij			"refclock_ripencc: time_pps_getcap failed: %m");
656106424Sroberto		return (0);
657106424Sroberto	}
658106424Sroberto	memset(&up->pps_params, 0, sizeof(pps_params_t));
659106424Sroberto	if (enb_clear)
660106424Sroberto		up->pps_params.mode = capability & PPS_CAPTURECLEAR;
661106424Sroberto	else
662106424Sroberto		up->pps_params.mode = capability & PPS_CAPTUREASSERT;
663106424Sroberto	if (!up->pps_params.mode) {
664106424Sroberto		msyslog(LOG_ERR,
665285612Sdelphij			"refclock_ripencc: invalid capture edge %d",
666285612Sdelphij			!enb_clear);
667106424Sroberto		return (0);
668106424Sroberto	}
669106424Sroberto	up->pps_params.mode |= PPS_TSFMT_TSPEC;
670106424Sroberto	if (time_pps_setparams(up->handle, &up->pps_params) < 0) {
671106424Sroberto		msyslog(LOG_ERR,
672285612Sdelphij			"refclock_ripencc: time_pps_setparams failed: %m");
673106424Sroberto		return (0);
674106424Sroberto	}
675106424Sroberto	if (enb_hardpps) {
676106424Sroberto		if (time_pps_kcbind(up->handle, PPS_KC_HARDPPS,
677106424Sroberto				    up->pps_params.mode & ~PPS_TSFMT_TSPEC,
678106424Sroberto				    PPS_TSFMT_TSPEC) < 0) {
679106424Sroberto			msyslog(LOG_ERR,
680285612Sdelphij				"refclock_ripencc: time_pps_kcbind failed: %m");
681106424Sroberto			return (0);
682106424Sroberto		}
683285612Sdelphij		hardpps_enable = 1;
684106424Sroberto	}
685106424Sroberto	peer->precision = PPS_PRECISION;
686106424Sroberto
687106424Sroberto#if DEBUG_NCC
688106424Sroberto	if (debug) {
689106424Sroberto		time_pps_getparams(up->handle, &up->pps_params);
690106424Sroberto		printf(
691285612Sdelphij			"refclock_ripencc: capability 0x%x version %d mode 0x%x kern %d\n",
692285612Sdelphij			capability, up->pps_params.api_version,
693285612Sdelphij			up->pps_params.mode, enb_hardpps);
694106424Sroberto	}
695106424Sroberto#endif /* DEBUG_NCC */
696106424Sroberto
697106424Sroberto	return (1);
698106424Sroberto}
699106424Sroberto
700106424Sroberto/*
701106424Sroberto * This function is called every 64 seconds from ripencc_receive
702106424Sroberto * It will fetch the pps time
703106424Sroberto *
704106424Sroberto * Return 0 on failure and 1 on success.
705106424Sroberto */
706106424Srobertostatic int
707106424Srobertoripencc_get_pps_ts(
708106424Sroberto	struct ripencc_unit *up,
709106424Sroberto	l_fp *tsptr
710106424Sroberto	)
711106424Sroberto{
712106424Sroberto	pps_info_t pps_info;
713106424Sroberto	struct timespec timeout, ts;
714106424Sroberto	double dtemp;
715106424Sroberto	l_fp tstmp;
716106424Sroberto
717106424Sroberto#ifdef DEBUG_PPS
718285612Sdelphij	msyslog(LOG_INFO,"ripencc_get_pps_ts");
719106424Sroberto#endif /* DEBUG_PPS */
720106424Sroberto
721106424Sroberto
722106424Sroberto	/*
723106424Sroberto	 * Convert the timespec nanoseconds field to ntp l_fp units.
724106424Sroberto	 */
725106424Sroberto	if (up->handle == 0)
726106424Sroberto		return (0);
727106424Sroberto	timeout.tv_sec = 0;
728106424Sroberto	timeout.tv_nsec = 0;
729106424Sroberto	memcpy(&pps_info, &up->pps_info, sizeof(pps_info_t));
730106424Sroberto	if (time_pps_fetch(up->handle, PPS_TSFMT_TSPEC, &up->pps_info,
731285612Sdelphij			   &timeout) < 0)
732106424Sroberto		return (0);
733106424Sroberto	if (up->pps_params.mode & PPS_CAPTUREASSERT) {
734106424Sroberto		if (pps_info.assert_sequence ==
735106424Sroberto		    up->pps_info.assert_sequence)
736106424Sroberto			return (0);
737106424Sroberto		ts = up->pps_info.assert_timestamp;
738106424Sroberto	} else if (up->pps_params.mode & PPS_CAPTURECLEAR) {
739106424Sroberto		if (pps_info.clear_sequence ==
740106424Sroberto		    up->pps_info.clear_sequence)
741106424Sroberto			return (0);
742106424Sroberto		ts = up->pps_info.clear_timestamp;
743106424Sroberto	} else {
744106424Sroberto		return (0);
745106424Sroberto	}
746106424Sroberto	if ((up->ts.tv_sec == ts.tv_sec) && (up->ts.tv_nsec == ts.tv_nsec))
747106424Sroberto		return (0);
748106424Sroberto	up->ts = ts;
749106424Sroberto
750106424Sroberto	tstmp.l_ui = ts.tv_sec + JAN_1970;
751106424Sroberto	dtemp = ts.tv_nsec * FRAC / 1e9;
752106424Sroberto	tstmp.l_uf = (u_int32)dtemp;
753106424Sroberto
754106424Sroberto#ifdef DEBUG_PPS
755285612Sdelphij	msyslog(LOG_INFO,"ts.tv_sec: %d",(int)ts.tv_sec);
756285612Sdelphij	msyslog(LOG_INFO,"ts.tv_nsec: %ld",ts.tv_nsec);
757106424Sroberto#endif /* DEBUG_PPS */
758106424Sroberto
759106424Sroberto	*tsptr = tstmp;
760106424Sroberto	return (1);
761106424Sroberto}
762106424Sroberto
763106424Sroberto/*
764106424Sroberto * ripencc_shutdown - shut down a GPS clock
765106424Sroberto */
766106424Srobertostatic void
767106424Srobertoripencc_shutdown(int unit, struct peer *peer)
768106424Sroberto{
769106424Sroberto	register struct ripencc_unit *up;
770106424Sroberto	struct refclockproc *pp;
771106424Sroberto
772106424Sroberto	pp = peer->procptr;
773285612Sdelphij	up = pp->unitptr;
774106424Sroberto
775285612Sdelphij	if (up != NULL) {
776285612Sdelphij		if (up->handle != 0)
777285612Sdelphij			time_pps_destroy(up->handle);
778285612Sdelphij		free(up);
779285612Sdelphij	}
780285612Sdelphij	if (-1 != pp->io.fd)
781285612Sdelphij		io_closeclock(&pp->io);
782106424Sroberto
783285612Sdelphij	return;
784106424Sroberto}
785106424Sroberto
786106424Sroberto/*
787106424Sroberto * ripencc_poll - called by the transmit procedure
788106424Sroberto */
789106424Srobertostatic void
790106424Srobertoripencc_poll(int unit, struct peer *peer)
791106424Sroberto{
792106424Sroberto	register struct ripencc_unit *up;
793106424Sroberto	struct refclockproc *pp;
794106424Sroberto	TSIPPKT spt;
795106424Sroberto
796106424Sroberto#ifdef DEBUG_NCC
797106424Sroberto	if (debug)
798106424Sroberto		fprintf(stderr, "ripencc_poll(%d)\n", unit);
799106424Sroberto#endif /* DEBUG_NCC */
800106424Sroberto	pp = peer->procptr;
801285612Sdelphij	up = pp->unitptr;
802106424Sroberto	if (up->pollcnt == 0)
803106424Sroberto		refclock_report(peer, CEVNT_TIMEOUT);
804106424Sroberto	else
805106424Sroberto		up->pollcnt--;
806106424Sroberto
807106424Sroberto	pp->polls++;
808106424Sroberto	up->polled = 1;
809106424Sroberto
810106424Sroberto	/* poll for UTC superpacket */
811106424Sroberto	cmd_0x8EADq (&spt);
812106424Sroberto	ripencc_send(peer,spt);
813106424Sroberto}
814106424Sroberto
815106424Sroberto/*
816106424Sroberto * ripencc_send - send message to clock
817106424Sroberto * use the structures being created by the trimble functions!
818106424Sroberto * makes the code more readable/clean
819106424Sroberto */
820106424Srobertostatic void
821106424Srobertoripencc_send(struct peer *peer, TSIPPKT spt)
822106424Sroberto{
823106424Sroberto	unsigned char *ip, *op;
824106424Sroberto	unsigned char obuf[512];
825106424Sroberto
826106424Sroberto#ifdef DEBUG_RAW
827106424Sroberto	{
828106424Sroberto		register struct ripencc_unit *up;
829106424Sroberto		register struct refclockproc *pp;
830106424Sroberto
831106424Sroberto		pp = peer->procptr;
832285612Sdelphij		up = pp->unitptr;
833106424Sroberto		if (debug)
834106424Sroberto			printf("ripencc_send(%d, %02X)\n", up->unit, cmd);
835106424Sroberto	}
836106424Sroberto#endif /* DEBUG_RAW */
837106424Sroberto
838106424Sroberto	ip = spt.buf;
839106424Sroberto	op = obuf;
840106424Sroberto
841106424Sroberto	*op++ = 0x10;
842106424Sroberto	*op++ = spt.code;
843106424Sroberto
844106424Sroberto	while (spt.len--) {
845106424Sroberto		if (op-obuf > sizeof(obuf)-5) {
846106424Sroberto			msyslog(LOG_ERR, "ripencc_send obuf overflow!");
847106424Sroberto			refclock_report(peer, CEVNT_FAULT);
848106424Sroberto			return;
849106424Sroberto		}
850106424Sroberto
851285612Sdelphij		if (*ip == 0x10) /* byte stuffing */
852106424Sroberto			*op++ = 0x10;
853106424Sroberto		*op++ = *ip++;
854106424Sroberto	}
855106424Sroberto
856106424Sroberto	*op++ = 0x10;
857106424Sroberto	*op++ = 0x03;
858106424Sroberto
859106424Sroberto#ifdef DEBUG_RAW
860106424Sroberto	if (debug) { /* print raw packet */
861106424Sroberto		unsigned char *cp;
862106424Sroberto		int i;
863106424Sroberto
864106424Sroberto		printf("ripencc_send: len %d\n", op-obuf);
865106424Sroberto		for (i=1, cp=obuf; cp<op; i++, cp++) {
866106424Sroberto			printf(" %02X", *cp);
867106424Sroberto			if (i%10 == 0)
868106424Sroberto				printf("\n");
869106424Sroberto		}
870106424Sroberto		printf("\n");
871106424Sroberto	}
872106424Sroberto#endif /* DEBUG_RAW */
873106424Sroberto
874106424Sroberto	if (write(peer->procptr->io.fd, obuf, op-obuf) == -1) {
875285612Sdelphij		refclock_report(peer, CEVNT_FAULT);
876106424Sroberto	}
877106424Sroberto}
878106424Sroberto
879106424Sroberto/*
880106424Sroberto * ripencc_receive()
881106424Sroberto *
882106424Sroberto * called when a packet is received on the serial port
883106424Sroberto * takes care of further processing
884106424Sroberto *
885106424Sroberto */
886106424Srobertostatic void
887106424Srobertoripencc_receive(struct recvbuf *rbufp)
888106424Sroberto{
889106424Sroberto	register struct ripencc_unit *up;
890106424Sroberto	register struct refclockproc *pp;
891106424Sroberto	struct peer *peer;
892285612Sdelphij	static TSIPPKT rpt;	/* for current incoming TSIP report */
893285612Sdelphij	TSIPPKT spt;		/* send packet */
894106424Sroberto	int ns_since_pps;
895106424Sroberto	int i;
896106424Sroberto	char *cp;
897285612Sdelphij	/* these variables hold data until we decide it's worth keeping */
898106424Sroberto	char    rd_lastcode[BMAX];
899106424Sroberto	l_fp    rd_tmp;
900106424Sroberto	u_short rd_lencode;
901106424Sroberto
902106424Sroberto	/* msyslog(LOG_INFO, "%s",__FUNCTION__); */
903106424Sroberto
904106424Sroberto	/*
905106424Sroberto	 * Initialize pointers and read the timecode and timestamp
906106424Sroberto	 */
907285612Sdelphij	peer = rbufp->recv_peer;
908106424Sroberto	pp = peer->procptr;
909285612Sdelphij	up = pp->unitptr;
910106424Sroberto	rd_lencode = refclock_gtlin(rbufp, rd_lastcode, BMAX, &rd_tmp);
911106424Sroberto
912106424Sroberto#ifdef DEBUG_RAW
913106424Sroberto	if (debug)
914106424Sroberto		fprintf(stderr, "ripencc_receive(%d)\n", up->unit);
915106424Sroberto#endif /* DEBUG_RAW */
916106424Sroberto
917106424Sroberto#ifdef DEBUG_RAW
918285612Sdelphij	if (debug) {		/* print raw packet */
919106424Sroberto		int i;
920106424Sroberto		unsigned char *cp;
921106424Sroberto
922106424Sroberto		printf("ripencc_receive: len %d\n", rbufp->recv_length);
923285612Sdelphij		for (i=1, cp=(char*)&rbufp->recv_space;
924285612Sdelphij		     i <= rbufp->recv_length;
925285612Sdelphij		     i++, cp++) {
926106424Sroberto			printf(" %02X", *cp);
927106424Sroberto			if (i%10 == 0)
928106424Sroberto				printf("\n");
929106424Sroberto		}
930106424Sroberto		printf("\n");
931106424Sroberto	}
932106424Sroberto#endif /* DEBUG_RAW */
933106424Sroberto
934106424Sroberto	cp = (char*) &rbufp->recv_space;
935106424Sroberto	i=rbufp->recv_length;
936106424Sroberto
937285612Sdelphij	while (i--) {		/* loop over received chars */
938106424Sroberto
939106424Sroberto		tsip_input_proc(&rpt, (unsigned char) *cp++);
940106424Sroberto
941106424Sroberto		if (rpt.status != TSIP_PARSED_FULL)
942106424Sroberto			continue;
943106424Sroberto
944106424Sroberto		switch (rpt.code) {
945106424Sroberto
946285612Sdelphij		    case 0x8F:	/* superpacket */
947106424Sroberto
948106424Sroberto			switch (rpt.buf[0]) {
949106424Sroberto
950285612Sdelphij			    case 0xAD:	/* UTC Time */
951106424Sroberto				/*
952285612Sdelphij				** When polling on port B the timecode is
953285612Sdelphij				** the time of the previous PPS.  If we
954285612Sdelphij				** completed receiving the packet less than
955285612Sdelphij				** 150ms after the turn of the second, it
956285612Sdelphij				** may have the code of the previous second.
957285612Sdelphij				** We do not trust that and simply poll
958285612Sdelphij				** again without even parsing it.
959285612Sdelphij				**
960285612Sdelphij				** More elegant would be to re-schedule the
961285612Sdelphij				** poll, but I do not know (yet) how to do
962285612Sdelphij				** that cleanly.
963285612Sdelphij				**
964285612Sdelphij				*/
965106424Sroberto				/* BLA ns_since_pps = ncc_tstmp(rbufp, &trtmp); */
966106424Sroberto/*   if (up->polled && ns_since_pps > -1 && ns_since_pps < 150) { */
967106424Sroberto
968285612Sdelphij				ns_since_pps = 200;
969106424Sroberto				if (up->polled && ns_since_pps < 150) {
970285612Sdelphij					msyslog(LOG_INFO, "%s(): up->polled",
971285612Sdelphij						__FUNCTION__);
972106424Sroberto					ripencc_poll(up->unit, peer);
973106424Sroberto					break;
974106424Sroberto				}
975106424Sroberto
976106424Sroberto			        /*
977106424Sroberto 				 * Parse primary utc time packet
978106424Sroberto				 * and fill refclock structure
979106424Sroberto				 * from results.
980106424Sroberto				 */
981106424Sroberto				if (parse0x8FAD(&rpt, peer) < 0) {
982285612Sdelphij					msyslog(LOG_INFO, "%s(): parse0x8FAD < 0",__FUNCTION__);
983285612Sdelphij					refclock_report(peer, CEVNT_BADREPLY);
984285612Sdelphij					break;
985106424Sroberto				}
986106424Sroberto				/*
987106424Sroberto				 * If the PPSAPI is working, rather use its
988106424Sroberto				 * timestamps.
989106424Sroberto				 * assume that the PPS occurs on the second
990106424Sroberto				 * so blow any msec
991106424Sroberto				 */
992106424Sroberto				if (ripencc_get_pps_ts(up, &rd_tmp) == 1) {
993106424Sroberto					pp->lastrec = up->tstamp = rd_tmp;
994132451Sroberto					pp->nsec = 0;
995106424Sroberto				}
996106424Sroberto				else
997285612Sdelphij					msyslog(LOG_INFO, "%s(): ripencc_get_pps_ts returns failure",__FUNCTION__);
998106424Sroberto
999106424Sroberto
1000106424Sroberto				if (!up->polled) {
1001285612Sdelphij					msyslog(LOG_INFO, "%s(): unrequested packet",__FUNCTION__);
1002106424Sroberto					/* unrequested packet */
1003106424Sroberto					break;
1004106424Sroberto				}
1005106424Sroberto
1006106424Sroberto				/* we have been polled ! */
1007106424Sroberto				up->polled = 0;
1008106424Sroberto				up->pollcnt = 2;
1009106424Sroberto
1010106424Sroberto				/* poll for next packet */
1011106424Sroberto				cmd_0x8E0Bq(&spt);
1012106424Sroberto				ripencc_send(peer,spt);
1013106424Sroberto
1014106424Sroberto				if (ns_since_pps < 0) { /* no PPS */
1015106424Sroberto					msyslog(LOG_INFO, "%s(): ns_since_pps < 0",__FUNCTION__);
1016106424Sroberto					refclock_report(peer, CEVNT_BADTIME);
1017106424Sroberto					break;
1018106424Sroberto				}
1019106424Sroberto
1020106424Sroberto				/*
1021285612Sdelphij				** Process the new sample in the median
1022285612Sdelphij				** filter and determine the reference clock
1023285612Sdelphij				** offset and dispersion.
1024285612Sdelphij				*/
1025106424Sroberto				if (!refclock_process(pp)) {
1026106424Sroberto					msyslog(LOG_INFO, "%s(): !refclock_process",__FUNCTION__);
1027106424Sroberto					refclock_report(peer, CEVNT_BADTIME);
1028106424Sroberto					break;
1029106424Sroberto				}
1030106424Sroberto
1031106424Sroberto				refclock_receive(peer);
1032106424Sroberto				break;
1033106424Sroberto
1034285612Sdelphij			    case 0x0B: /* comprehensive time packet */
1035106424Sroberto				parse0x8F0B(&rpt, peer);
1036106424Sroberto				break;
1037106424Sroberto
1038285612Sdelphij			    default: /* other superpackets */
1039106424Sroberto#ifdef DEBUG_NCC
1040285612Sdelphij				msyslog(LOG_INFO, "%s(): calling parseany",
1041285612Sdelphij					__FUNCTION__);
1042106424Sroberto#endif /* DEBUG_NCC */
1043106424Sroberto#ifdef TRIMBLE_OUTPUT_FUNC
1044106424Sroberto				parseany(&rpt, peer);
1045106424Sroberto#endif /* TRIMBLE_OUTPUT_FUNC */
1046106424Sroberto				break;
1047106424Sroberto			}
1048106424Sroberto			break;
1049106424Sroberto
1050285612Sdelphij		    case 0x4F:	/* UTC parameters, for leap info */
1051106424Sroberto			parse0x4F(&rpt, peer);
1052106424Sroberto			break;
1053106424Sroberto
1054285612Sdelphij		    case 0x5C:	/* sat tracking data */
1055106424Sroberto			parse0x5C(&rpt, peer);
1056106424Sroberto			break;
1057106424Sroberto
1058285612Sdelphij		    default:	/* other packets */
1059106424Sroberto#ifdef TRIMBLE_OUTPUT_FUNC
1060106424Sroberto			parseany(&rpt, peer);
1061106424Sroberto#endif /* TRIMBLE_OUTPUT_FUNC */
1062106424Sroberto			break;
1063106424Sroberto		}
1064106424Sroberto   		rpt.status = TSIP_PARSED_EMPTY;
1065106424Sroberto	}
1066106424Sroberto}
1067106424Sroberto
1068106424Sroberto/*
1069106424Sroberto * All trimble functions that are directly referenced from driver code
1070106424Sroberto * (so not from parseany)
1071106424Sroberto */
1072106424Sroberto
1073106424Sroberto/* request software versions */
1074285612Sdelphijvoid
1075285612Sdelphijcmd_0x1F(
1076285612Sdelphij	 TSIPPKT *cmd
1077285612Sdelphij	 )
1078106424Sroberto{
1079106424Sroberto	cmd->len = 0;
1080106424Sroberto	cmd->code = 0x1F;
1081106424Sroberto}
1082106424Sroberto
1083106424Sroberto/* request receiver health */
1084285612Sdelphijvoid
1085285612Sdelphijcmd_0x26(
1086285612Sdelphij	 TSIPPKT *cmd
1087285612Sdelphij	 )
1088106424Sroberto{
1089106424Sroberto	cmd->len = 0;
1090106424Sroberto	cmd->code = 0x26;
1091106424Sroberto}
1092106424Sroberto
1093106424Sroberto/* request UTC params */
1094285612Sdelphijvoid
1095285612Sdelphijcmd_0x2F(
1096285612Sdelphij	 TSIPPKT *cmd
1097285612Sdelphij	 )
1098106424Sroberto{
1099106424Sroberto	cmd->len = 0;
1100106424Sroberto	cmd->code = 0x2F;
1101106424Sroberto}
1102106424Sroberto
1103106424Sroberto/* set serial I/O options */
1104285612Sdelphijvoid
1105285612Sdelphijcmd_0x35s(
1106285612Sdelphij	 TSIPPKT *cmd,
1107285612Sdelphij	 unsigned char pos_code,
1108285612Sdelphij	 unsigned char vel_code,
1109285612Sdelphij	 unsigned char time_code,
1110285612Sdelphij	 unsigned char opts_code
1111285612Sdelphij	 )
1112106424Sroberto{
1113106424Sroberto	cmd->buf[0] = pos_code;
1114106424Sroberto	cmd->buf[1] = vel_code;
1115106424Sroberto	cmd->buf[2] = time_code;
1116106424Sroberto	cmd->buf[3] = opts_code;
1117106424Sroberto	cmd->len = 4;
1118106424Sroberto	cmd->code = 0x35;
1119106424Sroberto}
1120285612Sdelphij
1121106424Sroberto/* request tracking status */
1122285612Sdelphijvoid
1123285612Sdelphijcmd_0x3C(
1124285612Sdelphij	 TSIPPKT *cmd,
1125285612Sdelphij	 unsigned char sv_prn
1126285612Sdelphij	 )
1127106424Sroberto{
1128106424Sroberto	cmd->buf[0] = sv_prn;
1129106424Sroberto	cmd->len = 1;
1130106424Sroberto	cmd->code = 0x3C;
1131106424Sroberto}
1132106424Sroberto
1133106424Sroberto/* set Channel A configuration for dual-port operation */
1134285612Sdelphijvoid
1135285612Sdelphijcmd_0x3Ds(
1136285612Sdelphij	  TSIPPKT *cmd,
1137285612Sdelphij	  unsigned char baud_out,
1138285612Sdelphij	  unsigned char baud_inp,
1139285612Sdelphij	  unsigned char char_code,
1140285612Sdelphij	  unsigned char stopbitcode,
1141285612Sdelphij	  unsigned char output_mode,
1142285612Sdelphij	  unsigned char input_mode
1143285612Sdelphij	  )
1144106424Sroberto{
1145106424Sroberto	cmd->buf[0] = baud_out;		/* XMT baud rate */
1146106424Sroberto	cmd->buf[1] = baud_inp;		/* RCV baud rate */
1147285612Sdelphij	cmd->buf[2] = char_code;	/* parity and #bits per byte */
1148106424Sroberto	cmd->buf[3] = stopbitcode;	/* number of stop bits code */
1149106424Sroberto	cmd->buf[4] = output_mode;	/* Ch. A transmission mode */
1150106424Sroberto	cmd->buf[5] = input_mode;	/* Ch. A reception mode */
1151106424Sroberto	cmd->len = 6;
1152106424Sroberto	cmd->code = 0x3D;
1153106424Sroberto}
1154106424Sroberto
1155106424Sroberto
1156106424Sroberto/* query primary configuration */
1157285612Sdelphijvoid
1158285612Sdelphijcmd_0xBBq(
1159285612Sdelphij	  TSIPPKT *cmd,
1160285612Sdelphij	  unsigned char subcode
1161285612Sdelphij	  )
1162106424Sroberto{
1163106424Sroberto	cmd->len = 1;
1164106424Sroberto	cmd->code = 0xBB;
1165106424Sroberto	cmd->buf[0] = subcode;
1166106424Sroberto}
1167106424Sroberto
1168106424Sroberto
1169106424Sroberto/**** Superpackets ****/
1170106424Sroberto/* 8E-0B to query 8F-0B controls */
1171285612Sdelphijvoid
1172285612Sdelphijcmd_0x8E0Bq(
1173285612Sdelphij	    TSIPPKT *cmd
1174285612Sdelphij	    )
1175106424Sroberto{
1176106424Sroberto	cmd->len = 1;
1177106424Sroberto	cmd->code = 0x8E;
1178106424Sroberto	cmd->buf[0] = 0x0B;
1179106424Sroberto}
1180106424Sroberto
1181106424Sroberto
1182106424Sroberto/* 8F-41 to query board serial number */
1183285612Sdelphijvoid
1184285612Sdelphijcmd_0x8E41q(
1185285612Sdelphij	    TSIPPKT *cmd
1186285612Sdelphij	    )
1187106424Sroberto{
1188106424Sroberto	cmd->len = 1;
1189106424Sroberto	cmd->code = 0x8E;
1190106424Sroberto	cmd->buf[0] = 0x41;
1191106424Sroberto}
1192106424Sroberto
1193106424Sroberto
1194106424Sroberto/* 8F-42 to query product serial number */
1195285612Sdelphijvoid
1196285612Sdelphijcmd_0x8E42q(
1197285612Sdelphij	    TSIPPKT *cmd
1198285612Sdelphij	    )
1199106424Sroberto{
1200106424Sroberto	cmd->len = 1;
1201106424Sroberto	cmd->code = 0x8E;
1202106424Sroberto	cmd->buf[0] = 0x42;
1203106424Sroberto}
1204285612Sdelphij
1205285612Sdelphij
1206106424Sroberto/* 8F-4A to query PPS parameters */
1207285612Sdelphijvoid
1208285612Sdelphijcmd_0x8E4Aq(
1209285612Sdelphij	    TSIPPKT *cmd
1210285612Sdelphij	    )
1211106424Sroberto{
1212106424Sroberto	cmd->len = 1;
1213106424Sroberto	cmd->code = 0x8E;
1214106424Sroberto	cmd->buf[0] = 0x4A;
1215106424Sroberto}
1216106424Sroberto
1217106424Sroberto
1218106424Sroberto/* set i/o options */
1219285612Sdelphijvoid
1220285612Sdelphijcmd_0x8E4As(
1221285612Sdelphij	    TSIPPKT *cmd,
1222285612Sdelphij	    unsigned char PPSOnOff,
1223285612Sdelphij	    unsigned char TimeBase,
1224285612Sdelphij	    unsigned char Polarity,
1225285612Sdelphij	    double PPSOffset,
1226285612Sdelphij	    float Uncertainty
1227285612Sdelphij	    )
1228106424Sroberto{
1229106424Sroberto	cmd->len = 16;
1230106424Sroberto	cmd->code = 0x8E;
1231106424Sroberto	cmd->buf[0] = 0x4A;
1232106424Sroberto	cmd->buf[1] = PPSOnOff;
1233106424Sroberto	cmd->buf[2] = TimeBase;
1234106424Sroberto	cmd->buf[3] = Polarity;
1235106424Sroberto	bPutDouble (&PPSOffset, &cmd->buf[4]);
1236106424Sroberto	bPutFloat (&Uncertainty, &cmd->buf[12]);
1237106424Sroberto}
1238285612Sdelphij
1239106424Sroberto/* 8F-4B query survey limit */
1240285612Sdelphijvoid
1241285612Sdelphijcmd_0x8E4Bq(
1242285612Sdelphij	    TSIPPKT *cmd
1243285612Sdelphij	    )
1244106424Sroberto{
1245106424Sroberto	cmd->len = 1;
1246106424Sroberto	cmd->code = 0x8E;
1247106424Sroberto	cmd->buf[0] = 0x4B;
1248106424Sroberto}
1249106424Sroberto
1250106424Sroberto/* poll for UTC superpacket */
1251106424Sroberto/* 8E-AD to query 8F-AD controls */
1252285612Sdelphijvoid
1253285612Sdelphijcmd_0x8EADq(
1254285612Sdelphij	    TSIPPKT *cmd
1255285612Sdelphij	    )
1256106424Sroberto{
1257106424Sroberto	cmd->len = 1;
1258106424Sroberto	cmd->code = 0x8E;
1259106424Sroberto	cmd->buf[0] = 0xAD;
1260106424Sroberto}
1261106424Sroberto
1262106424Sroberto/* all outomatic packet output off */
1263285612Sdelphijvoid
1264285612Sdelphijcmd_0x8E4Ds(
1265285612Sdelphij	    TSIPPKT *cmd,
1266285612Sdelphij	    unsigned long AutoOutputMask
1267285612Sdelphij	    )
1268106424Sroberto{
1269106424Sroberto	cmd->len = 5;
1270106424Sroberto	cmd->code = 0x8E;
1271106424Sroberto	cmd->buf[0] = 0x4D;
1272106424Sroberto	bPutULong (&AutoOutputMask, &cmd->buf[1]);
1273106424Sroberto}
1274106424Sroberto
1275106424Sroberto
1276285612Sdelphij/*
1277285612Sdelphij * for DOS machines, reverse order of bytes as they come through the
1278285612Sdelphij * serial port.
1279285612Sdelphij */
1280106424Sroberto#ifdef BYTESWAP
1281285612Sdelphijstatic short
1282285612SdelphijbGetShort(
1283285612Sdelphij	  unsigned char *bp
1284285612Sdelphij	  )
1285106424Sroberto{
1286106424Sroberto	short outval;
1287285612Sdelphij	unsigned char *optr;
1288106424Sroberto
1289285612Sdelphij	optr = (unsigned char*)&outval + 1;
1290285612Sdelphij	*optr-- = *bp++;
1291285612Sdelphij	*optr = *bp;
1292106424Sroberto	return outval;
1293106424Sroberto}
1294106424Sroberto
1295106424Sroberto#ifdef TRIMBLE_OUTPUT_FUNC
1296285612Sdelphijstatic unsigned short
1297285612SdelphijbGetUShort(
1298285612Sdelphij	   unsigned char *bp
1299285612Sdelphij	   )
1300106424Sroberto{
1301106424Sroberto	unsigned short outval;
1302285612Sdelphij	unsigned char *optr;
1303106424Sroberto
1304285612Sdelphij	optr = (unsigned char*)&outval + 1;
1305285612Sdelphij	*optr-- = *bp++;
1306285612Sdelphij	*optr = *bp;
1307106424Sroberto	return outval;
1308106424Sroberto}
1309106424Sroberto
1310285612Sdelphijstatic long
1311285612SdelphijbGetLong(
1312285612Sdelphij	 unsigned char *bp
1313285612Sdelphij	 )
1314106424Sroberto{
1315106424Sroberto	long outval;
1316285612Sdelphij	unsigned char *optr;
1317106424Sroberto
1318285612Sdelphij	optr = (unsigned char*)&outval + 3;
1319285612Sdelphij	*optr-- = *bp++;
1320285612Sdelphij	*optr-- = *bp++;
1321285612Sdelphij	*optr-- = *bp++;
1322285612Sdelphij	*optr = *bp;
1323106424Sroberto	return outval;
1324106424Sroberto}
1325106424Sroberto
1326285612Sdelphijstatic unsigned long
1327285612SdelphijbGetULong(
1328285612Sdelphij	  unsigned char *bp
1329285612Sdelphij	  )
1330106424Sroberto{
1331106424Sroberto	unsigned long outval;
1332285612Sdelphij	unsigned char *optr;
1333106424Sroberto
1334285612Sdelphij	optr = (unsigned char*)&outval + 3;
1335285612Sdelphij	*optr-- = *bp++;
1336285612Sdelphij	*optr-- = *bp++;
1337285612Sdelphij	*optr-- = *bp++;
1338285612Sdelphij	*optr = *bp;
1339106424Sroberto	return outval;
1340106424Sroberto}
1341106424Sroberto#endif /* TRIMBLE_OUTPUT_FUNC */
1342106424Sroberto
1343285612Sdelphijstatic float
1344285612SdelphijbGetSingle(
1345285612Sdelphij	   unsigned char *bp
1346285612Sdelphij	   )
1347106424Sroberto{
1348106424Sroberto	float outval;
1349285612Sdelphij	unsigned char *optr;
1350106424Sroberto
1351285612Sdelphij	optr = (unsigned char*)&outval + 3;
1352285612Sdelphij	*optr-- = *bp++;
1353285612Sdelphij	*optr-- = *bp++;
1354285612Sdelphij	*optr-- = *bp++;
1355285612Sdelphij	*optr = *bp;
1356106424Sroberto	return outval;
1357106424Sroberto}
1358106424Sroberto
1359285612Sdelphijstatic double
1360285612SdelphijbGetDouble(
1361285612Sdelphij	   unsigned char *bp
1362285612Sdelphij	   )
1363106424Sroberto{
1364106424Sroberto	double outval;
1365285612Sdelphij	unsigned char *optr;
1366106424Sroberto
1367285612Sdelphij	optr = (unsigned char*)&outval + 7;
1368285612Sdelphij	*optr-- = *bp++;
1369285612Sdelphij	*optr-- = *bp++;
1370285612Sdelphij	*optr-- = *bp++;
1371285612Sdelphij	*optr-- = *bp++;
1372285612Sdelphij	*optr-- = *bp++;
1373285612Sdelphij	*optr-- = *bp++;
1374285612Sdelphij	*optr-- = *bp++;
1375285612Sdelphij	*optr = *bp;
1376106424Sroberto	return outval;
1377106424Sroberto}
1378106424Sroberto
1379106424Sroberto#else /* not BYTESWAP */
1380106424Sroberto
1381106424Sroberto#define bGetShort(bp) 	(*(short*)(bp))
1382106424Sroberto#define bGetLong(bp) 	(*(long*)(bp))
1383106424Sroberto#define bGetULong(bp) 	(*(unsigned long*)(bp))
1384106424Sroberto#define bGetSingle(bp) 	(*(float*)(bp))
1385106424Sroberto#define bGetDouble(bp)	(*(double*)(bp))
1386106424Sroberto
1387106424Sroberto#endif /* BYTESWAP */
1388106424Sroberto/*
1389106424Sroberto * Byte-reversal is necessary for little-endian (Intel-based) machines.
1390106424Sroberto * TSIP streams are Big-endian (Motorola-based).
1391106424Sroberto */
1392106424Sroberto#ifdef BYTESWAP
1393106424Sroberto
1394106424Srobertovoid
1395285612SdelphijbPutFloat(
1396285612Sdelphij	  float *in,
1397285612Sdelphij	  unsigned char *out
1398285612Sdelphij	  )
1399106424Sroberto{
1400106424Sroberto	unsigned char *inptr;
1401106424Sroberto
1402285612Sdelphij	inptr = (unsigned char*)in + 3;
1403285612Sdelphij	*out++ = *inptr--;
1404285612Sdelphij	*out++ = *inptr--;
1405285612Sdelphij	*out++ = *inptr--;
1406285612Sdelphij	*out = *inptr;
1407106424Sroberto}
1408106424Sroberto
1409106424Srobertostatic void
1410285612SdelphijbPutULong(
1411285612Sdelphij	  unsigned long *in,
1412285612Sdelphij	  unsigned char *out
1413285612Sdelphij	  )
1414106424Sroberto{
1415106424Sroberto	unsigned char *inptr;
1416106424Sroberto
1417285612Sdelphij	inptr = (unsigned char*)in + 3;
1418285612Sdelphij	*out++ = *inptr--;
1419285612Sdelphij	*out++ = *inptr--;
1420285612Sdelphij	*out++ = *inptr--;
1421285612Sdelphij	*out = *inptr;
1422106424Sroberto}
1423106424Sroberto
1424106424Srobertostatic void
1425285612SdelphijbPutDouble(
1426285612Sdelphij	   double *in,
1427285612Sdelphij	   unsigned char *out
1428285612Sdelphij	   )
1429106424Sroberto{
1430106424Sroberto	unsigned char *inptr;
1431106424Sroberto
1432285612Sdelphij	inptr = (unsigned char*)in + 7;
1433285612Sdelphij	*out++ = *inptr--;
1434285612Sdelphij	*out++ = *inptr--;
1435285612Sdelphij	*out++ = *inptr--;
1436285612Sdelphij	*out++ = *inptr--;
1437285612Sdelphij	*out++ = *inptr--;
1438285612Sdelphij	*out++ = *inptr--;
1439285612Sdelphij	*out++ = *inptr--;
1440285612Sdelphij	*out = *inptr;
1441106424Sroberto}
1442106424Sroberto
1443106424Sroberto#else	/* not BYTESWAP */
1444106424Sroberto
1445106424Srobertovoid bPutShort (short a, unsigned char *cmdbuf) {*(short*) cmdbuf = a;}
1446106424Srobertovoid bPutULong (long a, unsigned char *cmdbuf) 	{*(long*) cmdbuf = a;}
1447106424Srobertovoid bPutFloat (float a, unsigned char *cmdbuf) {*(float*) cmdbuf = a;}
1448106424Srobertovoid bPutDouble (double a, unsigned char *cmdbuf){*(double*) cmdbuf = a;}
1449106424Sroberto
1450106424Sroberto#endif /* BYTESWAP */
1451106424Sroberto
1452106424Sroberto/*
1453106424Sroberto * Parse primary utc time packet
1454106424Sroberto * and fill refclock structure
1455106424Sroberto * from results.
1456106424Sroberto *
1457106424Sroberto * 0 = success
1458106424Sroberto * -1 = errors
1459106424Sroberto */
1460106424Sroberto
1461106424Srobertostatic int
1462285612Sdelphijparse0x8FAD(
1463285612Sdelphij	    TSIPPKT *rpt,
1464285612Sdelphij	    struct peer *peer
1465285612Sdelphij	    )
1466106424Sroberto{
1467106424Sroberto	register struct refclockproc *pp;
1468106424Sroberto	register struct ripencc_unit *up;
1469106424Sroberto
1470106424Sroberto	unsigned day, month, year;	/* data derived from received timecode */
1471106424Sroberto	unsigned hour, minute, second;
1472106424Sroberto	unsigned char trackstat, utcflags;
1473106424Sroberto
1474106424Sroberto   	static char logbuf[1024];	/* logging string buffer */
1475106424Sroberto	int i;
1476106424Sroberto	unsigned char *buf;
1477106424Sroberto
1478106424Sroberto	buf = rpt->buf;
1479106424Sroberto	pp = peer->procptr;
1480106424Sroberto
1481106424Sroberto	if (rpt->len != 22)
1482106424Sroberto		return (-1);
1483106424Sroberto
1484106424Sroberto	if (bGetShort(&buf[1]) != 0) {
1485106424Sroberto#ifdef DEBUG_NCC
1486106424Sroberto		if (debug)
1487106424Sroberto			printf("parse0x8FAD: event count != 0\n");
1488106424Sroberto#endif /* DEBUG_NCC */
1489106424Sroberto		return(-1);
1490106424Sroberto	}
1491106424Sroberto
1492106424Sroberto	if (bGetDouble(&buf[3]) != 0.0) {
1493106424Sroberto#ifdef DEBUG_NCC
1494106424Sroberto		if (debug)
1495106424Sroberto			printf("parse0x8FAD: fracsecs != 0\n");
1496106424Sroberto#endif /* DEBUG_NCC */
1497106424Sroberto		return(-1);
1498106424Sroberto	}
1499106424Sroberto
1500285612Sdelphij	hour =		(unsigned int) buf[11];
1501285612Sdelphij	minute =	(unsigned int) buf[12];
1502285612Sdelphij	second =	(unsigned int) buf[13];
1503106424Sroberto	day =		(unsigned int) buf[14];
1504106424Sroberto	month =		(unsigned int) buf[15];
1505106424Sroberto	year =		bGetShort(&buf[16]);
1506285612Sdelphij	trackstat =	buf[18];
1507285612Sdelphij	utcflags =	buf[19];
1508106424Sroberto
1509106424Sroberto
1510106424Sroberto	sprintf(logbuf, "U1 %d.%d.%d %02d:%02d:%02d %d %02x",
1511106424Sroberto		day, month, year, hour, minute, second, trackstat, utcflags);
1512106424Sroberto
1513106424Sroberto#ifdef DEBUG_NCC
1514106424Sroberto	if (debug)
1515106424Sroberto   		puts(logbuf);
1516106424Sroberto#endif /* DEBUG_NCC */
1517106424Sroberto
1518106424Sroberto	record_clock_stats(&peer->srcadr, logbuf);
1519106424Sroberto
1520106424Sroberto	if (!utcflags & UTCF_UTC_AVAIL)
1521106424Sroberto		return(-1);
1522106424Sroberto
1523106424Sroberto	/* poll for UTC parameters once and then if UTC flag changed */
1524106424Sroberto	up = (struct ripencc_unit *) pp->unitptr;
1525106424Sroberto	if (utcflags != up->utcflags) {
1526285612Sdelphij		TSIPPKT spt;	/* local structure for send packet */
1527106424Sroberto		cmd_0x2F (&spt); /* request UTC params */
1528106424Sroberto		ripencc_send(peer,spt);
1529106424Sroberto		up->utcflags = utcflags;
1530106424Sroberto	}
1531106424Sroberto
1532106424Sroberto	/*
1533106424Sroberto	 * If we hit the leap second, we choose to skip this sample
1534106424Sroberto	 * rather than rely on other code to be perfectly correct.
1535106424Sroberto	 * No offense, just defense ;-).
1536106424Sroberto	 */
1537106424Sroberto	if (second == 60)
1538106424Sroberto		return(-1);
1539106424Sroberto
1540106424Sroberto	/* now check and convert the time we received */
1541106424Sroberto
1542106424Sroberto	pp->year = year;
1543106424Sroberto	if (month < 1 || month > 12 || day < 1 || day > 31)
1544106424Sroberto		return(-1);
1545106424Sroberto
1546285612Sdelphij	if (pp->year % 4) {	/* XXX: use is_leapyear() ? */
1547106424Sroberto		if (day > day1tab[month - 1])
1548106424Sroberto			return(-1);
1549106424Sroberto		for (i = 0; i < month - 1; i++)
1550106424Sroberto			day += day1tab[i];
1551106424Sroberto	} else {
1552106424Sroberto		if (day > day2tab[month - 1])
1553106424Sroberto			return(-1);
1554106424Sroberto		for (i = 0; i < month - 1; i++)
1555106424Sroberto			day += day2tab[i];
1556106424Sroberto	}
1557106424Sroberto	pp->day = day;
1558106424Sroberto	pp->hour = hour;
1559106424Sroberto	pp->minute = minute;
1560106424Sroberto	pp-> second = second;
1561132451Sroberto	pp->nsec = 0;
1562106424Sroberto
1563106424Sroberto	if ((utcflags&UTCF_LEAP_PNDG) && up->leapdelta != 0)
1564285612Sdelphij		pp-> leap = (up->leapdelta > 0)
1565285612Sdelphij		    ? LEAP_ADDSECOND
1566285612Sdelphij		    : LEAP_DELSECOND;
1567106424Sroberto	else
1568106424Sroberto		pp-> leap = LEAP_NOWARNING;
1569106424Sroberto
1570106424Sroberto	return (0);
1571106424Sroberto}
1572106424Sroberto
1573106424Sroberto/*
1574106424Sroberto * Parse comprehensive time packet
1575106424Sroberto *
1576285612Sdelphij *  0 = success
1577106424Sroberto * -1 = errors
1578106424Sroberto */
1579106424Sroberto
1580285612Sdelphijint
1581285612Sdelphijparse0x8F0B(
1582285612Sdelphij	    TSIPPKT *rpt,
1583285612Sdelphij	    struct peer *peer
1584285612Sdelphij	    )
1585106424Sroberto{
1586106424Sroberto	register struct refclockproc *pp;
1587106424Sroberto
1588106424Sroberto	unsigned day, month, year;	/* data derived from received timecode */
1589106424Sroberto	unsigned hour, minute, second;
1590106424Sroberto	unsigned utcoff;
1591106424Sroberto	unsigned char mode;
1592106424Sroberto	double  bias, rate;
1593106424Sroberto	float biasunc, rateunc;
1594106424Sroberto	double lat, lon, alt;
1595106424Sroberto	short lat_deg, lon_deg;
1596106424Sroberto	float lat_min, lon_min;
1597106424Sroberto	unsigned char north_south, east_west;
1598106424Sroberto	char sv[9];
1599106424Sroberto
1600106424Sroberto   	static char logbuf[1024];	/* logging string buffer */
1601106424Sroberto	unsigned char b;
1602106424Sroberto	int i;
1603106424Sroberto	unsigned char *buf;
1604106424Sroberto	double tow;
1605106424Sroberto
1606106424Sroberto	buf = rpt->buf;
1607106424Sroberto	pp = peer->procptr;
1608106424Sroberto
1609106424Sroberto	if (rpt->len != 74)
1610106424Sroberto		return (-1);
1611106424Sroberto
1612106424Sroberto	if (bGetShort(&buf[1]) != 0)
1613106424Sroberto		return(-1);;
1614106424Sroberto
1615106424Sroberto	tow =  bGetDouble(&buf[3]);
1616106424Sroberto
1617106424Sroberto	if (tow == -1.0) {
1618106424Sroberto		return(-1);
1619106424Sroberto	}
1620106424Sroberto	else if ((tow >= 604800.0) || (tow < 0.0)) {
1621106424Sroberto		return(-1);
1622106424Sroberto	}
1623106424Sroberto	else
1624106424Sroberto	{
1625106424Sroberto		if (tow < 604799.9) tow = tow + .00000001;
1626106424Sroberto		second = (unsigned int) fmod(tow, 60.);
1627106424Sroberto		minute =  (unsigned int) fmod(tow/60., 60.);
1628106424Sroberto		hour = (unsigned int )fmod(tow / 3600., 24.);
1629106424Sroberto	}
1630106424Sroberto
1631106424Sroberto	day =		(unsigned int) buf[11];
1632106424Sroberto	month =		(unsigned int) buf[12];
1633106424Sroberto	year =		bGetShort(&buf[13]);
1634106424Sroberto	mode =		buf[15];
1635106424Sroberto	utcoff =	bGetShort(&buf[16]);
1636106424Sroberto	bias = 		bGetDouble(&buf[18]) / GPS_C * 1e9;	/* ns */
1637106424Sroberto	rate = 		bGetDouble(&buf[26]) / GPS_C * 1e9;	/* ppb */
1638106424Sroberto	biasunc = 	bGetSingle(&buf[34]) / GPS_C * 1e9;	/* ns */
1639106424Sroberto	rateunc = 	bGetSingle(&buf[38]) / GPS_C * 1e9;	/* ppb */
1640106424Sroberto	lat = 		bGetDouble(&buf[42]) * R2D;
1641106424Sroberto	lon = 		bGetDouble(&buf[50]) * R2D;
1642106424Sroberto	alt = 		bGetDouble(&buf[58]);
1643106424Sroberto
1644106424Sroberto	if (lat < 0.0) {
1645106424Sroberto		north_south = 'S';
1646106424Sroberto		lat = -lat;
1647106424Sroberto	}
1648106424Sroberto	else {
1649106424Sroberto		north_south = 'N';
1650106424Sroberto	}
1651106424Sroberto	lat_deg = (short)lat;
1652106424Sroberto	lat_min = (lat - lat_deg) * 60.0;
1653106424Sroberto
1654106424Sroberto	if (lon < 0.0) {
1655106424Sroberto		east_west = 'W';
1656106424Sroberto		lon = -lon;
1657106424Sroberto	}
1658106424Sroberto	else {
1659106424Sroberto		east_west = 'E';
1660106424Sroberto	}
1661106424Sroberto
1662106424Sroberto	lon_deg = (short)lon;
1663106424Sroberto	lon_min = (lon - lon_deg) * 60.0;
1664106424Sroberto
1665106424Sroberto	for (i=0; i<8; i++) {
1666106424Sroberto		sv[i] = buf[i + 66];
1667106424Sroberto		if (sv[i]) {
1668106424Sroberto			TSIPPKT spt; /* local structure for sendpacket */
1669106424Sroberto			b = (unsigned char) (sv[i]<0 ? -sv[i] : sv[i]);
1670106424Sroberto			/* request tracking status */
1671106424Sroberto			cmd_0x3C  (&spt, b);
1672106424Sroberto			ripencc_send(peer,spt);
1673106424Sroberto		}
1674106424Sroberto	}
1675106424Sroberto
1676106424Sroberto
1677106424Sroberto	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",
1678285612Sdelphij		day, month, year, hour, minute, second, mode, bias, biasunc,
1679285612Sdelphij		rate, rateunc, utcoff, lat_deg, lat_min, north_south, lon_deg,
1680285612Sdelphij		lon_min, east_west, alt, sv[0], sv[1], sv[2], sv[3], sv[4],
1681285612Sdelphij		sv[5], sv[6], sv[7]);
1682106424Sroberto
1683106424Sroberto#ifdef DEBUG_NCC
1684106424Sroberto	if (debug)
1685106424Sroberto   		puts(logbuf);
1686106424Sroberto#endif /* DEBUG_NCC */
1687106424Sroberto
1688106424Sroberto	record_clock_stats(&peer->srcadr, logbuf);
1689106424Sroberto
1690106424Sroberto	return (0);
1691106424Sroberto}
1692106424Sroberto
1693106424Sroberto#ifdef TRIMBLE_OUTPUT_FUNC
1694106424Sroberto/*
1695106424Sroberto * Parse any packet using Trimble machinery
1696106424Sroberto */
1697285612Sdelphijint
1698285612Sdelphijparseany(
1699285612Sdelphij	 TSIPPKT *rpt,
1700285612Sdelphij	 struct peer *peer
1701285612Sdelphij	 )
1702106424Sroberto{
1703106424Sroberto   	static char logbuf[1024];	/* logging string buffer */
1704106424Sroberto
1705106424Sroberto   	TranslateTSIPReportToText (rpt, logbuf);	/* anything else */
1706106424Sroberto#ifdef DEBUG_NCC
1707106424Sroberto	if (debug)
1708106424Sroberto   		puts(&logbuf[1]);
1709106424Sroberto#endif /* DEBUG_NCC */
1710106424Sroberto	record_clock_stats(&peer->srcadr, &logbuf[1]);
1711106424Sroberto	return(0);
1712106424Sroberto}
1713106424Sroberto#endif /* TRIMBLE_OUTPUT_FUNC */
1714106424Sroberto
1715106424Sroberto
1716106424Sroberto/*
1717106424Sroberto * Parse UTC Parameter Packet
1718106424Sroberto *
1719106424Sroberto * See the IDE for documentation!
1720106424Sroberto *
1721106424Sroberto * 0 = success
1722106424Sroberto * -1 = errors
1723106424Sroberto */
1724106424Sroberto
1725285612Sdelphijint
1726285612Sdelphijparse0x4F(
1727285612Sdelphij	  TSIPPKT *rpt,
1728285612Sdelphij	  struct peer *peer
1729285612Sdelphij	  )
1730106424Sroberto{
1731106424Sroberto	register struct ripencc_unit *up;
1732106424Sroberto
1733106424Sroberto	double a0;
1734106424Sroberto	float a1, tot;
1735106424Sroberto	int dt_ls, wn_t, wn_lsf, dn, dt_lsf;
1736106424Sroberto
1737106424Sroberto   	static char logbuf[1024];	/* logging string buffer */
1738106424Sroberto	unsigned char *buf;
1739106424Sroberto
1740106424Sroberto	buf = rpt->buf;
1741106424Sroberto
1742106424Sroberto	if (rpt->len != 26)
1743106424Sroberto		return (-1);
1744106424Sroberto	a0 = bGetDouble (buf);
1745106424Sroberto	a1 = bGetSingle (&buf[8]);
1746106424Sroberto	dt_ls = bGetShort (&buf[12]);
1747106424Sroberto	tot = bGetSingle (&buf[14]);
1748106424Sroberto	wn_t = bGetShort (&buf[18]);
1749106424Sroberto	wn_lsf = bGetShort (&buf[20]);
1750106424Sroberto	dn = bGetShort (&buf[22]);
1751106424Sroberto	dt_lsf = bGetShort (&buf[24]);
1752106424Sroberto
1753106424Sroberto	sprintf(logbuf, "L1 %d %d %d %g %g %g %d %d %d",
1754106424Sroberto		dt_lsf - dt_ls, dt_ls, dt_lsf, a0, a1, tot, wn_t, wn_lsf, dn);
1755106424Sroberto
1756106424Sroberto#ifdef DEBUG_NCC
1757106424Sroberto	if (debug)
1758106424Sroberto   		puts(logbuf);
1759106424Sroberto#endif /* DEBUG_NCC */
1760106424Sroberto
1761106424Sroberto	record_clock_stats(&peer->srcadr, logbuf);
1762106424Sroberto
1763106424Sroberto	up = (struct ripencc_unit *) peer->procptr->unitptr;
1764106424Sroberto	up->leapdelta = dt_lsf - dt_ls;
1765106424Sroberto
1766106424Sroberto	return (0);
1767106424Sroberto}
1768106424Sroberto
1769106424Sroberto/*
1770106424Sroberto * Parse Tracking Status packet
1771106424Sroberto *
1772106424Sroberto * 0 = success
1773106424Sroberto * -1 = errors
1774106424Sroberto */
1775106424Sroberto
1776285612Sdelphijint
1777285612Sdelphijparse0x5C(
1778285612Sdelphij	  TSIPPKT *rpt,
1779285612Sdelphij	  struct peer *peer
1780285612Sdelphij	  )
1781106424Sroberto{
1782106424Sroberto	unsigned char prn, channel, aqflag, ephstat;
1783106424Sroberto	float snr, azinuth, elevation;
1784106424Sroberto
1785106424Sroberto   	static char logbuf[1024];	/* logging string buffer */
1786106424Sroberto	unsigned char *buf;
1787106424Sroberto
1788106424Sroberto	buf = rpt->buf;
1789106424Sroberto
1790106424Sroberto	if (rpt->len != 24)
1791106424Sroberto		return(-1);
1792106424Sroberto
1793106424Sroberto	prn = buf[0];
1794106424Sroberto	channel = (unsigned char)(buf[1] >> 3);
1795106424Sroberto	if (channel == 0x10)
1796106424Sroberto		channel = 2;
1797106424Sroberto	else
1798106424Sroberto		channel++;
1799106424Sroberto	aqflag = buf[2];
1800106424Sroberto	ephstat = buf[3];
1801106424Sroberto	snr = bGetSingle(&buf[4]);
1802106424Sroberto	elevation = bGetSingle(&buf[12]) * R2D;
1803106424Sroberto	azinuth = bGetSingle(&buf[16]) * R2D;
1804106424Sroberto
1805106424Sroberto	sprintf(logbuf, "S1 %02d %d %d %02x %4.1f %5.1f %4.1f",
1806106424Sroberto		prn, channel, aqflag, ephstat, snr, azinuth, elevation);
1807106424Sroberto
1808106424Sroberto#ifdef DEBUG_NCC
1809106424Sroberto	if (debug)
1810106424Sroberto   		puts(logbuf);
1811106424Sroberto#endif /* DEBUG_NCC */
1812106424Sroberto
1813106424Sroberto	record_clock_stats(&peer->srcadr, logbuf);
1814106424Sroberto
1815106424Sroberto	return (0);
1816106424Sroberto}
1817106424Sroberto
1818106424Sroberto/******* Code below is from Trimble Tsipchat *************/
1819106424Sroberto
1820106424Sroberto/*
1821106424Sroberto * *************************************************************************
1822106424Sroberto *
1823106424Sroberto * Trimble Navigation, Ltd.
1824106424Sroberto * OEM Products Development Group
1825106424Sroberto * P.O. Box 3642
1826106424Sroberto * 645 North Mary Avenue
1827106424Sroberto * Sunnyvale, California 94088-3642
1828106424Sroberto *
1829106424Sroberto * Corporate Headquarter:
1830106424Sroberto *    Telephone:  (408) 481-8000
1831106424Sroberto *    Fax:        (408) 481-6005
1832106424Sroberto *
1833106424Sroberto * Technical Support Center:
1834106424Sroberto *    Telephone:  (800) 767-4822	(U.S. and Canada)
1835106424Sroberto *                (408) 481-6940    (outside U.S. and Canada)
1836106424Sroberto *    Fax:        (408) 481-6020
1837106424Sroberto *    BBS:        (408) 481-7800
1838106424Sroberto *    e-mail:     trimble_support@trimble.com
1839106424Sroberto *		ftp://ftp.trimble.com/pub/sct/embedded/bin
1840106424Sroberto *
1841106424Sroberto * *************************************************************************
1842106424Sroberto *
1843106424Sroberto * -------  BYTE-SWAPPING  -------
1844106424Sroberto * TSIP is big-endian (Motorola) protocol.  To use on little-endian (Intel)
1845106424Sroberto * systems, the bytes of all multi-byte types (shorts, floats, doubles, etc.)
1846106424Sroberto * must be reversed.  This is controlled by the MACRO BYTESWAP; if defined, it
1847106424Sroberto * assumes little-endian protocol.
1848106424Sroberto * --------------------------------
1849106424Sroberto *
1850106424Sroberto * T_PARSER.C and T_PARSER.H contains primitive functions that interpret
1851106424Sroberto * reports received from the receiver.  A second source file pair,
1852106424Sroberto * T_FORMAT.C and T_FORMAT.H, contin the matching TSIP command formatters.
1853106424Sroberto *
1854106424Sroberto * The module is in very portable, basic C language.  It can be used as is, or
1855106424Sroberto * with minimal changes if a TSIP communications application is needed separate
1856106424Sroberto * from TSIPCHAT. The construction of most argument lists avoid the use of
1857106424Sroberto * structures, but the developer is encouraged to reconstruct them using such
1858106424Sroberto * definitions to meet project requirements.  Declarations of T_PARSER.C
1859106424Sroberto * functions are included in T_PARSER.H to provide prototyping definitions.
1860106424Sroberto *
1861106424Sroberto * There are two types of functions: a serial input processing routine,
1862106424Sroberto *                            tsip_input_proc()
1863106424Sroberto * which assembles incoming bytes into a TSIPPKT structure, and the
1864106424Sroberto * report parsers, rpt_0x??().
1865106424Sroberto *
1866106424Sroberto * 1) The function tsip_input_proc() accumulates bytes from the receiver,
1867106424Sroberto * strips control bytes (DLE), and checks if the report end sequence (DLE ETX)
1868106424Sroberto * has been received.  rpt.status is defined as TSIP_PARSED_FULL (== 1)
1869106424Sroberto * if a complete packet is available.
1870106424Sroberto *
1871106424Sroberto * 2) The functions rpt_0x??() are report string interpreters patterned after
1872106424Sroberto * the document called "Trimble Standard Interface Protocol".  It should be
1873106424Sroberto * noted that if the report buffer is sent into the receiver with the wrong
1874106424Sroberto * length (byte count), the rpt_0x??() returns the Boolean equivalence for
1875106424Sroberto * TRUE.
1876106424Sroberto *
1877106424Sroberto * *************************************************************************
1878106424Sroberto *
1879106424Sroberto */
1880106424Sroberto
1881106424Sroberto
1882285612Sdelphij/*
1883285612Sdelphij * reads bytes until serial buffer is empty or a complete report
1884106424Sroberto * has been received; end of report is signified by DLE ETX.
1885106424Sroberto */
1886285612Sdelphijstatic void
1887285612Sdelphijtsip_input_proc(
1888285612Sdelphij		TSIPPKT *rpt,
1889285612Sdelphij		int inbyte
1890285612Sdelphij		)
1891106424Sroberto{
1892106424Sroberto	unsigned char newbyte;
1893106424Sroberto
1894106424Sroberto	if (inbyte < 0 || inbyte > 0xFF) return;
1895106424Sroberto
1896106424Sroberto	newbyte = (unsigned char)(inbyte);
1897106424Sroberto	switch (rpt->status)
1898106424Sroberto	{
1899285612Sdelphij	    case TSIP_PARSED_DLE_1:
1900106424Sroberto		switch (newbyte)
1901106424Sroberto		{
1902285612Sdelphij		    case 0:
1903285612Sdelphij		    case ETX:
1904285612Sdelphij			/* illegal TSIP IDs */
1905285612Sdelphij			rpt->len = 0;
1906106424Sroberto			rpt->status = TSIP_PARSED_EMPTY;
1907106424Sroberto			break;
1908285612Sdelphij		    case DLE:
1909285612Sdelphij			/* try normal message start again */
1910106424Sroberto			rpt->len = 0;
1911106424Sroberto			rpt->status = TSIP_PARSED_DLE_1;
1912106424Sroberto			break;
1913285612Sdelphij		    default:
1914285612Sdelphij			/* legal TSIP ID; start message */
1915106424Sroberto			rpt->code = newbyte;
1916285612Sdelphij			rpt->len = 0;
1917106424Sroberto			rpt->status = TSIP_PARSED_DATA;
1918106424Sroberto			break;
1919106424Sroberto		}
1920106424Sroberto		break;
1921285612Sdelphij	    case TSIP_PARSED_DATA:
1922106424Sroberto		switch (newbyte) {
1923285612Sdelphij		    case DLE:
1924285612Sdelphij			/* expect DLE or ETX next */
1925106424Sroberto			rpt->status = TSIP_PARSED_DLE_2;
1926106424Sroberto			break;
1927285612Sdelphij		    default:
1928285612Sdelphij			/* normal data byte  */
1929106424Sroberto			rpt->buf[rpt->len] = newbyte;
1930106424Sroberto			rpt->len++;
1931285612Sdelphij			/* no change in rpt->status */
1932106424Sroberto			break;
1933106424Sroberto		}
1934106424Sroberto		break;
1935285612Sdelphij	    case TSIP_PARSED_DLE_2:
1936106424Sroberto		switch (newbyte) {
1937285612Sdelphij		    case DLE:
1938285612Sdelphij			/* normal data byte */
1939106424Sroberto			rpt->buf[rpt->len] = newbyte;
1940106424Sroberto			rpt->len++;
1941106424Sroberto			rpt->status = TSIP_PARSED_DATA;
1942106424Sroberto			break;
1943285612Sdelphij		    case ETX:
1944106424Sroberto			/* end of message; return TRUE here. */
1945106424Sroberto			rpt->status = TSIP_PARSED_FULL;
1946106424Sroberto			break;
1947285612Sdelphij		    default:
1948106424Sroberto			/* error: treat as TSIP_PARSED_DLE_1; start new report packet */
1949106424Sroberto			rpt->code = newbyte;
1950285612Sdelphij			rpt->len = 0;
1951106424Sroberto			rpt->status = TSIP_PARSED_DATA;
1952106424Sroberto		}
1953106424Sroberto		break;
1954285612Sdelphij	    case TSIP_PARSED_FULL:
1955285612Sdelphij	    case TSIP_PARSED_EMPTY:
1956285612Sdelphij	    default:
1957106424Sroberto		switch (newbyte) {
1958285612Sdelphij		    case DLE:
1959285612Sdelphij			/* normal message start */
1960106424Sroberto			rpt->len = 0;
1961106424Sroberto			rpt->status = TSIP_PARSED_DLE_1;
1962106424Sroberto			break;
1963285612Sdelphij		    default:
1964106424Sroberto			/* error: ignore newbyte */
1965106424Sroberto			rpt->len = 0;
1966106424Sroberto			rpt->status = TSIP_PARSED_EMPTY;
1967106424Sroberto		}
1968106424Sroberto		break;
1969106424Sroberto	}
1970106424Sroberto	if (rpt->len > MAX_RPTBUF) {
1971106424Sroberto		/* error: start new report packet */
1972106424Sroberto		rpt->status = TSIP_PARSED_EMPTY;
1973106424Sroberto		rpt->len = 0;
1974106424Sroberto	}
1975106424Sroberto}
1976106424Sroberto
1977106424Sroberto#ifdef TRIMBLE_OUTPUT_FUNC
1978106424Sroberto
1979106424Sroberto/**/
1980106424Sroberto/* Channel A configuration for dual port operation */
1981285612Sdelphijshort
1982285612Sdelphijrpt_0x3D(
1983285612Sdelphij	 TSIPPKT *rpt,
1984285612Sdelphij	 unsigned char *tx_baud_index,
1985285612Sdelphij	 unsigned char *rx_baud_index,
1986285612Sdelphij	 unsigned char *char_format_index,
1987285612Sdelphij	 unsigned char *stop_bits,
1988285612Sdelphij	 unsigned char *tx_mode_index,
1989285612Sdelphij	 unsigned char *rx_mode_index
1990285612Sdelphij	 )
1991106424Sroberto{
1992106424Sroberto	unsigned char *buf;
1993106424Sroberto	buf = rpt->buf;
1994106424Sroberto
1995106424Sroberto	if (rpt->len != 6) return TRUE;
1996106424Sroberto	*tx_baud_index = buf[0];
1997106424Sroberto	*rx_baud_index = buf[1];
1998106424Sroberto	*char_format_index = buf[2];
1999106424Sroberto	*stop_bits = (unsigned char)((buf[3] == 0x07) ? 1 : 2);
2000106424Sroberto	*tx_mode_index = buf[4];
2001106424Sroberto	*rx_mode_index = buf[5];
2002106424Sroberto	return FALSE;
2003106424Sroberto}
2004106424Sroberto
2005106424Sroberto/**/
2006106424Sroberto/* almanac data for specified satellite */
2007285612Sdelphijshort
2008285612Sdelphijrpt_0x40(
2009285612Sdelphij	 TSIPPKT *rpt,
2010285612Sdelphij	 unsigned char *sv_prn,
2011285612Sdelphij	 short *week_num,
2012285612Sdelphij	 float *t_zc,
2013285612Sdelphij	 float *eccentricity,
2014285612Sdelphij	 float *t_oa,
2015285612Sdelphij	 float *i_0,
2016285612Sdelphij	 float *OMEGA_dot,
2017285612Sdelphij	 float *sqrt_A,
2018285612Sdelphij	 float *OMEGA_0,
2019285612Sdelphij	 float *omega,
2020285612Sdelphij	 float *M_0
2021285612Sdelphij	 )
2022106424Sroberto{
2023106424Sroberto	unsigned char *buf;
2024106424Sroberto	buf = rpt->buf;
2025106424Sroberto
2026106424Sroberto	if (rpt->len != 39) return TRUE;
2027106424Sroberto	*sv_prn = buf[0];
2028106424Sroberto	*t_zc = bGetSingle (&buf[1]);
2029106424Sroberto	*week_num = bGetShort (&buf[5]);
2030106424Sroberto	*eccentricity = bGetSingle (&buf[7]);
2031106424Sroberto	*t_oa = bGetSingle (&buf[11]);
2032106424Sroberto	*i_0 = bGetSingle (&buf[15]);
2033106424Sroberto	*OMEGA_dot = bGetSingle (&buf[19]);
2034106424Sroberto	*sqrt_A = bGetSingle (&buf[23]);
2035106424Sroberto	*OMEGA_0 = bGetSingle (&buf[27]);
2036106424Sroberto	*omega = bGetSingle (&buf[31]);
2037106424Sroberto	*M_0 = bGetSingle (&buf[35]);
2038106424Sroberto	return FALSE;
2039106424Sroberto}
2040106424Sroberto
2041106424Sroberto/* GPS time */
2042285612Sdelphijshort
2043285612Sdelphijrpt_0x41(
2044285612Sdelphij	 TSIPPKT *rpt,
2045285612Sdelphij	 float *time_of_week,
2046285612Sdelphij	 float *UTC_offset,
2047285612Sdelphij	 short *week_num
2048285612Sdelphij	 )
2049106424Sroberto{
2050106424Sroberto	unsigned char *buf;
2051106424Sroberto	buf = rpt->buf;
2052106424Sroberto
2053106424Sroberto	if (rpt->len != 10) return TRUE;
2054106424Sroberto	*time_of_week = bGetSingle (buf);
2055106424Sroberto	*week_num = bGetShort (&buf[4]);
2056106424Sroberto	*UTC_offset = bGetSingle (&buf[6]);
2057106424Sroberto	return FALSE;
2058106424Sroberto}
2059106424Sroberto
2060106424Sroberto/* position in ECEF, single precision */
2061285612Sdelphijshort
2062285612Sdelphijrpt_0x42(
2063285612Sdelphij	 TSIPPKT *rpt,
2064285612Sdelphij	 float pos_ECEF[3],
2065285612Sdelphij	 float *time_of_fix
2066285612Sdelphij	 )
2067106424Sroberto{
2068106424Sroberto	unsigned char *buf;
2069106424Sroberto	buf = rpt->buf;
2070106424Sroberto
2071106424Sroberto	if (rpt->len != 16) return TRUE;
2072106424Sroberto	pos_ECEF[0] = bGetSingle (buf);
2073106424Sroberto	pos_ECEF[1]= bGetSingle (&buf[4]);
2074106424Sroberto	pos_ECEF[2]= bGetSingle (&buf[8]);
2075106424Sroberto	*time_of_fix = bGetSingle (&buf[12]);
2076106424Sroberto	return FALSE;
2077106424Sroberto}
2078106424Sroberto
2079106424Sroberto/* velocity in ECEF, single precision */
2080285612Sdelphijshort
2081285612Sdelphijrpt_0x43(
2082285612Sdelphij	 TSIPPKT *rpt,
2083285612Sdelphij	 float ECEF_vel[3],
2084285612Sdelphij	 float *freq_offset,
2085285612Sdelphij	 float *time_of_fix
2086285612Sdelphij	 )
2087106424Sroberto{
2088106424Sroberto	unsigned char *buf;
2089106424Sroberto	buf = rpt->buf;
2090106424Sroberto
2091106424Sroberto	if (rpt->len != 20) return TRUE;
2092106424Sroberto	ECEF_vel[0] = bGetSingle (buf);
2093106424Sroberto	ECEF_vel[1] = bGetSingle (&buf[4]);
2094106424Sroberto	ECEF_vel[2] = bGetSingle (&buf[8]);
2095106424Sroberto	*freq_offset = bGetSingle (&buf[12]);
2096106424Sroberto	*time_of_fix = bGetSingle (&buf[16]);
2097106424Sroberto	return FALSE;
2098106424Sroberto}
2099106424Sroberto
2100106424Sroberto/* software versions */
2101285612Sdelphijshort
2102285612Sdelphijrpt_0x45(
2103285612Sdelphij	 TSIPPKT *rpt,
2104285612Sdelphij	 unsigned char *major_nav_version,
2105285612Sdelphij	 unsigned char *minor_nav_version,
2106285612Sdelphij	 unsigned char *nav_day,
2107285612Sdelphij	 unsigned char *nav_month,
2108285612Sdelphij	 unsigned char *nav_year,
2109285612Sdelphij	 unsigned char *major_dsp_version,
2110285612Sdelphij	 unsigned char *minor_dsp_version,
2111285612Sdelphij	 unsigned char *dsp_day,
2112285612Sdelphij	 unsigned char *dsp_month,
2113285612Sdelphij	 unsigned char *dsp_year
2114285612Sdelphij	 )
2115106424Sroberto{
2116106424Sroberto	unsigned char *buf;
2117106424Sroberto	buf = rpt->buf;
2118106424Sroberto
2119106424Sroberto	if (rpt->len != 10) return TRUE;
2120106424Sroberto	*major_nav_version = buf[0];
2121106424Sroberto	*minor_nav_version = buf[1];
2122106424Sroberto	*nav_day = buf[2];
2123106424Sroberto	*nav_month = buf[3];
2124106424Sroberto	*nav_year = buf[4];
2125106424Sroberto	*major_dsp_version = buf[5];
2126106424Sroberto	*minor_dsp_version = buf[6];
2127106424Sroberto	*dsp_day = buf[7];
2128106424Sroberto	*dsp_month = buf[8];
2129106424Sroberto	*dsp_year = buf[9];
2130106424Sroberto	return FALSE;
2131106424Sroberto}
2132106424Sroberto
2133106424Sroberto/* receiver health and status */
2134285612Sdelphijshort
2135285612Sdelphijrpt_0x46(
2136285612Sdelphij	 TSIPPKT *rpt,
2137285612Sdelphij	 unsigned char *status1,
2138285612Sdelphij	 unsigned char *status2
2139285612Sdelphij	 )
2140106424Sroberto{
2141106424Sroberto	unsigned char *buf;
2142106424Sroberto	buf = rpt->buf;
2143106424Sroberto
2144106424Sroberto	if (rpt->len != 2) return TRUE;
2145106424Sroberto	*status1 = buf[0];
2146106424Sroberto	*status2 = buf[1];
2147106424Sroberto	return FALSE;
2148106424Sroberto}
2149106424Sroberto
2150106424Sroberto/* signal levels for all satellites tracked */
2151285612Sdelphijshort
2152285612Sdelphijrpt_0x47(
2153285612Sdelphij	 TSIPPKT *rpt,
2154285612Sdelphij	 unsigned char *nsvs,
2155285612Sdelphij	 unsigned char *sv_prn,
2156285612Sdelphij	 float *snr
2157285612Sdelphij	 )
2158106424Sroberto{
2159106424Sroberto	short isv;
2160106424Sroberto	unsigned char *buf;
2161106424Sroberto	buf = rpt->buf;
2162106424Sroberto
2163106424Sroberto	if (rpt->len != 1 + 5*buf[0]) return TRUE;
2164106424Sroberto	*nsvs = buf[0];
2165106424Sroberto	for (isv = 0; isv < (*nsvs); isv++) {
2166106424Sroberto		sv_prn[isv] = buf[5*isv + 1];
2167106424Sroberto		snr[isv] = bGetSingle (&buf[5*isv + 2]);
2168106424Sroberto	}
2169106424Sroberto	return FALSE;
2170106424Sroberto}
2171106424Sroberto
2172106424Sroberto/* GPS system message */
2173285612Sdelphijshort
2174285612Sdelphijrpt_0x48(
2175285612Sdelphij	 TSIPPKT *rpt,
2176285612Sdelphij	 unsigned char *message
2177285612Sdelphij	 )
2178106424Sroberto{
2179106424Sroberto	unsigned char *buf;
2180106424Sroberto	buf = rpt->buf;
2181106424Sroberto
2182106424Sroberto	if (rpt->len != 22) return TRUE;
2183106424Sroberto	memcpy (message, buf, 22);
2184106424Sroberto	message[22] = 0;
2185106424Sroberto	return FALSE;
2186106424Sroberto}
2187106424Sroberto
2188106424Sroberto/* health for all satellites from almanac health page */
2189285612Sdelphijshort
2190285612Sdelphijrpt_0x49(
2191285612Sdelphij	 TSIPPKT *rpt,
2192285612Sdelphij	 unsigned char *sv_health
2193285612Sdelphij	 )
2194106424Sroberto{
2195106424Sroberto	short i;
2196106424Sroberto	unsigned char *buf;
2197106424Sroberto	buf = rpt->buf;
2198106424Sroberto
2199106424Sroberto	if (rpt->len != 32) return TRUE;
2200106424Sroberto	for (i = 0; i < 32; i++) sv_health [i]= buf[i];
2201106424Sroberto	return FALSE;
2202106424Sroberto}
2203106424Sroberto
2204106424Sroberto/* position in lat-lon-alt, single precision */
2205285612Sdelphijshort
2206285612Sdelphijrpt_0x4A(
2207285612Sdelphij	 TSIPPKT *rpt,
2208285612Sdelphij	 float *lat,
2209285612Sdelphij	 float *lon,
2210285612Sdelphij	 float *alt,
2211285612Sdelphij	 float *clock_bias,
2212285612Sdelphij	 float *time_of_fix
2213285612Sdelphij	 )
2214106424Sroberto{
2215106424Sroberto	unsigned char *buf;
2216106424Sroberto	buf = rpt->buf;
2217106424Sroberto
2218106424Sroberto	if (rpt->len != 20) return TRUE;
2219106424Sroberto	*lat = bGetSingle (buf);
2220106424Sroberto	*lon = bGetSingle (&buf[4]);
2221106424Sroberto	*alt = bGetSingle (&buf[8]);
2222106424Sroberto	*clock_bias = bGetSingle (&buf[12]);
2223106424Sroberto	*time_of_fix = bGetSingle (&buf[16]);
2224106424Sroberto	return FALSE;
2225106424Sroberto}
2226106424Sroberto
2227106424Sroberto/* reference altitude parameters */
2228285612Sdelphijshort
2229285612Sdelphijrpt_0x4A_2(
2230285612Sdelphij	   TSIPPKT *rpt,
2231285612Sdelphij	   float *alt,
2232285612Sdelphij	   float *dummy,
2233285612Sdelphij	   unsigned char *alt_flag
2234285612Sdelphij	   )
2235106424Sroberto{
2236106424Sroberto	unsigned char *buf;
2237106424Sroberto
2238106424Sroberto	buf = rpt->buf;
2239106424Sroberto
2240106424Sroberto	if (rpt->len != 9) return TRUE;
2241106424Sroberto	*alt = bGetSingle (buf);
2242106424Sroberto	*dummy = bGetSingle (&buf[4]);
2243106424Sroberto	*alt_flag = buf[8];
2244106424Sroberto	return FALSE;
2245106424Sroberto}
2246106424Sroberto
2247106424Sroberto/* machine ID code, status */
2248285612Sdelphijshort
2249285612Sdelphijrpt_0x4B(
2250285612Sdelphij	 TSIPPKT *rpt,
2251285612Sdelphij	 unsigned char *machine_id,
2252285612Sdelphij	 unsigned char *status3,
2253285612Sdelphij	 unsigned char *status4
2254285612Sdelphij	 )
2255106424Sroberto{
2256106424Sroberto	unsigned char *buf;
2257106424Sroberto	buf = rpt->buf;
2258106424Sroberto
2259106424Sroberto	if (rpt->len != 3) return TRUE;
2260106424Sroberto	*machine_id = buf[0];
2261106424Sroberto	*status3 = buf[1];
2262106424Sroberto	*status4 = buf[2];
2263106424Sroberto	return FALSE;
2264106424Sroberto}
2265106424Sroberto
2266106424Sroberto/* operating parameters and masks */
2267285612Sdelphijshort
2268285612Sdelphijrpt_0x4C(
2269285612Sdelphij	 TSIPPKT *rpt,
2270285612Sdelphij	 unsigned char *dyn_code,
2271285612Sdelphij	 float *el_mask,
2272285612Sdelphij	 float *snr_mask,
2273285612Sdelphij	 float *dop_mask,
2274285612Sdelphij	 float *dop_switch
2275285612Sdelphij	 )
2276106424Sroberto{
2277106424Sroberto	unsigned char *buf;
2278106424Sroberto	buf = rpt->buf;
2279106424Sroberto
2280106424Sroberto	if (rpt->len != 17) return TRUE;
2281106424Sroberto	*dyn_code = buf[0];
2282106424Sroberto	*el_mask = bGetSingle (&buf[1]);
2283106424Sroberto	*snr_mask = bGetSingle (&buf[5]);
2284106424Sroberto	*dop_mask = bGetSingle (&buf[9]);
2285106424Sroberto	*dop_switch = bGetSingle (&buf[13]);
2286106424Sroberto	return FALSE;
2287106424Sroberto}
2288106424Sroberto
2289106424Sroberto/* oscillator offset */
2290285612Sdelphijshort
2291285612Sdelphijrpt_0x4D(
2292285612Sdelphij	 TSIPPKT *rpt,
2293285612Sdelphij	 float *osc_offset
2294285612Sdelphij	 )
2295106424Sroberto{
2296106424Sroberto	unsigned char *buf;
2297106424Sroberto	buf = rpt->buf;
2298106424Sroberto
2299106424Sroberto	if (rpt->len != 4) return TRUE;
2300106424Sroberto	*osc_offset = bGetSingle (buf);
2301106424Sroberto	return FALSE;
2302106424Sroberto}
2303106424Sroberto
2304106424Sroberto/* yes/no response to command to set GPS time */
2305285612Sdelphijshort
2306285612Sdelphijrpt_0x4E(
2307285612Sdelphij	 TSIPPKT *rpt,
2308285612Sdelphij	 unsigned char *response
2309285612Sdelphij	 )
2310106424Sroberto{
2311106424Sroberto	unsigned char *buf;
2312106424Sroberto	buf = rpt->buf;
2313106424Sroberto
2314106424Sroberto	if (rpt->len != 1) return TRUE;
2315106424Sroberto	*response = buf[0];
2316106424Sroberto	return FALSE;
2317106424Sroberto}
2318106424Sroberto
2319106424Sroberto/* UTC data */
2320285612Sdelphijshort
2321285612Sdelphijrpt_0x4F(
2322285612Sdelphij	 TSIPPKT *rpt,
2323285612Sdelphij	 double *a0,
2324285612Sdelphij	 float *a1,
2325285612Sdelphij	 float *time_of_data,
2326285612Sdelphij	 short *dt_ls,
2327285612Sdelphij	 short *wn_t,
2328285612Sdelphij	 short *wn_lsf,
2329285612Sdelphij	 short *dn,
2330285612Sdelphij	 short *dt_lsf
2331285612Sdelphij	 )
2332106424Sroberto{
2333106424Sroberto	unsigned char *buf;
2334106424Sroberto	buf = rpt->buf;
2335106424Sroberto
2336106424Sroberto	if (rpt->len != 26) return TRUE;
2337106424Sroberto	*a0 = bGetDouble (buf);
2338106424Sroberto	*a1 = bGetSingle (&buf[8]);
2339106424Sroberto	*dt_ls = bGetShort (&buf[12]);
2340106424Sroberto	*time_of_data = bGetSingle (&buf[14]);
2341106424Sroberto	*wn_t = bGetShort (&buf[18]);
2342106424Sroberto	*wn_lsf = bGetShort (&buf[20]);
2343106424Sroberto	*dn = bGetShort (&buf[22]);
2344106424Sroberto	*dt_lsf = bGetShort (&buf[24]);
2345106424Sroberto	return FALSE;
2346106424Sroberto}
2347106424Sroberto
2348106424Sroberto/**/
2349106424Sroberto/* clock offset and frequency offset in 1-SV (0-D) mode */
2350285612Sdelphijshort
2351285612Sdelphijrpt_0x54(
2352285612Sdelphij	 TSIPPKT *rpt,
2353285612Sdelphij	 float *clock_bias,
2354285612Sdelphij	 float *freq_offset,
2355285612Sdelphij	 float *time_of_fix
2356285612Sdelphij	 )
2357106424Sroberto{
2358106424Sroberto	unsigned char *buf;
2359106424Sroberto	buf = rpt->buf;
2360106424Sroberto
2361106424Sroberto	if (rpt->len != 12) return TRUE;
2362106424Sroberto	*clock_bias = bGetSingle (buf);
2363106424Sroberto	*freq_offset = bGetSingle (&buf[4]);
2364106424Sroberto	*time_of_fix = bGetSingle (&buf[8]);
2365106424Sroberto	return FALSE;
2366106424Sroberto}
2367106424Sroberto
2368106424Sroberto/* I/O serial options */
2369285612Sdelphijshort
2370285612Sdelphijrpt_0x55(
2371285612Sdelphij	 TSIPPKT *rpt,
2372285612Sdelphij	 unsigned char *pos_code,
2373285612Sdelphij	 unsigned char *vel_code,
2374285612Sdelphij	 unsigned char *time_code,
2375285612Sdelphij	 unsigned char *aux_code
2376285612Sdelphij	 )
2377106424Sroberto{
2378106424Sroberto	unsigned char *buf;
2379106424Sroberto	buf = rpt->buf;
2380106424Sroberto
2381106424Sroberto	if (rpt->len != 4) return TRUE;
2382106424Sroberto	*pos_code = buf[0];
2383106424Sroberto	*vel_code = buf[1];
2384106424Sroberto	*time_code = buf[2];
2385106424Sroberto	*aux_code = buf[3];
2386106424Sroberto	return FALSE;
2387106424Sroberto}
2388106424Sroberto
2389106424Sroberto/* velocity in east-north-up coordinates */
2390285612Sdelphijshort
2391285612Sdelphijrpt_0x56(
2392285612Sdelphij	 TSIPPKT *rpt,
2393285612Sdelphij	 float vel_ENU[3],
2394285612Sdelphij	 float *freq_offset,
2395285612Sdelphij	 float *time_of_fix
2396285612Sdelphij	 )
2397106424Sroberto{
2398106424Sroberto	unsigned char *buf;
2399106424Sroberto	buf = rpt->buf;
2400106424Sroberto
2401106424Sroberto	if (rpt->len != 20) return TRUE;
2402106424Sroberto	/* east */
2403106424Sroberto	vel_ENU[0] = bGetSingle (buf);
2404106424Sroberto	/* north */
2405106424Sroberto	vel_ENU[1] = bGetSingle (&buf[4]);
2406106424Sroberto	/* up */
2407106424Sroberto	vel_ENU[2] = bGetSingle (&buf[8]);
2408106424Sroberto	*freq_offset = bGetSingle (&buf[12]);
2409106424Sroberto	*time_of_fix = bGetSingle (&buf[16]);
2410106424Sroberto	return FALSE;
2411106424Sroberto}
2412106424Sroberto
2413106424Sroberto/* info about last computed fix */
2414285612Sdelphijshort
2415285612Sdelphijrpt_0x57(
2416285612Sdelphij	 TSIPPKT *rpt,
2417285612Sdelphij	 unsigned char *source_code,
2418285612Sdelphij	 unsigned char *diag_code,
2419285612Sdelphij	 short *week_num,
2420285612Sdelphij	 float *time_of_fix
2421285612Sdelphij	 )
2422106424Sroberto{
2423106424Sroberto	unsigned char *buf;
2424106424Sroberto	buf = rpt->buf;
2425106424Sroberto
2426106424Sroberto	if (rpt->len != 8) return TRUE;
2427106424Sroberto	*source_code = buf[0];
2428106424Sroberto	*diag_code = buf[1];
2429106424Sroberto	*time_of_fix = bGetSingle (&buf[2]);
2430106424Sroberto	*week_num = bGetShort (&buf[6]);
2431106424Sroberto	return FALSE;
2432106424Sroberto}
2433106424Sroberto
2434106424Sroberto/* GPS system data or acknowledgment of GPS system data load */
2435285612Sdelphijshort
2436285612Sdelphijrpt_0x58(
2437285612Sdelphij	 TSIPPKT *rpt,
2438285612Sdelphij	 unsigned char *op_code,
2439285612Sdelphij	 unsigned char *data_type,
2440285612Sdelphij	 unsigned char *sv_prn,
2441285612Sdelphij	 unsigned char *data_length,
2442285612Sdelphij	 unsigned char *data_packet
2443285612Sdelphij	 )
2444106424Sroberto{
2445106424Sroberto	unsigned char *buf, *buf4;
2446106424Sroberto	short dl;
2447106424Sroberto	ALM_INFO* alminfo;
2448106424Sroberto	ION_INFO* ioninfo;
2449106424Sroberto	UTC_INFO* utcinfo;
2450106424Sroberto	NAV_INFO* navinfo;
2451106424Sroberto
2452106424Sroberto	buf = rpt->buf;
2453106424Sroberto
2454106424Sroberto	if (buf[0] == 2) {
2455106424Sroberto		if (rpt->len < 4) return TRUE;
2456106424Sroberto		if (rpt->len != 4+buf[3]) return TRUE;
2457106424Sroberto	}
2458106424Sroberto	else if (rpt->len != 3) {
2459106424Sroberto		return TRUE;
2460106424Sroberto	}
2461106424Sroberto	*op_code = buf[0];
2462106424Sroberto	*data_type = buf[1];
2463106424Sroberto	*sv_prn = buf[2];
2464106424Sroberto	if (*op_code == 2) {
2465106424Sroberto		dl = buf[3];
2466106424Sroberto		*data_length = (unsigned char)dl;
2467106424Sroberto		buf4 = &buf[4];
2468106424Sroberto		switch (*data_type) {
2469285612Sdelphij		    case 2:
2470106424Sroberto			/* Almanac */
2471106424Sroberto			if (*data_length != sizeof (ALM_INFO)) return TRUE;
2472106424Sroberto			alminfo = (ALM_INFO*)data_packet;
2473106424Sroberto			alminfo->t_oa_raw  = buf4[0];
2474106424Sroberto			alminfo->SV_health = buf4[1];
2475106424Sroberto			alminfo->e         = bGetSingle(&buf4[2]);
2476106424Sroberto			alminfo->t_oa      = bGetSingle(&buf4[6]);
2477106424Sroberto			alminfo->i_0       = bGetSingle(&buf4[10]);
2478106424Sroberto			alminfo->OMEGADOT  = bGetSingle(&buf4[14]);
2479106424Sroberto			alminfo->sqrt_A    = bGetSingle(&buf4[18]);
2480106424Sroberto			alminfo->OMEGA_0   = bGetSingle(&buf4[22]);
2481106424Sroberto			alminfo->omega     = bGetSingle(&buf4[26]);
2482106424Sroberto			alminfo->M_0       = bGetSingle(&buf4[30]);
2483106424Sroberto			alminfo->a_f0      = bGetSingle(&buf4[34]);
2484106424Sroberto			alminfo->a_f1      = bGetSingle(&buf4[38]);
2485106424Sroberto			alminfo->Axis      = bGetSingle(&buf4[42]);
2486106424Sroberto			alminfo->n         = bGetSingle(&buf4[46]);
2487106424Sroberto			alminfo->OMEGA_n   = bGetSingle(&buf4[50]);
2488106424Sroberto			alminfo->ODOT_n    = bGetSingle(&buf4[54]);
2489106424Sroberto			alminfo->t_zc      = bGetSingle(&buf4[58]);
2490106424Sroberto			alminfo->weeknum   = bGetShort(&buf4[62]);
2491106424Sroberto			alminfo->wn_oa     = bGetShort(&buf4[64]);
2492106424Sroberto			break;
2493106424Sroberto
2494285612Sdelphij		    case 3:
2495106424Sroberto			/* Almanac health page */
2496106424Sroberto			if (*data_length != sizeof (ALH_PARMS) + 3) return TRUE;
2497106424Sroberto
2498106424Sroberto			/* this record is returned raw */
2499106424Sroberto			memcpy (data_packet, buf4, dl);
2500106424Sroberto			break;
2501106424Sroberto
2502285612Sdelphij		    case 4:
2503106424Sroberto			/* Ionosphere */
2504106424Sroberto			if (*data_length != sizeof (ION_INFO) + 8) return TRUE;
2505106424Sroberto			ioninfo = (ION_INFO*)data_packet;
2506106424Sroberto			ioninfo->alpha_0   = bGetSingle (&buf4[8]);
2507106424Sroberto			ioninfo->alpha_1   = bGetSingle (&buf4[12]);
2508106424Sroberto			ioninfo->alpha_2   = bGetSingle (&buf4[16]);
2509106424Sroberto			ioninfo->alpha_3   = bGetSingle (&buf4[20]);
2510106424Sroberto			ioninfo->beta_0    = bGetSingle (&buf4[24]);
2511106424Sroberto			ioninfo->beta_1    = bGetSingle (&buf4[28]);
2512106424Sroberto			ioninfo->beta_2    = bGetSingle (&buf4[32]);
2513106424Sroberto			ioninfo->beta_3    = bGetSingle (&buf4[36]);
2514106424Sroberto			break;
2515106424Sroberto
2516285612Sdelphij		    case 5:
2517106424Sroberto			/* UTC */
2518106424Sroberto			if (*data_length != sizeof (UTC_INFO) + 13) return TRUE;
2519106424Sroberto			utcinfo = (UTC_INFO*)data_packet;
2520106424Sroberto			utcinfo->A_0       = bGetDouble (&buf4[13]);
2521106424Sroberto			utcinfo->A_1       = bGetSingle (&buf4[21]);
2522106424Sroberto			utcinfo->delta_t_LS = bGetShort (&buf4[25]);
2523106424Sroberto			utcinfo->t_ot      = bGetSingle(&buf4[27]);
2524106424Sroberto			utcinfo->WN_t      = bGetShort (&buf4[31]);
2525106424Sroberto			utcinfo->WN_LSF    = bGetShort (&buf4[33]);
2526106424Sroberto			utcinfo->DN        = bGetShort (&buf4[35]);
2527106424Sroberto			utcinfo->delta_t_LSF = bGetShort (&buf4[37]);
2528106424Sroberto			break;
2529106424Sroberto
2530285612Sdelphij		    case 6:
2531106424Sroberto			/* Ephemeris */
2532106424Sroberto			if (*data_length != sizeof (NAV_INFO) - 1) return TRUE;
2533106424Sroberto
2534106424Sroberto			navinfo = (NAV_INFO*)data_packet;
2535106424Sroberto
2536106424Sroberto			navinfo->sv_number = buf4[0];
2537106424Sroberto			navinfo->t_ephem = bGetSingle (&buf4[1]);
2538106424Sroberto			navinfo->ephclk.weeknum = bGetShort (&buf4[5]);
2539106424Sroberto
2540106424Sroberto			navinfo->ephclk.codeL2 = buf4[7];
2541106424Sroberto			navinfo->ephclk.L2Pdata = buf4[8];
2542106424Sroberto			navinfo->ephclk.SVacc_raw = buf4[9];
2543106424Sroberto			navinfo->ephclk.SV_health = buf4[10];
2544106424Sroberto			navinfo->ephclk.IODC = bGetShort (&buf4[11]);
2545106424Sroberto			navinfo->ephclk.T_GD = bGetSingle (&buf4[13]);
2546106424Sroberto			navinfo->ephclk.t_oc = bGetSingle (&buf4[17]);
2547106424Sroberto			navinfo->ephclk.a_f2 = bGetSingle (&buf4[21]);
2548106424Sroberto			navinfo->ephclk.a_f1 = bGetSingle (&buf4[25]);
2549106424Sroberto			navinfo->ephclk.a_f0 = bGetSingle (&buf4[29]);
2550106424Sroberto			navinfo->ephclk.SVacc = bGetSingle (&buf4[33]);
2551106424Sroberto
2552106424Sroberto			navinfo->ephorb.IODE = buf4[37];
2553106424Sroberto			navinfo->ephorb.fit_interval = buf4[38];
2554106424Sroberto			navinfo->ephorb.C_rs = bGetSingle (&buf4[39]);
2555106424Sroberto			navinfo->ephorb.delta_n = bGetSingle (&buf4[43]);
2556106424Sroberto			navinfo->ephorb.M_0 = bGetDouble (&buf4[47]);
2557106424Sroberto			navinfo->ephorb.C_uc = bGetSingle (&buf4[55]);
2558106424Sroberto			navinfo->ephorb.e = bGetDouble (&buf4[59]);
2559106424Sroberto			navinfo->ephorb.C_us = bGetSingle (&buf4[67]);
2560106424Sroberto			navinfo->ephorb.sqrt_A = bGetDouble (&buf4[71]);
2561106424Sroberto			navinfo->ephorb.t_oe = bGetSingle (&buf4[79]);
2562106424Sroberto			navinfo->ephorb.C_ic = bGetSingle (&buf4[83]);
2563106424Sroberto			navinfo->ephorb.OMEGA_0 = bGetDouble (&buf4[87]);
2564106424Sroberto			navinfo->ephorb.C_is = bGetSingle (&buf4[95]);
2565106424Sroberto			navinfo->ephorb.i_0 = bGetDouble (&buf4[99]);
2566106424Sroberto			navinfo->ephorb.C_rc = bGetSingle (&buf4[107]);
2567106424Sroberto			navinfo->ephorb.omega = bGetDouble (&buf4[111]);
2568106424Sroberto			navinfo->ephorb.OMEGADOT=bGetSingle (&buf4[119]);
2569106424Sroberto			navinfo->ephorb.IDOT = bGetSingle (&buf4[123]);
2570106424Sroberto			navinfo->ephorb.Axis = bGetDouble (&buf4[127]);
2571106424Sroberto			navinfo->ephorb.n = bGetDouble (&buf4[135]);
2572106424Sroberto			navinfo->ephorb.r1me2 = bGetDouble (&buf4[143]);
2573106424Sroberto			navinfo->ephorb.OMEGA_n=bGetDouble (&buf4[151]);
2574106424Sroberto			navinfo->ephorb.ODOT_n = bGetDouble (&buf4[159]);
2575106424Sroberto			break;
2576106424Sroberto		}
2577106424Sroberto	}
2578106424Sroberto	return FALSE;
2579106424Sroberto}
2580106424Sroberto
2581106424Sroberto/* satellite enable/disable or health heed/ignore list */
2582285612Sdelphijshort
2583285612Sdelphijrpt_0x59(
2584285612Sdelphij	 TSIPPKT *rpt,
2585285612Sdelphij	 unsigned char *code_type,
2586285612Sdelphij	 unsigned char status_code[32]
2587285612Sdelphij	 )
2588106424Sroberto{
2589106424Sroberto	short iprn;
2590106424Sroberto	unsigned char *buf;
2591106424Sroberto	buf = rpt->buf;
2592106424Sroberto
2593106424Sroberto	if (rpt->len != 33) return TRUE;
2594106424Sroberto	*code_type = buf[0];
2595106424Sroberto	for (iprn = 0; iprn < 32; iprn++)
2596106424Sroberto		status_code[iprn] = buf[iprn + 1];
2597106424Sroberto	return FALSE;
2598106424Sroberto}
2599106424Sroberto
2600106424Sroberto/* raw measurement data - code phase/Doppler */
2601285612Sdelphijshort
2602285612Sdelphijrpt_0x5A(
2603285612Sdelphij	 TSIPPKT *rpt,
2604285612Sdelphij	 unsigned char *sv_prn,
2605285612Sdelphij	 float *sample_length,
2606285612Sdelphij	 float *signal_level,
2607285612Sdelphij	 float *code_phase,
2608285612Sdelphij	 float *Doppler,
2609285612Sdelphij	 double *time_of_fix
2610285612Sdelphij	 )
2611106424Sroberto{
2612106424Sroberto	unsigned char *buf;
2613106424Sroberto	buf = rpt->buf;
2614106424Sroberto
2615106424Sroberto	if (rpt->len != 25) return TRUE;
2616106424Sroberto	*sv_prn = buf[0];
2617106424Sroberto	*sample_length = bGetSingle (&buf[1]);
2618106424Sroberto	*signal_level = bGetSingle (&buf[5]);
2619106424Sroberto	*code_phase = bGetSingle (&buf[9]);
2620106424Sroberto	*Doppler = bGetSingle (&buf[13]);
2621106424Sroberto	*time_of_fix = bGetDouble (&buf[17]);
2622106424Sroberto	return FALSE;
2623106424Sroberto}
2624106424Sroberto
2625106424Sroberto/* satellite ephorb status */
2626285612Sdelphijshort
2627285612Sdelphijrpt_0x5B(
2628285612Sdelphij	 TSIPPKT *rpt,
2629285612Sdelphij	 unsigned char *sv_prn,
2630285612Sdelphij	 unsigned char *sv_health,
2631285612Sdelphij	 unsigned char *sv_iode,
2632285612Sdelphij	 unsigned char *fit_interval_flag,
2633285612Sdelphij	 float *time_of_collection,
2634285612Sdelphij	 float *time_of_eph,
2635285612Sdelphij	 float *sv_accy
2636285612Sdelphij	 )
2637106424Sroberto{
2638106424Sroberto	unsigned char *buf;
2639106424Sroberto	buf = rpt->buf;
2640106424Sroberto
2641106424Sroberto	if (rpt->len != 16) return TRUE;
2642106424Sroberto	*sv_prn = buf[0];
2643106424Sroberto	*time_of_collection = bGetSingle (&buf[1]);
2644106424Sroberto	*sv_health = buf[5];
2645106424Sroberto	*sv_iode = buf[6];
2646106424Sroberto	*time_of_eph = bGetSingle (&buf[7]);
2647106424Sroberto	*fit_interval_flag = buf[11];
2648106424Sroberto	*sv_accy = bGetSingle (&buf[12]);
2649106424Sroberto	return FALSE;
2650106424Sroberto}
2651106424Sroberto
2652106424Sroberto/* satellite tracking status */
2653285612Sdelphijshort
2654285612Sdelphijrpt_0x5C(
2655285612Sdelphij	 TSIPPKT *rpt,
2656285612Sdelphij	 unsigned char *sv_prn,
2657285612Sdelphij	 unsigned char *slot,
2658285612Sdelphij	 unsigned char *chan,
2659285612Sdelphij	 unsigned char *acq_flag,
2660285612Sdelphij	 unsigned char *eph_flag,
2661285612Sdelphij	 float *signal_level,
2662285612Sdelphij	 float *time_of_last_msmt,
2663285612Sdelphij	 float *elev,
2664285612Sdelphij	 float *azim,
2665285612Sdelphij	 unsigned char *old_msmt_flag,
2666285612Sdelphij	 unsigned char *integer_msec_flag,
2667285612Sdelphij	 unsigned char *bad_data_flag,
2668285612Sdelphij	 unsigned char *data_collect_flag
2669285612Sdelphij	 )
2670106424Sroberto{
2671106424Sroberto	unsigned char *buf;
2672106424Sroberto	buf = rpt->buf;
2673106424Sroberto
2674106424Sroberto	if (rpt->len != 24) return TRUE;
2675106424Sroberto	*sv_prn = buf[0];
2676106424Sroberto	*slot = (unsigned char)((buf[1] & 0x07) + 1);
2677106424Sroberto	*chan = (unsigned char)(buf[1] >> 3);
2678106424Sroberto	if (*chan == 0x10) *chan = 2;
2679106424Sroberto	else (*chan)++;
2680106424Sroberto	*acq_flag = buf[2];
2681106424Sroberto	*eph_flag = buf[3];
2682106424Sroberto	*signal_level = bGetSingle (&buf[4]);
2683106424Sroberto	*time_of_last_msmt = bGetSingle (&buf[8]);
2684106424Sroberto	*elev = bGetSingle (&buf[12]);
2685106424Sroberto	*azim = bGetSingle (&buf[16]);
2686106424Sroberto	*old_msmt_flag = buf[20];
2687106424Sroberto	*integer_msec_flag = buf[21];
2688106424Sroberto	*bad_data_flag = buf[22];
2689106424Sroberto	*data_collect_flag = buf[23];
2690106424Sroberto	return FALSE;
2691106424Sroberto}
2692106424Sroberto
2693106424Sroberto/**/
2694106424Sroberto/* over-determined satellite selection for position fixes, PDOP, fix mode */
2695285612Sdelphijshort
2696285612Sdelphijrpt_0x6D(
2697285612Sdelphij	 TSIPPKT *rpt,
2698285612Sdelphij	 unsigned char *manual_mode,
2699285612Sdelphij	 unsigned char *nsvs,
2700285612Sdelphij	 unsigned char *ndim,
2701285612Sdelphij	 unsigned char sv_prn[],
2702285612Sdelphij	 float *pdop,
2703285612Sdelphij	 float *hdop,
2704285612Sdelphij	 float *vdop,
2705285612Sdelphij	 float *tdop
2706285612Sdelphij	 )
2707106424Sroberto{
2708106424Sroberto	short islot;
2709106424Sroberto	unsigned char *buf;
2710106424Sroberto	buf = rpt->buf;
2711106424Sroberto
2712106424Sroberto	*nsvs = (unsigned char)((buf[0] & 0xF0) >> 4);
2713106424Sroberto	if ((*nsvs)>8) return TRUE;
2714106424Sroberto	if (rpt->len != 17 + (*nsvs) ) return TRUE;
2715106424Sroberto
2716106424Sroberto	*manual_mode = (unsigned char)(buf[0] & 0x08);
2717106424Sroberto	*ndim  = (unsigned char)((buf[0] & 0x07));
2718106424Sroberto	*pdop = bGetSingle (&buf[1]);
2719106424Sroberto	*hdop = bGetSingle (&buf[5]);
2720106424Sroberto	*vdop = bGetSingle (&buf[9]);
2721106424Sroberto	*tdop = bGetSingle (&buf[13]);
2722106424Sroberto	for (islot = 0; islot < (*nsvs); islot++)
2723106424Sroberto		sv_prn[islot] = buf[islot + 17];
2724106424Sroberto	return FALSE;
2725106424Sroberto}
2726106424Sroberto
2727106424Sroberto/**/
2728106424Sroberto/* differential fix mode */
2729285612Sdelphijshort
2730285612Sdelphijrpt_0x82(
2731285612Sdelphij	 TSIPPKT *rpt,
2732285612Sdelphij	 unsigned char *diff_mode
2733285612Sdelphij	 )
2734106424Sroberto{
2735106424Sroberto	unsigned char *buf;
2736106424Sroberto	buf = rpt->buf;
2737106424Sroberto
2738106424Sroberto	if (rpt->len != 1) return TRUE;
2739106424Sroberto	*diff_mode = buf[0];
2740106424Sroberto	return FALSE;
2741106424Sroberto}
2742106424Sroberto
2743106424Sroberto/* position, ECEF double precision */
2744285612Sdelphijshort
2745285612Sdelphijrpt_0x83(
2746285612Sdelphij	 TSIPPKT *rpt,
2747285612Sdelphij	 double ECEF_pos[3],
2748285612Sdelphij	 double *clock_bias,
2749285612Sdelphij	 float *time_of_fix
2750285612Sdelphij	 )
2751106424Sroberto{
2752106424Sroberto	unsigned char *buf;
2753106424Sroberto	buf = rpt->buf;
2754106424Sroberto
2755106424Sroberto	if (rpt->len != 36) return TRUE;
2756106424Sroberto	ECEF_pos[0] = bGetDouble (buf);
2757106424Sroberto	ECEF_pos[1] = bGetDouble (&buf[8]);
2758106424Sroberto	ECEF_pos[2] = bGetDouble (&buf[16]);
2759106424Sroberto	*clock_bias  = bGetDouble (&buf[24]);
2760106424Sroberto	*time_of_fix = bGetSingle (&buf[32]);
2761106424Sroberto	return FALSE;
2762106424Sroberto}
2763106424Sroberto
2764106424Sroberto/* position, lat-lon-alt double precision */
2765285612Sdelphijshort
2766285612Sdelphijrpt_0x84(
2767285612Sdelphij	 TSIPPKT *rpt,
2768285612Sdelphij	 double *lat,
2769285612Sdelphij	 double *lon,
2770285612Sdelphij	 double *alt,
2771285612Sdelphij	 double *clock_bias,
2772285612Sdelphij	 float *time_of_fix
2773285612Sdelphij	 )
2774106424Sroberto{
2775106424Sroberto	unsigned char *buf;
2776106424Sroberto	buf = rpt->buf;
2777106424Sroberto
2778106424Sroberto	if (rpt->len != 36) return TRUE;
2779106424Sroberto	*lat = bGetDouble (buf);
2780106424Sroberto	*lon = bGetDouble (&buf[8]);
2781106424Sroberto	*alt = bGetDouble (&buf[16]);
2782106424Sroberto	*clock_bias = bGetDouble (&buf[24]);
2783106424Sroberto	*time_of_fix = bGetSingle (&buf[32]);
2784106424Sroberto	return FALSE;
2785106424Sroberto}
2786106424Sroberto
2787285612Sdelphijshort
2788285612Sdelphijrpt_Paly0xBB(
2789285612Sdelphij	     TSIPPKT *rpt,
2790285612Sdelphij	     TSIP_RCVR_CFG *TsipxBB
2791285612Sdelphij	     )
2792106424Sroberto{
2793106424Sroberto	unsigned char *buf;
2794106424Sroberto	buf = rpt->buf;
2795106424Sroberto
2796285612Sdelphij	/* Palisade is inconsistent with other TSIP, which has a length of 40 */
2797106424Sroberto	/* if (rpt->len != 40) return TRUE; */
2798106424Sroberto	if (rpt->len != 43) return TRUE;
2799106424Sroberto
2800285612Sdelphij	TsipxBB->bSubcode	=  buf[0];
2801285612Sdelphij	TsipxBB->operating_mode	=  buf[1];
2802285612Sdelphij	TsipxBB->dyn_code	=  buf[3];
2803285612Sdelphij	TsipxBB->elev_mask	=  bGetSingle (&buf[5]);
2804285612Sdelphij	TsipxBB->cno_mask	=  bGetSingle (&buf[9]);
2805285612Sdelphij	TsipxBB->dop_mask 	=  bGetSingle (&buf[13]);
2806106424Sroberto	TsipxBB->dop_switch 	=  bGetSingle (&buf[17]);
2807106424Sroberto	return FALSE;
2808106424Sroberto}
2809106424Sroberto
2810106424Sroberto/* Receiver serial port configuration */
2811285612Sdelphijshort
2812285612Sdelphijrpt_0xBC(
2813285612Sdelphij	 TSIPPKT *rpt,
2814285612Sdelphij	 unsigned char *port_num,
2815285612Sdelphij	 unsigned char *in_baud,
2816285612Sdelphij	 unsigned char *out_baud,
2817285612Sdelphij	 unsigned char *data_bits,
2818285612Sdelphij	 unsigned char *parity,
2819285612Sdelphij	 unsigned char *stop_bits,
2820285612Sdelphij	 unsigned char *flow_control,
2821285612Sdelphij	 unsigned char *protocols_in,
2822285612Sdelphij	 unsigned char *protocols_out,
2823285612Sdelphij	 unsigned char *reserved
2824285612Sdelphij	 )
2825106424Sroberto{
2826106424Sroberto	unsigned char *buf;
2827106424Sroberto	buf = rpt->buf;
2828106424Sroberto
2829106424Sroberto	if (rpt->len != 10) return TRUE;
2830106424Sroberto	*port_num = buf[0];
2831106424Sroberto	*in_baud = buf[1];
2832106424Sroberto	*out_baud = buf[2];
2833106424Sroberto	*data_bits = buf[3];
2834106424Sroberto	*parity = buf[4];
2835106424Sroberto	*stop_bits = buf[5];
2836106424Sroberto	*flow_control = buf[6];
2837106424Sroberto	*protocols_in = buf[7];
2838106424Sroberto	*protocols_out = buf[8];
2839106424Sroberto	*reserved = buf[9];
2840106424Sroberto
2841106424Sroberto	return FALSE;
2842106424Sroberto}
2843106424Sroberto
2844106424Sroberto/**** Superpackets ****/
2845106424Sroberto
2846285612Sdelphijshort
2847285612Sdelphijrpt_0x8F0B(
2848285612Sdelphij	   TSIPPKT *rpt,
2849285612Sdelphij	   unsigned short *event,
2850285612Sdelphij	   double *tow,
2851285612Sdelphij	   unsigned char *date,
2852285612Sdelphij	   unsigned char *month,
2853285612Sdelphij	   short *year,
2854285612Sdelphij	   unsigned char *dim_mode,
2855285612Sdelphij	   short *utc_offset,
2856285612Sdelphij	   double *bias,
2857285612Sdelphij	   double *drift,
2858285612Sdelphij	   float *bias_unc,
2859285612Sdelphij	   float *dr_unc,
2860285612Sdelphij	   double *lat,
2861285612Sdelphij	   double *lon,
2862285612Sdelphij	   double *alt,
2863285612Sdelphij	   char sv_id[8]
2864285612Sdelphij	   )
2865106424Sroberto{
2866285612Sdelphij	short local_index;
2867285612Sdelphij	unsigned char *buf;
2868106424Sroberto
2869106424Sroberto	buf = rpt->buf;
2870285612Sdelphij	if (rpt->len != 74) return TRUE;
2871285612Sdelphij	*event = bGetShort(&buf[1]);
2872285612Sdelphij	*tow = bGetDouble(&buf[3]);
2873285612Sdelphij	*date = buf[11];
2874285612Sdelphij	*month = buf[12];
2875285612Sdelphij	*year = bGetShort(&buf[13]);
2876285612Sdelphij	*dim_mode = buf[15];
2877285612Sdelphij	*utc_offset = bGetShort(&buf[16]);
2878285612Sdelphij	*bias = bGetDouble(&buf[18]);
2879285612Sdelphij	*drift = bGetDouble(&buf[26]);
2880285612Sdelphij	*bias_unc = bGetSingle(&buf[34]);
2881285612Sdelphij	*dr_unc = bGetSingle(&buf[38]);
2882285612Sdelphij	*lat = bGetDouble(&buf[42]);
2883285612Sdelphij	*lon = bGetDouble(&buf[50]);
2884285612Sdelphij	*alt = bGetDouble(&buf[58]);
2885106424Sroberto
2886285612Sdelphij	for (local_index=0; local_index<8; local_index++) sv_id[local_index] = buf[local_index + 66];
2887285612Sdelphij	return FALSE;
2888106424Sroberto}
2889106424Sroberto
2890285612Sdelphij/* datum index and coefficients  */
2891285612Sdelphijshort
2892285612Sdelphijrpt_0x8F14(
2893285612Sdelphij	   TSIPPKT *rpt,
2894285612Sdelphij	   short *datum_idx,
2895285612Sdelphij	   double datum_coeffs[5]
2896285612Sdelphij	   )
2897106424Sroberto{
2898106424Sroberto	unsigned char *buf;
2899106424Sroberto	buf = rpt->buf;
2900106424Sroberto
2901106424Sroberto	if (rpt->len != 43) return TRUE;
2902106424Sroberto	*datum_idx = bGetShort(&buf[1]);
2903106424Sroberto	datum_coeffs[0] = bGetDouble (&buf[3]);
2904106424Sroberto	datum_coeffs[1] = bGetDouble (&buf[11]);
2905106424Sroberto	datum_coeffs[2] = bGetDouble (&buf[19]);
2906106424Sroberto	datum_coeffs[3] = bGetDouble (&buf[27]);
2907106424Sroberto	datum_coeffs[4] = bGetDouble (&buf[35]);
2908106424Sroberto	return FALSE;
2909106424Sroberto}
2910106424Sroberto
2911106424Sroberto
2912285612Sdelphij/* datum index and coefficients  */
2913285612Sdelphijshort
2914285612Sdelphijrpt_0x8F15(
2915285612Sdelphij	   TSIPPKT *rpt,
2916285612Sdelphij	   short *datum_idx,
2917285612Sdelphij	   double datum_coeffs[5]
2918285612Sdelphij	   )
2919106424Sroberto{
2920106424Sroberto	unsigned char *buf;
2921106424Sroberto	buf = rpt->buf;
2922106424Sroberto
2923106424Sroberto	if (rpt->len != 43) return TRUE;
2924106424Sroberto	*datum_idx = bGetShort(&buf[1]);
2925106424Sroberto	datum_coeffs[0] = bGetDouble (&buf[3]);
2926106424Sroberto	datum_coeffs[1] = bGetDouble (&buf[11]);
2927106424Sroberto	datum_coeffs[2] = bGetDouble (&buf[19]);
2928106424Sroberto	datum_coeffs[3] = bGetDouble (&buf[27]);
2929106424Sroberto	datum_coeffs[4] = bGetDouble (&buf[35]);
2930106424Sroberto	return FALSE;
2931106424Sroberto}
2932106424Sroberto
2933106424Sroberto
2934106424Sroberto#define MAX_LONG  (2147483648.)   /* 2**31 */
2935106424Sroberto
2936285612Sdelphijshort
2937285612Sdelphijrpt_0x8F20(
2938285612Sdelphij	   TSIPPKT *rpt,
2939285612Sdelphij	   unsigned char *info,
2940285612Sdelphij	   double *lat,
2941285612Sdelphij	   double *lon,
2942285612Sdelphij	   double *alt,
2943285612Sdelphij	   double vel_enu[],
2944285612Sdelphij	   double *time_of_fix,
2945285612Sdelphij	   short *week_num,
2946285612Sdelphij	   unsigned char *nsvs,
2947285612Sdelphij	   unsigned char sv_prn[],
2948285612Sdelphij	   short sv_IODC[],
2949285612Sdelphij	   short *datum_index
2950285612Sdelphij	   )
2951106424Sroberto{
2952106424Sroberto	short
2953285612Sdelphij	    isv;
2954106424Sroberto	unsigned char
2955285612Sdelphij	    *buf, prnx, iode;
2956106424Sroberto	unsigned long
2957285612Sdelphij	    ulongtemp;
2958106424Sroberto	long
2959285612Sdelphij	    longtemp;
2960106424Sroberto	double
2961285612Sdelphij	    vel_scale;
2962106424Sroberto
2963106424Sroberto	buf = rpt->buf;
2964106424Sroberto
2965106424Sroberto	if (rpt->len != 56) return TRUE;
2966106424Sroberto
2967106424Sroberto	vel_scale = (buf[24]&1)? 0.020 : 0.005;
2968106424Sroberto	vel_enu[0] = bGetShort (buf+2)*vel_scale;
2969106424Sroberto	vel_enu[1] = bGetShort (buf+4)*vel_scale;
2970106424Sroberto	vel_enu[2] = bGetShort (buf+6)*vel_scale;
2971106424Sroberto
2972106424Sroberto	*time_of_fix = bGetULong (buf+8)*.001;
2973106424Sroberto
2974106424Sroberto	longtemp = bGetLong (buf+12);
2975106424Sroberto	*lat = longtemp*(GPS_PI/MAX_LONG);
2976106424Sroberto
2977106424Sroberto	ulongtemp = bGetULong (buf+16);
2978106424Sroberto	*lon = ulongtemp*(GPS_PI/MAX_LONG);
2979106424Sroberto	if (*lon > GPS_PI) *lon -= 2.0*GPS_PI;
2980106424Sroberto
2981106424Sroberto	*alt = bGetLong (buf+20)*.001;
2982106424Sroberto	/* 25 blank; 29 = UTC */
2983106424Sroberto	(*datum_index) = (short)((short)buf[26]-1);
2984106424Sroberto	*info = buf[27];
2985106424Sroberto	*nsvs = buf[28];
2986106424Sroberto	*week_num = bGetShort (&buf[30]);
2987106424Sroberto	for (isv = 0; isv < 8; isv++) {
2988106424Sroberto		prnx = buf[32+2*isv];
2989106424Sroberto		sv_prn[isv] = (unsigned char)(prnx&0x3F);
2990285612Sdelphij		iode = buf[33+2*isv];
2991106424Sroberto		sv_IODC[isv] = (short)(iode | ((prnx>>6)<<8));
2992106424Sroberto	}
2993106424Sroberto	return FALSE;
2994106424Sroberto}
2995106424Sroberto
2996285612Sdelphijshort
2997285612Sdelphijrpt_0x8F41(
2998285612Sdelphij	   TSIPPKT *rpt,
2999285612Sdelphij	   unsigned char *bSearchRange,
3000285612Sdelphij	   unsigned char *bBoardOptions,
3001285612Sdelphij	   unsigned long *iiSerialNumber,
3002285612Sdelphij	   unsigned char *bBuildYear,
3003285612Sdelphij	   unsigned char *bBuildMonth,
3004285612Sdelphij	   unsigned char *bBuildDay,
3005285612Sdelphij	   unsigned char *bBuildHour,
3006285612Sdelphij	   float *fOscOffset,
3007285612Sdelphij	   unsigned short *iTestCodeId
3008285612Sdelphij	   )
3009106424Sroberto{
3010285612Sdelphij	if (rpt->len != 17) return FALSE;
3011106424Sroberto	*bSearchRange = rpt->buf[1];
3012106424Sroberto	*bBoardOptions = rpt->buf[2];
3013106424Sroberto	*iiSerialNumber = bGetLong(&rpt->buf[3]);
3014106424Sroberto	*bBuildYear = rpt->buf[7];
3015106424Sroberto	*bBuildMonth = rpt->buf[8];
3016106424Sroberto	*bBuildDay = rpt->buf[9];
3017106424Sroberto	*bBuildHour =	rpt->buf[10];
3018106424Sroberto	*fOscOffset = bGetSingle(&rpt->buf[11]);
3019106424Sroberto	*iTestCodeId = bGetShort(&rpt->buf[15]);
3020106424Sroberto/*	Tsipx8E41Data = *Tsipx8E41; */
3021106424Sroberto	return TRUE;
3022106424Sroberto}
3023106424Sroberto
3024285612Sdelphijshort
3025285612Sdelphijrpt_0x8F42(
3026285612Sdelphij	   TSIPPKT *rpt,
3027285612Sdelphij	   unsigned char *bProdOptionsPre,
3028285612Sdelphij	   unsigned char *bProdNumberExt,
3029285612Sdelphij	   unsigned short *iCaseSerialNumberPre,
3030285612Sdelphij	   unsigned long *iiCaseSerialNumber,
3031285612Sdelphij	   unsigned long *iiProdNumber,
3032285612Sdelphij	   unsigned short *iPremiumOptions,
3033285612Sdelphij	   unsigned short *iMachineID,
3034285612Sdelphij	   unsigned short *iKey
3035285612Sdelphij	   )
3036106424Sroberto{
3037285612Sdelphij	if (rpt->len != 19) return FALSE;
3038106424Sroberto	*bProdOptionsPre = rpt->buf[1];
3039106424Sroberto	*bProdNumberExt = rpt->buf[2];
3040106424Sroberto	*iCaseSerialNumberPre = bGetShort(&rpt->buf[3]);
3041106424Sroberto	*iiCaseSerialNumber = bGetLong(&rpt->buf[5]);
3042106424Sroberto	*iiProdNumber = bGetLong(&rpt->buf[9]);
3043106424Sroberto	*iPremiumOptions = bGetShort(&rpt->buf[13]);
3044106424Sroberto	*iMachineID = bGetShort(&rpt->buf[15]);
3045106424Sroberto	*iKey = bGetShort(&rpt->buf[17]);
3046106424Sroberto	return TRUE;
3047106424Sroberto}
3048106424Sroberto
3049285612Sdelphijshort
3050285612Sdelphijrpt_0x8F45(
3051285612Sdelphij	   TSIPPKT *rpt,
3052285612Sdelphij	   unsigned char *bSegMask
3053285612Sdelphij	   )
3054106424Sroberto{
3055285612Sdelphij	if (rpt->len != 2) return FALSE;
3056106424Sroberto	*bSegMask = rpt->buf[1];
3057106424Sroberto	return TRUE;
3058106424Sroberto}
3059106424Sroberto
3060106424Sroberto/* Stinger PPS definition */
3061285612Sdelphijshort
3062285612Sdelphijrpt_0x8F4A_16(
3063285612Sdelphij	      TSIPPKT *rpt,
3064285612Sdelphij	      unsigned char *pps_enabled,
3065285612Sdelphij	      unsigned char *pps_timebase,
3066285612Sdelphij	      unsigned char *pos_polarity,
3067285612Sdelphij	      double *pps_offset,
3068285612Sdelphij	      float *bias_unc_threshold
3069285612Sdelphij	      )
3070106424Sroberto{
3071106424Sroberto	unsigned char
3072285612Sdelphij	    *buf;
3073106424Sroberto
3074285612Sdelphij	buf = rpt->buf;
3075285612Sdelphij	if (rpt->len != 16) return TRUE;
3076285612Sdelphij	*pps_enabled = buf[1];
3077285612Sdelphij	*pps_timebase = buf[2];
3078285612Sdelphij	*pos_polarity = buf[3];
3079285612Sdelphij	*pps_offset = bGetDouble(&buf[4]);
3080285612Sdelphij	*bias_unc_threshold = bGetSingle(&buf[12]);
3081106424Sroberto	return FALSE;
3082106424Sroberto}
3083106424Sroberto
3084285612Sdelphijshort
3085285612Sdelphijrpt_0x8F4B(
3086285612Sdelphij	   TSIPPKT *rpt,
3087285612Sdelphij	   unsigned long *decorr_max
3088285612Sdelphij	   )
3089106424Sroberto{
3090106424Sroberto	unsigned char
3091285612Sdelphij	    *buf;
3092106424Sroberto
3093285612Sdelphij	buf = rpt->buf;
3094285612Sdelphij	if (rpt->len != 5) return TRUE;
3095285612Sdelphij	*decorr_max = bGetLong(&buf[1]);
3096285612Sdelphij	return FALSE;
3097106424Sroberto}
3098106424Sroberto
3099285612Sdelphijshort
3100285612Sdelphijrpt_0x8F4D(
3101285612Sdelphij	   TSIPPKT *rpt,
3102285612Sdelphij	   unsigned long *event_mask
3103285612Sdelphij	   )
3104106424Sroberto{
3105106424Sroberto	unsigned char
3106285612Sdelphij	    *buf;
3107106424Sroberto
3108285612Sdelphij	buf = rpt->buf;
3109285612Sdelphij	if (rpt->len != 5) return TRUE;
3110285612Sdelphij	*event_mask = bGetULong (&buf[1]);
3111285612Sdelphij	return FALSE;
3112106424Sroberto}
3113106424Sroberto
3114285612Sdelphijshort
3115285612Sdelphijrpt_0x8FA5(
3116285612Sdelphij	   TSIPPKT *rpt,
3117285612Sdelphij	   unsigned char *spktmask
3118285612Sdelphij	   )
3119106424Sroberto{
3120106424Sroberto	unsigned char
3121285612Sdelphij	    *buf;
3122106424Sroberto
3123285612Sdelphij	buf = rpt->buf;
3124285612Sdelphij	if (rpt->len != 5) return TRUE;
3125285612Sdelphij	spktmask[0] = buf[1];
3126285612Sdelphij	spktmask[1] = buf[2];
3127285612Sdelphij	spktmask[2] = buf[3];
3128285612Sdelphij	spktmask[3] = buf[4];
3129285612Sdelphij	return FALSE;
3130106424Sroberto}
3131106424Sroberto
3132285612Sdelphijshort
3133285612Sdelphijrpt_0x8FAD(
3134285612Sdelphij	   TSIPPKT *rpt,
3135285612Sdelphij	   unsigned short *COUNT,
3136285612Sdelphij	   double *FracSec,
3137285612Sdelphij	   unsigned char *Hour,
3138285612Sdelphij	   unsigned char *Minute,
3139285612Sdelphij	   unsigned char *Second,
3140285612Sdelphij	   unsigned char *Day,
3141285612Sdelphij	   unsigned char *Month,
3142285612Sdelphij	   unsigned short *Year,
3143285612Sdelphij	   unsigned char *Status,
3144285612Sdelphij	   unsigned char *Flags
3145285612Sdelphij	   )
3146106424Sroberto{
3147106424Sroberto	if (rpt->len != 22) return TRUE;
3148106424Sroberto
3149285612Sdelphij	*COUNT = bGetUShort(&rpt->buf[1]);
3150285612Sdelphij	*FracSec = bGetDouble(&rpt->buf[3]);
3151285612Sdelphij	*Hour = rpt->buf[11];
3152285612Sdelphij	*Minute = rpt->buf[12];
3153285612Sdelphij	*Second = rpt->buf[13];
3154285612Sdelphij	*Day = rpt->buf[14];
3155285612Sdelphij	*Month = rpt->buf[15];
3156285612Sdelphij	*Year = bGetUShort(&rpt->buf[16]);
3157285612Sdelphij	*Status = rpt->buf[18];
3158285612Sdelphij	*Flags = rpt->buf[19];
3159285612Sdelphij	return FALSE;
3160106424Sroberto}
3161106424Sroberto
3162106424Sroberto
3163106424Sroberto/*
3164106424Sroberto * *************************************************************************
3165106424Sroberto *
3166106424Sroberto * Trimble Navigation, Ltd.
3167106424Sroberto * OEM Products Development Group
3168106424Sroberto * P.O. Box 3642
3169106424Sroberto * 645 North Mary Avenue
3170106424Sroberto * Sunnyvale, California 94088-3642
3171106424Sroberto *
3172106424Sroberto * Corporate Headquarter:
3173106424Sroberto *    Telephone:  (408) 481-8000
3174106424Sroberto *    Fax:        (408) 481-6005
3175106424Sroberto *
3176106424Sroberto * Technical Support Center:
3177106424Sroberto *    Telephone:  (800) 767-4822	(U.S. and Canada)
3178106424Sroberto *                (408) 481-6940    (outside U.S. and Canada)
3179106424Sroberto *    Fax:        (408) 481-6020
3180106424Sroberto *    BBS:        (408) 481-7800
3181106424Sroberto *    e-mail:     trimble_support@trimble.com
3182106424Sroberto *		ftp://ftp.trimble.com/pub/sct/embedded/bin
3183106424Sroberto *
3184106424Sroberto * *************************************************************************
3185106424Sroberto *
3186106424Sroberto * T_REPORT.C consists of a primary function TranslateTSIPReportToText()
3187106424Sroberto * called by main().
3188106424Sroberto *
3189106424Sroberto * This function takes a character buffer that has been received as a report
3190106424Sroberto * from a TSIP device and interprets it.  The character buffer has been
3191106424Sroberto * assembled using tsip_input_proc() in T_PARSER.C.
3192106424Sroberto *
3193106424Sroberto * A large case statement directs processing to one of many mid-level
3194106424Sroberto * functions.  The mid-level functions specific to the current report
3195106424Sroberto * code passes the report buffer to the appropriate report decoder
3196106424Sroberto * rpt_0x?? () in T_PARSER.C, which converts the byte stream in rpt.buf
3197106424Sroberto * to data values approporaite for use.
3198106424Sroberto *
3199106424Sroberto * *************************************************************************
3200106424Sroberto *
3201106424Sroberto */
3202106424Sroberto
3203106424Sroberto
3204106424Sroberto#define GOOD_PARSE 0
3205106424Sroberto#define BADID_PARSE 1
3206106424Sroberto#define BADLEN_PARSE 2
3207106424Sroberto#define BADDATA_PARSE 3
3208106424Sroberto
3209106424Sroberto#define B_TSIP	0x02
3210106424Sroberto#define B_NMEA	0x04
3211106424Sroberto
3212106424Sroberto
3213106424Sroberto/* pbuf is the pointer to the current location of the text output */
3214106424Srobertostatic char
3215285612Sdelphij*pbuf;
3216106424Sroberto
3217106424Sroberto/* keep track of whether the message has been successfully parsed */
3218106424Srobertostatic short
3219285612Sdelphijparsed;
3220106424Sroberto
3221106424Sroberto
3222106424Sroberto/* convert time of week into day-hour-minute-second and print */
3223285612Sdelphijchar *
3224285612Sdelphijshow_time(
3225285612Sdelphij	  float time_of_week
3226285612Sdelphij	  )
3227106424Sroberto{
3228106424Sroberto	short	days, hours, minutes;
3229106424Sroberto	float seconds;
3230106424Sroberto	double tow = 0;
3231285612Sdelphij	static char timestring [80];
3232106424Sroberto
3233106424Sroberto	if (time_of_week == -1.0)
3234285612Sdelphij	{
3235106424Sroberto		sprintf(timestring, "   <No time yet>   ");
3236106424Sroberto	}
3237106424Sroberto	else if ((time_of_week >= 604800.0) || (time_of_week < 0.0))
3238285612Sdelphij	{
3239106424Sroberto		sprintf(timestring, "     <Bad time>     ");
3240106424Sroberto	}
3241285612Sdelphij	else
3242285612Sdelphij	{
3243106424Sroberto		if (time_of_week < 604799.9)
3244106424Sroberto			tow = time_of_week + .00000001;
3245106424Sroberto		seconds = (float)fmod(tow, 60.);
3246106424Sroberto		minutes =  (short) fmod(tow/60., 60.);
3247106424Sroberto		hours = (short)fmod(tow / 3600., 24.);
3248106424Sroberto		days = (short)(tow / 86400.0);
3249106424Sroberto		sprintf(timestring, " %s %02d:%02d:%05.2f   ",
3250285612Sdelphij			dayname[days], hours, minutes, seconds);
3251285612Sdelphij	}
3252285612Sdelphij	return timestring;
3253106424Sroberto}
3254106424Sroberto
3255106424Sroberto/**/
3256106424Sroberto/* 0x3D */
3257285612Sdelphijstatic void
3258285612Sdelphijrpt_chan_A_config(
3259285612Sdelphij		  TSIPPKT *rpt
3260285612Sdelphij		  )
3261106424Sroberto{
3262106424Sroberto	unsigned char
3263285612Sdelphij	    tx_baud_index, rx_baud_index,
3264285612Sdelphij	    char_format_index, stop_bits,
3265285612Sdelphij	    tx_mode_index, rx_mode_index,
3266285612Sdelphij	    databits, parity;
3267106424Sroberto	int
3268285612Sdelphij	    i, nbaud;
3269106424Sroberto
3270106424Sroberto	/* unload rptbuf */
3271106424Sroberto	if (rpt_0x3D (rpt,
3272285612Sdelphij		      &tx_baud_index, &rx_baud_index, &char_format_index,
3273285612Sdelphij		      &stop_bits, &tx_mode_index, &rx_mode_index)) {
3274106424Sroberto		parsed = BADLEN_PARSE;
3275106424Sroberto		return;
3276106424Sroberto	}
3277106424Sroberto
3278106424Sroberto	pbuf += sprintf(pbuf, "\nChannel A Configuration");
3279106424Sroberto
3280285612Sdelphij	nbaud = sizeof(old_baudnum);
3281106424Sroberto
3282106424Sroberto	for (i = 0; i < nbaud; ++i) if (tx_baud_index == old_baudnum[i]) break;
3283106424Sroberto	pbuf += sprintf(pbuf, "\n   Transmit speed: %s at %s",
3284285612Sdelphij			old_output_ch[tx_mode_index], st_baud_text_app[i]);
3285106424Sroberto
3286106424Sroberto	for (i = 0; i < nbaud; ++i) if (rx_baud_index == old_baudnum[i]) break;
3287106424Sroberto	pbuf += sprintf(pbuf, "\n   Receive speed: %s at %s",
3288285612Sdelphij			old_input_ch[rx_mode_index], st_baud_text_app[i]);
3289106424Sroberto
3290106424Sroberto	databits = (unsigned char)((char_format_index & 0x03) + 5);
3291106424Sroberto
3292106424Sroberto	parity = (unsigned char)(char_format_index >> 2);
3293106424Sroberto	if (parity > 4) parity = 2;
3294106424Sroberto
3295106424Sroberto	pbuf += sprintf(pbuf, "\n   Character format (bits/char, parity, stop bits): %d-%s-%d",
3296285612Sdelphij			databits, old_parity_text[parity], stop_bits);
3297106424Sroberto}
3298106424Sroberto
3299106424Sroberto/**/
3300106424Sroberto/* 0x40 */
3301285612Sdelphijstatic void
3302285612Sdelphijrpt_almanac_data_page(
3303285612Sdelphij		      TSIPPKT *rpt
3304285612Sdelphij		      )
3305106424Sroberto{
3306106424Sroberto	unsigned char
3307285612Sdelphij	    sv_prn;
3308106424Sroberto	short
3309285612Sdelphij	    week_num;
3310106424Sroberto	float
3311285612Sdelphij	    t_zc,
3312285612Sdelphij	    eccentricity,
3313285612Sdelphij	    t_oa,
3314285612Sdelphij	    i_0,
3315285612Sdelphij	    OMEGA_dot,
3316285612Sdelphij	    sqrt_A,
3317285612Sdelphij	    OMEGA_0,
3318285612Sdelphij	    omega,
3319285612Sdelphij	    M_0;
3320106424Sroberto
3321106424Sroberto	/* unload rptbuf */
3322106424Sroberto	if (rpt_0x40 (rpt,
3323285612Sdelphij		      &sv_prn, &week_num, &t_zc, &eccentricity, &t_oa,
3324285612Sdelphij		      &i_0, &OMEGA_dot, &sqrt_A, &OMEGA_0, &omega, &M_0)) {
3325106424Sroberto		parsed = BADLEN_PARSE;
3326106424Sroberto		return;
3327106424Sroberto	}
3328106424Sroberto
3329106424Sroberto	pbuf += sprintf(pbuf, "\nAlmanac for SV %02d", sv_prn);
3330106424Sroberto	pbuf += sprintf(pbuf, "\n       Captured:%15.0f %s",
3331285612Sdelphij			t_zc, show_time (t_zc));
3332106424Sroberto	pbuf += sprintf(pbuf, "\n           week:%15d", week_num);
3333106424Sroberto	pbuf += sprintf(pbuf, "\n   Eccentricity:%15g", eccentricity);
3334106424Sroberto	pbuf += sprintf(pbuf, "\n           T_oa:%15.0f %s",
3335285612Sdelphij			t_oa, show_time (t_oa));
3336106424Sroberto	pbuf += sprintf(pbuf, "\n            i 0:%15g", i_0);
3337106424Sroberto	pbuf += sprintf(pbuf, "\n      OMEGA dot:%15g", OMEGA_dot);
3338106424Sroberto	pbuf += sprintf(pbuf, "\n         sqrt A:%15g", sqrt_A);
3339106424Sroberto	pbuf += sprintf(pbuf, "\n        OMEGA 0:%15g", OMEGA_0);
3340106424Sroberto	pbuf += sprintf(pbuf, "\n          omega:%15g", omega);
3341106424Sroberto	pbuf += sprintf(pbuf, "\n            M 0:%15g", M_0);
3342106424Sroberto}
3343106424Sroberto
3344106424Sroberto/* 0x41 */
3345285612Sdelphijstatic void
3346285612Sdelphijrpt_GPS_time(
3347285612Sdelphij	     TSIPPKT *rpt
3348285612Sdelphij	     )
3349106424Sroberto{
3350106424Sroberto	float
3351285612Sdelphij	    time_of_week, UTC_offset;
3352106424Sroberto	short
3353285612Sdelphij	    week_num;
3354106424Sroberto
3355106424Sroberto	/* unload rptbuf */
3356106424Sroberto	if (rpt_0x41 (rpt, &time_of_week, &UTC_offset, &week_num)) {
3357106424Sroberto		parsed = BADLEN_PARSE;
3358106424Sroberto		return;
3359106424Sroberto	}
3360106424Sroberto
3361106424Sroberto	pbuf += sprintf(pbuf, "\nGPS time:%s GPS week: %d   UTC offset %.1f",
3362285612Sdelphij			show_time(time_of_week), week_num, UTC_offset);
3363106424Sroberto
3364106424Sroberto}
3365106424Sroberto
3366106424Sroberto/* 0x42 */
3367285612Sdelphijstatic void
3368285612Sdelphijrpt_single_ECEF_position(
3369285612Sdelphij			 TSIPPKT *rpt
3370285612Sdelphij			 )
3371106424Sroberto{
3372106424Sroberto	float
3373285612Sdelphij	    ECEF_pos[3], time_of_fix;
3374106424Sroberto
3375106424Sroberto	/* unload rptbuf */
3376106424Sroberto	if (rpt_0x42 (rpt, ECEF_pos, &time_of_fix)) {
3377106424Sroberto		parsed = BADLEN_PARSE;
3378106424Sroberto		return;
3379106424Sroberto	}
3380106424Sroberto
3381106424Sroberto	pbuf += sprintf(pbuf, "\nSXYZ:  %15.0f  %15.0f  %15.0f    %s",
3382285612Sdelphij			ECEF_pos[0], ECEF_pos[1], ECEF_pos[2],
3383285612Sdelphij			show_time(time_of_fix));
3384106424Sroberto}
3385106424Sroberto
3386106424Sroberto/* 0x43 */
3387285612Sdelphijstatic void
3388285612Sdelphijrpt_single_ECEF_velocity(
3389285612Sdelphij			 TSIPPKT *rpt
3390285612Sdelphij			 )
3391106424Sroberto{
3392106424Sroberto
3393106424Sroberto	float
3394285612Sdelphij	    ECEF_vel[3], freq_offset, time_of_fix;
3395106424Sroberto
3396106424Sroberto	/* unload rptbuf */
3397106424Sroberto	if (rpt_0x43 (rpt, ECEF_vel, &freq_offset, &time_of_fix)) {
3398106424Sroberto		parsed = BADLEN_PARSE;
3399106424Sroberto		return;
3400106424Sroberto	}
3401106424Sroberto
3402106424Sroberto	pbuf += sprintf(pbuf, "\nVelECEF: %11.3f  %11.3f  %11.3f  %12.3f%s",
3403285612Sdelphij			ECEF_vel[0], ECEF_vel[1], ECEF_vel[2], freq_offset,
3404285612Sdelphij			show_time(time_of_fix));
3405106424Sroberto}
3406106424Sroberto
3407106424Sroberto/*  0x45  */
3408285612Sdelphijstatic void
3409285612Sdelphijrpt_SW_version(
3410285612Sdelphij	       TSIPPKT *rpt
3411285612Sdelphij	       )
3412285612Sdelphij{
3413106424Sroberto	unsigned char
3414285612Sdelphij	    major_nav_version, minor_nav_version,
3415285612Sdelphij	    nav_day, nav_month, nav_year,
3416285612Sdelphij	    major_dsp_version, minor_dsp_version,
3417285612Sdelphij	    dsp_day, dsp_month, dsp_year;
3418106424Sroberto
3419106424Sroberto	/* unload rptbuf */
3420106424Sroberto	if (rpt_0x45 (rpt,
3421285612Sdelphij		      &major_nav_version, &minor_nav_version,
3422285612Sdelphij		      &nav_day, &nav_month, &nav_year,
3423285612Sdelphij		      &major_dsp_version, &minor_dsp_version,
3424285612Sdelphij		      &dsp_day, &dsp_month, &dsp_year)) {
3425106424Sroberto		parsed = BADLEN_PARSE;
3426106424Sroberto		return;
3427106424Sroberto	}
3428106424Sroberto
3429106424Sroberto	pbuf += sprintf(pbuf,
3430285612Sdelphij			"\nFW Versions:  Nav Proc %2d.%02d  %2d/%2d/%2d  Sig Proc %2d.%02d  %2d/%2d/%2d",
3431285612Sdelphij			major_nav_version, minor_nav_version, nav_day, nav_month, nav_year,
3432285612Sdelphij			major_dsp_version, minor_dsp_version, dsp_day, dsp_month, dsp_year);
3433106424Sroberto}
3434106424Sroberto
3435106424Sroberto/* 0x46 */
3436285612Sdelphijstatic void
3437285612Sdelphijrpt_rcvr_health(
3438285612Sdelphij		TSIPPKT *rpt
3439285612Sdelphij		)
3440106424Sroberto{
3441106424Sroberto	unsigned char
3442285612Sdelphij	    status1, status2;
3443285612Sdelphij	const char
3444285612Sdelphij	    *text;
3445285612Sdelphij	static const char const
3446285612Sdelphij	    *sc_text[] = {
3447285612Sdelphij		"Doing position fixes",
3448285612Sdelphij		"Don't have GPS time yet",
3449285612Sdelphij		"Waiting for almanac collection",
3450285612Sdelphij		"DOP too high          ",
3451285612Sdelphij		"No satellites available",
3452285612Sdelphij		"Only 1 satellite available",
3453285612Sdelphij		"Only 2 satellites available",
3454285612Sdelphij		"Only 3 satellites available",
3455285612Sdelphij		"No satellites usable   ",
3456285612Sdelphij		"Only 1 satellite usable",
3457285612Sdelphij		"Only 2 satellites usable",
3458285612Sdelphij		"Only 3 satellites usable",
3459285612Sdelphij		"Chosen satellite unusable"};
3460106424Sroberto
3461106424Sroberto
3462106424Sroberto	/* unload rptbuf */
3463106424Sroberto	if (rpt_0x46 (rpt, &status1, &status2))
3464106424Sroberto	{
3465106424Sroberto		parsed = BADLEN_PARSE;
3466106424Sroberto		return;
3467106424Sroberto	}
3468106424Sroberto
3469285612Sdelphij	text = (status1 < COUNTOF(sc_text))
3470285612Sdelphij	    ? sc_text[status1]
3471285612Sdelphij	    : "(out of range)";
3472106424Sroberto	pbuf += sprintf(pbuf, "\nRcvr status1: %s (%02Xh); ",
3473285612Sdelphij			text, status1);
3474106424Sroberto
3475106424Sroberto	pbuf += sprintf(pbuf, "status2: %s, %s (%02Xh)",
3476285612Sdelphij			(status2 & 0x01)?"No BBRAM":"BBRAM OK",
3477285612Sdelphij			(status2 & 0x10)?"No Ant":"Ant OK",
3478285612Sdelphij			status2);
3479106424Sroberto}
3480106424Sroberto
3481106424Sroberto/* 0x47 */
3482285612Sdelphijstatic void
3483285612Sdelphijrpt_SNR_all_SVs(
3484285612Sdelphij		TSIPPKT *rpt
3485285612Sdelphij		)
3486106424Sroberto{
3487106424Sroberto	unsigned char
3488285612Sdelphij	    nsvs, sv_prn[12];
3489106424Sroberto	short
3490285612Sdelphij	    isv;
3491106424Sroberto	float
3492285612Sdelphij	    snr[12];
3493106424Sroberto
3494106424Sroberto	/* unload rptbuf */
3495106424Sroberto	if (rpt_0x47 (rpt, &nsvs, sv_prn, snr))
3496285612Sdelphij	{
3497106424Sroberto		parsed = BADLEN_PARSE;
3498106424Sroberto		return;
3499106424Sroberto	}
3500106424Sroberto
3501106424Sroberto	pbuf += sprintf(pbuf, "\nSNR for satellites: %d", nsvs);
3502106424Sroberto	for (isv = 0; isv < nsvs; isv++)
3503285612Sdelphij	{
3504106424Sroberto		pbuf += sprintf(pbuf, "\n    SV %02d   %6.2f",
3505285612Sdelphij				sv_prn[isv], snr[isv]);
3506106424Sroberto	}
3507106424Sroberto}
3508106424Sroberto
3509106424Sroberto/* 0x48 */
3510285612Sdelphijstatic void
3511285612Sdelphijrpt_GPS_system_message(
3512285612Sdelphij		       TSIPPKT *rpt
3513285612Sdelphij		       )
3514106424Sroberto{
3515106424Sroberto	unsigned char
3516285612Sdelphij	    message[23];
3517106424Sroberto
3518106424Sroberto	/* unload rptbuf */
3519106424Sroberto	if (rpt_0x48 (rpt, message))
3520285612Sdelphij	{
3521106424Sroberto		parsed = BADLEN_PARSE;
3522106424Sroberto		return;
3523106424Sroberto	}
3524106424Sroberto
3525106424Sroberto	pbuf += sprintf(pbuf, "\nGPS message: %s", message);
3526106424Sroberto}
3527106424Sroberto
3528106424Sroberto/* 0x49 */
3529285612Sdelphijstatic void
3530285612Sdelphijrpt_almanac_health_page(
3531285612Sdelphij			TSIPPKT *rpt
3532285612Sdelphij			)
3533106424Sroberto{
3534106424Sroberto	short
3535285612Sdelphij	    iprn;
3536106424Sroberto	unsigned char
3537285612Sdelphij	    sv_health [32];
3538106424Sroberto
3539106424Sroberto	/* unload rptbuf */
3540106424Sroberto	if (rpt_0x49 (rpt, sv_health))
3541285612Sdelphij	{
3542106424Sroberto		parsed = BADLEN_PARSE;
3543106424Sroberto		return;
3544106424Sroberto	}
3545106424Sroberto
3546106424Sroberto	pbuf += sprintf(pbuf, "\nAlmanac health page:");
3547106424Sroberto	for (iprn = 0; iprn < 32; iprn++)
3548285612Sdelphij	{
3549106424Sroberto		if (!(iprn%5)) *pbuf++ = '\n';
3550106424Sroberto		pbuf += sprintf(pbuf, "    SV%02d  %2X",
3551285612Sdelphij				(iprn+1) , sv_health[iprn]);
3552106424Sroberto	}
3553106424Sroberto}
3554106424Sroberto
3555106424Sroberto/* 0x4A */
3556285612Sdelphijstatic void
3557285612Sdelphijrpt_single_lla_position(
3558285612Sdelphij			TSIPPKT *rpt
3559285612Sdelphij			)
3560285612Sdelphij{
3561106424Sroberto	short
3562285612Sdelphij	    lat_deg, lon_deg;
3563106424Sroberto	float
3564285612Sdelphij	    lat, lon,
3565285612Sdelphij	    alt, clock_bias, time_of_fix;
3566106424Sroberto	double lat_min, lon_min;
3567106424Sroberto	unsigned char
3568285612Sdelphij	    north_south, east_west;
3569106424Sroberto
3570106424Sroberto	if (rpt_0x4A (rpt,
3571285612Sdelphij		      &lat, &lon, &alt, &clock_bias, &time_of_fix))
3572285612Sdelphij	{
3573106424Sroberto		parsed = BADLEN_PARSE;
3574106424Sroberto		return;
3575106424Sroberto	}
3576106424Sroberto
3577106424Sroberto	/* convert from radians to degrees */
3578106424Sroberto	lat *= (float)R2D;
3579106424Sroberto	north_south = 'N';
3580106424Sroberto	if (lat < 0.0)
3581285612Sdelphij	{
3582106424Sroberto		north_south = 'S';
3583106424Sroberto		lat = -lat;
3584106424Sroberto	}
3585106424Sroberto	lat_deg = (short)lat;
3586106424Sroberto	lat_min = (lat - lat_deg) * 60.0;
3587106424Sroberto
3588106424Sroberto	lon *= (float)R2D;
3589106424Sroberto	east_west = 'E';
3590106424Sroberto	if (lon < 0.0)
3591285612Sdelphij	{
3592106424Sroberto		east_west = 'W';
3593106424Sroberto		lon = -lon;
3594106424Sroberto	}
3595106424Sroberto	lon_deg = (short)lon;
3596106424Sroberto	lon_min = (lon - lon_deg) * 60.0;
3597106424Sroberto
3598106424Sroberto	pbuf += sprintf(pbuf, "\nSLLA: %4d: %06.3f  %c%5d:%06.3f  %c%10.2f  %12.2f%s",
3599285612Sdelphij			lat_deg, lat_min, north_south,
3600285612Sdelphij			lon_deg, lon_min, east_west,
3601285612Sdelphij			alt, clock_bias,
3602285612Sdelphij			show_time(time_of_fix));
3603106424Sroberto}
3604106424Sroberto
3605106424Sroberto/* 0x4A */
3606285612Sdelphijstatic void
3607285612Sdelphijrpt_ref_alt(
3608285612Sdelphij	    TSIPPKT *rpt
3609285612Sdelphij	    )
3610285612Sdelphij{
3611106424Sroberto	float
3612285612Sdelphij	    alt, dummy;
3613106424Sroberto	unsigned char
3614285612Sdelphij	    alt_flag;
3615106424Sroberto
3616285612Sdelphij	if (rpt_0x4A_2 (rpt, &alt, &dummy, &alt_flag))
3617285612Sdelphij	{
3618106424Sroberto		parsed = BADLEN_PARSE;
3619106424Sroberto		return;
3620106424Sroberto	}
3621106424Sroberto
3622106424Sroberto	pbuf += sprintf(pbuf, "\nReference Alt:   %.1f m;    %s",
3623285612Sdelphij			alt, alt_flag?"ON":"OFF");
3624106424Sroberto}
3625106424Sroberto
3626106424Sroberto/* 0x4B */
3627285612Sdelphijstatic void
3628285612Sdelphijrpt_rcvr_id_and_status(
3629285612Sdelphij		       TSIPPKT *rpt
3630285612Sdelphij		       )
3631106424Sroberto{
3632106424Sroberto
3633106424Sroberto	unsigned char
3634285612Sdelphij	    machine_id, status3, status4;
3635106424Sroberto
3636106424Sroberto	/* unload rptbuf */
3637106424Sroberto	if (rpt_0x4B (rpt, &machine_id, &status3, &status4))
3638285612Sdelphij	{
3639106424Sroberto		parsed = BADLEN_PARSE;
3640106424Sroberto		return;
3641106424Sroberto	}
3642106424Sroberto
3643106424Sroberto	pbuf += sprintf(pbuf, "\nRcvr Machine ID: %d; Status3 = %s, %s (%02Xh)",
3644285612Sdelphij			machine_id,
3645285612Sdelphij			(status3 & 0x02)?"No RTC":"RTC OK",
3646285612Sdelphij			(status3 & 0x08)?"No Alm":"Alm OK",
3647285612Sdelphij			status3);
3648106424Sroberto}
3649106424Sroberto
3650106424Sroberto/* 0x4C */
3651285612Sdelphijstatic void
3652285612Sdelphijrpt_operating_parameters(
3653285612Sdelphij			 TSIPPKT *rpt
3654285612Sdelphij			 )
3655106424Sroberto{
3656106424Sroberto	unsigned char
3657285612Sdelphij	    dyn_code;
3658106424Sroberto	float
3659285612Sdelphij	    el_mask, snr_mask, dop_mask, dop_switch;
3660106424Sroberto
3661106424Sroberto	/* unload rptbuf */
3662106424Sroberto	if (rpt_0x4C (rpt, &dyn_code, &el_mask,
3663285612Sdelphij		      &snr_mask, &dop_mask, &dop_switch))
3664285612Sdelphij	{
3665106424Sroberto		parsed = BADLEN_PARSE;
3666106424Sroberto		return;
3667106424Sroberto	}
3668106424Sroberto
3669106424Sroberto	pbuf += sprintf(pbuf, "\nOperating Parameters:");
3670106424Sroberto	pbuf += sprintf(pbuf, "\n     Dynamics code = %d %s",
3671285612Sdelphij			dyn_code, dyn_text[dyn_code]);
3672285612Sdelphij	pbuf += sprintf(pbuf, "\n     Elevation mask = %.2f", el_mask * R2D);
3673106424Sroberto	pbuf += sprintf(pbuf, "\n     SNR mask = %.2f", snr_mask);
3674106424Sroberto	pbuf += sprintf(pbuf, "\n     DOP mask = %.2f", dop_mask);
3675106424Sroberto	pbuf += sprintf(pbuf, "\n     DOP switch = %.2f", dop_switch);
3676106424Sroberto}
3677106424Sroberto
3678106424Sroberto/* 0x4D */
3679285612Sdelphijstatic void
3680285612Sdelphijrpt_oscillator_offset(
3681285612Sdelphij		      TSIPPKT *rpt
3682285612Sdelphij		      )
3683106424Sroberto{
3684106424Sroberto	float
3685285612Sdelphij	    osc_offset;
3686106424Sroberto
3687106424Sroberto	/* unload rptbuf */
3688106424Sroberto	if (rpt_0x4D (rpt, &osc_offset))
3689285612Sdelphij	{
3690106424Sroberto		parsed = BADLEN_PARSE;
3691106424Sroberto		return;
3692106424Sroberto	}
3693106424Sroberto
3694106424Sroberto	pbuf += sprintf(pbuf, "\nOscillator offset: %.2f Hz = %.3f PPM",
3695285612Sdelphij			osc_offset, osc_offset/1575.42);
3696106424Sroberto}
3697106424Sroberto
3698106424Sroberto/* 0x4E */
3699285612Sdelphijstatic void
3700285612Sdelphijrpt_GPS_time_set_response(
3701285612Sdelphij			  TSIPPKT *rpt
3702285612Sdelphij			  )
3703106424Sroberto{
3704106424Sroberto	unsigned char
3705285612Sdelphij	    response;
3706106424Sroberto
3707106424Sroberto	/* unload rptbuf */
3708106424Sroberto	if (rpt_0x4E (rpt, &response))
3709285612Sdelphij	{
3710106424Sroberto		parsed = BADLEN_PARSE;
3711106424Sroberto		return;
3712106424Sroberto	}
3713106424Sroberto
3714106424Sroberto	switch (response)
3715285612Sdelphij	{
3716285612Sdelphij	    case 'Y':
3717106424Sroberto		pbuf += sprintf(pbuf, "\nTime set accepted");
3718106424Sroberto		break;
3719106424Sroberto
3720285612Sdelphij	    case 'N':
3721106424Sroberto		pbuf += sprintf(pbuf, "\nTime set rejected or not required");
3722106424Sroberto		break;
3723106424Sroberto
3724285612Sdelphij	    default:
3725106424Sroberto		parsed = BADDATA_PARSE;
3726106424Sroberto	}
3727106424Sroberto}
3728106424Sroberto
3729106424Sroberto/* 0x4F */
3730285612Sdelphijstatic void
3731285612Sdelphijrpt_UTC_offset(
3732285612Sdelphij	       TSIPPKT *rpt
3733285612Sdelphij	       )
3734106424Sroberto{
3735106424Sroberto	double
3736285612Sdelphij	    a0;
3737106424Sroberto	float
3738285612Sdelphij	    a1, time_of_data;
3739106424Sroberto	short
3740285612Sdelphij	    dt_ls, wn_t, wn_lsf, dn, dt_lsf;
3741106424Sroberto
3742106424Sroberto	/* unload rptbuf */
3743106424Sroberto	if (rpt_0x4F (rpt, &a0, &a1, &time_of_data,
3744285612Sdelphij		      &dt_ls, &wn_t, &wn_lsf, &dn, &dt_lsf)) {
3745106424Sroberto		parsed = BADLEN_PARSE;
3746106424Sroberto		return;
3747106424Sroberto	}
3748106424Sroberto
3749106424Sroberto	pbuf += sprintf(pbuf, "\nUTC Correction Data");
3750106424Sroberto	pbuf += sprintf(pbuf, "\n   A_0         = %g  ", a0);
3751106424Sroberto	pbuf += sprintf(pbuf, "\n   A_1         = %g  ", a1);
3752106424Sroberto	pbuf += sprintf(pbuf, "\n   delta_t_LS  = %d  ", dt_ls);
3753106424Sroberto	pbuf += sprintf(pbuf, "\n   t_ot        = %.0f  ", time_of_data);
3754106424Sroberto	pbuf += sprintf(pbuf, "\n   WN_t        = %d  ", wn_t );
3755106424Sroberto	pbuf += sprintf(pbuf, "\n   WN_LSF      = %d  ", wn_lsf );
3756106424Sroberto	pbuf += sprintf(pbuf, "\n   DN          = %d  ", dn );
3757106424Sroberto	pbuf += sprintf(pbuf, "\n   delta_t_LSF = %d  ", dt_lsf );
3758106424Sroberto}
3759106424Sroberto
3760106424Sroberto/**/
3761106424Sroberto/* 0x54 */
3762285612Sdelphijstatic void
3763285612Sdelphijrpt_1SV_bias(
3764285612Sdelphij	     TSIPPKT *rpt
3765285612Sdelphij	     )
3766106424Sroberto{
3767106424Sroberto	float
3768285612Sdelphij	    clock_bias, freq_offset, time_of_fix;
3769106424Sroberto
3770106424Sroberto	/* unload rptbuf */
3771106424Sroberto	if (rpt_0x54 (rpt, &clock_bias, &freq_offset, &time_of_fix)) {
3772106424Sroberto		parsed = BADLEN_PARSE;
3773106424Sroberto		return;
3774106424Sroberto	}
3775106424Sroberto
3776106424Sroberto	pbuf += sprintf (pbuf, "\nTime Fix   Clock Bias: %6.2f m  Freq Bias: %6.2f m/s%s",
3777285612Sdelphij			 clock_bias, freq_offset, show_time (time_of_fix));
3778106424Sroberto}
3779106424Sroberto
3780106424Sroberto/* 0x55 */
3781285612Sdelphijstatic void
3782285612Sdelphijrpt_io_opt(
3783285612Sdelphij	   TSIPPKT *rpt
3784285612Sdelphij	   )
3785106424Sroberto{
3786106424Sroberto	unsigned char
3787285612Sdelphij	    pos_code, vel_code, time_code, aux_code;
3788106424Sroberto
3789106424Sroberto	/* unload rptbuf */
3790106424Sroberto	if (rpt_0x55 (rpt,
3791285612Sdelphij		      &pos_code, &vel_code, &time_code, &aux_code)) {
3792106424Sroberto		parsed = BADLEN_PARSE;
3793106424Sroberto		return;
3794106424Sroberto	}
3795106424Sroberto	/* rptbuf unloaded */
3796106424Sroberto
3797106424Sroberto	pbuf += sprintf(pbuf, "\nI/O Options: %2X %2X %2X %2X",
3798285612Sdelphij			pos_code, vel_code, time_code, aux_code);
3799106424Sroberto
3800106424Sroberto	if (pos_code & 0x01) {
3801106424Sroberto		pbuf += sprintf(pbuf, "\n    ECEF XYZ position output");
3802106424Sroberto	}
3803106424Sroberto
3804106424Sroberto	if (pos_code & 0x02) {
3805106424Sroberto		pbuf += sprintf(pbuf, "\n    LLA position output");
3806106424Sroberto	}
3807106424Sroberto
3808106424Sroberto	pbuf += sprintf(pbuf, (pos_code & 0x04)?
3809285612Sdelphij			"\n    MSL altitude output (Geoid height) ":
3810285612Sdelphij			"\n    WGS-84 altitude output");
3811106424Sroberto
3812106424Sroberto	pbuf += sprintf(pbuf, (pos_code & 0x08)?
3813285612Sdelphij			"\n    MSL altitude input":
3814285612Sdelphij			"\n    WGS-84 altitude input");
3815106424Sroberto
3816106424Sroberto	pbuf += sprintf(pbuf, (pos_code & 0x10)?
3817285612Sdelphij			"\n    Double precision":
3818285612Sdelphij			"\n    Single precision");
3819106424Sroberto
3820106424Sroberto	if (pos_code & 0x20) {
3821106424Sroberto		pbuf += sprintf(pbuf, "\n    All Enabled Superpackets");
3822106424Sroberto	}
3823106424Sroberto
3824106424Sroberto	if (vel_code & 0x01) {
3825106424Sroberto		pbuf += sprintf(pbuf, "\n    ECEF XYZ velocity output");
3826106424Sroberto	}
3827106424Sroberto
3828106424Sroberto	if (vel_code & 0x02) {
3829106424Sroberto		pbuf += sprintf(pbuf, "\n    ENU velocity output");
3830106424Sroberto	}
3831106424Sroberto
3832106424Sroberto	pbuf += sprintf(pbuf, (time_code & 0x01)?
3833285612Sdelphij			"\n    Time tags in UTC":
3834285612Sdelphij			"\n    Time tags in GPS time");
3835106424Sroberto
3836106424Sroberto	if (time_code & 0x02) {
3837106424Sroberto		pbuf += sprintf(pbuf, "\n    Fixes delayed to integer seconds");
3838106424Sroberto	}
3839106424Sroberto
3840106424Sroberto	if (time_code & 0x04) {
3841106424Sroberto		pbuf += sprintf(pbuf, "\n    Fixes sent only on request");
3842106424Sroberto	}
3843106424Sroberto
3844106424Sroberto	if (time_code & 0x08) {
3845106424Sroberto		pbuf += sprintf(pbuf, "\n    Synchronized measurements");
3846106424Sroberto	}
3847106424Sroberto
3848106424Sroberto	if (time_code & 0x10) {
3849106424Sroberto		pbuf += sprintf(pbuf, "\n    Minimize measurement propagation");
3850106424Sroberto	}
3851106424Sroberto
3852285612Sdelphij	pbuf += sprintf(pbuf, (time_code & 0x20) ?
3853285612Sdelphij			"\n    PPS output at all times" :
3854285612Sdelphij			"\n    PPS output during fixes");
3855106424Sroberto
3856106424Sroberto	if (aux_code & 0x01) {
3857106424Sroberto		pbuf += sprintf(pbuf, "\n    Raw measurement output");
3858106424Sroberto	}
3859106424Sroberto
3860106424Sroberto	if (aux_code & 0x02) {
3861106424Sroberto		pbuf += sprintf(pbuf, "\n    Code-phase smoothed before output");
3862106424Sroberto	}
3863106424Sroberto
3864106424Sroberto	if (aux_code & 0x04) {
3865106424Sroberto		pbuf += sprintf(pbuf, "\n    Additional fix status");
3866106424Sroberto	}
3867106424Sroberto
3868106424Sroberto	pbuf += sprintf(pbuf, (aux_code & 0x08)?
3869285612Sdelphij			"\n    Signal Strength Output as dBHz" :
3870285612Sdelphij			"\n    Signal Strength Output as AMU");
3871106424Sroberto}
3872106424Sroberto
3873106424Sroberto/* 0x56 */
3874285612Sdelphijstatic void
3875285612Sdelphijrpt_ENU_velocity(
3876285612Sdelphij		 TSIPPKT *rpt
3877285612Sdelphij		 )
3878106424Sroberto{
3879106424Sroberto	float
3880285612Sdelphij	    vel_ENU[3], freq_offset, time_of_fix;
3881106424Sroberto
3882106424Sroberto	/* unload rptbuf */
3883106424Sroberto	if (rpt_0x56 (rpt, vel_ENU, &freq_offset, &time_of_fix)) {
3884106424Sroberto		parsed = BADLEN_PARSE;
3885106424Sroberto		return;
3886106424Sroberto	}
3887106424Sroberto
3888106424Sroberto	pbuf += sprintf(pbuf, "\nVel ENU: %11.3f  %11.3f  %11.3f  %12.3f%s",
3889285612Sdelphij			vel_ENU[0], vel_ENU[1], vel_ENU[2], freq_offset,
3890285612Sdelphij			show_time (time_of_fix));
3891106424Sroberto}
3892106424Sroberto
3893106424Sroberto/* 0x57 */
3894285612Sdelphijstatic void
3895285612Sdelphijrpt_last_fix_info(
3896285612Sdelphij		  TSIPPKT *rpt
3897285612Sdelphij		  )
3898106424Sroberto{
3899106424Sroberto	unsigned char
3900285612Sdelphij	    source_code, diag_code;
3901106424Sroberto	short
3902285612Sdelphij	    week_num;
3903106424Sroberto	float
3904285612Sdelphij	    time_of_fix;
3905106424Sroberto
3906106424Sroberto	/* unload rptbuf */
3907106424Sroberto	if (rpt_0x57 (rpt, &source_code, &diag_code, &week_num, &time_of_fix)) {
3908106424Sroberto		parsed = BADLEN_PARSE;
3909106424Sroberto		return;
3910106424Sroberto	}
3911106424Sroberto
3912106424Sroberto	pbuf += sprintf(pbuf, "\n source code %d;   diag code: %2Xh",
3913285612Sdelphij			source_code, diag_code);
3914106424Sroberto	pbuf += sprintf(pbuf, "\n    Time of last fix:%s", show_time(time_of_fix));
3915106424Sroberto	pbuf += sprintf(pbuf, "\n    Week of last fix: %d", week_num);
3916106424Sroberto}
3917106424Sroberto
3918106424Sroberto/* 0x58 */
3919285612Sdelphijstatic void
3920285612Sdelphijrpt_GPS_system_data(
3921285612Sdelphij		    TSIPPKT *rpt
3922285612Sdelphij		    )
3923106424Sroberto{
3924106424Sroberto	unsigned char
3925285612Sdelphij	    iprn,
3926285612Sdelphij	    op_code, data_type, sv_prn,
3927285612Sdelphij	    data_length, data_packet[250];
3928106424Sroberto	ALM_INFO
3929285612Sdelphij	    *almanac;
3930106424Sroberto	ALH_PARMS
3931285612Sdelphij	    *almh;
3932106424Sroberto	UTC_INFO
3933285612Sdelphij	    *utc;
3934106424Sroberto	ION_INFO
3935285612Sdelphij	    *ionosphere;
3936106424Sroberto	EPHEM_CLOCK
3937285612Sdelphij	    *cdata;
3938106424Sroberto	EPHEM_ORBIT
3939285612Sdelphij	    *edata;
3940106424Sroberto	NAV_INFO
3941285612Sdelphij	    *nav_data;
3942106424Sroberto	unsigned char
3943285612Sdelphij	    curr_t_oa;
3944106424Sroberto	unsigned short
3945285612Sdelphij	    curr_wn_oa;
3946106424Sroberto	static char
3947285612Sdelphij	    *datname[] =
3948285612Sdelphij	    {"", "", "Almanac Orbit",
3949285612Sdelphij	     "Health Page & Ref Time", "Ionosphere", "UTC ",
3950285612Sdelphij	     "Ephemeris"};
3951106424Sroberto
3952106424Sroberto	/* unload rptbuf */
3953106424Sroberto	if (rpt_0x58 (rpt, &op_code, &data_type, &sv_prn,
3954285612Sdelphij		      &data_length, data_packet))
3955285612Sdelphij	{
3956106424Sroberto		parsed = BADLEN_PARSE;
3957106424Sroberto		return;
3958106424Sroberto	}
3959106424Sroberto
3960106424Sroberto	pbuf += sprintf(pbuf, "\nSystem data [%d]:  %s  SV%02d",
3961285612Sdelphij			data_type, datname[data_type], sv_prn);
3962106424Sroberto	switch (op_code)
3963106424Sroberto	{
3964285612Sdelphij	    case 1:
3965106424Sroberto		pbuf += sprintf(pbuf, "  Acknowledgment");
3966106424Sroberto		break;
3967285612Sdelphij	    case 2:
3968106424Sroberto		pbuf += sprintf(pbuf, "  length = %d bytes", data_length);
3969106424Sroberto		switch (data_type) {
3970285612Sdelphij		    case 2:
3971106424Sroberto			/* Almanac */
3972106424Sroberto			if (sv_prn == 0 || sv_prn > 32) {
3973106424Sroberto				pbuf += sprintf(pbuf, "  Binary PRN invalid");
3974106424Sroberto				return;
3975106424Sroberto			}
3976106424Sroberto			almanac = (ALM_INFO*)data_packet;
3977106424Sroberto			pbuf += sprintf(pbuf, "\n   t_oa_raw = % -12d    SV_hlth  = % -12d  ",
3978285612Sdelphij					almanac->t_oa_raw , almanac->SV_health );
3979106424Sroberto			pbuf += sprintf(pbuf, "\n   e        = % -12g    t_oa     = % -12g  ",
3980285612Sdelphij					almanac->e        , almanac->t_oa     );
3981106424Sroberto			pbuf += sprintf(pbuf, "\n   i_0      = % -12g    OMEGADOT = % -12g  ",
3982285612Sdelphij					almanac->i_0      , almanac->OMEGADOT );
3983106424Sroberto			pbuf += sprintf(pbuf, "\n   sqrt_A   = % -12g    OMEGA_0  = % -12g  ",
3984285612Sdelphij					almanac->sqrt_A   , almanac->OMEGA_0  );
3985106424Sroberto			pbuf += sprintf(pbuf, "\n   omega    = % -12g    M_0      = % -12g  ",
3986285612Sdelphij					almanac->omega    , almanac->M_0      );
3987106424Sroberto			pbuf += sprintf(pbuf, "\n   a_f0     = % -12g    a_f1     = % -12g  ",
3988285612Sdelphij					almanac->a_f0     , almanac->a_f1     );
3989106424Sroberto			pbuf += sprintf(pbuf, "\n   Axis     = % -12g    n        = % -12g  ",
3990285612Sdelphij					almanac->Axis     , almanac->n        );
3991106424Sroberto			pbuf += sprintf(pbuf, "\n   OMEGA_n  = % -12g    ODOT_n   = % -12g  ",
3992285612Sdelphij					almanac->OMEGA_n  , almanac->ODOT_n   );
3993106424Sroberto			pbuf += sprintf(pbuf, "\n   t_zc     = % -12g    weeknum  = % -12d  ",
3994285612Sdelphij					almanac->t_zc     , almanac->weeknum  );
3995106424Sroberto			pbuf += sprintf(pbuf, "\n   wn_oa    = % -12d", almanac->wn_oa    );
3996106424Sroberto			break;
3997106424Sroberto
3998285612Sdelphij		    case 3:
3999106424Sroberto			/* Almanac health page */
4000106424Sroberto			almh = (ALH_PARMS*)data_packet;
4001106424Sroberto			pbuf += sprintf(pbuf, "\n   t_oa = %d, wn_oa&0xFF = %d  ",
4002285612Sdelphij					almh->t_oa, almh->WN_a);
4003106424Sroberto			pbuf += sprintf(pbuf, "\nAlmanac health page:");
4004106424Sroberto			for (iprn = 0; iprn < 32; iprn++) {
4005106424Sroberto				if (!(iprn%5)) *pbuf++ = '\n';
4006106424Sroberto				pbuf += sprintf(pbuf, "    SV%02d  %2X",
4007285612Sdelphij						(iprn+1) , almh->SV_health[iprn]);
4008106424Sroberto			}
4009106424Sroberto			curr_t_oa = data_packet[34];
4010106424Sroberto			curr_wn_oa = (unsigned short)((data_packet[35]<<8) + data_packet[36]);
4011106424Sroberto			pbuf += sprintf(pbuf, "\n   current t_oa = %d, wn_oa = %d  ",
4012285612Sdelphij					curr_t_oa, curr_wn_oa);
4013106424Sroberto			break;
4014106424Sroberto
4015285612Sdelphij		    case 4:
4016106424Sroberto			/* Ionosphere */
4017106424Sroberto			ionosphere = (ION_INFO*)data_packet;
4018106424Sroberto			pbuf += sprintf(pbuf, "\n   alpha_0 = % -12g  alpha_1 = % -12g ",
4019285612Sdelphij					ionosphere->alpha_0, ionosphere->alpha_1);
4020106424Sroberto			pbuf += sprintf(pbuf, "\n   alpha_2 = % -12g  alpha_3 = % -12g ",
4021285612Sdelphij					ionosphere->alpha_2, ionosphere->alpha_3);
4022106424Sroberto			pbuf += sprintf(pbuf, "\n   beta_0  = % -12g  beta_1  = % -12g  ",
4023285612Sdelphij					ionosphere->beta_0, ionosphere->beta_1);
4024106424Sroberto			pbuf += sprintf(pbuf, "\n   beta_2  = % -12g  beta_3  = % -12g  ",
4025285612Sdelphij					ionosphere->beta_2, ionosphere->beta_3);
4026106424Sroberto			break;
4027106424Sroberto
4028285612Sdelphij		    case 5:
4029106424Sroberto			/* UTC */
4030106424Sroberto			utc = (UTC_INFO*)data_packet;
4031106424Sroberto			pbuf += sprintf(pbuf, "\n   A_0         = %g  ", utc->A_0);
4032106424Sroberto			pbuf += sprintf(pbuf, "\n   A_1         = %g  ", utc->A_1);
4033106424Sroberto			pbuf += sprintf(pbuf, "\n   delta_t_LS  = %d  ", utc->delta_t_LS);
4034106424Sroberto			pbuf += sprintf(pbuf, "\n   t_ot        = %.0f  ", utc->t_ot );
4035106424Sroberto			pbuf += sprintf(pbuf, "\n   WN_t        = %d  ", utc->WN_t );
4036106424Sroberto			pbuf += sprintf(pbuf, "\n   WN_LSF      = %d  ", utc->WN_LSF );
4037106424Sroberto			pbuf += sprintf(pbuf, "\n   DN          = %d  ", utc->DN );
4038106424Sroberto			pbuf += sprintf(pbuf, "\n   delta_t_LSF = %d  ", utc->delta_t_LSF );
4039106424Sroberto			break;
4040106424Sroberto
4041285612Sdelphij		    case 6: /* Ephemeris */
4042106424Sroberto			if (sv_prn == 0 || sv_prn > 32) {
4043106424Sroberto				pbuf += sprintf(pbuf, "  Binary PRN invalid");
4044106424Sroberto				return;
4045106424Sroberto			}
4046106424Sroberto			nav_data = (NAV_INFO*)data_packet;
4047106424Sroberto
4048106424Sroberto			pbuf += sprintf(pbuf, "\n     SV_PRN = % -12d .  t_ephem = % -12g . ",
4049285612Sdelphij					nav_data->sv_number , nav_data->t_ephem );
4050106424Sroberto			cdata = &(nav_data->ephclk);
4051106424Sroberto			pbuf += sprintf(pbuf,
4052285612Sdelphij					"\n    weeknum = % -12d .   codeL2 = % -12d .  L2Pdata = % -12d",
4053285612Sdelphij					cdata->weeknum , cdata->codeL2 , cdata->L2Pdata );
4054106424Sroberto			pbuf += sprintf(pbuf,
4055285612Sdelphij					"\n  SVacc_raw = % -12d .SV_health = % -12d .     IODC = % -12d",
4056285612Sdelphij					cdata->SVacc_raw, cdata->SV_health, cdata->IODC );
4057106424Sroberto			pbuf += sprintf(pbuf,
4058285612Sdelphij					"\n       T_GD = % -12g .     t_oc = % -12g .     a_f2 = % -12g",
4059285612Sdelphij					cdata->T_GD, cdata->t_oc, cdata->a_f2 );
4060106424Sroberto			pbuf += sprintf(pbuf,
4061285612Sdelphij					"\n       a_f1 = % -12g .     a_f0 = % -12g .    SVacc = % -12g",
4062285612Sdelphij					cdata->a_f1, cdata->a_f0, cdata->SVacc );
4063106424Sroberto			edata = &(nav_data->ephorb);
4064106424Sroberto			pbuf += sprintf(pbuf,
4065285612Sdelphij					"\n       IODE = % -12d .fit_intvl = % -12d .     C_rs = % -12g",
4066285612Sdelphij					edata->IODE, edata->fit_interval, edata->C_rs );
4067106424Sroberto			pbuf += sprintf(pbuf,
4068285612Sdelphij					"\n    delta_n = % -12g .      M_0 = % -12g .     C_uc = % -12g",
4069285612Sdelphij					edata->delta_n, edata->M_0, edata->C_uc );
4070106424Sroberto			pbuf += sprintf(pbuf,
4071285612Sdelphij					"\n        ecc = % -12g .     C_us = % -12g .   sqrt_A = % -12g",
4072285612Sdelphij					edata->e, edata->C_us, edata->sqrt_A );
4073106424Sroberto			pbuf += sprintf(pbuf,
4074285612Sdelphij					"\n       t_oe = % -12g .     C_ic = % -12g .  OMEGA_0 = % -12g",
4075285612Sdelphij					edata->t_oe, edata->C_ic, edata->OMEGA_0 );
4076106424Sroberto			pbuf += sprintf(pbuf,
4077285612Sdelphij					"\n       C_is = % -12g .      i_0 = % -12g .     C_rc = % -12g",
4078285612Sdelphij					edata->C_is, edata->i_0, edata->C_rc );
4079106424Sroberto			pbuf += sprintf(pbuf,
4080285612Sdelphij					"\n      omega = % -12g . OMEGADOT = % -12g .     IDOT = % -12g",
4081285612Sdelphij					edata->omega, edata->OMEGADOT, edata->IDOT );
4082106424Sroberto			pbuf += sprintf(pbuf,
4083285612Sdelphij					"\n       Axis = % -12g .        n = % -12g .    r1me2 = % -12g",
4084285612Sdelphij					edata->Axis, edata->n, edata->r1me2 );
4085106424Sroberto			pbuf += sprintf(pbuf,
4086285612Sdelphij					"\n    OMEGA_n = % -12g .   ODOT_n = % -12g",
4087285612Sdelphij					edata->OMEGA_n, edata->ODOT_n );
4088106424Sroberto			break;
4089106424Sroberto		}
4090106424Sroberto	}
4091106424Sroberto}
4092106424Sroberto
4093106424Sroberto
4094106424Sroberto/* 0x59: */
4095285612Sdelphijstatic void
4096285612Sdelphijrpt_SVs_enabled(
4097285612Sdelphij		TSIPPKT *rpt
4098285612Sdelphij		)
4099106424Sroberto{
4100106424Sroberto	unsigned char
4101285612Sdelphij	    numsvs,
4102285612Sdelphij	    code_type,
4103285612Sdelphij	    status_code[32];
4104106424Sroberto	short
4105285612Sdelphij	    iprn;
4106106424Sroberto
4107106424Sroberto	/* unload rptbuf */
4108106424Sroberto	if (rpt_0x59 (rpt, &code_type, status_code))
4109285612Sdelphij	{
4110106424Sroberto		parsed = BADLEN_PARSE;
4111106424Sroberto		return;
4112106424Sroberto	}
4113285612Sdelphij	switch (code_type)
4114285612Sdelphij	{
4115285612Sdelphij	    case 3: pbuf += sprintf(pbuf, "\nSVs Disabled:\n"); break;
4116285612Sdelphij	    case 6: pbuf += sprintf(pbuf, "\nSVs with Health Ignored:\n"); break;
4117285612Sdelphij	    default: return;
4118285612Sdelphij	}
4119285612Sdelphij	numsvs = 0;
4120285612Sdelphij	for (iprn = 0; iprn < 32; iprn++)
4121285612Sdelphij	{
4122285612Sdelphij		if (status_code[iprn])
4123285612Sdelphij		{
4124285612Sdelphij			pbuf += sprintf(pbuf, " %02d", iprn+1);
4125285612Sdelphij			numsvs++;
4126285612Sdelphij		}
4127285612Sdelphij	}
4128285612Sdelphij	if (numsvs == 0) pbuf += sprintf(pbuf, "None");
4129106424Sroberto}
4130106424Sroberto
4131106424Sroberto
4132106424Sroberto/* 0x5A */
4133285612Sdelphijstatic void
4134285612Sdelphijrpt_raw_msmt(
4135285612Sdelphij	     TSIPPKT *rpt
4136285612Sdelphij	     )
4137106424Sroberto{
4138106424Sroberto	unsigned char
4139285612Sdelphij	    sv_prn;
4140106424Sroberto	float
4141285612Sdelphij	    sample_length, signal_level, code_phase, Doppler;
4142106424Sroberto	double
4143285612Sdelphij	    time_of_fix;
4144106424Sroberto
4145106424Sroberto	/* unload rptbuf */
4146106424Sroberto	if (rpt_0x5A (rpt, &sv_prn, &sample_length, &signal_level,
4147285612Sdelphij		      &code_phase, &Doppler, &time_of_fix))
4148285612Sdelphij	{
4149106424Sroberto		parsed = BADLEN_PARSE;
4150106424Sroberto		return;
4151106424Sroberto	}
4152106424Sroberto
4153106424Sroberto	pbuf += sprintf(pbuf, "\n   %02d %5.0f %7.1f %10.2f %10.2f %12.3f %s",
4154285612Sdelphij			sv_prn, sample_length, signal_level, code_phase, Doppler, time_of_fix,
4155285612Sdelphij			show_time ((float)time_of_fix));
4156106424Sroberto}
4157106424Sroberto
4158106424Sroberto/* 0x5B */
4159285612Sdelphijstatic void
4160285612Sdelphijrpt_SV_ephemeris_status(
4161285612Sdelphij			TSIPPKT *rpt
4162285612Sdelphij			)
4163106424Sroberto{
4164106424Sroberto	unsigned char
4165285612Sdelphij	    sv_prn, sv_health, sv_iode, fit_interval_flag;
4166106424Sroberto	float
4167285612Sdelphij	    time_of_collection, time_of_eph, sv_accy;
4168106424Sroberto
4169106424Sroberto	/* unload rptbuf */
4170106424Sroberto	if (rpt_0x5B (rpt, &sv_prn, &sv_health, &sv_iode, &fit_interval_flag,
4171285612Sdelphij		      &time_of_collection, &time_of_eph, &sv_accy))
4172285612Sdelphij	{
4173106424Sroberto		parsed = BADLEN_PARSE;
4174106424Sroberto		return;
4175106424Sroberto	}
4176106424Sroberto
4177106424Sroberto	pbuf += sprintf(pbuf, "\n  SV%02d  %s   %2Xh     %2Xh ",
4178285612Sdelphij			sv_prn, show_time (time_of_collection), sv_health, sv_iode);
4179106424Sroberto	/* note: cannot use show_time twice in same call */
4180106424Sroberto	pbuf += sprintf(pbuf, "%s   %1d   %4.1f",
4181285612Sdelphij			show_time (time_of_eph), fit_interval_flag, sv_accy);
4182106424Sroberto}
4183106424Sroberto
4184106424Sroberto/* 0x5C */
4185285612Sdelphijstatic void
4186285612Sdelphijrpt_SV_tracking_status(
4187285612Sdelphij		       TSIPPKT *rpt
4188285612Sdelphij		       )
4189106424Sroberto{
4190106424Sroberto	unsigned char
4191285612Sdelphij	    sv_prn, chan, slot, acq_flag, eph_flag,
4192285612Sdelphij	    old_msmt_flag, integer_msec_flag, bad_data_flag,
4193285612Sdelphij	    data_collect_flag;
4194106424Sroberto	float
4195285612Sdelphij	    signal_level, time_of_last_msmt,
4196285612Sdelphij	    elev, azim;
4197106424Sroberto
4198106424Sroberto	/* unload rptbuf */
4199106424Sroberto	if (rpt_0x5C (rpt,
4200285612Sdelphij		      &sv_prn, &slot, &chan, &acq_flag, &eph_flag,
4201285612Sdelphij		      &signal_level, &time_of_last_msmt, &elev, &azim,
4202285612Sdelphij		      &old_msmt_flag, &integer_msec_flag, &bad_data_flag,
4203285612Sdelphij		      &data_collect_flag))
4204285612Sdelphij	{
4205106424Sroberto		parsed = BADLEN_PARSE;
4206106424Sroberto		return;
4207106424Sroberto	}
4208106424Sroberto
4209106424Sroberto	pbuf += sprintf(pbuf,
4210285612Sdelphij			"\n SV%2d  %1d   %1d   %1d   %4.1f  %s  %5.1f  %5.1f",
4211285612Sdelphij			sv_prn, chan,
4212285612Sdelphij			acq_flag, eph_flag, signal_level,
4213285612Sdelphij			show_time(time_of_last_msmt),
4214285612Sdelphij			elev*R2D, azim*R2D);
4215106424Sroberto}
4216106424Sroberto
4217106424Sroberto/**/
4218106424Sroberto/* 0x6D */
4219285612Sdelphijstatic void
4220285612Sdelphijrpt_allSV_selection(
4221285612Sdelphij		    TSIPPKT *rpt
4222285612Sdelphij		    )
4223106424Sroberto{
4224106424Sroberto	unsigned char
4225285612Sdelphij	    manual_mode, nsvs, sv_prn[8], ndim;
4226106424Sroberto	short
4227285612Sdelphij	    islot;
4228106424Sroberto	float
4229285612Sdelphij	    pdop, hdop, vdop, tdop;
4230106424Sroberto
4231106424Sroberto	/* unload rptbuf */
4232106424Sroberto	if (rpt_0x6D (rpt,
4233285612Sdelphij		      &manual_mode, &nsvs, &ndim, sv_prn,
4234285612Sdelphij		      &pdop, &hdop, &vdop, &tdop))
4235285612Sdelphij	{
4236106424Sroberto		parsed = BADLEN_PARSE;
4237106424Sroberto		return;
4238106424Sroberto	}
4239106424Sroberto
4240106424Sroberto	switch (ndim)
4241285612Sdelphij	{
4242285612Sdelphij	    case 0:
4243106424Sroberto		pbuf += sprintf(pbuf, "\nMode: Searching, %d-SV:", nsvs);
4244285612Sdelphij		break;
4245285612Sdelphij	    case 1:
4246106424Sroberto		pbuf += sprintf(pbuf, "\nMode: One-SV Timing:");
4247285612Sdelphij		break;
4248285612Sdelphij	    case 3: case 4:
4249106424Sroberto		pbuf += sprintf(pbuf, "\nMode: %c-%dD, %d-SV:",
4250285612Sdelphij				manual_mode ? 'M' : 'A', ndim - 1,  nsvs);
4251285612Sdelphij		break;
4252285612Sdelphij	    case 5:
4253106424Sroberto		pbuf += sprintf(pbuf, "\nMode: Timing, %d-SV:", nsvs);
4254285612Sdelphij		break;
4255285612Sdelphij	    default:
4256106424Sroberto		pbuf += sprintf(pbuf, "\nMode: Unknown = %d:", ndim);
4257285612Sdelphij		break;
4258285612Sdelphij	}
4259106424Sroberto
4260106424Sroberto	for (islot = 0; islot < nsvs; islot++)
4261285612Sdelphij	{
4262106424Sroberto		if (sv_prn[islot]) pbuf += sprintf(pbuf, " %02d", sv_prn[islot]);
4263106424Sroberto	}
4264285612Sdelphij	if (ndim == 3 || ndim == 4)
4265285612Sdelphij	{
4266106424Sroberto		pbuf += sprintf(pbuf, ";  DOPs: P %.1f H %.1f V %.1f T %.1f",
4267285612Sdelphij				pdop, hdop, vdop, tdop);
4268285612Sdelphij	}
4269106424Sroberto}
4270106424Sroberto
4271106424Sroberto/**/
4272106424Sroberto/* 0x82 */
4273285612Sdelphijstatic void
4274285612Sdelphijrpt_DGPS_position_mode(
4275285612Sdelphij		       TSIPPKT *rpt
4276285612Sdelphij		       )
4277106424Sroberto{
4278106424Sroberto	unsigned char
4279285612Sdelphij	    diff_mode;
4280106424Sroberto
4281106424Sroberto	/* unload rptbuf */
4282106424Sroberto	if (rpt_0x82 (rpt, &diff_mode)) {
4283106424Sroberto		parsed = BADLEN_PARSE;
4284106424Sroberto		return;
4285106424Sroberto	}
4286106424Sroberto
4287106424Sroberto	pbuf += sprintf(pbuf, "\nFix is%s DGPS-corrected (%s mode)  (%d)",
4288285612Sdelphij			(diff_mode&1) ? "" : " not",
4289285612Sdelphij			(diff_mode&2) ? "auto" : "manual",
4290285612Sdelphij			diff_mode);
4291106424Sroberto}
4292106424Sroberto
4293106424Sroberto/* 0x83 */
4294285612Sdelphijstatic void
4295285612Sdelphijrpt_double_ECEF_position(
4296285612Sdelphij			 TSIPPKT *rpt
4297285612Sdelphij			 )
4298106424Sroberto{
4299106424Sroberto	double
4300285612Sdelphij	    ECEF_pos[3], clock_bias;
4301106424Sroberto	float
4302285612Sdelphij	    time_of_fix;
4303106424Sroberto
4304106424Sroberto	/* unload rptbuf */
4305106424Sroberto	if (rpt_0x83 (rpt, ECEF_pos, &clock_bias, &time_of_fix))
4306285612Sdelphij	{
4307106424Sroberto		parsed = BADLEN_PARSE;
4308106424Sroberto		return;
4309106424Sroberto	}
4310106424Sroberto
4311106424Sroberto	pbuf += sprintf(pbuf, "\nDXYZ:%12.2f  %13.2f  %13.2f %12.2f%s",
4312285612Sdelphij			ECEF_pos[0], ECEF_pos[1], ECEF_pos[2], clock_bias,
4313285612Sdelphij			show_time(time_of_fix));
4314106424Sroberto}
4315106424Sroberto
4316106424Sroberto/* 0x84 */
4317285612Sdelphijstatic void
4318285612Sdelphijrpt_double_lla_position(
4319285612Sdelphij			TSIPPKT *rpt
4320285612Sdelphij			)
4321106424Sroberto{
4322106424Sroberto	short
4323285612Sdelphij	    lat_deg, lon_deg;
4324106424Sroberto	double
4325285612Sdelphij	    lat, lon, lat_min, lon_min,
4326285612Sdelphij	    alt, clock_bias;
4327106424Sroberto	float
4328285612Sdelphij	    time_of_fix;
4329106424Sroberto	unsigned char
4330285612Sdelphij	    north_south, east_west;
4331106424Sroberto
4332106424Sroberto	/* unload rptbuf */
4333106424Sroberto	if (rpt_0x84 (rpt,
4334285612Sdelphij		      &lat, &lon, &alt, &clock_bias, &time_of_fix))
4335285612Sdelphij	{
4336106424Sroberto		parsed = BADLEN_PARSE;
4337106424Sroberto		return;
4338106424Sroberto	}
4339106424Sroberto
4340106424Sroberto	lat *= R2D;
4341106424Sroberto	lon *= R2D;
4342106424Sroberto	if (lat < 0.0) {
4343106424Sroberto		north_south = 'S';
4344106424Sroberto		lat = -lat;
4345106424Sroberto	} else {
4346106424Sroberto		north_south = 'N';
4347106424Sroberto	}
4348106424Sroberto	lat_deg = (short)lat;
4349106424Sroberto	lat_min = (lat - lat_deg) * 60.0;
4350106424Sroberto
4351106424Sroberto	if (lon < 0.0) {
4352106424Sroberto		east_west = 'W';
4353106424Sroberto		lon = -lon;
4354106424Sroberto	} else {
4355106424Sroberto		east_west = 'E';
4356106424Sroberto	}
4357106424Sroberto	lon_deg = (short)lon;
4358106424Sroberto	lon_min = (lon - lon_deg) * 60.0;
4359106424Sroberto	pbuf += sprintf(pbuf, "\nDLLA: %2d:%08.5f %c; %3d:%08.5f %c; %10.2f %12.2f%s",
4360285612Sdelphij			lat_deg, lat_min, north_south,
4361285612Sdelphij			lon_deg, lon_min, east_west,
4362285612Sdelphij			alt, clock_bias,
4363285612Sdelphij			show_time(time_of_fix));
4364106424Sroberto}
4365106424Sroberto
4366106424Sroberto/* 0xBB */
4367285612Sdelphijstatic void
4368285612Sdelphijrpt_complete_rcvr_config(
4369285612Sdelphij			 TSIPPKT *rpt
4370285612Sdelphij			 )
4371106424Sroberto{
4372106424Sroberto	TSIP_RCVR_CFG TsipxBB ;
4373106424Sroberto	/* unload rptbuf */
4374106424Sroberto	if (rpt_Paly0xBB (rpt, &TsipxBB))
4375106424Sroberto	{
4376106424Sroberto		parsed = BADLEN_PARSE;
4377106424Sroberto		return;
4378106424Sroberto	}
4379106424Sroberto
4380106424Sroberto	pbuf += sprintf(pbuf, "\n   operating mode:      %s",
4381285612Sdelphij			NavModeText0xBB[TsipxBB.operating_mode]);
4382106424Sroberto	pbuf += sprintf(pbuf, "\n   dynamics:            %s",
4383285612Sdelphij			dyn_text[TsipxBB.dyn_code]);
4384106424Sroberto	pbuf += sprintf(pbuf, "\n   elev angle mask:     %g deg",
4385285612Sdelphij			TsipxBB.elev_mask * R2D);
4386106424Sroberto	pbuf += sprintf(pbuf, "\n   SNR mask:            %g AMU",
4387285612Sdelphij			TsipxBB.cno_mask);
4388106424Sroberto	pbuf += sprintf(pbuf, "\n   DOP mask:            %g",
4389285612Sdelphij			TsipxBB.dop_mask);
4390106424Sroberto	pbuf += sprintf(pbuf, "\n   DOP switch:          %g",
4391285612Sdelphij			TsipxBB.dop_switch);
4392106424Sroberto	return ;
4393106424Sroberto}
4394106424Sroberto
4395106424Sroberto/* 0xBC */
4396285612Sdelphijstatic void
4397285612Sdelphijrpt_rcvr_serial_port_config(
4398285612Sdelphij			    TSIPPKT *rpt
4399285612Sdelphij			    )
4400106424Sroberto{
4401106424Sroberto	unsigned char
4402285612Sdelphij	    port_num, in_baud, out_baud, data_bits, parity, stop_bits, flow_control,
4403285612Sdelphij	    protocols_in, protocols_out, reserved;
4404106424Sroberto	unsigned char known;
4405106424Sroberto
4406106424Sroberto	/* unload rptbuf */
4407106424Sroberto	if (rpt_0xBC (rpt, &port_num, &in_baud, &out_baud, &data_bits, &parity,
4408285612Sdelphij		      &stop_bits, &flow_control, &protocols_in, &protocols_out, &reserved)) {
4409106424Sroberto		parsed = BADLEN_PARSE;
4410106424Sroberto		return;
4411106424Sroberto	}
4412106424Sroberto	/* rptbuf unloaded */
4413106424Sroberto
4414106424Sroberto	pbuf += sprintf(pbuf, "\n   RECEIVER serial port %s config:",
4415285612Sdelphij			rcvr_port_text[port_num]);
4416106424Sroberto
4417106424Sroberto	pbuf += sprintf(pbuf, "\n             I/O Baud %s/%s, %d - %s - %d",
4418285612Sdelphij			st_baud_text_app[in_baud],
4419285612Sdelphij			st_baud_text_app[out_baud],
4420285612Sdelphij			data_bits+5,
4421285612Sdelphij			parity_text[parity],
4422285612Sdelphij			stop_bits=1);
4423106424Sroberto	pbuf += sprintf(pbuf, "\n             Input protocols: ");
4424106424Sroberto	known = FALSE;
4425106424Sroberto	if (protocols_in&B_TSIP)
4426285612Sdelphij	{
4427106424Sroberto		pbuf += sprintf(pbuf, "%s ", protocols_in_text[1]);
4428106424Sroberto		known = TRUE;
4429106424Sroberto	}
4430106424Sroberto	if (known == FALSE) pbuf += sprintf(pbuf, "No known");
4431106424Sroberto
4432106424Sroberto	pbuf += sprintf(pbuf, "\n             Output protocols: ");
4433106424Sroberto	known = FALSE;
4434106424Sroberto	if (protocols_out&B_TSIP)
4435285612Sdelphij	{
4436106424Sroberto		pbuf += sprintf(pbuf, "%s ", protocols_out_text[1]);
4437106424Sroberto		known = TRUE;
4438106424Sroberto	}
4439106424Sroberto	if (protocols_out&B_NMEA)
4440285612Sdelphij	{
4441106424Sroberto		pbuf += sprintf(pbuf, "%s ", protocols_out_text[2]);
4442106424Sroberto		known = TRUE;
4443106424Sroberto	}
4444106424Sroberto	if (known == FALSE) pbuf += sprintf(pbuf, "No known");
4445106424Sroberto	reserved = reserved;
4446106424Sroberto
4447285612Sdelphij}
4448106424Sroberto
4449106424Sroberto/* 0x8F */
4450106424Sroberto/* 8F0B */
4451285612Sdelphijstatic void
4452285612Sdelphijrpt_8F0B(
4453285612Sdelphij	 TSIPPKT *rpt
4454285612Sdelphij	 )
4455106424Sroberto{
4456106424Sroberto	const char
4457285612Sdelphij	    *oprtng_dim[7] = {
4458285612Sdelphij		"horizontal (2-D)",
4459285612Sdelphij		"full position (3-D)",
4460285612Sdelphij		"single satellite (0-D)",
4461285612Sdelphij		"automatic",
4462285612Sdelphij		"N/A",
4463285612Sdelphij		"N/A",
4464285612Sdelphij		"overdetermined clock"};
4465285612Sdelphij	char
4466285612Sdelphij	    sv_id[8];
4467285612Sdelphij	unsigned char
4468285612Sdelphij	    month,
4469285612Sdelphij	    date,
4470285612Sdelphij	    dim_mode,
4471285612Sdelphij	    north_south,
4472285612Sdelphij	    east_west;
4473285612Sdelphij	unsigned short
4474285612Sdelphij	    event;
4475106424Sroberto	short
4476285612Sdelphij	    utc_offset,
4477285612Sdelphij	    year,
4478285612Sdelphij	    local_index;
4479285612Sdelphij	short
4480285612Sdelphij	    lat_deg,
4481285612Sdelphij	    lon_deg;
4482285612Sdelphij	float
4483285612Sdelphij	    bias_unc,
4484285612Sdelphij	    dr_unc;
4485285612Sdelphij	double
4486285612Sdelphij	    tow,
4487285612Sdelphij	    bias,
4488285612Sdelphij	    drift,
4489285612Sdelphij	    lat,
4490285612Sdelphij	    lon,
4491285612Sdelphij	    alt,
4492285612Sdelphij	    lat_min,
4493285612Sdelphij	    lon_min;
4494285612Sdelphij	int
4495285612Sdelphij	    numfix,
4496285612Sdelphij	    numnotfix;
4497106424Sroberto
4498106424Sroberto	if (rpt_0x8F0B(rpt,
4499285612Sdelphij		       &event,
4500285612Sdelphij		       &tow,
4501285612Sdelphij		       &date,
4502285612Sdelphij		       &month,
4503285612Sdelphij		       &year,
4504285612Sdelphij		       &dim_mode,
4505285612Sdelphij		       &utc_offset,
4506285612Sdelphij		       &bias,
4507285612Sdelphij		       &drift,
4508285612Sdelphij		       &bias_unc,
4509285612Sdelphij		       &dr_unc,
4510285612Sdelphij		       &lat,
4511285612Sdelphij		       &lon,
4512285612Sdelphij		       &alt,
4513285612Sdelphij		       sv_id))
4514285612Sdelphij	{
4515106424Sroberto		parsed = BADLEN_PARSE;
4516106424Sroberto		return;
4517106424Sroberto	}
4518106424Sroberto
4519106424Sroberto	if (event == 0)
4520285612Sdelphij	{
4521285612Sdelphij		pbuf += sprintf(pbuf, "\nNew partial+full meas");
4522106424Sroberto	}
4523285612Sdelphij	else
4524285612Sdelphij	{
4525106424Sroberto		pbuf += sprintf(pbuf, "\nEvent count: %5d", event);
4526285612Sdelphij	}
4527106424Sroberto
4528106424Sroberto	pbuf += sprintf(pbuf, "\nGPS time  : %s %2d/%2d/%2d (DMY)",
4529285612Sdelphij			show_time(tow), date, month, year);
4530106424Sroberto	pbuf += sprintf(pbuf, "\nMode      : %s", oprtng_dim[dim_mode]);
4531106424Sroberto	pbuf += sprintf(pbuf, "\nUTC offset: %2d", utc_offset);
4532106424Sroberto	pbuf += sprintf(pbuf, "\nClock Bias: %6.2f m", bias);
4533106424Sroberto	pbuf += sprintf(pbuf, "\nFreq bias : %6.2f m/s", drift);
4534106424Sroberto	pbuf += sprintf(pbuf, "\nBias unc  : %6.2f m", bias_unc);
4535106424Sroberto	pbuf += sprintf(pbuf, "\nFreq unc  : %6.2f m/s", dr_unc);
4536106424Sroberto
4537106424Sroberto	lat *= R2D; /* convert from radians to degrees */
4538106424Sroberto	lon *= R2D;
4539106424Sroberto	if (lat < 0.0)
4540285612Sdelphij	{
4541106424Sroberto		north_south = 'S';
4542106424Sroberto		lat = -lat;
4543106424Sroberto	}
4544285612Sdelphij	else
4545285612Sdelphij	{
4546106424Sroberto		north_south = 'N';
4547106424Sroberto	}
4548106424Sroberto
4549106424Sroberto	lat_deg = (short)lat;
4550106424Sroberto	lat_min = (lat - lat_deg) * 60.0;
4551106424Sroberto	if (lon < 0.0)
4552285612Sdelphij	{
4553106424Sroberto		east_west = 'W';
4554106424Sroberto		lon = -lon;
4555106424Sroberto	}
4556285612Sdelphij	else
4557285612Sdelphij	{
4558106424Sroberto		east_west = 'E';
4559106424Sroberto	}
4560106424Sroberto
4561106424Sroberto	lon_deg = (short)lon;
4562106424Sroberto	lon_min = (lon - lon_deg) * 60.0;
4563106424Sroberto	pbuf += sprintf(pbuf, "\nPosition  :");
4564106424Sroberto	pbuf += sprintf(pbuf, " %4d %6.3f %c", lat_deg, lat_min, north_south);
4565106424Sroberto	pbuf += sprintf(pbuf, " %5d %6.3f %c", lon_deg, lon_min, east_west);
4566106424Sroberto	pbuf += sprintf(pbuf, " %10.2f", alt);
4567106424Sroberto
4568285612Sdelphij	numfix = numnotfix = 0;
4569106424Sroberto	for (local_index=0; local_index<8; local_index++)
4570285612Sdelphij	{
4571106424Sroberto		if (sv_id[local_index] < 0) numnotfix++;
4572106424Sroberto		if (sv_id[local_index] > 0) numfix++;
4573285612Sdelphij	}
4574285612Sdelphij	if (numfix > 0)
4575285612Sdelphij	{
4576106424Sroberto		pbuf += sprintf(pbuf, "\nSVs used in fix  : ");
4577106424Sroberto		for (local_index=0; local_index<8; local_index++)
4578285612Sdelphij		{
4579106424Sroberto			if (sv_id[local_index] > 0)
4580285612Sdelphij			{
4581285612Sdelphij				pbuf += sprintf(pbuf, "%2d ", sv_id[local_index]);
4582285612Sdelphij			}
4583285612Sdelphij		}
4584285612Sdelphij	}
4585285612Sdelphij	if (numnotfix > 0)
4586285612Sdelphij	{
4587106424Sroberto		pbuf += sprintf(pbuf, "\nOther SVs tracked: ");
4588106424Sroberto		for (local_index=0; local_index<8; local_index++)
4589285612Sdelphij		{
4590106424Sroberto			if (sv_id[local_index] < 0)
4591285612Sdelphij			{
4592285612Sdelphij				pbuf += sprintf(pbuf, "%2d ", sv_id[local_index]);
4593285612Sdelphij			}
4594285612Sdelphij		}
4595285612Sdelphij	}
4596106424Sroberto}
4597106424Sroberto
4598106424Sroberto/* 0x8F14 */
4599106424Sroberto/* Datum parameters */
4600285612Sdelphijstatic void
4601285612Sdelphijrpt_8F14(
4602285612Sdelphij	 TSIPPKT *rpt
4603285612Sdelphij	 )
4604106424Sroberto{
4605106424Sroberto	double
4606285612Sdelphij	    datum_coeffs[5];
4607106424Sroberto	short
4608285612Sdelphij	    datum_idx;
4609106424Sroberto
4610106424Sroberto	/* unload rptbuf */
4611106424Sroberto	if (rpt_0x8F14 (rpt, &datum_idx, datum_coeffs))
4612285612Sdelphij	{
4613106424Sroberto		parsed = BADLEN_PARSE;
4614106424Sroberto		return;
4615106424Sroberto	}
4616106424Sroberto
4617106424Sroberto	if (datum_idx == -1)
4618285612Sdelphij	{
4619285612Sdelphij		pbuf += sprintf(pbuf, "\nUser-Entered Datum:");
4620106424Sroberto		pbuf += sprintf(pbuf, "\n   dx        = %6.1f", datum_coeffs[0]);
4621106424Sroberto		pbuf += sprintf(pbuf, "\n   dy        = %6.1f", datum_coeffs[1]);
4622106424Sroberto		pbuf += sprintf(pbuf, "\n   dz        = %6.1f", datum_coeffs[2]);
4623106424Sroberto		pbuf += sprintf(pbuf, "\n   a-axis    = %10.3f", datum_coeffs[3]);
4624106424Sroberto		pbuf += sprintf(pbuf, "\n   e-squared = %16.14f", datum_coeffs[4]);
4625285612Sdelphij	}
4626285612Sdelphij	else if (datum_idx == 0)
4627285612Sdelphij	{
4628285612Sdelphij		pbuf += sprintf(pbuf, "\nWGS-84 datum, Index 0 ");
4629285612Sdelphij	}
4630285612Sdelphij	else
4631285612Sdelphij	{
4632285612Sdelphij		pbuf += sprintf(pbuf, "\nStandard Datum, Index %3d ", datum_idx);
4633285612Sdelphij	}
4634106424Sroberto}
4635106424Sroberto
4636106424Sroberto/* 0x8F15 */
4637106424Sroberto/* Datum parameters */
4638285612Sdelphijstatic void
4639285612Sdelphijrpt_8F15(
4640285612Sdelphij	 TSIPPKT *rpt
4641285612Sdelphij	 )
4642106424Sroberto{
4643106424Sroberto	double
4644285612Sdelphij	    datum_coeffs[5];
4645106424Sroberto	short
4646285612Sdelphij	    datum_idx;
4647106424Sroberto
4648106424Sroberto	/* unload rptbuf */
4649106424Sroberto	if (rpt_0x8F15 (rpt, &datum_idx, datum_coeffs)) {
4650106424Sroberto		parsed = BADLEN_PARSE;
4651106424Sroberto		return;
4652106424Sroberto	}
4653106424Sroberto
4654106424Sroberto	if (datum_idx == -1)
4655285612Sdelphij	{
4656285612Sdelphij		pbuf += sprintf(pbuf, "\nUser-Entered Datum:");
4657106424Sroberto		pbuf += sprintf(pbuf, "\n   dx        = %6.1f", datum_coeffs[0]);
4658106424Sroberto		pbuf += sprintf(pbuf, "\n   dy        = %6.1f", datum_coeffs[1]);
4659106424Sroberto		pbuf += sprintf(pbuf, "\n   dz        = %6.1f", datum_coeffs[2]);
4660106424Sroberto		pbuf += sprintf(pbuf, "\n   a-axis    = %10.3f", datum_coeffs[3]);
4661106424Sroberto		pbuf += sprintf(pbuf, "\n   e-squared = %16.14f", datum_coeffs[4]);
4662285612Sdelphij	}
4663285612Sdelphij	else if (datum_idx == 0)
4664285612Sdelphij	{
4665285612Sdelphij		pbuf += sprintf(pbuf, "\nWGS-84 datum, Index 0 ");
4666285612Sdelphij	}
4667285612Sdelphij	else
4668285612Sdelphij	{
4669285612Sdelphij		pbuf += sprintf(pbuf, "\nStandard Datum, Index %3d ", datum_idx);
4670285612Sdelphij	}
4671106424Sroberto}
4672106424Sroberto
4673106424Sroberto/* 0x8F20 */
4674106424Sroberto#define INFO_DGPS       0x02
4675106424Sroberto#define INFO_2D         0x04
4676106424Sroberto#define INFO_ALTSET     0x08
4677106424Sroberto#define INFO_FILTERED   0x10
4678285612Sdelphijstatic void
4679285612Sdelphijrpt_8F20(
4680285612Sdelphij	 TSIPPKT *rpt
4681285612Sdelphij	 )
4682106424Sroberto{
4683106424Sroberto	unsigned char
4684285612Sdelphij	    info, nsvs, sv_prn[32];
4685106424Sroberto	short
4686285612Sdelphij	    week_num, datum_index, sv_IODC[32];
4687106424Sroberto	double
4688285612Sdelphij	    lat, lon, alt, time_of_fix;
4689106424Sroberto	double
4690285612Sdelphij	    londeg, latdeg, vel[3];
4691106424Sroberto	short
4692285612Sdelphij	    isv;
4693285612Sdelphij	char
4694285612Sdelphij	    datum_string[20];
4695106424Sroberto
4696106424Sroberto	/* unload rptbuf */
4697106424Sroberto	if (rpt_0x8F20 (rpt,
4698285612Sdelphij			&info, &lat, &lon, &alt, vel,
4699285612Sdelphij			&time_of_fix,
4700285612Sdelphij			&week_num, &nsvs, sv_prn, sv_IODC, &datum_index))
4701106424Sroberto	{
4702106424Sroberto		parsed = BADLEN_PARSE;
4703106424Sroberto		return;
4704106424Sroberto	}
4705106424Sroberto	pbuf += sprintf(pbuf,
4706285612Sdelphij			"\nFix at: %04d:%3s:%02d:%02d:%06.3f GPS (=UTC+%2ds)  FixType: %s%s%s",
4707285612Sdelphij			week_num,
4708285612Sdelphij			dayname[(short)(time_of_fix/86400.0)],
4709285612Sdelphij			(short)fmod(time_of_fix/3600., 24.),
4710285612Sdelphij			(short)fmod(time_of_fix/60., 60.),
4711285612Sdelphij			fmod(time_of_fix, 60.),
4712285612Sdelphij			(char)rpt->buf[29],		/* UTC offset */
4713285612Sdelphij			(info & INFO_DGPS)?"Diff":"",
4714285612Sdelphij			(info & INFO_2D)?"2D":"3D",
4715285612Sdelphij			(info & INFO_FILTERED)?"-Filtrd":"");
4716106424Sroberto
4717285612Sdelphij	if (datum_index > 0)
4718285612Sdelphij	{
4719106424Sroberto		sprintf(datum_string, "Datum%3d", datum_index);
4720285612Sdelphij	}
4721285612Sdelphij	else if (datum_index)
4722285612Sdelphij	{
4723106424Sroberto		sprintf(datum_string, "Unknown ");
4724285612Sdelphij	}
4725285612Sdelphij	else
4726285612Sdelphij	{
4727106424Sroberto		sprintf(datum_string, "WGS-84");
4728285612Sdelphij	}
4729106424Sroberto
4730106424Sroberto	/* convert from radians to degrees */
4731106424Sroberto	latdeg = R2D * fabs(lat);
4732106424Sroberto	londeg = R2D * fabs(lon);
4733106424Sroberto	pbuf += sprintf(pbuf,
4734285612Sdelphij			"\n   Pos: %4d:%09.6f %c %5d:%09.6f %c %10.2f m HAE (%s)",
4735285612Sdelphij			(short)latdeg, fmod (latdeg, 1.)*60.0,
4736285612Sdelphij			(lat<0.0)?'S':'N',
4737285612Sdelphij			(short)londeg, fmod (londeg, 1.)*60.0,
4738285612Sdelphij			(lon<0.0)?'W':'E',
4739285612Sdelphij			alt,
4740285612Sdelphij			datum_string);
4741106424Sroberto	pbuf += sprintf(pbuf,
4742285612Sdelphij			"\n   Vel:    %9.3f E       %9.3f N      %9.3f U   (m/sec)",
4743285612Sdelphij			vel[0], vel[1], vel[2]);
4744106424Sroberto
4745106424Sroberto	pbuf += sprintf(pbuf,
4746285612Sdelphij			"\n   SVs: ");
4747106424Sroberto	for (isv = 0; isv < nsvs; isv++) {
4748106424Sroberto		pbuf += sprintf(pbuf, " %02d", sv_prn[isv]);
4749106424Sroberto	}
4750106424Sroberto	pbuf += sprintf(pbuf, "     (IODEs:");
4751106424Sroberto	for (isv = 0; isv < nsvs; isv++) {
4752106424Sroberto		pbuf += sprintf(pbuf, " %02X", sv_IODC[isv]&0xFF);
4753106424Sroberto	}
4754106424Sroberto	pbuf += sprintf(pbuf, ")");
4755106424Sroberto}
4756106424Sroberto
4757106424Sroberto/* 0x8F41 */
4758285612Sdelphijstatic void
4759285612Sdelphijrpt_8F41(
4760285612Sdelphij	 TSIPPKT *rpt
4761285612Sdelphij	 )
4762106424Sroberto{
4763106424Sroberto	unsigned char
4764285612Sdelphij	    bSearchRange,
4765285612Sdelphij	    bBoardOptions,
4766285612Sdelphij	    bBuildYear,
4767285612Sdelphij	    bBuildMonth,
4768285612Sdelphij	    bBuildDay,
4769285612Sdelphij	    bBuildHour;
4770106424Sroberto	float
4771285612Sdelphij	    fOscOffset;
4772106424Sroberto	unsigned short
4773285612Sdelphij	    iTestCodeId;
4774106424Sroberto	unsigned long
4775285612Sdelphij	    iiSerialNumber;
4776106424Sroberto
4777285612Sdelphij	if (!rpt_0x8F41(rpt,
4778285612Sdelphij			&bSearchRange,
4779285612Sdelphij			&bBoardOptions,
4780285612Sdelphij			&iiSerialNumber,
4781285612Sdelphij			&bBuildYear,
4782285612Sdelphij			&bBuildMonth,
4783285612Sdelphij			&bBuildDay,
4784285612Sdelphij			&bBuildHour,
4785285612Sdelphij			&fOscOffset,
4786285612Sdelphij			&iTestCodeId))
4787285612Sdelphij	{
4788106424Sroberto		parsed = BADLEN_PARSE;
4789285612Sdelphij		return;
4790285612Sdelphij	}
4791106424Sroberto
4792285612Sdelphij	pbuf += sprintf(pbuf, "\n  search range:          %d",
4793285612Sdelphij			bSearchRange);
4794285612Sdelphij	pbuf += sprintf(pbuf, "\n  board options:         %d",
4795285612Sdelphij			bBoardOptions);
4796285612Sdelphij	pbuf += sprintf(pbuf, "\n  board serial #:        %ld",
4797285612Sdelphij			iiSerialNumber);
4798285612Sdelphij	pbuf += sprintf(pbuf, "\n  build date/hour:       %02d/%02d/%02d %02d:00",
4799285612Sdelphij			bBuildDay, bBuildMonth, bBuildYear, bBuildHour);
4800285612Sdelphij	pbuf += sprintf(pbuf, "\n  osc offset:            %.3f PPM (%.0f Hz)",
4801285612Sdelphij			fOscOffset/1575.42, fOscOffset);
4802285612Sdelphij	pbuf += sprintf(pbuf, "\n  test code:             %d",
4803285612Sdelphij			iTestCodeId);
4804106424Sroberto}
4805106424Sroberto
4806106424Sroberto/* 0x8F42 */
4807285612Sdelphijstatic void
4808285612Sdelphijrpt_8F42(
4809285612Sdelphij	 TSIPPKT *rpt
4810285612Sdelphij	 )
4811106424Sroberto{
4812106424Sroberto	unsigned char
4813285612Sdelphij	    bProdOptionsPre,
4814285612Sdelphij	    bProdNumberExt;
4815106424Sroberto	unsigned short
4816285612Sdelphij	    iCaseSerialNumberPre,
4817285612Sdelphij	    iPremiumOptions,
4818285612Sdelphij	    iMachineID,
4819285612Sdelphij	    iKey;
4820106424Sroberto	unsigned long
4821285612Sdelphij	    iiCaseSerialNumber,
4822285612Sdelphij	    iiProdNumber;
4823106424Sroberto
4824285612Sdelphij	if (!rpt_0x8F42(rpt,
4825285612Sdelphij			&bProdOptionsPre,
4826285612Sdelphij			&bProdNumberExt,
4827285612Sdelphij			&iCaseSerialNumberPre,
4828285612Sdelphij			&iiCaseSerialNumber,
4829285612Sdelphij			&iiProdNumber,
4830285612Sdelphij			&iPremiumOptions,
4831285612Sdelphij			&iMachineID,
4832285612Sdelphij			&iKey))
4833285612Sdelphij	{
4834106424Sroberto		parsed = BADLEN_PARSE;
4835285612Sdelphij		return;
4836285612Sdelphij	}
4837106424Sroberto
4838106424Sroberto	pbuf += sprintf(pbuf, "\nProduct ID 8F42");
4839285612Sdelphij	pbuf += sprintf(pbuf, "\n   extension:            %d", bProdNumberExt);
4840285612Sdelphij	pbuf += sprintf(pbuf, "\n   case serial # prefix: %d", iCaseSerialNumberPre);
4841285612Sdelphij	pbuf += sprintf(pbuf, "\n   case serial #:        %ld", iiCaseSerialNumber);
4842285612Sdelphij	pbuf += sprintf(pbuf, "\n   prod. #:              %ld", iiProdNumber);
4843106424Sroberto	pbuf += sprintf(pbuf, "\n   premium options:      %Xh", iPremiumOptions);
4844285612Sdelphij	pbuf += sprintf(pbuf, "\n   machine ID:           %d", iMachineID);
4845285612Sdelphij	pbuf += sprintf(pbuf, "\n   key:                  %Xh", iKey);
4846106424Sroberto}
4847106424Sroberto
4848106424Sroberto/* 0x8F45 */
4849285612Sdelphijstatic void
4850285612Sdelphijrpt_8F45(
4851285612Sdelphij	 TSIPPKT *rpt
4852285612Sdelphij	 )
4853106424Sroberto{
4854285612Sdelphij	unsigned char bSegMask;
4855106424Sroberto
4856285612Sdelphij	if (!rpt_0x8F45(rpt,
4857285612Sdelphij			&bSegMask))
4858285612Sdelphij	{
4859106424Sroberto		parsed = BADLEN_PARSE;
4860106424Sroberto		return;
4861106424Sroberto	}
4862106424Sroberto	pbuf += sprintf(pbuf, "\nCleared Segment Mask: %Xh", bSegMask);
4863106424Sroberto}
4864106424Sroberto
4865106424Sroberto/* Stinger PPS def */
4866285612Sdelphijstatic void
4867285612Sdelphijrpt_8F4A(
4868285612Sdelphij	 TSIPPKT *rpt
4869285612Sdelphij	 )
4870106424Sroberto{
4871106424Sroberto	unsigned char
4872285612Sdelphij	    pps_enabled,
4873285612Sdelphij	    pps_timebase,
4874285612Sdelphij	    pps_polarity;
4875285612Sdelphij	float
4876285612Sdelphij	    bias_unc_threshold;
4877285612Sdelphij	double
4878285612Sdelphij	    pps_offset;
4879106424Sroberto
4880106424Sroberto  	if (rpt_0x8F4A_16 (rpt,
4881285612Sdelphij			   &pps_enabled,
4882285612Sdelphij			   &pps_timebase,
4883285612Sdelphij			   &pps_polarity,
4884285612Sdelphij			   &pps_offset,
4885285612Sdelphij			   &bias_unc_threshold))
4886285612Sdelphij	{
4887285612Sdelphij		parsed = BADLEN_PARSE;
4888285612Sdelphij		return;
4889285612Sdelphij	}
4890106424Sroberto
4891106424Sroberto	pbuf += sprintf(pbuf, "\nPPS is         %s",	pps_enabled?"enabled":"disabled");
4892285612Sdelphij	pbuf += sprintf(pbuf, "\n   timebase:   %s", PPSTimeBaseText[pps_timebase]);
4893285612Sdelphij	pbuf += sprintf(pbuf, "\n   polarity:   %s", PPSPolarityText[pps_polarity]);
4894285612Sdelphij	pbuf += sprintf(pbuf, "\n   offset:     %.1f ns, ", pps_offset*1.e9);
4895285612Sdelphij	pbuf += sprintf(pbuf, "\n   biasunc:    %.1f ns", bias_unc_threshold/GPS_C*1.e9);
4896106424Sroberto}
4897106424Sroberto
4898106424Sroberto/* fast-SA decorrolation time for self-survey */
4899285612Sdelphijstatic void
4900285612Sdelphijrpt_8F4B(
4901285612Sdelphij	 TSIPPKT *rpt
4902285612Sdelphij	 )
4903106424Sroberto{
4904106424Sroberto	unsigned long
4905285612Sdelphij	    decorr_max;
4906106424Sroberto
4907285612Sdelphij	if (rpt_0x8F4B(rpt, &decorr_max))
4908285612Sdelphij	{
4909106424Sroberto		parsed = BADLEN_PARSE;
4910285612Sdelphij		return;
4911285612Sdelphij	}
4912106424Sroberto
4913285612Sdelphij	pbuf += sprintf(pbuf,
4914285612Sdelphij			"\nMax # of position fixes for self-survey : %ld",
4915285612Sdelphij			decorr_max);
4916106424Sroberto}
4917106424Sroberto
4918285612Sdelphijstatic void
4919285612Sdelphijrpt_8F4D(
4920285612Sdelphij	 TSIPPKT *rpt
4921285612Sdelphij	 )
4922106424Sroberto{
4923106424Sroberto	static char
4924285612Sdelphij	    *linestart;
4925106424Sroberto	unsigned long
4926285612Sdelphij	    OutputMask;
4927285612Sdelphij	static unsigned long
4928285612Sdelphij	    MaskBit[] = {
4929285612Sdelphij		0x00000001, 0x00000002, 0x00000004, 0x00000008, 0x00000010,
4930285612Sdelphij		0x00000020,
4931285612Sdelphij		0x00000100L, 0x00000800L, 0x00001000L,
4932285612Sdelphij		0x40000000L, 0x80000000L};
4933285612Sdelphij	int
4934285612Sdelphij	    ichoice,
4935285612Sdelphij	    numchoices;
4936106424Sroberto
4937285612Sdelphij	if (rpt_0x8F4D(rpt, &OutputMask))
4938285612Sdelphij	{
4939106424Sroberto		parsed = BADLEN_PARSE;
4940285612Sdelphij		return;
4941285612Sdelphij	}
4942106424Sroberto
4943285612Sdelphij	pbuf += sprintf(pbuf, "\nAuto-Report Mask: %02X %02X %02X %02X",
4944285612Sdelphij			(unsigned char)(OutputMask>>24),
4945285612Sdelphij			(unsigned char)(OutputMask>>16),
4946285612Sdelphij			(unsigned char)(OutputMask>>8),
4947285612Sdelphij			(unsigned char)OutputMask);
4948106424Sroberto
4949285612Sdelphij	numchoices = sizeof(MaskText)/sizeof(char*);
4950285612Sdelphij	pbuf += sprintf(pbuf, "\nAuto-Reports scheduled for Output:");
4951285612Sdelphij	linestart = pbuf;
4952285612Sdelphij	for (ichoice = 0; ichoice < numchoices; ichoice++)
4953285612Sdelphij	{
4954285612Sdelphij		if (OutputMask&MaskBit[ichoice])
4955285612Sdelphij		{
4956285612Sdelphij			pbuf += sprintf(pbuf, "%s %s",
4957285612Sdelphij					(pbuf==linestart)?"\n     ":",",
4958285612Sdelphij					MaskText[ichoice]);
4959106424Sroberto			if (pbuf-linestart > 60) linestart = pbuf;
4960285612Sdelphij		}
4961285612Sdelphij	}
4962106424Sroberto
4963285612Sdelphij	pbuf += sprintf(pbuf, "\nAuto-Reports NOT scheduled for Output:");
4964285612Sdelphij	linestart = pbuf;
4965285612Sdelphij	for (ichoice = 0; ichoice < numchoices; ichoice++)
4966285612Sdelphij	{
4967285612Sdelphij		if (OutputMask&MaskBit[ichoice]) continue;
4968106424Sroberto	     	pbuf += sprintf(pbuf, "%s %s",
4969285612Sdelphij				(pbuf==linestart)?"\n     ":",",
4970285612Sdelphij				MaskText[ichoice]);
4971106424Sroberto		if (pbuf-linestart > 60) linestart = pbuf;
4972285612Sdelphij	}
4973106424Sroberto}
4974106424Sroberto
4975285612Sdelphijstatic void
4976285612Sdelphijrpt_8FA5(
4977285612Sdelphij	 TSIPPKT *rpt
4978285612Sdelphij	 )
4979106424Sroberto{
4980106424Sroberto	unsigned char
4981285612Sdelphij	    spktmask[4];
4982106424Sroberto
4983285612Sdelphij	if (rpt_0x8FA5(rpt, spktmask))
4984285612Sdelphij	{
4985106424Sroberto		parsed = BADLEN_PARSE;
4986285612Sdelphij		return;
4987285612Sdelphij	}
4988106424Sroberto
4989285612Sdelphij	pbuf += sprintf(pbuf, "\nSuperpacket auto-output mask: %02X %02X %02X %02X",
4990285612Sdelphij			spktmask[0], spktmask[1], spktmask[2], spktmask[3]);
4991106424Sroberto
4992285612Sdelphij	if (spktmask[0]&0x01) pbuf+= sprintf (pbuf, "\n    PPS   8F-0B");
4993285612Sdelphij	if (spktmask[0]&0x02) pbuf+= sprintf (pbuf, "\n    Event 8F-0B");
4994285612Sdelphij	if (spktmask[0]&0x10) pbuf+= sprintf (pbuf, "\n    PPS   8F-AD");
4995285612Sdelphij	if (spktmask[0]&0x20) pbuf+= sprintf (pbuf, "\n    Event 8F-AD");
4996285612Sdelphij	if (spktmask[2]&0x01) pbuf+= sprintf (pbuf, "\n    ppos Fix 8F-20");
4997106424Sroberto}
4998106424Sroberto
4999285612Sdelphijstatic void
5000285612Sdelphijrpt_8FAD(
5001285612Sdelphij	 TSIPPKT *rpt
5002285612Sdelphij	 )
5003106424Sroberto{
5004285612Sdelphij	unsigned short
5005285612Sdelphij	    Count,
5006285612Sdelphij	    Year;
5007285612Sdelphij	double
5008285612Sdelphij	    FracSec;
5009285612Sdelphij	unsigned char
5010285612Sdelphij	    Hour,
5011285612Sdelphij	    Minute,
5012285612Sdelphij	    Second,
5013285612Sdelphij	    Day,
5014285612Sdelphij	    Month,
5015285612Sdelphij	    Status,
5016285612Sdelphij	    Flags;
5017106424Sroberto	static char* Status8FADText[] = {
5018285612Sdelphij		"CODE_DOING_FIXES",
5019285612Sdelphij		"CODE_GOOD_1_SV",
5020285612Sdelphij		"CODE_APPX_1SV",
5021285612Sdelphij		"CODE_NEED_TIME",
5022285612Sdelphij		"CODE_NEED_INITIALIZATION",
5023285612Sdelphij		"CODE_PDOP_HIGH",
5024285612Sdelphij		"CODE_BAD_1SV",
5025285612Sdelphij		"CODE_0SVS",
5026285612Sdelphij		"CODE_1SV",
5027285612Sdelphij		"CODE_2SVS",
5028285612Sdelphij		"CODE_3SVS",
5029285612Sdelphij		"CODE_NO_INTEGRITY",
5030285612Sdelphij		"CODE_DCORR_GEN",
5031285612Sdelphij		"CODE_OVERDET_CLK",
5032285612Sdelphij		"Invalid Status"},
5033285612Sdelphij	    *LeapStatusText[] = {
5034285612Sdelphij		    " UTC Avail", " ", " ", " ",
5035285612Sdelphij		    " Scheduled", " Pending", " Warning", " In Progress"};
5036285612Sdelphij	int i;
5037106424Sroberto
5038106424Sroberto	if (rpt_0x8FAD (rpt,
5039285612Sdelphij			&Count,
5040285612Sdelphij			&FracSec,
5041285612Sdelphij			&Hour,
5042285612Sdelphij			&Minute,
5043285612Sdelphij			&Second,
5044285612Sdelphij			&Day,
5045285612Sdelphij			&Month,
5046285612Sdelphij			&Year,
5047285612Sdelphij			&Status,
5048285612Sdelphij			&Flags))
5049285612Sdelphij	{
5050106424Sroberto		parsed = BADLEN_PARSE;
5051106424Sroberto		return;
5052285612Sdelphij	}
5053106424Sroberto
5054106424Sroberto	pbuf += sprintf(pbuf,    "\n8FAD   Count: %d   Status: %s",
5055285612Sdelphij			Count, Status8FADText[Status]);
5056106424Sroberto
5057285612Sdelphij	pbuf += sprintf(pbuf, "\n   Leap Flags:");
5058285612Sdelphij	if (Flags)
5059285612Sdelphij	{
5060285612Sdelphij		for (i=0; i<8; i++)
5061285612Sdelphij		{
5062285612Sdelphij			if (Flags&(1<<i)) pbuf += sprintf(pbuf, LeapStatusText[i]);
5063285612Sdelphij		}
5064285612Sdelphij	}
5065285612Sdelphij	else
5066285612Sdelphij	{
5067285612Sdelphij		pbuf += sprintf(pbuf, "  UTC info not available");
5068285612Sdelphij	}
5069106424Sroberto
5070106424Sroberto	pbuf += sprintf(pbuf,     "\n      %02d/%02d/%04d (DMY)  %02d:%02d:%02d.%09ld UTC",
5071285612Sdelphij			Day, Month, Year, Hour, Minute, Second, (long)(FracSec*1.e9));
5072106424Sroberto}
5073106424Sroberto
5074106424Sroberto
5075285612Sdelphijint
5076285612Sdelphijprint_msg_table_header(
5077285612Sdelphij		       int rptcode,
5078285612Sdelphij		       char *HdrStr,
5079285612Sdelphij		       int force
5080285612Sdelphij		       )
5081106424Sroberto{
5082106424Sroberto	/* force header is to help auto-output function */
5083106424Sroberto	/* last_rptcode is to determine whether to print a header */
5084132451Sroberto	/* for the first occurrence of a series of reports */
5085106424Sroberto	static int
5086285612Sdelphij	    last_rptcode = 0;
5087285612Sdelphij	int
5088285612Sdelphij	    numchars;
5089106424Sroberto
5090285612Sdelphij	numchars = 0;
5091106424Sroberto	if (force || rptcode!=last_rptcode)
5092285612Sdelphij	{
5093106424Sroberto		/* supply a header in console output */
5094285612Sdelphij		switch (rptcode)
5095106424Sroberto		{
5096285612Sdelphij		    case 0x5A:
5097106424Sroberto			numchars = sprintf(HdrStr, "\nRaw Measurement Data");
5098106424Sroberto			numchars += sprintf(HdrStr+numchars,
5099285612Sdelphij					    "\n   SV  Sample   SNR  Code Phase   Doppler    Seconds     Time of Meas");
5100106424Sroberto			break;
5101106424Sroberto
5102285612Sdelphij		    case 0x5B:
5103106424Sroberto			numchars = sprintf(HdrStr, "\nEphemeris Status");
5104106424Sroberto			numchars += sprintf(HdrStr+numchars,
5105285612Sdelphij					    "\n    SV     Time collected     Health  IODE        t oe         Fit   URA");
5106106424Sroberto			break;
5107106424Sroberto
5108285612Sdelphij		    case 0x5C:
5109106424Sroberto			numchars = sprintf(HdrStr, "\nTracking Info");
5110106424Sroberto			numchars += sprintf(HdrStr+numchars,
5111285612Sdelphij					    "\n   SV  C Acq Eph   SNR     Time of Meas       Elev  Azim   ");
5112106424Sroberto			break;
5113106424Sroberto
5114285612Sdelphij		}
5115106424Sroberto	}
5116106424Sroberto	last_rptcode = rptcode;
5117285612Sdelphij	return (short)numchars;
5118106424Sroberto}
5119106424Sroberto
5120285612Sdelphijstatic void
5121285612Sdelphijunknown_rpt(
5122285612Sdelphij	    TSIPPKT *rpt
5123285612Sdelphij	    )
5124106424Sroberto{
5125106424Sroberto	int i;
5126106424Sroberto
5127106424Sroberto	/* app-specific rpt packets */
5128106424Sroberto	if (parsed == BADLEN_PARSE)
5129285612Sdelphij	{
5130106424Sroberto		pbuf += sprintf(pbuf, "\nTSIP report packet ID %2Xh, length %d: Bad length",
5131285612Sdelphij				rpt->code, rpt->len);
5132285612Sdelphij	}
5133106424Sroberto	if (parsed == BADID_PARSE)
5134285612Sdelphij	{
5135106424Sroberto		pbuf += sprintf(pbuf,
5136285612Sdelphij				"\nTSIP report packet ID %2Xh, length %d: translation not supported",
5137285612Sdelphij				rpt->code, rpt->len);
5138285612Sdelphij	}
5139106424Sroberto
5140106424Sroberto	if (parsed == BADDATA_PARSE)
5141285612Sdelphij	{
5142106424Sroberto		pbuf += sprintf(pbuf,
5143285612Sdelphij				"\nTSIP report packet ID %2Xh, length %d: data content incorrect",
5144285612Sdelphij				rpt->code, rpt->len);
5145285612Sdelphij	}
5146106424Sroberto
5147106424Sroberto	for (i = 0; i < rpt->len; i++) {
5148106424Sroberto		if ((i % 20) == 0) *pbuf++ = '\n';
5149106424Sroberto		pbuf += sprintf(pbuf, " %02X", rpt->buf[i]);
5150106424Sroberto	}
5151106424Sroberto}
5152106424Sroberto/**/
5153285612Sdelphij
5154106424Sroberto/*
5155106424Sroberto** main subroutine, called from ProcessInputBytesWhileWaitingForKBHit()
5156106424Sroberto*/
5157285612Sdelphijvoid
5158285612SdelphijTranslateTSIPReportToText(
5159285612Sdelphij			  TSIPPKT *rpt,
5160285612Sdelphij			  char *TextOutputBuffer
5161285612Sdelphij			  )
5162106424Sroberto{
5163106424Sroberto
5164106424Sroberto	/* pbuf is the pointer to the current location of the text output */
5165106424Sroberto	pbuf = TextOutputBuffer;
5166106424Sroberto
5167285612Sdelphij	/* keep track of whether the message has been successfully parsed */
5168106424Sroberto	parsed = GOOD_PARSE;
5169106424Sroberto
5170106424Sroberto	/* print a header if this is the first of a series of messages */
5171106424Sroberto	pbuf += print_msg_table_header (rpt->code, pbuf, FALSE);
5172106424Sroberto
5173285612Sdelphij	/* process incoming TSIP report according to code */
5174106424Sroberto	switch (rpt->code)
5175285612Sdelphij	{
5176285612Sdelphij	    case 0x3D: rpt_chan_A_config (rpt); break;
5177285612Sdelphij	    case 0x40: rpt_almanac_data_page (rpt); break;
5178285612Sdelphij	    case 0x41: rpt_GPS_time (rpt); break;
5179285612Sdelphij	    case 0x42: rpt_single_ECEF_position (rpt); break;
5180285612Sdelphij	    case 0x43: rpt_single_ECEF_velocity (rpt); break;
5181285612Sdelphij	    case 0x45: rpt_SW_version (rpt); break;
5182285612Sdelphij	    case 0x46: rpt_rcvr_health (rpt); break;
5183285612Sdelphij	    case 0x47: rpt_SNR_all_SVs (rpt); break;
5184285612Sdelphij	    case 0x48: rpt_GPS_system_message (rpt); break;
5185285612Sdelphij	    case 0x49: rpt_almanac_health_page (rpt); break;
5186285612Sdelphij	    case 0x4A: switch (rpt->len) {
5187285612Sdelphij			/*
5188285612Sdelphij			** special case (=slip-up) in the TSIP protocol;
5189285612Sdelphij			** parsing method depends on length
5190285612Sdelphij			*/
5191285612Sdelphij		    case 20: rpt_single_lla_position (rpt); break;
5192285612Sdelphij		    case  9: rpt_ref_alt (rpt); break;
5193106424Sroberto		} break;
5194285612Sdelphij	    case 0x4B: rpt_rcvr_id_and_status (rpt);break;
5195285612Sdelphij	    case 0x4C: rpt_operating_parameters (rpt); break;
5196285612Sdelphij	    case 0x4D: rpt_oscillator_offset (rpt); break;
5197285612Sdelphij	    case 0x4E: rpt_GPS_time_set_response (rpt); break;
5198285612Sdelphij	    case 0x4F: rpt_UTC_offset (rpt); break;
5199285612Sdelphij	    case 0x54: rpt_1SV_bias (rpt); break;
5200285612Sdelphij	    case 0x55: rpt_io_opt (rpt); break;
5201285612Sdelphij	    case 0x56: rpt_ENU_velocity (rpt); break;
5202285612Sdelphij	    case 0x57: rpt_last_fix_info (rpt); break;
5203285612Sdelphij	    case 0x58: rpt_GPS_system_data (rpt); break;
5204285612Sdelphij	    case 0x59: rpt_SVs_enabled (rpt); break;
5205285612Sdelphij	    case 0x5A: rpt_raw_msmt (rpt); break;
5206285612Sdelphij	    case 0x5B: rpt_SV_ephemeris_status (rpt); break;
5207285612Sdelphij	    case 0x5C: rpt_SV_tracking_status (rpt); break;
5208285612Sdelphij	    case 0x6D: rpt_allSV_selection (rpt); break;
5209285612Sdelphij	    case 0x82: rpt_DGPS_position_mode (rpt); break;
5210285612Sdelphij	    case 0x83: rpt_double_ECEF_position (rpt); break;
5211285612Sdelphij	    case 0x84: rpt_double_lla_position (rpt); break;
5212285612Sdelphij	    case 0xBB: rpt_complete_rcvr_config (rpt); break;
5213285612Sdelphij	    case 0xBC: rpt_rcvr_serial_port_config (rpt); break;
5214106424Sroberto
5215285612Sdelphij	    case 0x8F: switch (rpt->buf[0])
5216285612Sdelphij		{
5217285612Sdelphij			/* superpackets; parsed according to subcodes */
5218285612Sdelphij		    case 0x0B: rpt_8F0B(rpt); break;
5219285612Sdelphij		    case 0x14: rpt_8F14(rpt); break;
5220285612Sdelphij		    case 0x15: rpt_8F15(rpt); break;
5221285612Sdelphij		    case 0x20: rpt_8F20(rpt); break;
5222285612Sdelphij		    case 0x41: rpt_8F41(rpt); break;
5223285612Sdelphij		    case 0x42: rpt_8F42(rpt); break;
5224285612Sdelphij		    case 0x45: rpt_8F45(rpt); break;
5225285612Sdelphij		    case 0x4A: rpt_8F4A(rpt); break;
5226285612Sdelphij		    case 0x4B: rpt_8F4B(rpt); break;
5227285612Sdelphij		    case 0x4D: rpt_8F4D(rpt); break;
5228285612Sdelphij		    case 0xA5: rpt_8FA5(rpt); break;
5229285612Sdelphij		    case 0xAD: rpt_8FAD(rpt); break;
5230285612Sdelphij		    default: parsed = BADID_PARSE; break;
5231106424Sroberto		}
5232106424Sroberto		break;
5233106424Sroberto
5234285612Sdelphij	    default: parsed = BADID_PARSE; break;
5235106424Sroberto	}
5236106424Sroberto
5237106424Sroberto	if (parsed != GOOD_PARSE)
5238106424Sroberto	{
5239285612Sdelphij		/*
5240285612Sdelphij		**The message has TSIP structure (DLEs, etc.)
5241285612Sdelphij		** but could not be parsed by above routines
5242285612Sdelphij		*/
5243106424Sroberto		unknown_rpt (rpt);
5244106424Sroberto	}
5245106424Sroberto
5246285612Sdelphij	/* close TextOutputBuffer */
5247285612Sdelphij	pbuf = '\0';
5248106424Sroberto}
5249106424Sroberto
5250106424Sroberto#endif /* TRIMBLE_OUTPUT_FUNC */
5251106424Sroberto
5252106424Sroberto#else  /* defined(REFCLOCK) && defined(CLOCK_RIPENCC) */
5253106424Srobertoint refclock_ripencc_bs;
5254106424Sroberto#endif /* defined(REFCLOCK) && defined(CLOCK_RIPENCC) */
5255106424Sroberto
5256