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
93290001Sglebius#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
112290001Sglebius	    counter,		/* counter */
113290001Sglebius	    len;		/* size of buf; < MAX_RPTBUF unsigned chars */
114106424Sroberto	unsigned char
115290001Sglebius	    status,		/* TSIP packet format/parse status */
116290001Sglebius	    code,		/* TSIP code */
117290001Sglebius	    buf[MAX_RPTBUF];	/* report or command string */
118106424Sroberto} TSIPPKT;
119106424Sroberto
120106424Sroberto/* TSIP binary data structures */
121106424Srobertotypedef struct {
122106424Sroberto	unsigned char
123290001Sglebius	    t_oa_raw, SV_health;
124106424Sroberto	float
125290001Sglebius	    e, t_oa, i_0, OMEGADOT, sqrt_A,
126290001Sglebius	    OMEGA_0, omega, M_0, a_f0, a_f1,
127290001Sglebius	    Axis, n, OMEGA_n, ODOT_n, t_zc;
128106424Sroberto	short
129290001Sglebius	    weeknum, wn_oa;
130106424Sroberto} ALM_INFO;
131106424Sroberto
132290001Sglebiustypedef struct {		/*  Almanac health page (25) parameters  */
133106424Sroberto	unsigned char
134290001Sglebius	    WN_a, SV_health[32], t_oa;
135106424Sroberto} ALH_PARMS;
136106424Sroberto
137290001Sglebiustypedef struct {		/*  Universal Coordinated Time (UTC) parms */
138106424Sroberto	double
139290001Sglebius	    A_0;
140106424Sroberto	float
141290001Sglebius	    A_1;
142106424Sroberto	short
143290001Sglebius	    delta_t_LS;
144106424Sroberto	float
145290001Sglebius	    t_ot;
146106424Sroberto	short
147290001Sglebius	    WN_t, WN_LSF, DN, delta_t_LSF;
148106424Sroberto} UTC_INFO;
149106424Sroberto
150290001Sglebiustypedef struct {		/*  Ionospheric info (float)  */
151106424Sroberto	float
152290001Sglebius	    alpha_0, alpha_1, alpha_2, alpha_3,
153290001Sglebius	    beta_0, beta_1, beta_2, beta_3;
154106424Sroberto} ION_INFO;
155106424Sroberto
156290001Sglebiustypedef struct {		/*  Subframe 1 info (float)  */
157106424Sroberto	short
158290001Sglebius	    weeknum;
159106424Sroberto	unsigned char
160290001Sglebius	    codeL2, L2Pdata, SVacc_raw, SV_health;
161106424Sroberto	short
162290001Sglebius	    IODC;
163106424Sroberto	float
164290001Sglebius	    T_GD, t_oc, a_f2, a_f1, a_f0, SVacc;
165106424Sroberto} EPHEM_CLOCK;
166106424Sroberto
167290001Sglebiustypedef	struct {		/*  Ephemeris info (float)  */
168106424Sroberto	unsigned char
169290001Sglebius	    IODE, fit_interval;
170106424Sroberto	float
171290001Sglebius	    C_rs, delta_n;
172106424Sroberto	double
173290001Sglebius	    M_0;
174106424Sroberto	float
175290001Sglebius	    C_uc;
176106424Sroberto	double
177290001Sglebius	    e;
178106424Sroberto	float
179290001Sglebius	    C_us;
180106424Sroberto	double
181290001Sglebius	    sqrt_A;
182106424Sroberto	float
183290001Sglebius	    t_oe, C_ic;
184106424Sroberto	double
185290001Sglebius	    OMEGA_0;
186106424Sroberto	float
187290001Sglebius	    C_is;
188106424Sroberto	double
189290001Sglebius	    i_0;
190106424Sroberto	float
191290001Sglebius	    C_rc;
192106424Sroberto	double
193290001Sglebius	    omega;
194106424Sroberto	float
195290001Sglebius	    OMEGADOT, IDOT;
196106424Sroberto	double
197290001Sglebius	    Axis, n, r1me2, OMEGA_n, ODOT_n;
198106424Sroberto} EPHEM_ORBIT;
199106424Sroberto
200290001Sglebiustypedef struct {		/* Navigation data structure */
201106424Sroberto	short
202290001Sglebius	    sv_number;		/* SV number (0 = no entry) */
203106424Sroberto	float
204290001Sglebius	    t_ephem;		/* time of ephemeris collection */
205106424Sroberto	EPHEM_CLOCK
206290001Sglebius	    ephclk;		/* subframe 1 data */
207106424Sroberto	EPHEM_ORBIT
208290001Sglebius	    ephorb;		/* ephemeris data */
209106424Sroberto} NAV_INFO;
210106424Sroberto
211106424Srobertotypedef struct {
212106424Sroberto	unsigned char
213290001Sglebius	    bSubcode,
214290001Sglebius	    operating_mode,
215290001Sglebius	    dgps_mode,
216290001Sglebius	    dyn_code,
217290001Sglebius	    trackmode;
218106424Sroberto	float
219290001Sglebius	    elev_mask,
220290001Sglebius	    cno_mask,
221290001Sglebius	    dop_mask,
222290001Sglebius	    dop_switch;
223106424Sroberto	unsigned char
224290001Sglebius	    dgps_age_limit;
225106424Sroberto} TSIP_RCVR_CFG;
226106424Sroberto
227106424Sroberto
228106424Sroberto#ifdef TRIMBLE_OUTPUT_FUNC
229106424Srobertostatic char
230290001Sglebius        *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",
233290001Sglebius				" 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",
243290001Sglebius			      "3-D", "", "", "OverDetermined Time"},
244106424Sroberto	*PPSTimeBaseText[] = {"GPS", "UTC", "USER"},
245106424Sroberto	*PPSPolarityText[] = {"Positive", "Negative"},
246106424Sroberto  	*MaskText[] = { "Almanac  ", "Ephemeris", "UTC      ", "Iono     ",
247290001Sglebius			"GPS Msg  ", "Alm Hlth ", "Time Fix ", "SV Select",
248290001Sglebius			"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,
275290001Sglebius		unsigned char *rx_baud_index, unsigned char *char_format_index,
276290001Sglebius		unsigned char *stop_bits, unsigned char *tx_mode_index,
277290001Sglebius		unsigned char *rx_mode_index);
278106424Srobertoshort rpt_0x40 (TSIPPKT *rpt, unsigned char *sv_prn, short *week_num,
279290001Sglebius		float *t_zc, float *eccentricity, float *t_oa, float *i_0,
280290001Sglebius		float *OMEGA_dot, float *sqrt_A, float *OMEGA_0, float *omega,
281290001Sglebius		float *M_0);
282106424Srobertoshort rpt_0x41 (TSIPPKT *rpt, float *time_of_week, float *UTC_offset,
283290001Sglebius		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,
286290001Sglebius		float *time_of_fix);
287106424Srobertoshort rpt_0x45 (TSIPPKT *rpt, unsigned char *major_nav_version,
288290001Sglebius		unsigned char *minor_nav_version, unsigned char *nav_day,
289290001Sglebius		unsigned char *nav_month, unsigned char *nav_year,
290290001Sglebius		unsigned char *major_dsp_version, unsigned char *minor_dsp_version,
291290001Sglebius		unsigned char *dsp_day, unsigned char *dsp_month,
292290001Sglebius		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,
295290001Sglebius		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,
299290001Sglebius		float *clock_bias, float *time_of_fix);
300106424Srobertoshort rpt_0x4A_2 (TSIPPKT *rpt, float *alt, float *dummy,
301290001Sglebius		  unsigned char *alt_flag);
302106424Srobertoshort rpt_0x4B (TSIPPKT *rpt, unsigned char *machine_id,
303290001Sglebius		unsigned char *status3, unsigned char *status4);
304106424Srobertoshort rpt_0x4C (TSIPPKT *rpt, unsigned char *dyn_code, float *el_mask,
305290001Sglebius		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,
309290001Sglebius		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,
311290001Sglebius		float *time_of_fix);
312106424Srobertoshort rpt_0x55 (TSIPPKT *rpt, unsigned char *pos_code, unsigned char *vel_code,
313290001Sglebius		unsigned char *time_code, unsigned char *aux_code);
314106424Srobertoshort rpt_0x56 (TSIPPKT *rpt, float vel_ENU[3], float *freq_offset,
315290001Sglebius		float *time_of_fix);
316106424Srobertoshort rpt_0x57 (TSIPPKT *rpt, unsigned char *source_code,
317290001Sglebius		unsigned char *diag_code, short *week_num, float *time_of_fix);
318106424Srobertoshort rpt_0x58 (TSIPPKT *rpt, unsigned char *op_code, unsigned char *data_type,
319290001Sglebius		unsigned char *sv_prn, unsigned char *data_length,
320290001Sglebius		unsigned char *data_packet);
321106424Srobertoshort rpt_0x59 (TSIPPKT *rpt, unsigned char *code_type,
322290001Sglebius		unsigned char status_code[32]);
323106424Srobertoshort rpt_0x5A (TSIPPKT *rpt, unsigned char *sv_prn, float *sample_length,
324290001Sglebius		float *signal_level, float *code_phase, float *Doppler,
325290001Sglebius		double *time_of_fix);
326106424Srobertoshort rpt_0x5B (TSIPPKT *rpt, unsigned char *sv_prn, unsigned char *sv_health,
327290001Sglebius		unsigned char *sv_iode, unsigned char *fit_interval_flag,
328290001Sglebius		float *time_of_collection, float *time_of_eph, float *sv_accy);
329106424Srobertoshort rpt_0x5C (TSIPPKT *rpt, unsigned char *sv_prn, unsigned char *slot,
330290001Sglebius		unsigned char *chan, unsigned char *acq_flag, unsigned char *eph_flag,
331290001Sglebius		float *signal_level, float *time_of_last_msmt, float *elev,
332290001Sglebius		float *azim, unsigned char *old_msmt_flag,
333290001Sglebius		unsigned char *integer_msec_flag, unsigned char *bad_data_flag,
334290001Sglebius		unsigned char *data_collect_flag);
335106424Srobertoshort rpt_0x6D (TSIPPKT *rpt, unsigned char *manual_mode, unsigned char *nsvs,
336290001Sglebius		unsigned char *ndim, unsigned char sv_prn[], float *pdop,
337290001Sglebius		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,
340290001Sglebius		float *time_of_fix);
341106424Srobertoshort rpt_0x84 (TSIPPKT *rpt, double *lat, double *lon, double *alt,
342290001Sglebius		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,
345290001Sglebius		  unsigned char *in_baud, unsigned char *out_baud,
346290001Sglebius		  unsigned char *data_bits, unsigned char *parity,
347290001Sglebius		  unsigned char *stop_bits, unsigned char *flow_control,
348290001Sglebius		  unsigned char *protocols_in, unsigned char *protocols_out,
349290001Sglebius		  unsigned char *reserved);
350106424Sroberto
351106424Sroberto/* prototypes for superpacket parsers */
352106424Sroberto
353106424Srobertoshort rpt_0x8F0B (TSIPPKT *rpt, unsigned short *event, double *tow,
354290001Sglebius		  unsigned char *date, unsigned char *month, short *year,
355290001Sglebius		  unsigned char *dim_mode, short *utc_offset, double *bias, double *drift,
356290001Sglebius		  float *bias_unc, float *dr_unc, double *lat, double *lon, double *alt,
357290001Sglebius		  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,
361290001Sglebius		  double *lon, double *alt, double vel_enu[], double *time_of_fix,
362290001Sglebius		  short *week_num, unsigned char *nsvs, unsigned char sv_prn[],
363290001Sglebius		  short sv_IODC[], short *datum_index);
364106424Srobertoshort rpt_0x8F41 (TSIPPKT *rpt, unsigned char *bSearchRange,
365290001Sglebius		  unsigned char *bBoardOptions, unsigned long *iiSerialNumber,
366290001Sglebius		  unsigned char *bBuildYear, unsigned char *bBuildMonth,
367290001Sglebius		  unsigned char *bBuildDay, unsigned char *bBuildHour,
368290001Sglebius		  float *fOscOffset, unsigned short *iTestCodeId);
369106424Srobertoshort rpt_0x8F42 (TSIPPKT *rpt, unsigned char *bProdOptionsPre,
370290001Sglebius		  unsigned char *bProdNumberExt, unsigned short *iCaseSerialNumberPre,
371290001Sglebius		  unsigned long *iiCaseSerialNumber, unsigned long *iiProdNumber,
372290001Sglebius		  unsigned short *iPremiumOptions, unsigned short *iMachineID,
373290001Sglebius		  unsigned short *iKey);
374106424Srobertoshort rpt_0x8F45 (TSIPPKT *rpt, unsigned char *bSegMask);
375106424Srobertoshort rpt_0x8F4A_16 (TSIPPKT *rpt, unsigned char *pps_enabled,
376290001Sglebius		     unsigned char *pps_timebase, unsigned char *pos_polarity,
377290001Sglebius		     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,
382290001Sglebius		  unsigned char *Hour, unsigned char *Minute, unsigned char *Second,
383290001Sglebius		  unsigned char *Day, unsigned char *Month, unsigned short *Year,
384290001Sglebius		  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,
393290001Sglebius		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,
396290001Sglebius		unsigned char char_code, unsigned char stopbitcode,
397290001Sglebius		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,
406290001Sglebius		  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 */
414290001Sglebiusstatic 	int	parse0x8FAD	(TSIPPKT *, struct peer *);
415290001Sglebiusstatic 	int	parse0x8F0B	(TSIPPKT *, struct peer *);
416106424Sroberto#ifdef TRIMBLE_OUTPUT_FUNC
417290001Sglebiusstatic 	int	parseany	(TSIPPKT *, struct peer *);
418290001Sglebiusstatic 	void	TranslateTSIPReportToText	(TSIPPKT *, char *);
419106424Sroberto#endif /* TRIMBLE_OUTPUT_FUNC */
420290001Sglebiusstatic 	int	parse0x5C	(TSIPPKT *, struct peer *);
421290001Sglebiusstatic 	int	parse0x4F	(TSIPPKT *, struct peer *);
422290001Sglebiusstatic	void	tsip_input_proc	(TSIPPKT *, int);
423106424Sroberto
424106424Sroberto/* Trimble helper functions */
425290001Sglebiusstatic	void	bPutFloat 	(float *, unsigned char *);
426290001Sglebiusstatic	void	bPutDouble 	(double *, unsigned char *);
427290001Sglebiusstatic	void	bPutULong 	(unsigned long *, unsigned char *);
428290001Sglebiusstatic	int	print_msg_table_header	(int rptcode, char *HdrStr, int force);
429290001Sglebiusstatic	char *	show_time	(float time_of_week);
430106424Sroberto
431106424Sroberto/* RIPE NCC functions */
432290001Sglebiusstatic	void	ripencc_control	(int, const struct refclockstat *,
433290001Sglebius				 struct refclockstat *, struct peer *);
434290001Sglebiusstatic	int	ripencc_ppsapi	(struct peer *, int, int);
435290001Sglebiusstatic	int	ripencc_get_pps_ts	(struct ripencc_unit *, l_fp *);
436290001Sglebiusstatic	int	ripencc_start	(int, struct peer *);
437290001Sglebiusstatic 	void	ripencc_shutdown	(int, struct peer *);
438290001Sglebiusstatic 	void	ripencc_poll	(int, struct peer *);
439290001Sglebiusstatic 	void	ripencc_send	(struct peer *, TSIPPKT spt);
440290001Sglebiusstatic 	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
474290001Sglebius	pp = peer->procptr;
475290001Sglebius
476106424Sroberto	/*
477106424Sroberto	 * Open serial port
478106424Sroberto	 */
479106424Sroberto	(void)snprintf(device, sizeof(device), DEVICE, unit);
480290001Sglebius	fd = refclock_open(device, SPEED232, LDISC_RAW);
481290001Sglebius	if (fd <= 0) {
482290001Sglebius		pp->io.fd = -1;
483106424Sroberto		return (0);
484290001Sglebius	}
485106424Sroberto
486290001Sglebius	pp->io.fd = fd;
487290001Sglebius
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	 */
507290001Sglebius	up = emalloc_zero(sizeof(*up));
508290001Sglebius
509106424Sroberto	pp->io.clock_recv = ripencc_receive;
510290001Sglebius	pp->io.srcclock = peer;
511106424Sroberto	pp->io.datalen = 0;
512106424Sroberto	if (!io_addclock(&pp->io)) {
513290001Sglebius		pp->io.fd = -1;
514290001Sglebius		close(fd);
515106424Sroberto		free(up);
516106424Sroberto		return (0);
517106424Sroberto	}
518290001Sglebius	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,
553290001Sglebius		  0x1C, 	/* position */
554290001Sglebius		  0x00, 	/* velocity */
555290001Sglebius		  0x05, 	/* timing */
556290001Sglebius		  0x0a); 	/* auxilary */
557106424Sroberto	ripencc_send(peer, spt);
558106424Sroberto
559106424Sroberto	/* turn off port A */
560106424Sroberto	cmd_0x3Ds (&spt,
561290001Sglebius		   0x0B,	/* baud_out */
562290001Sglebius		   0x0B,	/* baud_inp */
563290001Sglebius		   0x07,	/* char_code */
564290001Sglebius		   0x07,	/* stopbitcode */
565290001Sglebius		   0x01,	/* output_mode */
566290001Sglebius		   0x00);	/* input_mode */
567106424Sroberto	ripencc_send(peer, spt);
568106424Sroberto
569106424Sroberto	/* set i/o options */
570106424Sroberto	cmd_0x8E4As (&spt,
571290001Sglebius		     0x01,	/* PPS on */
572290001Sglebius		     0x01,	/* Timebase UTC */
573290001Sglebius		     0x00,	/* polarity positive */
574290001Sglebius		     0.,	/* 100 ft. cable XXX make flag */
575290001Sglebius		     1e-6 * GPS_C); 	/* turn of biasuncert. > (1us) */
576106424Sroberto	ripencc_send(peer,spt);
577106424Sroberto
578106424Sroberto	/* all outomatic packet output off */
579106424Sroberto	cmd_0x8E4Ds(&spt,
580290001Sglebius		    0x00000000); /* AutoOutputMask */
581106424Sroberto	ripencc_send(peer, spt);
582106424Sroberto
583106424Sroberto	cmd_0xBBq (&spt,
584290001Sglebius		   0x00);	/* query primary configuration */
585106424Sroberto	ripencc_send(peer,spt);
586106424Sroberto
587106424Sroberto
588106424Sroberto	/* query PPS parameters */
589290001Sglebius	cmd_0x8E4Aq (&spt);	/* query PPS params */
590106424Sroberto	ripencc_send(peer,spt);
591106424Sroberto
592106424Sroberto	/* query survey limit */
593290001Sglebius	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) */
620290001Sglebius	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,
633290001Sglebius		       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;
652290001Sglebius	up = pp->unitptr;
653106424Sroberto	if (time_pps_getcap(up->handle, &capability) < 0) {
654106424Sroberto		msyslog(LOG_ERR,
655290001Sglebius			"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,
665290001Sglebius			"refclock_ripencc: invalid capture edge %d",
666290001Sglebius			!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,
672290001Sglebius			"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,
680290001Sglebius				"refclock_ripencc: time_pps_kcbind failed: %m");
681106424Sroberto			return (0);
682106424Sroberto		}
683290001Sglebius		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(
691290001Sglebius			"refclock_ripencc: capability 0x%x version %d mode 0x%x kern %d\n",
692290001Sglebius			capability, up->pps_params.api_version,
693290001Sglebius			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
718290001Sglebius	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,
731290001Sglebius			   &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
755290001Sglebius	msyslog(LOG_INFO,"ts.tv_sec: %d",(int)ts.tv_sec);
756290001Sglebius	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;
773290001Sglebius	up = pp->unitptr;
774106424Sroberto
775290001Sglebius	if (up != NULL) {
776290001Sglebius		if (up->handle != 0)
777290001Sglebius			time_pps_destroy(up->handle);
778290001Sglebius		free(up);
779290001Sglebius	}
780290001Sglebius	if (-1 != pp->io.fd)
781290001Sglebius		io_closeclock(&pp->io);
782106424Sroberto
783290001Sglebius	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;
801290001Sglebius	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;
832290001Sglebius		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
851290001Sglebius		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) {
875290001Sglebius		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;
892290001Sglebius	static TSIPPKT rpt;	/* for current incoming TSIP report */
893290001Sglebius	TSIPPKT spt;		/* send packet */
894106424Sroberto	int ns_since_pps;
895106424Sroberto	int i;
896106424Sroberto	char *cp;
897290001Sglebius	/* 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	 */
907290001Sglebius	peer = rbufp->recv_peer;
908106424Sroberto	pp = peer->procptr;
909290001Sglebius	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
918290001Sglebius	if (debug) {		/* print raw packet */
919106424Sroberto		int i;
920106424Sroberto		unsigned char *cp;
921106424Sroberto
922106424Sroberto		printf("ripencc_receive: len %d\n", rbufp->recv_length);
923290001Sglebius		for (i=1, cp=(char*)&rbufp->recv_space;
924290001Sglebius		     i <= rbufp->recv_length;
925290001Sglebius		     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
937290001Sglebius	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
946290001Sglebius		    case 0x8F:	/* superpacket */
947106424Sroberto
948106424Sroberto			switch (rpt.buf[0]) {
949106424Sroberto
950290001Sglebius			    case 0xAD:	/* UTC Time */
951106424Sroberto				/*
952290001Sglebius				** When polling on port B the timecode is
953290001Sglebius				** the time of the previous PPS.  If we
954290001Sglebius				** completed receiving the packet less than
955290001Sglebius				** 150ms after the turn of the second, it
956290001Sglebius				** may have the code of the previous second.
957290001Sglebius				** We do not trust that and simply poll
958290001Sglebius				** again without even parsing it.
959290001Sglebius				**
960290001Sglebius				** More elegant would be to re-schedule the
961290001Sglebius				** poll, but I do not know (yet) how to do
962290001Sglebius				** that cleanly.
963290001Sglebius				**
964290001Sglebius				*/
965106424Sroberto				/* BLA ns_since_pps = ncc_tstmp(rbufp, &trtmp); */
966106424Sroberto/*   if (up->polled && ns_since_pps > -1 && ns_since_pps < 150) { */
967106424Sroberto
968290001Sglebius				ns_since_pps = 200;
969106424Sroberto				if (up->polled && ns_since_pps < 150) {
970290001Sglebius					msyslog(LOG_INFO, "%s(): up->polled",
971290001Sglebius						__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) {
982290001Sglebius					msyslog(LOG_INFO, "%s(): parse0x8FAD < 0",__FUNCTION__);
983290001Sglebius					refclock_report(peer, CEVNT_BADREPLY);
984290001Sglebius					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
997290001Sglebius					msyslog(LOG_INFO, "%s(): ripencc_get_pps_ts returns failure",__FUNCTION__);
998106424Sroberto
999106424Sroberto
1000106424Sroberto				if (!up->polled) {
1001290001Sglebius					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				/*
1021290001Sglebius				** Process the new sample in the median
1022290001Sglebius				** filter and determine the reference clock
1023290001Sglebius				** offset and dispersion.
1024290001Sglebius				*/
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
1034290001Sglebius			    case 0x0B: /* comprehensive time packet */
1035106424Sroberto				parse0x8F0B(&rpt, peer);
1036106424Sroberto				break;
1037106424Sroberto
1038290001Sglebius			    default: /* other superpackets */
1039106424Sroberto#ifdef DEBUG_NCC
1040290001Sglebius				msyslog(LOG_INFO, "%s(): calling parseany",
1041290001Sglebius					__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
1050290001Sglebius		    case 0x4F:	/* UTC parameters, for leap info */
1051106424Sroberto			parse0x4F(&rpt, peer);
1052106424Sroberto			break;
1053106424Sroberto
1054290001Sglebius		    case 0x5C:	/* sat tracking data */
1055106424Sroberto			parse0x5C(&rpt, peer);
1056106424Sroberto			break;
1057106424Sroberto
1058290001Sglebius		    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 */
1074290001Sglebiusvoid
1075290001Sglebiuscmd_0x1F(
1076290001Sglebius	 TSIPPKT *cmd
1077290001Sglebius	 )
1078106424Sroberto{
1079106424Sroberto	cmd->len = 0;
1080106424Sroberto	cmd->code = 0x1F;
1081106424Sroberto}
1082106424Sroberto
1083106424Sroberto/* request receiver health */
1084290001Sglebiusvoid
1085290001Sglebiuscmd_0x26(
1086290001Sglebius	 TSIPPKT *cmd
1087290001Sglebius	 )
1088106424Sroberto{
1089106424Sroberto	cmd->len = 0;
1090106424Sroberto	cmd->code = 0x26;
1091106424Sroberto}
1092106424Sroberto
1093106424Sroberto/* request UTC params */
1094290001Sglebiusvoid
1095290001Sglebiuscmd_0x2F(
1096290001Sglebius	 TSIPPKT *cmd
1097290001Sglebius	 )
1098106424Sroberto{
1099106424Sroberto	cmd->len = 0;
1100106424Sroberto	cmd->code = 0x2F;
1101106424Sroberto}
1102106424Sroberto
1103106424Sroberto/* set serial I/O options */
1104290001Sglebiusvoid
1105290001Sglebiuscmd_0x35s(
1106290001Sglebius	 TSIPPKT *cmd,
1107290001Sglebius	 unsigned char pos_code,
1108290001Sglebius	 unsigned char vel_code,
1109290001Sglebius	 unsigned char time_code,
1110290001Sglebius	 unsigned char opts_code
1111290001Sglebius	 )
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}
1120290001Sglebius
1121106424Sroberto/* request tracking status */
1122290001Sglebiusvoid
1123290001Sglebiuscmd_0x3C(
1124290001Sglebius	 TSIPPKT *cmd,
1125290001Sglebius	 unsigned char sv_prn
1126290001Sglebius	 )
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 */
1134290001Sglebiusvoid
1135290001Sglebiuscmd_0x3Ds(
1136290001Sglebius	  TSIPPKT *cmd,
1137290001Sglebius	  unsigned char baud_out,
1138290001Sglebius	  unsigned char baud_inp,
1139290001Sglebius	  unsigned char char_code,
1140290001Sglebius	  unsigned char stopbitcode,
1141290001Sglebius	  unsigned char output_mode,
1142290001Sglebius	  unsigned char input_mode
1143290001Sglebius	  )
1144106424Sroberto{
1145106424Sroberto	cmd->buf[0] = baud_out;		/* XMT baud rate */
1146106424Sroberto	cmd->buf[1] = baud_inp;		/* RCV baud rate */
1147290001Sglebius	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 */
1157290001Sglebiusvoid
1158290001Sglebiuscmd_0xBBq(
1159290001Sglebius	  TSIPPKT *cmd,
1160290001Sglebius	  unsigned char subcode
1161290001Sglebius	  )
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 */
1171290001Sglebiusvoid
1172290001Sglebiuscmd_0x8E0Bq(
1173290001Sglebius	    TSIPPKT *cmd
1174290001Sglebius	    )
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 */
1183290001Sglebiusvoid
1184290001Sglebiuscmd_0x8E41q(
1185290001Sglebius	    TSIPPKT *cmd
1186290001Sglebius	    )
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 */
1195290001Sglebiusvoid
1196290001Sglebiuscmd_0x8E42q(
1197290001Sglebius	    TSIPPKT *cmd
1198290001Sglebius	    )
1199106424Sroberto{
1200106424Sroberto	cmd->len = 1;
1201106424Sroberto	cmd->code = 0x8E;
1202106424Sroberto	cmd->buf[0] = 0x42;
1203106424Sroberto}
1204290001Sglebius
1205290001Sglebius
1206106424Sroberto/* 8F-4A to query PPS parameters */
1207290001Sglebiusvoid
1208290001Sglebiuscmd_0x8E4Aq(
1209290001Sglebius	    TSIPPKT *cmd
1210290001Sglebius	    )
1211106424Sroberto{
1212106424Sroberto	cmd->len = 1;
1213106424Sroberto	cmd->code = 0x8E;
1214106424Sroberto	cmd->buf[0] = 0x4A;
1215106424Sroberto}
1216106424Sroberto
1217106424Sroberto
1218106424Sroberto/* set i/o options */
1219290001Sglebiusvoid
1220290001Sglebiuscmd_0x8E4As(
1221290001Sglebius	    TSIPPKT *cmd,
1222290001Sglebius	    unsigned char PPSOnOff,
1223290001Sglebius	    unsigned char TimeBase,
1224290001Sglebius	    unsigned char Polarity,
1225290001Sglebius	    double PPSOffset,
1226290001Sglebius	    float Uncertainty
1227290001Sglebius	    )
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}
1238290001Sglebius
1239106424Sroberto/* 8F-4B query survey limit */
1240290001Sglebiusvoid
1241290001Sglebiuscmd_0x8E4Bq(
1242290001Sglebius	    TSIPPKT *cmd
1243290001Sglebius	    )
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 */
1252290001Sglebiusvoid
1253290001Sglebiuscmd_0x8EADq(
1254290001Sglebius	    TSIPPKT *cmd
1255290001Sglebius	    )
1256106424Sroberto{
1257106424Sroberto	cmd->len = 1;
1258106424Sroberto	cmd->code = 0x8E;
1259106424Sroberto	cmd->buf[0] = 0xAD;
1260106424Sroberto}
1261106424Sroberto
1262106424Sroberto/* all outomatic packet output off */
1263290001Sglebiusvoid
1264290001Sglebiuscmd_0x8E4Ds(
1265290001Sglebius	    TSIPPKT *cmd,
1266290001Sglebius	    unsigned long AutoOutputMask
1267290001Sglebius	    )
1268106424Sroberto{
1269106424Sroberto	cmd->len = 5;
1270106424Sroberto	cmd->code = 0x8E;
1271106424Sroberto	cmd->buf[0] = 0x4D;
1272106424Sroberto	bPutULong (&AutoOutputMask, &cmd->buf[1]);
1273106424Sroberto}
1274106424Sroberto
1275106424Sroberto
1276290001Sglebius/*
1277290001Sglebius * for DOS machines, reverse order of bytes as they come through the
1278290001Sglebius * serial port.
1279290001Sglebius */
1280106424Sroberto#ifdef BYTESWAP
1281290001Sglebiusstatic short
1282290001SglebiusbGetShort(
1283290001Sglebius	  unsigned char *bp
1284290001Sglebius	  )
1285106424Sroberto{
1286106424Sroberto	short outval;
1287290001Sglebius	unsigned char *optr;
1288106424Sroberto
1289290001Sglebius	optr = (unsigned char*)&outval + 1;
1290290001Sglebius	*optr-- = *bp++;
1291290001Sglebius	*optr = *bp;
1292106424Sroberto	return outval;
1293106424Sroberto}
1294106424Sroberto
1295106424Sroberto#ifdef TRIMBLE_OUTPUT_FUNC
1296290001Sglebiusstatic unsigned short
1297290001SglebiusbGetUShort(
1298290001Sglebius	   unsigned char *bp
1299290001Sglebius	   )
1300106424Sroberto{
1301106424Sroberto	unsigned short outval;
1302290001Sglebius	unsigned char *optr;
1303106424Sroberto
1304290001Sglebius	optr = (unsigned char*)&outval + 1;
1305290001Sglebius	*optr-- = *bp++;
1306290001Sglebius	*optr = *bp;
1307106424Sroberto	return outval;
1308106424Sroberto}
1309106424Sroberto
1310290001Sglebiusstatic long
1311290001SglebiusbGetLong(
1312290001Sglebius	 unsigned char *bp
1313290001Sglebius	 )
1314106424Sroberto{
1315106424Sroberto	long outval;
1316290001Sglebius	unsigned char *optr;
1317106424Sroberto
1318290001Sglebius	optr = (unsigned char*)&outval + 3;
1319290001Sglebius	*optr-- = *bp++;
1320290001Sglebius	*optr-- = *bp++;
1321290001Sglebius	*optr-- = *bp++;
1322290001Sglebius	*optr = *bp;
1323106424Sroberto	return outval;
1324106424Sroberto}
1325106424Sroberto
1326290001Sglebiusstatic unsigned long
1327290001SglebiusbGetULong(
1328290001Sglebius	  unsigned char *bp
1329290001Sglebius	  )
1330106424Sroberto{
1331106424Sroberto	unsigned long outval;
1332290001Sglebius	unsigned char *optr;
1333106424Sroberto
1334290001Sglebius	optr = (unsigned char*)&outval + 3;
1335290001Sglebius	*optr-- = *bp++;
1336290001Sglebius	*optr-- = *bp++;
1337290001Sglebius	*optr-- = *bp++;
1338290001Sglebius	*optr = *bp;
1339106424Sroberto	return outval;
1340106424Sroberto}
1341106424Sroberto#endif /* TRIMBLE_OUTPUT_FUNC */
1342106424Sroberto
1343290001Sglebiusstatic float
1344290001SglebiusbGetSingle(
1345290001Sglebius	   unsigned char *bp
1346290001Sglebius	   )
1347106424Sroberto{
1348106424Sroberto	float outval;
1349290001Sglebius	unsigned char *optr;
1350106424Sroberto
1351290001Sglebius	optr = (unsigned char*)&outval + 3;
1352290001Sglebius	*optr-- = *bp++;
1353290001Sglebius	*optr-- = *bp++;
1354290001Sglebius	*optr-- = *bp++;
1355290001Sglebius	*optr = *bp;
1356106424Sroberto	return outval;
1357106424Sroberto}
1358106424Sroberto
1359290001Sglebiusstatic double
1360290001SglebiusbGetDouble(
1361290001Sglebius	   unsigned char *bp
1362290001Sglebius	   )
1363106424Sroberto{
1364106424Sroberto	double outval;
1365290001Sglebius	unsigned char *optr;
1366106424Sroberto
1367290001Sglebius	optr = (unsigned char*)&outval + 7;
1368290001Sglebius	*optr-- = *bp++;
1369290001Sglebius	*optr-- = *bp++;
1370290001Sglebius	*optr-- = *bp++;
1371290001Sglebius	*optr-- = *bp++;
1372290001Sglebius	*optr-- = *bp++;
1373290001Sglebius	*optr-- = *bp++;
1374290001Sglebius	*optr-- = *bp++;
1375290001Sglebius	*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
1395290001SglebiusbPutFloat(
1396290001Sglebius	  float *in,
1397290001Sglebius	  unsigned char *out
1398290001Sglebius	  )
1399106424Sroberto{
1400106424Sroberto	unsigned char *inptr;
1401106424Sroberto
1402290001Sglebius	inptr = (unsigned char*)in + 3;
1403290001Sglebius	*out++ = *inptr--;
1404290001Sglebius	*out++ = *inptr--;
1405290001Sglebius	*out++ = *inptr--;
1406290001Sglebius	*out = *inptr;
1407106424Sroberto}
1408106424Sroberto
1409106424Srobertostatic void
1410290001SglebiusbPutULong(
1411290001Sglebius	  unsigned long *in,
1412290001Sglebius	  unsigned char *out
1413290001Sglebius	  )
1414106424Sroberto{
1415106424Sroberto	unsigned char *inptr;
1416106424Sroberto
1417290001Sglebius	inptr = (unsigned char*)in + 3;
1418290001Sglebius	*out++ = *inptr--;
1419290001Sglebius	*out++ = *inptr--;
1420290001Sglebius	*out++ = *inptr--;
1421290001Sglebius	*out = *inptr;
1422106424Sroberto}
1423106424Sroberto
1424106424Srobertostatic void
1425290001SglebiusbPutDouble(
1426290001Sglebius	   double *in,
1427290001Sglebius	   unsigned char *out
1428290001Sglebius	   )
1429106424Sroberto{
1430106424Sroberto	unsigned char *inptr;
1431106424Sroberto
1432290001Sglebius	inptr = (unsigned char*)in + 7;
1433290001Sglebius	*out++ = *inptr--;
1434290001Sglebius	*out++ = *inptr--;
1435290001Sglebius	*out++ = *inptr--;
1436290001Sglebius	*out++ = *inptr--;
1437290001Sglebius	*out++ = *inptr--;
1438290001Sglebius	*out++ = *inptr--;
1439290001Sglebius	*out++ = *inptr--;
1440290001Sglebius	*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
1462290001Sglebiusparse0x8FAD(
1463290001Sglebius	    TSIPPKT *rpt,
1464290001Sglebius	    struct peer *peer
1465290001Sglebius	    )
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
1500290001Sglebius	hour =		(unsigned int) buf[11];
1501290001Sglebius	minute =	(unsigned int) buf[12];
1502290001Sglebius	second =	(unsigned int) buf[13];
1503106424Sroberto	day =		(unsigned int) buf[14];
1504106424Sroberto	month =		(unsigned int) buf[15];
1505106424Sroberto	year =		bGetShort(&buf[16]);
1506290001Sglebius	trackstat =	buf[18];
1507290001Sglebius	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) {
1526290001Sglebius		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
1546290001Sglebius	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)
1564290001Sglebius		pp-> leap = (up->leapdelta > 0)
1565290001Sglebius		    ? LEAP_ADDSECOND
1566290001Sglebius		    : LEAP_DELSECOND;
1567106424Sroberto	else
1568106424Sroberto		pp-> leap = LEAP_NOWARNING;
1569106424Sroberto
1570106424Sroberto	return (0);
1571106424Sroberto}
1572106424Sroberto
1573106424Sroberto/*
1574106424Sroberto * Parse comprehensive time packet
1575106424Sroberto *
1576290001Sglebius *  0 = success
1577106424Sroberto * -1 = errors
1578106424Sroberto */
1579106424Sroberto
1580290001Sglebiusint
1581290001Sglebiusparse0x8F0B(
1582290001Sglebius	    TSIPPKT *rpt,
1583290001Sglebius	    struct peer *peer
1584290001Sglebius	    )
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",
1678290001Sglebius		day, month, year, hour, minute, second, mode, bias, biasunc,
1679290001Sglebius		rate, rateunc, utcoff, lat_deg, lat_min, north_south, lon_deg,
1680290001Sglebius		lon_min, east_west, alt, sv[0], sv[1], sv[2], sv[3], sv[4],
1681290001Sglebius		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 */
1697290001Sglebiusint
1698290001Sglebiusparseany(
1699290001Sglebius	 TSIPPKT *rpt,
1700290001Sglebius	 struct peer *peer
1701290001Sglebius	 )
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
1725290001Sglebiusint
1726290001Sglebiusparse0x4F(
1727290001Sglebius	  TSIPPKT *rpt,
1728290001Sglebius	  struct peer *peer
1729290001Sglebius	  )
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
1776290001Sglebiusint
1777290001Sglebiusparse0x5C(
1778290001Sglebius	  TSIPPKT *rpt,
1779290001Sglebius	  struct peer *peer
1780290001Sglebius	  )
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
1882290001Sglebius/*
1883290001Sglebius * reads bytes until serial buffer is empty or a complete report
1884106424Sroberto * has been received; end of report is signified by DLE ETX.
1885106424Sroberto */
1886290001Sglebiusstatic void
1887290001Sglebiustsip_input_proc(
1888290001Sglebius		TSIPPKT *rpt,
1889290001Sglebius		int inbyte
1890290001Sglebius		)
1891106424Sroberto{
1892106424Sroberto	unsigned char newbyte;
1893106424Sroberto
1894106424Sroberto	if (inbyte < 0 || inbyte > 0xFF) return;
1895106424Sroberto
1896106424Sroberto	newbyte = (unsigned char)(inbyte);
1897106424Sroberto	switch (rpt->status)
1898106424Sroberto	{
1899290001Sglebius	    case TSIP_PARSED_DLE_1:
1900106424Sroberto		switch (newbyte)
1901106424Sroberto		{
1902290001Sglebius		    case 0:
1903290001Sglebius		    case ETX:
1904290001Sglebius			/* illegal TSIP IDs */
1905290001Sglebius			rpt->len = 0;
1906106424Sroberto			rpt->status = TSIP_PARSED_EMPTY;
1907106424Sroberto			break;
1908290001Sglebius		    case DLE:
1909290001Sglebius			/* try normal message start again */
1910106424Sroberto			rpt->len = 0;
1911106424Sroberto			rpt->status = TSIP_PARSED_DLE_1;
1912106424Sroberto			break;
1913290001Sglebius		    default:
1914290001Sglebius			/* legal TSIP ID; start message */
1915106424Sroberto			rpt->code = newbyte;
1916290001Sglebius			rpt->len = 0;
1917106424Sroberto			rpt->status = TSIP_PARSED_DATA;
1918106424Sroberto			break;
1919106424Sroberto		}
1920106424Sroberto		break;
1921290001Sglebius	    case TSIP_PARSED_DATA:
1922106424Sroberto		switch (newbyte) {
1923290001Sglebius		    case DLE:
1924290001Sglebius			/* expect DLE or ETX next */
1925106424Sroberto			rpt->status = TSIP_PARSED_DLE_2;
1926106424Sroberto			break;
1927290001Sglebius		    default:
1928290001Sglebius			/* normal data byte  */
1929106424Sroberto			rpt->buf[rpt->len] = newbyte;
1930106424Sroberto			rpt->len++;
1931290001Sglebius			/* no change in rpt->status */
1932106424Sroberto			break;
1933106424Sroberto		}
1934106424Sroberto		break;
1935290001Sglebius	    case TSIP_PARSED_DLE_2:
1936106424Sroberto		switch (newbyte) {
1937290001Sglebius		    case DLE:
1938290001Sglebius			/* normal data byte */
1939106424Sroberto			rpt->buf[rpt->len] = newbyte;
1940106424Sroberto			rpt->len++;
1941106424Sroberto			rpt->status = TSIP_PARSED_DATA;
1942106424Sroberto			break;
1943290001Sglebius		    case ETX:
1944106424Sroberto			/* end of message; return TRUE here. */
1945106424Sroberto			rpt->status = TSIP_PARSED_FULL;
1946106424Sroberto			break;
1947290001Sglebius		    default:
1948106424Sroberto			/* error: treat as TSIP_PARSED_DLE_1; start new report packet */
1949106424Sroberto			rpt->code = newbyte;
1950290001Sglebius			rpt->len = 0;
1951106424Sroberto			rpt->status = TSIP_PARSED_DATA;
1952106424Sroberto		}
1953106424Sroberto		break;
1954290001Sglebius	    case TSIP_PARSED_FULL:
1955290001Sglebius	    case TSIP_PARSED_EMPTY:
1956290001Sglebius	    default:
1957106424Sroberto		switch (newbyte) {
1958290001Sglebius		    case DLE:
1959290001Sglebius			/* normal message start */
1960106424Sroberto			rpt->len = 0;
1961106424Sroberto			rpt->status = TSIP_PARSED_DLE_1;
1962106424Sroberto			break;
1963290001Sglebius		    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 */
1981290001Sglebiusshort
1982290001Sglebiusrpt_0x3D(
1983290001Sglebius	 TSIPPKT *rpt,
1984290001Sglebius	 unsigned char *tx_baud_index,
1985290001Sglebius	 unsigned char *rx_baud_index,
1986290001Sglebius	 unsigned char *char_format_index,
1987290001Sglebius	 unsigned char *stop_bits,
1988290001Sglebius	 unsigned char *tx_mode_index,
1989290001Sglebius	 unsigned char *rx_mode_index
1990290001Sglebius	 )
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 */
2007290001Sglebiusshort
2008290001Sglebiusrpt_0x40(
2009290001Sglebius	 TSIPPKT *rpt,
2010290001Sglebius	 unsigned char *sv_prn,
2011290001Sglebius	 short *week_num,
2012290001Sglebius	 float *t_zc,
2013290001Sglebius	 float *eccentricity,
2014290001Sglebius	 float *t_oa,
2015290001Sglebius	 float *i_0,
2016290001Sglebius	 float *OMEGA_dot,
2017290001Sglebius	 float *sqrt_A,
2018290001Sglebius	 float *OMEGA_0,
2019290001Sglebius	 float *omega,
2020290001Sglebius	 float *M_0
2021290001Sglebius	 )
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 */
2042290001Sglebiusshort
2043290001Sglebiusrpt_0x41(
2044290001Sglebius	 TSIPPKT *rpt,
2045290001Sglebius	 float *time_of_week,
2046290001Sglebius	 float *UTC_offset,
2047290001Sglebius	 short *week_num
2048290001Sglebius	 )
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 */
2061290001Sglebiusshort
2062290001Sglebiusrpt_0x42(
2063290001Sglebius	 TSIPPKT *rpt,
2064290001Sglebius	 float pos_ECEF[3],
2065290001Sglebius	 float *time_of_fix
2066290001Sglebius	 )
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 */
2080290001Sglebiusshort
2081290001Sglebiusrpt_0x43(
2082290001Sglebius	 TSIPPKT *rpt,
2083290001Sglebius	 float ECEF_vel[3],
2084290001Sglebius	 float *freq_offset,
2085290001Sglebius	 float *time_of_fix
2086290001Sglebius	 )
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 */
2101290001Sglebiusshort
2102290001Sglebiusrpt_0x45(
2103290001Sglebius	 TSIPPKT *rpt,
2104290001Sglebius	 unsigned char *major_nav_version,
2105290001Sglebius	 unsigned char *minor_nav_version,
2106290001Sglebius	 unsigned char *nav_day,
2107290001Sglebius	 unsigned char *nav_month,
2108290001Sglebius	 unsigned char *nav_year,
2109290001Sglebius	 unsigned char *major_dsp_version,
2110290001Sglebius	 unsigned char *minor_dsp_version,
2111290001Sglebius	 unsigned char *dsp_day,
2112290001Sglebius	 unsigned char *dsp_month,
2113290001Sglebius	 unsigned char *dsp_year
2114290001Sglebius	 )
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 */
2134290001Sglebiusshort
2135290001Sglebiusrpt_0x46(
2136290001Sglebius	 TSIPPKT *rpt,
2137290001Sglebius	 unsigned char *status1,
2138290001Sglebius	 unsigned char *status2
2139290001Sglebius	 )
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 */
2151290001Sglebiusshort
2152290001Sglebiusrpt_0x47(
2153290001Sglebius	 TSIPPKT *rpt,
2154290001Sglebius	 unsigned char *nsvs,
2155290001Sglebius	 unsigned char *sv_prn,
2156290001Sglebius	 float *snr
2157290001Sglebius	 )
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 */
2173290001Sglebiusshort
2174290001Sglebiusrpt_0x48(
2175290001Sglebius	 TSIPPKT *rpt,
2176290001Sglebius	 unsigned char *message
2177290001Sglebius	 )
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 */
2189290001Sglebiusshort
2190290001Sglebiusrpt_0x49(
2191290001Sglebius	 TSIPPKT *rpt,
2192290001Sglebius	 unsigned char *sv_health
2193290001Sglebius	 )
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 */
2205290001Sglebiusshort
2206290001Sglebiusrpt_0x4A(
2207290001Sglebius	 TSIPPKT *rpt,
2208290001Sglebius	 float *lat,
2209290001Sglebius	 float *lon,
2210290001Sglebius	 float *alt,
2211290001Sglebius	 float *clock_bias,
2212290001Sglebius	 float *time_of_fix
2213290001Sglebius	 )
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 */
2228290001Sglebiusshort
2229290001Sglebiusrpt_0x4A_2(
2230290001Sglebius	   TSIPPKT *rpt,
2231290001Sglebius	   float *alt,
2232290001Sglebius	   float *dummy,
2233290001Sglebius	   unsigned char *alt_flag
2234290001Sglebius	   )
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 */
2248290001Sglebiusshort
2249290001Sglebiusrpt_0x4B(
2250290001Sglebius	 TSIPPKT *rpt,
2251290001Sglebius	 unsigned char *machine_id,
2252290001Sglebius	 unsigned char *status3,
2253290001Sglebius	 unsigned char *status4
2254290001Sglebius	 )
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 */
2267290001Sglebiusshort
2268290001Sglebiusrpt_0x4C(
2269290001Sglebius	 TSIPPKT *rpt,
2270290001Sglebius	 unsigned char *dyn_code,
2271290001Sglebius	 float *el_mask,
2272290001Sglebius	 float *snr_mask,
2273290001Sglebius	 float *dop_mask,
2274290001Sglebius	 float *dop_switch
2275290001Sglebius	 )
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 */
2290290001Sglebiusshort
2291290001Sglebiusrpt_0x4D(
2292290001Sglebius	 TSIPPKT *rpt,
2293290001Sglebius	 float *osc_offset
2294290001Sglebius	 )
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 */
2305290001Sglebiusshort
2306290001Sglebiusrpt_0x4E(
2307290001Sglebius	 TSIPPKT *rpt,
2308290001Sglebius	 unsigned char *response
2309290001Sglebius	 )
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 */
2320290001Sglebiusshort
2321290001Sglebiusrpt_0x4F(
2322290001Sglebius	 TSIPPKT *rpt,
2323290001Sglebius	 double *a0,
2324290001Sglebius	 float *a1,
2325290001Sglebius	 float *time_of_data,
2326290001Sglebius	 short *dt_ls,
2327290001Sglebius	 short *wn_t,
2328290001Sglebius	 short *wn_lsf,
2329290001Sglebius	 short *dn,
2330290001Sglebius	 short *dt_lsf
2331290001Sglebius	 )
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 */
2350290001Sglebiusshort
2351290001Sglebiusrpt_0x54(
2352290001Sglebius	 TSIPPKT *rpt,
2353290001Sglebius	 float *clock_bias,
2354290001Sglebius	 float *freq_offset,
2355290001Sglebius	 float *time_of_fix
2356290001Sglebius	 )
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 */
2369290001Sglebiusshort
2370290001Sglebiusrpt_0x55(
2371290001Sglebius	 TSIPPKT *rpt,
2372290001Sglebius	 unsigned char *pos_code,
2373290001Sglebius	 unsigned char *vel_code,
2374290001Sglebius	 unsigned char *time_code,
2375290001Sglebius	 unsigned char *aux_code
2376290001Sglebius	 )
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 */
2390290001Sglebiusshort
2391290001Sglebiusrpt_0x56(
2392290001Sglebius	 TSIPPKT *rpt,
2393290001Sglebius	 float vel_ENU[3],
2394290001Sglebius	 float *freq_offset,
2395290001Sglebius	 float *time_of_fix
2396290001Sglebius	 )
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 */
2414290001Sglebiusshort
2415290001Sglebiusrpt_0x57(
2416290001Sglebius	 TSIPPKT *rpt,
2417290001Sglebius	 unsigned char *source_code,
2418290001Sglebius	 unsigned char *diag_code,
2419290001Sglebius	 short *week_num,
2420290001Sglebius	 float *time_of_fix
2421290001Sglebius	 )
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 */
2435290001Sglebiusshort
2436290001Sglebiusrpt_0x58(
2437290001Sglebius	 TSIPPKT *rpt,
2438290001Sglebius	 unsigned char *op_code,
2439290001Sglebius	 unsigned char *data_type,
2440290001Sglebius	 unsigned char *sv_prn,
2441290001Sglebius	 unsigned char *data_length,
2442290001Sglebius	 unsigned char *data_packet
2443290001Sglebius	 )
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) {
2469290001Sglebius		    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
2494290001Sglebius		    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
2502290001Sglebius		    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
2516290001Sglebius		    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
2530290001Sglebius		    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 */
2582290001Sglebiusshort
2583290001Sglebiusrpt_0x59(
2584290001Sglebius	 TSIPPKT *rpt,
2585290001Sglebius	 unsigned char *code_type,
2586290001Sglebius	 unsigned char status_code[32]
2587290001Sglebius	 )
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 */
2601290001Sglebiusshort
2602290001Sglebiusrpt_0x5A(
2603290001Sglebius	 TSIPPKT *rpt,
2604290001Sglebius	 unsigned char *sv_prn,
2605290001Sglebius	 float *sample_length,
2606290001Sglebius	 float *signal_level,
2607290001Sglebius	 float *code_phase,
2608290001Sglebius	 float *Doppler,
2609290001Sglebius	 double *time_of_fix
2610290001Sglebius	 )
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 */
2626290001Sglebiusshort
2627290001Sglebiusrpt_0x5B(
2628290001Sglebius	 TSIPPKT *rpt,
2629290001Sglebius	 unsigned char *sv_prn,
2630290001Sglebius	 unsigned char *sv_health,
2631290001Sglebius	 unsigned char *sv_iode,
2632290001Sglebius	 unsigned char *fit_interval_flag,
2633290001Sglebius	 float *time_of_collection,
2634290001Sglebius	 float *time_of_eph,
2635290001Sglebius	 float *sv_accy
2636290001Sglebius	 )
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 */
2653290001Sglebiusshort
2654290001Sglebiusrpt_0x5C(
2655290001Sglebius	 TSIPPKT *rpt,
2656290001Sglebius	 unsigned char *sv_prn,
2657290001Sglebius	 unsigned char *slot,
2658290001Sglebius	 unsigned char *chan,
2659290001Sglebius	 unsigned char *acq_flag,
2660290001Sglebius	 unsigned char *eph_flag,
2661290001Sglebius	 float *signal_level,
2662290001Sglebius	 float *time_of_last_msmt,
2663290001Sglebius	 float *elev,
2664290001Sglebius	 float *azim,
2665290001Sglebius	 unsigned char *old_msmt_flag,
2666290001Sglebius	 unsigned char *integer_msec_flag,
2667290001Sglebius	 unsigned char *bad_data_flag,
2668290001Sglebius	 unsigned char *data_collect_flag
2669290001Sglebius	 )
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 */
2695290001Sglebiusshort
2696290001Sglebiusrpt_0x6D(
2697290001Sglebius	 TSIPPKT *rpt,
2698290001Sglebius	 unsigned char *manual_mode,
2699290001Sglebius	 unsigned char *nsvs,
2700290001Sglebius	 unsigned char *ndim,
2701290001Sglebius	 unsigned char sv_prn[],
2702290001Sglebius	 float *pdop,
2703290001Sglebius	 float *hdop,
2704290001Sglebius	 float *vdop,
2705290001Sglebius	 float *tdop
2706290001Sglebius	 )
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 */
2729290001Sglebiusshort
2730290001Sglebiusrpt_0x82(
2731290001Sglebius	 TSIPPKT *rpt,
2732290001Sglebius	 unsigned char *diff_mode
2733290001Sglebius	 )
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 */
2744290001Sglebiusshort
2745290001Sglebiusrpt_0x83(
2746290001Sglebius	 TSIPPKT *rpt,
2747290001Sglebius	 double ECEF_pos[3],
2748290001Sglebius	 double *clock_bias,
2749290001Sglebius	 float *time_of_fix
2750290001Sglebius	 )
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 */
2765290001Sglebiusshort
2766290001Sglebiusrpt_0x84(
2767290001Sglebius	 TSIPPKT *rpt,
2768290001Sglebius	 double *lat,
2769290001Sglebius	 double *lon,
2770290001Sglebius	 double *alt,
2771290001Sglebius	 double *clock_bias,
2772290001Sglebius	 float *time_of_fix
2773290001Sglebius	 )
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
2787290001Sglebiusshort
2788290001Sglebiusrpt_Paly0xBB(
2789290001Sglebius	     TSIPPKT *rpt,
2790290001Sglebius	     TSIP_RCVR_CFG *TsipxBB
2791290001Sglebius	     )
2792106424Sroberto{
2793106424Sroberto	unsigned char *buf;
2794106424Sroberto	buf = rpt->buf;
2795106424Sroberto
2796290001Sglebius	/* 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
2800290001Sglebius	TsipxBB->bSubcode	=  buf[0];
2801290001Sglebius	TsipxBB->operating_mode	=  buf[1];
2802290001Sglebius	TsipxBB->dyn_code	=  buf[3];
2803290001Sglebius	TsipxBB->elev_mask	=  bGetSingle (&buf[5]);
2804290001Sglebius	TsipxBB->cno_mask	=  bGetSingle (&buf[9]);
2805290001Sglebius	TsipxBB->dop_mask 	=  bGetSingle (&buf[13]);
2806106424Sroberto	TsipxBB->dop_switch 	=  bGetSingle (&buf[17]);
2807106424Sroberto	return FALSE;
2808106424Sroberto}
2809106424Sroberto
2810106424Sroberto/* Receiver serial port configuration */
2811290001Sglebiusshort
2812290001Sglebiusrpt_0xBC(
2813290001Sglebius	 TSIPPKT *rpt,
2814290001Sglebius	 unsigned char *port_num,
2815290001Sglebius	 unsigned char *in_baud,
2816290001Sglebius	 unsigned char *out_baud,
2817290001Sglebius	 unsigned char *data_bits,
2818290001Sglebius	 unsigned char *parity,
2819290001Sglebius	 unsigned char *stop_bits,
2820290001Sglebius	 unsigned char *flow_control,
2821290001Sglebius	 unsigned char *protocols_in,
2822290001Sglebius	 unsigned char *protocols_out,
2823290001Sglebius	 unsigned char *reserved
2824290001Sglebius	 )
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
2846290001Sglebiusshort
2847290001Sglebiusrpt_0x8F0B(
2848290001Sglebius	   TSIPPKT *rpt,
2849290001Sglebius	   unsigned short *event,
2850290001Sglebius	   double *tow,
2851290001Sglebius	   unsigned char *date,
2852290001Sglebius	   unsigned char *month,
2853290001Sglebius	   short *year,
2854290001Sglebius	   unsigned char *dim_mode,
2855290001Sglebius	   short *utc_offset,
2856290001Sglebius	   double *bias,
2857290001Sglebius	   double *drift,
2858290001Sglebius	   float *bias_unc,
2859290001Sglebius	   float *dr_unc,
2860290001Sglebius	   double *lat,
2861290001Sglebius	   double *lon,
2862290001Sglebius	   double *alt,
2863290001Sglebius	   char sv_id[8]
2864290001Sglebius	   )
2865106424Sroberto{
2866290001Sglebius	short local_index;
2867290001Sglebius	unsigned char *buf;
2868106424Sroberto
2869106424Sroberto	buf = rpt->buf;
2870290001Sglebius	if (rpt->len != 74) return TRUE;
2871290001Sglebius	*event = bGetShort(&buf[1]);
2872290001Sglebius	*tow = bGetDouble(&buf[3]);
2873290001Sglebius	*date = buf[11];
2874290001Sglebius	*month = buf[12];
2875290001Sglebius	*year = bGetShort(&buf[13]);
2876290001Sglebius	*dim_mode = buf[15];
2877290001Sglebius	*utc_offset = bGetShort(&buf[16]);
2878290001Sglebius	*bias = bGetDouble(&buf[18]);
2879290001Sglebius	*drift = bGetDouble(&buf[26]);
2880290001Sglebius	*bias_unc = bGetSingle(&buf[34]);
2881290001Sglebius	*dr_unc = bGetSingle(&buf[38]);
2882290001Sglebius	*lat = bGetDouble(&buf[42]);
2883290001Sglebius	*lon = bGetDouble(&buf[50]);
2884290001Sglebius	*alt = bGetDouble(&buf[58]);
2885106424Sroberto
2886290001Sglebius	for (local_index=0; local_index<8; local_index++) sv_id[local_index] = buf[local_index + 66];
2887290001Sglebius	return FALSE;
2888106424Sroberto}
2889106424Sroberto
2890290001Sglebius/* datum index and coefficients  */
2891290001Sglebiusshort
2892290001Sglebiusrpt_0x8F14(
2893290001Sglebius	   TSIPPKT *rpt,
2894290001Sglebius	   short *datum_idx,
2895290001Sglebius	   double datum_coeffs[5]
2896290001Sglebius	   )
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
2912290001Sglebius/* datum index and coefficients  */
2913290001Sglebiusshort
2914290001Sglebiusrpt_0x8F15(
2915290001Sglebius	   TSIPPKT *rpt,
2916290001Sglebius	   short *datum_idx,
2917290001Sglebius	   double datum_coeffs[5]
2918290001Sglebius	   )
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
2936290001Sglebiusshort
2937290001Sglebiusrpt_0x8F20(
2938290001Sglebius	   TSIPPKT *rpt,
2939290001Sglebius	   unsigned char *info,
2940290001Sglebius	   double *lat,
2941290001Sglebius	   double *lon,
2942290001Sglebius	   double *alt,
2943290001Sglebius	   double vel_enu[],
2944290001Sglebius	   double *time_of_fix,
2945290001Sglebius	   short *week_num,
2946290001Sglebius	   unsigned char *nsvs,
2947290001Sglebius	   unsigned char sv_prn[],
2948290001Sglebius	   short sv_IODC[],
2949290001Sglebius	   short *datum_index
2950290001Sglebius	   )
2951106424Sroberto{
2952106424Sroberto	short
2953290001Sglebius	    isv;
2954106424Sroberto	unsigned char
2955290001Sglebius	    *buf, prnx, iode;
2956106424Sroberto	unsigned long
2957290001Sglebius	    ulongtemp;
2958106424Sroberto	long
2959290001Sglebius	    longtemp;
2960106424Sroberto	double
2961290001Sglebius	    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);
2990290001Sglebius		iode = buf[33+2*isv];
2991106424Sroberto		sv_IODC[isv] = (short)(iode | ((prnx>>6)<<8));
2992106424Sroberto	}
2993106424Sroberto	return FALSE;
2994106424Sroberto}
2995106424Sroberto
2996290001Sglebiusshort
2997290001Sglebiusrpt_0x8F41(
2998290001Sglebius	   TSIPPKT *rpt,
2999290001Sglebius	   unsigned char *bSearchRange,
3000290001Sglebius	   unsigned char *bBoardOptions,
3001290001Sglebius	   unsigned long *iiSerialNumber,
3002290001Sglebius	   unsigned char *bBuildYear,
3003290001Sglebius	   unsigned char *bBuildMonth,
3004290001Sglebius	   unsigned char *bBuildDay,
3005290001Sglebius	   unsigned char *bBuildHour,
3006290001Sglebius	   float *fOscOffset,
3007290001Sglebius	   unsigned short *iTestCodeId
3008290001Sglebius	   )
3009106424Sroberto{
3010290001Sglebius	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
3024290001Sglebiusshort
3025290001Sglebiusrpt_0x8F42(
3026290001Sglebius	   TSIPPKT *rpt,
3027290001Sglebius	   unsigned char *bProdOptionsPre,
3028290001Sglebius	   unsigned char *bProdNumberExt,
3029290001Sglebius	   unsigned short *iCaseSerialNumberPre,
3030290001Sglebius	   unsigned long *iiCaseSerialNumber,
3031290001Sglebius	   unsigned long *iiProdNumber,
3032290001Sglebius	   unsigned short *iPremiumOptions,
3033290001Sglebius	   unsigned short *iMachineID,
3034290001Sglebius	   unsigned short *iKey
3035290001Sglebius	   )
3036106424Sroberto{
3037290001Sglebius	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
3049290001Sglebiusshort
3050290001Sglebiusrpt_0x8F45(
3051290001Sglebius	   TSIPPKT *rpt,
3052290001Sglebius	   unsigned char *bSegMask
3053290001Sglebius	   )
3054106424Sroberto{
3055290001Sglebius	if (rpt->len != 2) return FALSE;
3056106424Sroberto	*bSegMask = rpt->buf[1];
3057106424Sroberto	return TRUE;
3058106424Sroberto}
3059106424Sroberto
3060106424Sroberto/* Stinger PPS definition */
3061290001Sglebiusshort
3062290001Sglebiusrpt_0x8F4A_16(
3063290001Sglebius	      TSIPPKT *rpt,
3064290001Sglebius	      unsigned char *pps_enabled,
3065290001Sglebius	      unsigned char *pps_timebase,
3066290001Sglebius	      unsigned char *pos_polarity,
3067290001Sglebius	      double *pps_offset,
3068290001Sglebius	      float *bias_unc_threshold
3069290001Sglebius	      )
3070106424Sroberto{
3071106424Sroberto	unsigned char
3072290001Sglebius	    *buf;
3073106424Sroberto
3074290001Sglebius	buf = rpt->buf;
3075290001Sglebius	if (rpt->len != 16) return TRUE;
3076290001Sglebius	*pps_enabled = buf[1];
3077290001Sglebius	*pps_timebase = buf[2];
3078290001Sglebius	*pos_polarity = buf[3];
3079290001Sglebius	*pps_offset = bGetDouble(&buf[4]);
3080290001Sglebius	*bias_unc_threshold = bGetSingle(&buf[12]);
3081106424Sroberto	return FALSE;
3082106424Sroberto}
3083106424Sroberto
3084290001Sglebiusshort
3085290001Sglebiusrpt_0x8F4B(
3086290001Sglebius	   TSIPPKT *rpt,
3087290001Sglebius	   unsigned long *decorr_max
3088290001Sglebius	   )
3089106424Sroberto{
3090106424Sroberto	unsigned char
3091290001Sglebius	    *buf;
3092106424Sroberto
3093290001Sglebius	buf = rpt->buf;
3094290001Sglebius	if (rpt->len != 5) return TRUE;
3095290001Sglebius	*decorr_max = bGetLong(&buf[1]);
3096290001Sglebius	return FALSE;
3097106424Sroberto}
3098106424Sroberto
3099290001Sglebiusshort
3100290001Sglebiusrpt_0x8F4D(
3101290001Sglebius	   TSIPPKT *rpt,
3102290001Sglebius	   unsigned long *event_mask
3103290001Sglebius	   )
3104106424Sroberto{
3105106424Sroberto	unsigned char
3106290001Sglebius	    *buf;
3107106424Sroberto
3108290001Sglebius	buf = rpt->buf;
3109290001Sglebius	if (rpt->len != 5) return TRUE;
3110290001Sglebius	*event_mask = bGetULong (&buf[1]);
3111290001Sglebius	return FALSE;
3112106424Sroberto}
3113106424Sroberto
3114290001Sglebiusshort
3115290001Sglebiusrpt_0x8FA5(
3116290001Sglebius	   TSIPPKT *rpt,
3117290001Sglebius	   unsigned char *spktmask
3118290001Sglebius	   )
3119106424Sroberto{
3120106424Sroberto	unsigned char
3121290001Sglebius	    *buf;
3122106424Sroberto
3123290001Sglebius	buf = rpt->buf;
3124290001Sglebius	if (rpt->len != 5) return TRUE;
3125290001Sglebius	spktmask[0] = buf[1];
3126290001Sglebius	spktmask[1] = buf[2];
3127290001Sglebius	spktmask[2] = buf[3];
3128290001Sglebius	spktmask[3] = buf[4];
3129290001Sglebius	return FALSE;
3130106424Sroberto}
3131106424Sroberto
3132290001Sglebiusshort
3133290001Sglebiusrpt_0x8FAD(
3134290001Sglebius	   TSIPPKT *rpt,
3135290001Sglebius	   unsigned short *COUNT,
3136290001Sglebius	   double *FracSec,
3137290001Sglebius	   unsigned char *Hour,
3138290001Sglebius	   unsigned char *Minute,
3139290001Sglebius	   unsigned char *Second,
3140290001Sglebius	   unsigned char *Day,
3141290001Sglebius	   unsigned char *Month,
3142290001Sglebius	   unsigned short *Year,
3143290001Sglebius	   unsigned char *Status,
3144290001Sglebius	   unsigned char *Flags
3145290001Sglebius	   )
3146106424Sroberto{
3147106424Sroberto	if (rpt->len != 22) return TRUE;
3148106424Sroberto
3149290001Sglebius	*COUNT = bGetUShort(&rpt->buf[1]);
3150290001Sglebius	*FracSec = bGetDouble(&rpt->buf[3]);
3151290001Sglebius	*Hour = rpt->buf[11];
3152290001Sglebius	*Minute = rpt->buf[12];
3153290001Sglebius	*Second = rpt->buf[13];
3154290001Sglebius	*Day = rpt->buf[14];
3155290001Sglebius	*Month = rpt->buf[15];
3156290001Sglebius	*Year = bGetUShort(&rpt->buf[16]);
3157290001Sglebius	*Status = rpt->buf[18];
3158290001Sglebius	*Flags = rpt->buf[19];
3159290001Sglebius	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
3215290001Sglebius*pbuf;
3216106424Sroberto
3217106424Sroberto/* keep track of whether the message has been successfully parsed */
3218106424Srobertostatic short
3219290001Sglebiusparsed;
3220106424Sroberto
3221106424Sroberto
3222106424Sroberto/* convert time of week into day-hour-minute-second and print */
3223290001Sglebiuschar *
3224290001Sglebiusshow_time(
3225290001Sglebius	  float time_of_week
3226290001Sglebius	  )
3227106424Sroberto{
3228106424Sroberto	short	days, hours, minutes;
3229106424Sroberto	float seconds;
3230106424Sroberto	double tow = 0;
3231290001Sglebius	static char timestring [80];
3232106424Sroberto
3233106424Sroberto	if (time_of_week == -1.0)
3234290001Sglebius	{
3235106424Sroberto		sprintf(timestring, "   <No time yet>   ");
3236106424Sroberto	}
3237106424Sroberto	else if ((time_of_week >= 604800.0) || (time_of_week < 0.0))
3238290001Sglebius	{
3239106424Sroberto		sprintf(timestring, "     <Bad time>     ");
3240106424Sroberto	}
3241290001Sglebius	else
3242290001Sglebius	{
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   ",
3250290001Sglebius			dayname[days], hours, minutes, seconds);
3251290001Sglebius	}
3252290001Sglebius	return timestring;
3253106424Sroberto}
3254106424Sroberto
3255106424Sroberto/**/
3256106424Sroberto/* 0x3D */
3257290001Sglebiusstatic void
3258290001Sglebiusrpt_chan_A_config(
3259290001Sglebius		  TSIPPKT *rpt
3260290001Sglebius		  )
3261106424Sroberto{
3262106424Sroberto	unsigned char
3263290001Sglebius	    tx_baud_index, rx_baud_index,
3264290001Sglebius	    char_format_index, stop_bits,
3265290001Sglebius	    tx_mode_index, rx_mode_index,
3266290001Sglebius	    databits, parity;
3267106424Sroberto	int
3268290001Sglebius	    i, nbaud;
3269106424Sroberto
3270106424Sroberto	/* unload rptbuf */
3271106424Sroberto	if (rpt_0x3D (rpt,
3272290001Sglebius		      &tx_baud_index, &rx_baud_index, &char_format_index,
3273290001Sglebius		      &stop_bits, &tx_mode_index, &rx_mode_index)) {
3274106424Sroberto		parsed = BADLEN_PARSE;
3275106424Sroberto		return;
3276106424Sroberto	}
3277106424Sroberto
3278106424Sroberto	pbuf += sprintf(pbuf, "\nChannel A Configuration");
3279106424Sroberto
3280290001Sglebius	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",
3284290001Sglebius			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",
3288290001Sglebius			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",
3296290001Sglebius			databits, old_parity_text[parity], stop_bits);
3297106424Sroberto}
3298106424Sroberto
3299106424Sroberto/**/
3300106424Sroberto/* 0x40 */
3301290001Sglebiusstatic void
3302290001Sglebiusrpt_almanac_data_page(
3303290001Sglebius		      TSIPPKT *rpt
3304290001Sglebius		      )
3305106424Sroberto{
3306106424Sroberto	unsigned char
3307290001Sglebius	    sv_prn;
3308106424Sroberto	short
3309290001Sglebius	    week_num;
3310106424Sroberto	float
3311290001Sglebius	    t_zc,
3312290001Sglebius	    eccentricity,
3313290001Sglebius	    t_oa,
3314290001Sglebius	    i_0,
3315290001Sglebius	    OMEGA_dot,
3316290001Sglebius	    sqrt_A,
3317290001Sglebius	    OMEGA_0,
3318290001Sglebius	    omega,
3319290001Sglebius	    M_0;
3320106424Sroberto
3321106424Sroberto	/* unload rptbuf */
3322106424Sroberto	if (rpt_0x40 (rpt,
3323290001Sglebius		      &sv_prn, &week_num, &t_zc, &eccentricity, &t_oa,
3324290001Sglebius		      &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",
3331290001Sglebius			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",
3335290001Sglebius			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 */
3345290001Sglebiusstatic void
3346290001Sglebiusrpt_GPS_time(
3347290001Sglebius	     TSIPPKT *rpt
3348290001Sglebius	     )
3349106424Sroberto{
3350106424Sroberto	float
3351290001Sglebius	    time_of_week, UTC_offset;
3352106424Sroberto	short
3353290001Sglebius	    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",
3362290001Sglebius			show_time(time_of_week), week_num, UTC_offset);
3363106424Sroberto
3364106424Sroberto}
3365106424Sroberto
3366106424Sroberto/* 0x42 */
3367290001Sglebiusstatic void
3368290001Sglebiusrpt_single_ECEF_position(
3369290001Sglebius			 TSIPPKT *rpt
3370290001Sglebius			 )
3371106424Sroberto{
3372106424Sroberto	float
3373290001Sglebius	    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",
3382290001Sglebius			ECEF_pos[0], ECEF_pos[1], ECEF_pos[2],
3383290001Sglebius			show_time(time_of_fix));
3384106424Sroberto}
3385106424Sroberto
3386106424Sroberto/* 0x43 */
3387290001Sglebiusstatic void
3388290001Sglebiusrpt_single_ECEF_velocity(
3389290001Sglebius			 TSIPPKT *rpt
3390290001Sglebius			 )
3391106424Sroberto{
3392106424Sroberto
3393106424Sroberto	float
3394290001Sglebius	    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",
3403290001Sglebius			ECEF_vel[0], ECEF_vel[1], ECEF_vel[2], freq_offset,
3404290001Sglebius			show_time(time_of_fix));
3405106424Sroberto}
3406106424Sroberto
3407106424Sroberto/*  0x45  */
3408290001Sglebiusstatic void
3409290001Sglebiusrpt_SW_version(
3410290001Sglebius	       TSIPPKT *rpt
3411290001Sglebius	       )
3412290001Sglebius{
3413106424Sroberto	unsigned char
3414290001Sglebius	    major_nav_version, minor_nav_version,
3415290001Sglebius	    nav_day, nav_month, nav_year,
3416290001Sglebius	    major_dsp_version, minor_dsp_version,
3417290001Sglebius	    dsp_day, dsp_month, dsp_year;
3418106424Sroberto
3419106424Sroberto	/* unload rptbuf */
3420106424Sroberto	if (rpt_0x45 (rpt,
3421290001Sglebius		      &major_nav_version, &minor_nav_version,
3422290001Sglebius		      &nav_day, &nav_month, &nav_year,
3423290001Sglebius		      &major_dsp_version, &minor_dsp_version,
3424290001Sglebius		      &dsp_day, &dsp_month, &dsp_year)) {
3425106424Sroberto		parsed = BADLEN_PARSE;
3426106424Sroberto		return;
3427106424Sroberto	}
3428106424Sroberto
3429106424Sroberto	pbuf += sprintf(pbuf,
3430290001Sglebius			"\nFW Versions:  Nav Proc %2d.%02d  %2d/%2d/%2d  Sig Proc %2d.%02d  %2d/%2d/%2d",
3431290001Sglebius			major_nav_version, minor_nav_version, nav_day, nav_month, nav_year,
3432290001Sglebius			major_dsp_version, minor_dsp_version, dsp_day, dsp_month, dsp_year);
3433106424Sroberto}
3434106424Sroberto
3435106424Sroberto/* 0x46 */
3436290001Sglebiusstatic void
3437290001Sglebiusrpt_rcvr_health(
3438290001Sglebius		TSIPPKT *rpt
3439290001Sglebius		)
3440106424Sroberto{
3441106424Sroberto	unsigned char
3442290001Sglebius	    status1, status2;
3443290001Sglebius	const char
3444290001Sglebius	    *text;
3445290001Sglebius	static const char const
3446290001Sglebius	    *sc_text[] = {
3447290001Sglebius		"Doing position fixes",
3448290001Sglebius		"Don't have GPS time yet",
3449290001Sglebius		"Waiting for almanac collection",
3450290001Sglebius		"DOP too high          ",
3451290001Sglebius		"No satellites available",
3452290001Sglebius		"Only 1 satellite available",
3453290001Sglebius		"Only 2 satellites available",
3454290001Sglebius		"Only 3 satellites available",
3455290001Sglebius		"No satellites usable   ",
3456290001Sglebius		"Only 1 satellite usable",
3457290001Sglebius		"Only 2 satellites usable",
3458290001Sglebius		"Only 3 satellites usable",
3459290001Sglebius		"Chosen satellite unusable"};
3460106424Sroberto
3461106424Sroberto
3462106424Sroberto	/* unload rptbuf */
3463106424Sroberto	if (rpt_0x46 (rpt, &status1, &status2))
3464106424Sroberto	{
3465106424Sroberto		parsed = BADLEN_PARSE;
3466106424Sroberto		return;
3467106424Sroberto	}
3468106424Sroberto
3469290001Sglebius	text = (status1 < COUNTOF(sc_text))
3470290001Sglebius	    ? sc_text[status1]
3471290001Sglebius	    : "(out of range)";
3472106424Sroberto	pbuf += sprintf(pbuf, "\nRcvr status1: %s (%02Xh); ",
3473290001Sglebius			text, status1);
3474106424Sroberto
3475106424Sroberto	pbuf += sprintf(pbuf, "status2: %s, %s (%02Xh)",
3476290001Sglebius			(status2 & 0x01)?"No BBRAM":"BBRAM OK",
3477290001Sglebius			(status2 & 0x10)?"No Ant":"Ant OK",
3478290001Sglebius			status2);
3479106424Sroberto}
3480106424Sroberto
3481106424Sroberto/* 0x47 */
3482290001Sglebiusstatic void
3483290001Sglebiusrpt_SNR_all_SVs(
3484290001Sglebius		TSIPPKT *rpt
3485290001Sglebius		)
3486106424Sroberto{
3487106424Sroberto	unsigned char
3488290001Sglebius	    nsvs, sv_prn[12];
3489106424Sroberto	short
3490290001Sglebius	    isv;
3491106424Sroberto	float
3492290001Sglebius	    snr[12];
3493106424Sroberto
3494106424Sroberto	/* unload rptbuf */
3495106424Sroberto	if (rpt_0x47 (rpt, &nsvs, sv_prn, snr))
3496290001Sglebius	{
3497106424Sroberto		parsed = BADLEN_PARSE;
3498106424Sroberto		return;
3499106424Sroberto	}
3500106424Sroberto
3501106424Sroberto	pbuf += sprintf(pbuf, "\nSNR for satellites: %d", nsvs);
3502106424Sroberto	for (isv = 0; isv < nsvs; isv++)
3503290001Sglebius	{
3504106424Sroberto		pbuf += sprintf(pbuf, "\n    SV %02d   %6.2f",
3505290001Sglebius				sv_prn[isv], snr[isv]);
3506106424Sroberto	}
3507106424Sroberto}
3508106424Sroberto
3509106424Sroberto/* 0x48 */
3510290001Sglebiusstatic void
3511290001Sglebiusrpt_GPS_system_message(
3512290001Sglebius		       TSIPPKT *rpt
3513290001Sglebius		       )
3514106424Sroberto{
3515106424Sroberto	unsigned char
3516290001Sglebius	    message[23];
3517106424Sroberto
3518106424Sroberto	/* unload rptbuf */
3519106424Sroberto	if (rpt_0x48 (rpt, message))
3520290001Sglebius	{
3521106424Sroberto		parsed = BADLEN_PARSE;
3522106424Sroberto		return;
3523106424Sroberto	}
3524106424Sroberto
3525106424Sroberto	pbuf += sprintf(pbuf, "\nGPS message: %s", message);
3526106424Sroberto}
3527106424Sroberto
3528106424Sroberto/* 0x49 */
3529290001Sglebiusstatic void
3530290001Sglebiusrpt_almanac_health_page(
3531290001Sglebius			TSIPPKT *rpt
3532290001Sglebius			)
3533106424Sroberto{
3534106424Sroberto	short
3535290001Sglebius	    iprn;
3536106424Sroberto	unsigned char
3537290001Sglebius	    sv_health [32];
3538106424Sroberto
3539106424Sroberto	/* unload rptbuf */
3540106424Sroberto	if (rpt_0x49 (rpt, sv_health))
3541290001Sglebius	{
3542106424Sroberto		parsed = BADLEN_PARSE;
3543106424Sroberto		return;
3544106424Sroberto	}
3545106424Sroberto
3546106424Sroberto	pbuf += sprintf(pbuf, "\nAlmanac health page:");
3547106424Sroberto	for (iprn = 0; iprn < 32; iprn++)
3548290001Sglebius	{
3549106424Sroberto		if (!(iprn%5)) *pbuf++ = '\n';
3550106424Sroberto		pbuf += sprintf(pbuf, "    SV%02d  %2X",
3551290001Sglebius				(iprn+1) , sv_health[iprn]);
3552106424Sroberto	}
3553106424Sroberto}
3554106424Sroberto
3555106424Sroberto/* 0x4A */
3556290001Sglebiusstatic void
3557290001Sglebiusrpt_single_lla_position(
3558290001Sglebius			TSIPPKT *rpt
3559290001Sglebius			)
3560290001Sglebius{
3561106424Sroberto	short
3562290001Sglebius	    lat_deg, lon_deg;
3563106424Sroberto	float
3564290001Sglebius	    lat, lon,
3565290001Sglebius	    alt, clock_bias, time_of_fix;
3566106424Sroberto	double lat_min, lon_min;
3567106424Sroberto	unsigned char
3568290001Sglebius	    north_south, east_west;
3569106424Sroberto
3570106424Sroberto	if (rpt_0x4A (rpt,
3571290001Sglebius		      &lat, &lon, &alt, &clock_bias, &time_of_fix))
3572290001Sglebius	{
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)
3581290001Sglebius	{
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)
3591290001Sglebius	{
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",
3599290001Sglebius			lat_deg, lat_min, north_south,
3600290001Sglebius			lon_deg, lon_min, east_west,
3601290001Sglebius			alt, clock_bias,
3602290001Sglebius			show_time(time_of_fix));
3603106424Sroberto}
3604106424Sroberto
3605106424Sroberto/* 0x4A */
3606290001Sglebiusstatic void
3607290001Sglebiusrpt_ref_alt(
3608290001Sglebius	    TSIPPKT *rpt
3609290001Sglebius	    )
3610290001Sglebius{
3611106424Sroberto	float
3612290001Sglebius	    alt, dummy;
3613106424Sroberto	unsigned char
3614290001Sglebius	    alt_flag;
3615106424Sroberto
3616290001Sglebius	if (rpt_0x4A_2 (rpt, &alt, &dummy, &alt_flag))
3617290001Sglebius	{
3618106424Sroberto		parsed = BADLEN_PARSE;
3619106424Sroberto		return;
3620106424Sroberto	}
3621106424Sroberto
3622106424Sroberto	pbuf += sprintf(pbuf, "\nReference Alt:   %.1f m;    %s",
3623290001Sglebius			alt, alt_flag?"ON":"OFF");
3624106424Sroberto}
3625106424Sroberto
3626106424Sroberto/* 0x4B */
3627290001Sglebiusstatic void
3628290001Sglebiusrpt_rcvr_id_and_status(
3629290001Sglebius		       TSIPPKT *rpt
3630290001Sglebius		       )
3631106424Sroberto{
3632106424Sroberto
3633106424Sroberto	unsigned char
3634290001Sglebius	    machine_id, status3, status4;
3635106424Sroberto
3636106424Sroberto	/* unload rptbuf */
3637106424Sroberto	if (rpt_0x4B (rpt, &machine_id, &status3, &status4))
3638290001Sglebius	{
3639106424Sroberto		parsed = BADLEN_PARSE;
3640106424Sroberto		return;
3641106424Sroberto	}
3642106424Sroberto
3643106424Sroberto	pbuf += sprintf(pbuf, "\nRcvr Machine ID: %d; Status3 = %s, %s (%02Xh)",
3644290001Sglebius			machine_id,
3645290001Sglebius			(status3 & 0x02)?"No RTC":"RTC OK",
3646290001Sglebius			(status3 & 0x08)?"No Alm":"Alm OK",
3647290001Sglebius			status3);
3648106424Sroberto}
3649106424Sroberto
3650106424Sroberto/* 0x4C */
3651290001Sglebiusstatic void
3652290001Sglebiusrpt_operating_parameters(
3653290001Sglebius			 TSIPPKT *rpt
3654290001Sglebius			 )
3655106424Sroberto{
3656106424Sroberto	unsigned char
3657290001Sglebius	    dyn_code;
3658106424Sroberto	float
3659290001Sglebius	    el_mask, snr_mask, dop_mask, dop_switch;
3660106424Sroberto
3661106424Sroberto	/* unload rptbuf */
3662106424Sroberto	if (rpt_0x4C (rpt, &dyn_code, &el_mask,
3663290001Sglebius		      &snr_mask, &dop_mask, &dop_switch))
3664290001Sglebius	{
3665106424Sroberto		parsed = BADLEN_PARSE;
3666106424Sroberto		return;
3667106424Sroberto	}
3668106424Sroberto
3669106424Sroberto	pbuf += sprintf(pbuf, "\nOperating Parameters:");
3670106424Sroberto	pbuf += sprintf(pbuf, "\n     Dynamics code = %d %s",
3671290001Sglebius			dyn_code, dyn_text[dyn_code]);
3672290001Sglebius	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 */
3679290001Sglebiusstatic void
3680290001Sglebiusrpt_oscillator_offset(
3681290001Sglebius		      TSIPPKT *rpt
3682290001Sglebius		      )
3683106424Sroberto{
3684106424Sroberto	float
3685290001Sglebius	    osc_offset;
3686106424Sroberto
3687106424Sroberto	/* unload rptbuf */
3688106424Sroberto	if (rpt_0x4D (rpt, &osc_offset))
3689290001Sglebius	{
3690106424Sroberto		parsed = BADLEN_PARSE;
3691106424Sroberto		return;
3692106424Sroberto	}
3693106424Sroberto
3694106424Sroberto	pbuf += sprintf(pbuf, "\nOscillator offset: %.2f Hz = %.3f PPM",
3695290001Sglebius			osc_offset, osc_offset/1575.42);
3696106424Sroberto}
3697106424Sroberto
3698106424Sroberto/* 0x4E */
3699290001Sglebiusstatic void
3700290001Sglebiusrpt_GPS_time_set_response(
3701290001Sglebius			  TSIPPKT *rpt
3702290001Sglebius			  )
3703106424Sroberto{
3704106424Sroberto	unsigned char
3705290001Sglebius	    response;
3706106424Sroberto
3707106424Sroberto	/* unload rptbuf */
3708106424Sroberto	if (rpt_0x4E (rpt, &response))
3709290001Sglebius	{
3710106424Sroberto		parsed = BADLEN_PARSE;
3711106424Sroberto		return;
3712106424Sroberto	}
3713106424Sroberto
3714106424Sroberto	switch (response)
3715290001Sglebius	{
3716290001Sglebius	    case 'Y':
3717106424Sroberto		pbuf += sprintf(pbuf, "\nTime set accepted");
3718106424Sroberto		break;
3719106424Sroberto
3720290001Sglebius	    case 'N':
3721106424Sroberto		pbuf += sprintf(pbuf, "\nTime set rejected or not required");
3722106424Sroberto		break;
3723106424Sroberto
3724290001Sglebius	    default:
3725106424Sroberto		parsed = BADDATA_PARSE;
3726106424Sroberto	}
3727106424Sroberto}
3728106424Sroberto
3729106424Sroberto/* 0x4F */
3730290001Sglebiusstatic void
3731290001Sglebiusrpt_UTC_offset(
3732290001Sglebius	       TSIPPKT *rpt
3733290001Sglebius	       )
3734106424Sroberto{
3735106424Sroberto	double
3736290001Sglebius	    a0;
3737106424Sroberto	float
3738290001Sglebius	    a1, time_of_data;
3739106424Sroberto	short
3740290001Sglebius	    dt_ls, wn_t, wn_lsf, dn, dt_lsf;
3741106424Sroberto
3742106424Sroberto	/* unload rptbuf */
3743106424Sroberto	if (rpt_0x4F (rpt, &a0, &a1, &time_of_data,
3744290001Sglebius		      &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 */
3762290001Sglebiusstatic void
3763290001Sglebiusrpt_1SV_bias(
3764290001Sglebius	     TSIPPKT *rpt
3765290001Sglebius	     )
3766106424Sroberto{
3767106424Sroberto	float
3768290001Sglebius	    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",
3777290001Sglebius			 clock_bias, freq_offset, show_time (time_of_fix));
3778106424Sroberto}
3779106424Sroberto
3780106424Sroberto/* 0x55 */
3781290001Sglebiusstatic void
3782290001Sglebiusrpt_io_opt(
3783290001Sglebius	   TSIPPKT *rpt
3784290001Sglebius	   )
3785106424Sroberto{
3786106424Sroberto	unsigned char
3787290001Sglebius	    pos_code, vel_code, time_code, aux_code;
3788106424Sroberto
3789106424Sroberto	/* unload rptbuf */
3790106424Sroberto	if (rpt_0x55 (rpt,
3791290001Sglebius		      &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",
3798290001Sglebius			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)?
3809290001Sglebius			"\n    MSL altitude output (Geoid height) ":
3810290001Sglebius			"\n    WGS-84 altitude output");
3811106424Sroberto
3812106424Sroberto	pbuf += sprintf(pbuf, (pos_code & 0x08)?
3813290001Sglebius			"\n    MSL altitude input":
3814290001Sglebius			"\n    WGS-84 altitude input");
3815106424Sroberto
3816106424Sroberto	pbuf += sprintf(pbuf, (pos_code & 0x10)?
3817290001Sglebius			"\n    Double precision":
3818290001Sglebius			"\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)?
3833290001Sglebius			"\n    Time tags in UTC":
3834290001Sglebius			"\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
3852290001Sglebius	pbuf += sprintf(pbuf, (time_code & 0x20) ?
3853290001Sglebius			"\n    PPS output at all times" :
3854290001Sglebius			"\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)?
3869290001Sglebius			"\n    Signal Strength Output as dBHz" :
3870290001Sglebius			"\n    Signal Strength Output as AMU");
3871106424Sroberto}
3872106424Sroberto
3873106424Sroberto/* 0x56 */
3874290001Sglebiusstatic void
3875290001Sglebiusrpt_ENU_velocity(
3876290001Sglebius		 TSIPPKT *rpt
3877290001Sglebius		 )
3878106424Sroberto{
3879106424Sroberto	float
3880290001Sglebius	    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",
3889290001Sglebius			vel_ENU[0], vel_ENU[1], vel_ENU[2], freq_offset,
3890290001Sglebius			show_time (time_of_fix));
3891106424Sroberto}
3892106424Sroberto
3893106424Sroberto/* 0x57 */
3894290001Sglebiusstatic void
3895290001Sglebiusrpt_last_fix_info(
3896290001Sglebius		  TSIPPKT *rpt
3897290001Sglebius		  )
3898106424Sroberto{
3899106424Sroberto	unsigned char
3900290001Sglebius	    source_code, diag_code;
3901106424Sroberto	short
3902290001Sglebius	    week_num;
3903106424Sroberto	float
3904290001Sglebius	    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",
3913290001Sglebius			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 */
3919290001Sglebiusstatic void
3920290001Sglebiusrpt_GPS_system_data(
3921290001Sglebius		    TSIPPKT *rpt
3922290001Sglebius		    )
3923106424Sroberto{
3924106424Sroberto	unsigned char
3925290001Sglebius	    iprn,
3926290001Sglebius	    op_code, data_type, sv_prn,
3927290001Sglebius	    data_length, data_packet[250];
3928106424Sroberto	ALM_INFO
3929290001Sglebius	    *almanac;
3930106424Sroberto	ALH_PARMS
3931290001Sglebius	    *almh;
3932106424Sroberto	UTC_INFO
3933290001Sglebius	    *utc;
3934106424Sroberto	ION_INFO
3935290001Sglebius	    *ionosphere;
3936106424Sroberto	EPHEM_CLOCK
3937290001Sglebius	    *cdata;
3938106424Sroberto	EPHEM_ORBIT
3939290001Sglebius	    *edata;
3940106424Sroberto	NAV_INFO
3941290001Sglebius	    *nav_data;
3942106424Sroberto	unsigned char
3943290001Sglebius	    curr_t_oa;
3944106424Sroberto	unsigned short
3945290001Sglebius	    curr_wn_oa;
3946106424Sroberto	static char
3947290001Sglebius	    *datname[] =
3948290001Sglebius	    {"", "", "Almanac Orbit",
3949290001Sglebius	     "Health Page & Ref Time", "Ionosphere", "UTC ",
3950290001Sglebius	     "Ephemeris"};
3951106424Sroberto
3952106424Sroberto	/* unload rptbuf */
3953106424Sroberto	if (rpt_0x58 (rpt, &op_code, &data_type, &sv_prn,
3954290001Sglebius		      &data_length, data_packet))
3955290001Sglebius	{
3956106424Sroberto		parsed = BADLEN_PARSE;
3957106424Sroberto		return;
3958106424Sroberto	}
3959106424Sroberto
3960106424Sroberto	pbuf += sprintf(pbuf, "\nSystem data [%d]:  %s  SV%02d",
3961290001Sglebius			data_type, datname[data_type], sv_prn);
3962106424Sroberto	switch (op_code)
3963106424Sroberto	{
3964290001Sglebius	    case 1:
3965106424Sroberto		pbuf += sprintf(pbuf, "  Acknowledgment");
3966106424Sroberto		break;
3967290001Sglebius	    case 2:
3968106424Sroberto		pbuf += sprintf(pbuf, "  length = %d bytes", data_length);
3969106424Sroberto		switch (data_type) {
3970290001Sglebius		    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  ",
3978290001Sglebius					almanac->t_oa_raw , almanac->SV_health );
3979106424Sroberto			pbuf += sprintf(pbuf, "\n   e        = % -12g    t_oa     = % -12g  ",
3980290001Sglebius					almanac->e        , almanac->t_oa     );
3981106424Sroberto			pbuf += sprintf(pbuf, "\n   i_0      = % -12g    OMEGADOT = % -12g  ",
3982290001Sglebius					almanac->i_0      , almanac->OMEGADOT );
3983106424Sroberto			pbuf += sprintf(pbuf, "\n   sqrt_A   = % -12g    OMEGA_0  = % -12g  ",
3984290001Sglebius					almanac->sqrt_A   , almanac->OMEGA_0  );
3985106424Sroberto			pbuf += sprintf(pbuf, "\n   omega    = % -12g    M_0      = % -12g  ",
3986290001Sglebius					almanac->omega    , almanac->M_0      );
3987106424Sroberto			pbuf += sprintf(pbuf, "\n   a_f0     = % -12g    a_f1     = % -12g  ",
3988290001Sglebius					almanac->a_f0     , almanac->a_f1     );
3989106424Sroberto			pbuf += sprintf(pbuf, "\n   Axis     = % -12g    n        = % -12g  ",
3990290001Sglebius					almanac->Axis     , almanac->n        );
3991106424Sroberto			pbuf += sprintf(pbuf, "\n   OMEGA_n  = % -12g    ODOT_n   = % -12g  ",
3992290001Sglebius					almanac->OMEGA_n  , almanac->ODOT_n   );
3993106424Sroberto			pbuf += sprintf(pbuf, "\n   t_zc     = % -12g    weeknum  = % -12d  ",
3994290001Sglebius					almanac->t_zc     , almanac->weeknum  );
3995106424Sroberto			pbuf += sprintf(pbuf, "\n   wn_oa    = % -12d", almanac->wn_oa    );
3996106424Sroberto			break;
3997106424Sroberto
3998290001Sglebius		    case 3:
3999106424Sroberto			/* Almanac health page */
4000106424Sroberto			almh = (ALH_PARMS*)data_packet;
4001106424Sroberto			pbuf += sprintf(pbuf, "\n   t_oa = %d, wn_oa&0xFF = %d  ",
4002290001Sglebius					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",
4007290001Sglebius						(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  ",
4012290001Sglebius					curr_t_oa, curr_wn_oa);
4013106424Sroberto			break;
4014106424Sroberto
4015290001Sglebius		    case 4:
4016106424Sroberto			/* Ionosphere */
4017106424Sroberto			ionosphere = (ION_INFO*)data_packet;
4018106424Sroberto			pbuf += sprintf(pbuf, "\n   alpha_0 = % -12g  alpha_1 = % -12g ",
4019290001Sglebius					ionosphere->alpha_0, ionosphere->alpha_1);
4020106424Sroberto			pbuf += sprintf(pbuf, "\n   alpha_2 = % -12g  alpha_3 = % -12g ",
4021290001Sglebius					ionosphere->alpha_2, ionosphere->alpha_3);
4022106424Sroberto			pbuf += sprintf(pbuf, "\n   beta_0  = % -12g  beta_1  = % -12g  ",
4023290001Sglebius					ionosphere->beta_0, ionosphere->beta_1);
4024106424Sroberto			pbuf += sprintf(pbuf, "\n   beta_2  = % -12g  beta_3  = % -12g  ",
4025290001Sglebius					ionosphere->beta_2, ionosphere->beta_3);
4026106424Sroberto			break;
4027106424Sroberto
4028290001Sglebius		    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
4041290001Sglebius		    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 . ",
4049290001Sglebius					nav_data->sv_number , nav_data->t_ephem );
4050106424Sroberto			cdata = &(nav_data->ephclk);
4051106424Sroberto			pbuf += sprintf(pbuf,
4052290001Sglebius					"\n    weeknum = % -12d .   codeL2 = % -12d .  L2Pdata = % -12d",
4053290001Sglebius					cdata->weeknum , cdata->codeL2 , cdata->L2Pdata );
4054106424Sroberto			pbuf += sprintf(pbuf,
4055290001Sglebius					"\n  SVacc_raw = % -12d .SV_health = % -12d .     IODC = % -12d",
4056290001Sglebius					cdata->SVacc_raw, cdata->SV_health, cdata->IODC );
4057106424Sroberto			pbuf += sprintf(pbuf,
4058290001Sglebius					"\n       T_GD = % -12g .     t_oc = % -12g .     a_f2 = % -12g",
4059290001Sglebius					cdata->T_GD, cdata->t_oc, cdata->a_f2 );
4060106424Sroberto			pbuf += sprintf(pbuf,
4061290001Sglebius					"\n       a_f1 = % -12g .     a_f0 = % -12g .    SVacc = % -12g",
4062290001Sglebius					cdata->a_f1, cdata->a_f0, cdata->SVacc );
4063106424Sroberto			edata = &(nav_data->ephorb);
4064106424Sroberto			pbuf += sprintf(pbuf,
4065290001Sglebius					"\n       IODE = % -12d .fit_intvl = % -12d .     C_rs = % -12g",
4066290001Sglebius					edata->IODE, edata->fit_interval, edata->C_rs );
4067106424Sroberto			pbuf += sprintf(pbuf,
4068290001Sglebius					"\n    delta_n = % -12g .      M_0 = % -12g .     C_uc = % -12g",
4069290001Sglebius					edata->delta_n, edata->M_0, edata->C_uc );
4070106424Sroberto			pbuf += sprintf(pbuf,
4071290001Sglebius					"\n        ecc = % -12g .     C_us = % -12g .   sqrt_A = % -12g",
4072290001Sglebius					edata->e, edata->C_us, edata->sqrt_A );
4073106424Sroberto			pbuf += sprintf(pbuf,
4074290001Sglebius					"\n       t_oe = % -12g .     C_ic = % -12g .  OMEGA_0 = % -12g",
4075290001Sglebius					edata->t_oe, edata->C_ic, edata->OMEGA_0 );
4076106424Sroberto			pbuf += sprintf(pbuf,
4077290001Sglebius					"\n       C_is = % -12g .      i_0 = % -12g .     C_rc = % -12g",
4078290001Sglebius					edata->C_is, edata->i_0, edata->C_rc );
4079106424Sroberto			pbuf += sprintf(pbuf,
4080290001Sglebius					"\n      omega = % -12g . OMEGADOT = % -12g .     IDOT = % -12g",
4081290001Sglebius					edata->omega, edata->OMEGADOT, edata->IDOT );
4082106424Sroberto			pbuf += sprintf(pbuf,
4083290001Sglebius					"\n       Axis = % -12g .        n = % -12g .    r1me2 = % -12g",
4084290001Sglebius					edata->Axis, edata->n, edata->r1me2 );
4085106424Sroberto			pbuf += sprintf(pbuf,
4086290001Sglebius					"\n    OMEGA_n = % -12g .   ODOT_n = % -12g",
4087290001Sglebius					edata->OMEGA_n, edata->ODOT_n );
4088106424Sroberto			break;
4089106424Sroberto		}
4090106424Sroberto	}
4091106424Sroberto}
4092106424Sroberto
4093106424Sroberto
4094106424Sroberto/* 0x59: */
4095290001Sglebiusstatic void
4096290001Sglebiusrpt_SVs_enabled(
4097290001Sglebius		TSIPPKT *rpt
4098290001Sglebius		)
4099106424Sroberto{
4100106424Sroberto	unsigned char
4101290001Sglebius	    numsvs,
4102290001Sglebius	    code_type,
4103290001Sglebius	    status_code[32];
4104106424Sroberto	short
4105290001Sglebius	    iprn;
4106106424Sroberto
4107106424Sroberto	/* unload rptbuf */
4108106424Sroberto	if (rpt_0x59 (rpt, &code_type, status_code))
4109290001Sglebius	{
4110106424Sroberto		parsed = BADLEN_PARSE;
4111106424Sroberto		return;
4112106424Sroberto	}
4113290001Sglebius	switch (code_type)
4114290001Sglebius	{
4115290001Sglebius	    case 3: pbuf += sprintf(pbuf, "\nSVs Disabled:\n"); break;
4116290001Sglebius	    case 6: pbuf += sprintf(pbuf, "\nSVs with Health Ignored:\n"); break;
4117290001Sglebius	    default: return;
4118290001Sglebius	}
4119290001Sglebius	numsvs = 0;
4120290001Sglebius	for (iprn = 0; iprn < 32; iprn++)
4121290001Sglebius	{
4122290001Sglebius		if (status_code[iprn])
4123290001Sglebius		{
4124290001Sglebius			pbuf += sprintf(pbuf, " %02d", iprn+1);
4125290001Sglebius			numsvs++;
4126290001Sglebius		}
4127290001Sglebius	}
4128290001Sglebius	if (numsvs == 0) pbuf += sprintf(pbuf, "None");
4129106424Sroberto}
4130106424Sroberto
4131106424Sroberto
4132106424Sroberto/* 0x5A */
4133290001Sglebiusstatic void
4134290001Sglebiusrpt_raw_msmt(
4135290001Sglebius	     TSIPPKT *rpt
4136290001Sglebius	     )
4137106424Sroberto{
4138106424Sroberto	unsigned char
4139290001Sglebius	    sv_prn;
4140106424Sroberto	float
4141290001Sglebius	    sample_length, signal_level, code_phase, Doppler;
4142106424Sroberto	double
4143290001Sglebius	    time_of_fix;
4144106424Sroberto
4145106424Sroberto	/* unload rptbuf */
4146106424Sroberto	if (rpt_0x5A (rpt, &sv_prn, &sample_length, &signal_level,
4147290001Sglebius		      &code_phase, &Doppler, &time_of_fix))
4148290001Sglebius	{
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",
4154290001Sglebius			sv_prn, sample_length, signal_level, code_phase, Doppler, time_of_fix,
4155290001Sglebius			show_time ((float)time_of_fix));
4156106424Sroberto}
4157106424Sroberto
4158106424Sroberto/* 0x5B */
4159290001Sglebiusstatic void
4160290001Sglebiusrpt_SV_ephemeris_status(
4161290001Sglebius			TSIPPKT *rpt
4162290001Sglebius			)
4163106424Sroberto{
4164106424Sroberto	unsigned char
4165290001Sglebius	    sv_prn, sv_health, sv_iode, fit_interval_flag;
4166106424Sroberto	float
4167290001Sglebius	    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,
4171290001Sglebius		      &time_of_collection, &time_of_eph, &sv_accy))
4172290001Sglebius	{
4173106424Sroberto		parsed = BADLEN_PARSE;
4174106424Sroberto		return;
4175106424Sroberto	}
4176106424Sroberto
4177106424Sroberto	pbuf += sprintf(pbuf, "\n  SV%02d  %s   %2Xh     %2Xh ",
4178290001Sglebius			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",
4181290001Sglebius			show_time (time_of_eph), fit_interval_flag, sv_accy);
4182106424Sroberto}
4183106424Sroberto
4184106424Sroberto/* 0x5C */
4185290001Sglebiusstatic void
4186290001Sglebiusrpt_SV_tracking_status(
4187290001Sglebius		       TSIPPKT *rpt
4188290001Sglebius		       )
4189106424Sroberto{
4190106424Sroberto	unsigned char
4191290001Sglebius	    sv_prn, chan, slot, acq_flag, eph_flag,
4192290001Sglebius	    old_msmt_flag, integer_msec_flag, bad_data_flag,
4193290001Sglebius	    data_collect_flag;
4194106424Sroberto	float
4195290001Sglebius	    signal_level, time_of_last_msmt,
4196290001Sglebius	    elev, azim;
4197106424Sroberto
4198106424Sroberto	/* unload rptbuf */
4199106424Sroberto	if (rpt_0x5C (rpt,
4200290001Sglebius		      &sv_prn, &slot, &chan, &acq_flag, &eph_flag,
4201290001Sglebius		      &signal_level, &time_of_last_msmt, &elev, &azim,
4202290001Sglebius		      &old_msmt_flag, &integer_msec_flag, &bad_data_flag,
4203290001Sglebius		      &data_collect_flag))
4204290001Sglebius	{
4205106424Sroberto		parsed = BADLEN_PARSE;
4206106424Sroberto		return;
4207106424Sroberto	}
4208106424Sroberto
4209106424Sroberto	pbuf += sprintf(pbuf,
4210290001Sglebius			"\n SV%2d  %1d   %1d   %1d   %4.1f  %s  %5.1f  %5.1f",
4211290001Sglebius			sv_prn, chan,
4212290001Sglebius			acq_flag, eph_flag, signal_level,
4213290001Sglebius			show_time(time_of_last_msmt),
4214290001Sglebius			elev*R2D, azim*R2D);
4215106424Sroberto}
4216106424Sroberto
4217106424Sroberto/**/
4218106424Sroberto/* 0x6D */
4219290001Sglebiusstatic void
4220290001Sglebiusrpt_allSV_selection(
4221290001Sglebius		    TSIPPKT *rpt
4222290001Sglebius		    )
4223106424Sroberto{
4224106424Sroberto	unsigned char
4225290001Sglebius	    manual_mode, nsvs, sv_prn[8], ndim;
4226106424Sroberto	short
4227290001Sglebius	    islot;
4228106424Sroberto	float
4229290001Sglebius	    pdop, hdop, vdop, tdop;
4230106424Sroberto
4231106424Sroberto	/* unload rptbuf */
4232106424Sroberto	if (rpt_0x6D (rpt,
4233290001Sglebius		      &manual_mode, &nsvs, &ndim, sv_prn,
4234290001Sglebius		      &pdop, &hdop, &vdop, &tdop))
4235290001Sglebius	{
4236106424Sroberto		parsed = BADLEN_PARSE;
4237106424Sroberto		return;
4238106424Sroberto	}
4239106424Sroberto
4240106424Sroberto	switch (ndim)
4241290001Sglebius	{
4242290001Sglebius	    case 0:
4243106424Sroberto		pbuf += sprintf(pbuf, "\nMode: Searching, %d-SV:", nsvs);
4244290001Sglebius		break;
4245290001Sglebius	    case 1:
4246106424Sroberto		pbuf += sprintf(pbuf, "\nMode: One-SV Timing:");
4247290001Sglebius		break;
4248290001Sglebius	    case 3: case 4:
4249106424Sroberto		pbuf += sprintf(pbuf, "\nMode: %c-%dD, %d-SV:",
4250290001Sglebius				manual_mode ? 'M' : 'A', ndim - 1,  nsvs);
4251290001Sglebius		break;
4252290001Sglebius	    case 5:
4253106424Sroberto		pbuf += sprintf(pbuf, "\nMode: Timing, %d-SV:", nsvs);
4254290001Sglebius		break;
4255290001Sglebius	    default:
4256106424Sroberto		pbuf += sprintf(pbuf, "\nMode: Unknown = %d:", ndim);
4257290001Sglebius		break;
4258290001Sglebius	}
4259106424Sroberto
4260106424Sroberto	for (islot = 0; islot < nsvs; islot++)
4261290001Sglebius	{
4262106424Sroberto		if (sv_prn[islot]) pbuf += sprintf(pbuf, " %02d", sv_prn[islot]);
4263106424Sroberto	}
4264290001Sglebius	if (ndim == 3 || ndim == 4)
4265290001Sglebius	{
4266106424Sroberto		pbuf += sprintf(pbuf, ";  DOPs: P %.1f H %.1f V %.1f T %.1f",
4267290001Sglebius				pdop, hdop, vdop, tdop);
4268290001Sglebius	}
4269106424Sroberto}
4270106424Sroberto
4271106424Sroberto/**/
4272106424Sroberto/* 0x82 */
4273290001Sglebiusstatic void
4274290001Sglebiusrpt_DGPS_position_mode(
4275290001Sglebius		       TSIPPKT *rpt
4276290001Sglebius		       )
4277106424Sroberto{
4278106424Sroberto	unsigned char
4279290001Sglebius	    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)",
4288290001Sglebius			(diff_mode&1) ? "" : " not",
4289290001Sglebius			(diff_mode&2) ? "auto" : "manual",
4290290001Sglebius			diff_mode);
4291106424Sroberto}
4292106424Sroberto
4293106424Sroberto/* 0x83 */
4294290001Sglebiusstatic void
4295290001Sglebiusrpt_double_ECEF_position(
4296290001Sglebius			 TSIPPKT *rpt
4297290001Sglebius			 )
4298106424Sroberto{
4299106424Sroberto	double
4300290001Sglebius	    ECEF_pos[3], clock_bias;
4301106424Sroberto	float
4302290001Sglebius	    time_of_fix;
4303106424Sroberto
4304106424Sroberto	/* unload rptbuf */
4305106424Sroberto	if (rpt_0x83 (rpt, ECEF_pos, &clock_bias, &time_of_fix))
4306290001Sglebius	{
4307106424Sroberto		parsed = BADLEN_PARSE;
4308106424Sroberto		return;
4309106424Sroberto	}
4310106424Sroberto
4311106424Sroberto	pbuf += sprintf(pbuf, "\nDXYZ:%12.2f  %13.2f  %13.2f %12.2f%s",
4312290001Sglebius			ECEF_pos[0], ECEF_pos[1], ECEF_pos[2], clock_bias,
4313290001Sglebius			show_time(time_of_fix));
4314106424Sroberto}
4315106424Sroberto
4316106424Sroberto/* 0x84 */
4317290001Sglebiusstatic void
4318290001Sglebiusrpt_double_lla_position(
4319290001Sglebius			TSIPPKT *rpt
4320290001Sglebius			)
4321106424Sroberto{
4322106424Sroberto	short
4323290001Sglebius	    lat_deg, lon_deg;
4324106424Sroberto	double
4325290001Sglebius	    lat, lon, lat_min, lon_min,
4326290001Sglebius	    alt, clock_bias;
4327106424Sroberto	float
4328290001Sglebius	    time_of_fix;
4329106424Sroberto	unsigned char
4330290001Sglebius	    north_south, east_west;
4331106424Sroberto
4332106424Sroberto	/* unload rptbuf */
4333106424Sroberto	if (rpt_0x84 (rpt,
4334290001Sglebius		      &lat, &lon, &alt, &clock_bias, &time_of_fix))
4335290001Sglebius	{
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",
4360290001Sglebius			lat_deg, lat_min, north_south,
4361290001Sglebius			lon_deg, lon_min, east_west,
4362290001Sglebius			alt, clock_bias,
4363290001Sglebius			show_time(time_of_fix));
4364106424Sroberto}
4365106424Sroberto
4366106424Sroberto/* 0xBB */
4367290001Sglebiusstatic void
4368290001Sglebiusrpt_complete_rcvr_config(
4369290001Sglebius			 TSIPPKT *rpt
4370290001Sglebius			 )
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",
4381290001Sglebius			NavModeText0xBB[TsipxBB.operating_mode]);
4382106424Sroberto	pbuf += sprintf(pbuf, "\n   dynamics:            %s",
4383290001Sglebius			dyn_text[TsipxBB.dyn_code]);
4384106424Sroberto	pbuf += sprintf(pbuf, "\n   elev angle mask:     %g deg",
4385290001Sglebius			TsipxBB.elev_mask * R2D);
4386106424Sroberto	pbuf += sprintf(pbuf, "\n   SNR mask:            %g AMU",
4387290001Sglebius			TsipxBB.cno_mask);
4388106424Sroberto	pbuf += sprintf(pbuf, "\n   DOP mask:            %g",
4389290001Sglebius			TsipxBB.dop_mask);
4390106424Sroberto	pbuf += sprintf(pbuf, "\n   DOP switch:          %g",
4391290001Sglebius			TsipxBB.dop_switch);
4392106424Sroberto	return ;
4393106424Sroberto}
4394106424Sroberto
4395106424Sroberto/* 0xBC */
4396290001Sglebiusstatic void
4397290001Sglebiusrpt_rcvr_serial_port_config(
4398290001Sglebius			    TSIPPKT *rpt
4399290001Sglebius			    )
4400106424Sroberto{
4401106424Sroberto	unsigned char
4402290001Sglebius	    port_num, in_baud, out_baud, data_bits, parity, stop_bits, flow_control,
4403290001Sglebius	    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,
4408290001Sglebius		      &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:",
4415290001Sglebius			rcvr_port_text[port_num]);
4416106424Sroberto
4417106424Sroberto	pbuf += sprintf(pbuf, "\n             I/O Baud %s/%s, %d - %s - %d",
4418290001Sglebius			st_baud_text_app[in_baud],
4419290001Sglebius			st_baud_text_app[out_baud],
4420290001Sglebius			data_bits+5,
4421290001Sglebius			parity_text[parity],
4422290001Sglebius			stop_bits=1);
4423106424Sroberto	pbuf += sprintf(pbuf, "\n             Input protocols: ");
4424106424Sroberto	known = FALSE;
4425106424Sroberto	if (protocols_in&B_TSIP)
4426290001Sglebius	{
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)
4435290001Sglebius	{
4436106424Sroberto		pbuf += sprintf(pbuf, "%s ", protocols_out_text[1]);
4437106424Sroberto		known = TRUE;
4438106424Sroberto	}
4439106424Sroberto	if (protocols_out&B_NMEA)
4440290001Sglebius	{
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
4447290001Sglebius}
4448106424Sroberto
4449106424Sroberto/* 0x8F */
4450106424Sroberto/* 8F0B */
4451290001Sglebiusstatic void
4452290001Sglebiusrpt_8F0B(
4453290001Sglebius	 TSIPPKT *rpt
4454290001Sglebius	 )
4455106424Sroberto{
4456106424Sroberto	const char
4457290001Sglebius	    *oprtng_dim[7] = {
4458290001Sglebius		"horizontal (2-D)",
4459290001Sglebius		"full position (3-D)",
4460290001Sglebius		"single satellite (0-D)",
4461290001Sglebius		"automatic",
4462290001Sglebius		"N/A",
4463290001Sglebius		"N/A",
4464290001Sglebius		"overdetermined clock"};
4465290001Sglebius	char
4466290001Sglebius	    sv_id[8];
4467290001Sglebius	unsigned char
4468290001Sglebius	    month,
4469290001Sglebius	    date,
4470290001Sglebius	    dim_mode,
4471290001Sglebius	    north_south,
4472290001Sglebius	    east_west;
4473290001Sglebius	unsigned short
4474290001Sglebius	    event;
4475106424Sroberto	short
4476290001Sglebius	    utc_offset,
4477290001Sglebius	    year,
4478290001Sglebius	    local_index;
4479290001Sglebius	short
4480290001Sglebius	    lat_deg,
4481290001Sglebius	    lon_deg;
4482290001Sglebius	float
4483290001Sglebius	    bias_unc,
4484290001Sglebius	    dr_unc;
4485290001Sglebius	double
4486290001Sglebius	    tow,
4487290001Sglebius	    bias,
4488290001Sglebius	    drift,
4489290001Sglebius	    lat,
4490290001Sglebius	    lon,
4491290001Sglebius	    alt,
4492290001Sglebius	    lat_min,
4493290001Sglebius	    lon_min;
4494290001Sglebius	int
4495290001Sglebius	    numfix,
4496290001Sglebius	    numnotfix;
4497106424Sroberto
4498106424Sroberto	if (rpt_0x8F0B(rpt,
4499290001Sglebius		       &event,
4500290001Sglebius		       &tow,
4501290001Sglebius		       &date,
4502290001Sglebius		       &month,
4503290001Sglebius		       &year,
4504290001Sglebius		       &dim_mode,
4505290001Sglebius		       &utc_offset,
4506290001Sglebius		       &bias,
4507290001Sglebius		       &drift,
4508290001Sglebius		       &bias_unc,
4509290001Sglebius		       &dr_unc,
4510290001Sglebius		       &lat,
4511290001Sglebius		       &lon,
4512290001Sglebius		       &alt,
4513290001Sglebius		       sv_id))
4514290001Sglebius	{
4515106424Sroberto		parsed = BADLEN_PARSE;
4516106424Sroberto		return;
4517106424Sroberto	}
4518106424Sroberto
4519106424Sroberto	if (event == 0)
4520290001Sglebius	{
4521290001Sglebius		pbuf += sprintf(pbuf, "\nNew partial+full meas");
4522106424Sroberto	}
4523290001Sglebius	else
4524290001Sglebius	{
4525106424Sroberto		pbuf += sprintf(pbuf, "\nEvent count: %5d", event);
4526290001Sglebius	}
4527106424Sroberto
4528106424Sroberto	pbuf += sprintf(pbuf, "\nGPS time  : %s %2d/%2d/%2d (DMY)",
4529290001Sglebius			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)
4540290001Sglebius	{
4541106424Sroberto		north_south = 'S';
4542106424Sroberto		lat = -lat;
4543106424Sroberto	}
4544290001Sglebius	else
4545290001Sglebius	{
4546106424Sroberto		north_south = 'N';
4547106424Sroberto	}
4548106424Sroberto
4549106424Sroberto	lat_deg = (short)lat;
4550106424Sroberto	lat_min = (lat - lat_deg) * 60.0;
4551106424Sroberto	if (lon < 0.0)
4552290001Sglebius	{
4553106424Sroberto		east_west = 'W';
4554106424Sroberto		lon = -lon;
4555106424Sroberto	}
4556290001Sglebius	else
4557290001Sglebius	{
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
4568290001Sglebius	numfix = numnotfix = 0;
4569106424Sroberto	for (local_index=0; local_index<8; local_index++)
4570290001Sglebius	{
4571106424Sroberto		if (sv_id[local_index] < 0) numnotfix++;
4572106424Sroberto		if (sv_id[local_index] > 0) numfix++;
4573290001Sglebius	}
4574290001Sglebius	if (numfix > 0)
4575290001Sglebius	{
4576106424Sroberto		pbuf += sprintf(pbuf, "\nSVs used in fix  : ");
4577106424Sroberto		for (local_index=0; local_index<8; local_index++)
4578290001Sglebius		{
4579106424Sroberto			if (sv_id[local_index] > 0)
4580290001Sglebius			{
4581290001Sglebius				pbuf += sprintf(pbuf, "%2d ", sv_id[local_index]);
4582290001Sglebius			}
4583290001Sglebius		}
4584290001Sglebius	}
4585290001Sglebius	if (numnotfix > 0)
4586290001Sglebius	{
4587106424Sroberto		pbuf += sprintf(pbuf, "\nOther SVs tracked: ");
4588106424Sroberto		for (local_index=0; local_index<8; local_index++)
4589290001Sglebius		{
4590106424Sroberto			if (sv_id[local_index] < 0)
4591290001Sglebius			{
4592290001Sglebius				pbuf += sprintf(pbuf, "%2d ", sv_id[local_index]);
4593290001Sglebius			}
4594290001Sglebius		}
4595290001Sglebius	}
4596106424Sroberto}
4597106424Sroberto
4598106424Sroberto/* 0x8F14 */
4599106424Sroberto/* Datum parameters */
4600290001Sglebiusstatic void
4601290001Sglebiusrpt_8F14(
4602290001Sglebius	 TSIPPKT *rpt
4603290001Sglebius	 )
4604106424Sroberto{
4605106424Sroberto	double
4606290001Sglebius	    datum_coeffs[5];
4607106424Sroberto	short
4608290001Sglebius	    datum_idx;
4609106424Sroberto
4610106424Sroberto	/* unload rptbuf */
4611106424Sroberto	if (rpt_0x8F14 (rpt, &datum_idx, datum_coeffs))
4612290001Sglebius	{
4613106424Sroberto		parsed = BADLEN_PARSE;
4614106424Sroberto		return;
4615106424Sroberto	}
4616106424Sroberto
4617106424Sroberto	if (datum_idx == -1)
4618290001Sglebius	{
4619290001Sglebius		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]);
4625290001Sglebius	}
4626290001Sglebius	else if (datum_idx == 0)
4627290001Sglebius	{
4628290001Sglebius		pbuf += sprintf(pbuf, "\nWGS-84 datum, Index 0 ");
4629290001Sglebius	}
4630290001Sglebius	else
4631290001Sglebius	{
4632290001Sglebius		pbuf += sprintf(pbuf, "\nStandard Datum, Index %3d ", datum_idx);
4633290001Sglebius	}
4634106424Sroberto}
4635106424Sroberto
4636106424Sroberto/* 0x8F15 */
4637106424Sroberto/* Datum parameters */
4638290001Sglebiusstatic void
4639290001Sglebiusrpt_8F15(
4640290001Sglebius	 TSIPPKT *rpt
4641290001Sglebius	 )
4642106424Sroberto{
4643106424Sroberto	double
4644290001Sglebius	    datum_coeffs[5];
4645106424Sroberto	short
4646290001Sglebius	    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)
4655290001Sglebius	{
4656290001Sglebius		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]);
4662290001Sglebius	}
4663290001Sglebius	else if (datum_idx == 0)
4664290001Sglebius	{
4665290001Sglebius		pbuf += sprintf(pbuf, "\nWGS-84 datum, Index 0 ");
4666290001Sglebius	}
4667290001Sglebius	else
4668290001Sglebius	{
4669290001Sglebius		pbuf += sprintf(pbuf, "\nStandard Datum, Index %3d ", datum_idx);
4670290001Sglebius	}
4671106424Sroberto}
4672106424Sroberto
4673106424Sroberto/* 0x8F20 */
4674106424Sroberto#define INFO_DGPS       0x02
4675106424Sroberto#define INFO_2D         0x04
4676106424Sroberto#define INFO_ALTSET     0x08
4677106424Sroberto#define INFO_FILTERED   0x10
4678290001Sglebiusstatic void
4679290001Sglebiusrpt_8F20(
4680290001Sglebius	 TSIPPKT *rpt
4681290001Sglebius	 )
4682106424Sroberto{
4683106424Sroberto	unsigned char
4684290001Sglebius	    info, nsvs, sv_prn[32];
4685106424Sroberto	short
4686290001Sglebius	    week_num, datum_index, sv_IODC[32];
4687106424Sroberto	double
4688290001Sglebius	    lat, lon, alt, time_of_fix;
4689106424Sroberto	double
4690290001Sglebius	    londeg, latdeg, vel[3];
4691106424Sroberto	short
4692290001Sglebius	    isv;
4693290001Sglebius	char
4694290001Sglebius	    datum_string[20];
4695106424Sroberto
4696106424Sroberto	/* unload rptbuf */
4697106424Sroberto	if (rpt_0x8F20 (rpt,
4698290001Sglebius			&info, &lat, &lon, &alt, vel,
4699290001Sglebius			&time_of_fix,
4700290001Sglebius			&week_num, &nsvs, sv_prn, sv_IODC, &datum_index))
4701106424Sroberto	{
4702106424Sroberto		parsed = BADLEN_PARSE;
4703106424Sroberto		return;
4704106424Sroberto	}
4705106424Sroberto	pbuf += sprintf(pbuf,
4706290001Sglebius			"\nFix at: %04d:%3s:%02d:%02d:%06.3f GPS (=UTC+%2ds)  FixType: %s%s%s",
4707290001Sglebius			week_num,
4708290001Sglebius			dayname[(short)(time_of_fix/86400.0)],
4709290001Sglebius			(short)fmod(time_of_fix/3600., 24.),
4710290001Sglebius			(short)fmod(time_of_fix/60., 60.),
4711290001Sglebius			fmod(time_of_fix, 60.),
4712290001Sglebius			(char)rpt->buf[29],		/* UTC offset */
4713290001Sglebius			(info & INFO_DGPS)?"Diff":"",
4714290001Sglebius			(info & INFO_2D)?"2D":"3D",
4715290001Sglebius			(info & INFO_FILTERED)?"-Filtrd":"");
4716106424Sroberto
4717290001Sglebius	if (datum_index > 0)
4718290001Sglebius	{
4719106424Sroberto		sprintf(datum_string, "Datum%3d", datum_index);
4720290001Sglebius	}
4721290001Sglebius	else if (datum_index)
4722290001Sglebius	{
4723106424Sroberto		sprintf(datum_string, "Unknown ");
4724290001Sglebius	}
4725290001Sglebius	else
4726290001Sglebius	{
4727106424Sroberto		sprintf(datum_string, "WGS-84");
4728290001Sglebius	}
4729106424Sroberto
4730106424Sroberto	/* convert from radians to degrees */
4731106424Sroberto	latdeg = R2D * fabs(lat);
4732106424Sroberto	londeg = R2D * fabs(lon);
4733106424Sroberto	pbuf += sprintf(pbuf,
4734290001Sglebius			"\n   Pos: %4d:%09.6f %c %5d:%09.6f %c %10.2f m HAE (%s)",
4735290001Sglebius			(short)latdeg, fmod (latdeg, 1.)*60.0,
4736290001Sglebius			(lat<0.0)?'S':'N',
4737290001Sglebius			(short)londeg, fmod (londeg, 1.)*60.0,
4738290001Sglebius			(lon<0.0)?'W':'E',
4739290001Sglebius			alt,
4740290001Sglebius			datum_string);
4741106424Sroberto	pbuf += sprintf(pbuf,
4742290001Sglebius			"\n   Vel:    %9.3f E       %9.3f N      %9.3f U   (m/sec)",
4743290001Sglebius			vel[0], vel[1], vel[2]);
4744106424Sroberto
4745106424Sroberto	pbuf += sprintf(pbuf,
4746290001Sglebius			"\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 */
4758290001Sglebiusstatic void
4759290001Sglebiusrpt_8F41(
4760290001Sglebius	 TSIPPKT *rpt
4761290001Sglebius	 )
4762106424Sroberto{
4763106424Sroberto	unsigned char
4764290001Sglebius	    bSearchRange,
4765290001Sglebius	    bBoardOptions,
4766290001Sglebius	    bBuildYear,
4767290001Sglebius	    bBuildMonth,
4768290001Sglebius	    bBuildDay,
4769290001Sglebius	    bBuildHour;
4770106424Sroberto	float
4771290001Sglebius	    fOscOffset;
4772106424Sroberto	unsigned short
4773290001Sglebius	    iTestCodeId;
4774106424Sroberto	unsigned long
4775290001Sglebius	    iiSerialNumber;
4776106424Sroberto
4777290001Sglebius	if (!rpt_0x8F41(rpt,
4778290001Sglebius			&bSearchRange,
4779290001Sglebius			&bBoardOptions,
4780290001Sglebius			&iiSerialNumber,
4781290001Sglebius			&bBuildYear,
4782290001Sglebius			&bBuildMonth,
4783290001Sglebius			&bBuildDay,
4784290001Sglebius			&bBuildHour,
4785290001Sglebius			&fOscOffset,
4786290001Sglebius			&iTestCodeId))
4787290001Sglebius	{
4788106424Sroberto		parsed = BADLEN_PARSE;
4789290001Sglebius		return;
4790290001Sglebius	}
4791106424Sroberto
4792290001Sglebius	pbuf += sprintf(pbuf, "\n  search range:          %d",
4793290001Sglebius			bSearchRange);
4794290001Sglebius	pbuf += sprintf(pbuf, "\n  board options:         %d",
4795290001Sglebius			bBoardOptions);
4796290001Sglebius	pbuf += sprintf(pbuf, "\n  board serial #:        %ld",
4797290001Sglebius			iiSerialNumber);
4798290001Sglebius	pbuf += sprintf(pbuf, "\n  build date/hour:       %02d/%02d/%02d %02d:00",
4799290001Sglebius			bBuildDay, bBuildMonth, bBuildYear, bBuildHour);
4800290001Sglebius	pbuf += sprintf(pbuf, "\n  osc offset:            %.3f PPM (%.0f Hz)",
4801290001Sglebius			fOscOffset/1575.42, fOscOffset);
4802290001Sglebius	pbuf += sprintf(pbuf, "\n  test code:             %d",
4803290001Sglebius			iTestCodeId);
4804106424Sroberto}
4805106424Sroberto
4806106424Sroberto/* 0x8F42 */
4807290001Sglebiusstatic void
4808290001Sglebiusrpt_8F42(
4809290001Sglebius	 TSIPPKT *rpt
4810290001Sglebius	 )
4811106424Sroberto{
4812106424Sroberto	unsigned char
4813290001Sglebius	    bProdOptionsPre,
4814290001Sglebius	    bProdNumberExt;
4815106424Sroberto	unsigned short
4816290001Sglebius	    iCaseSerialNumberPre,
4817290001Sglebius	    iPremiumOptions,
4818290001Sglebius	    iMachineID,
4819290001Sglebius	    iKey;
4820106424Sroberto	unsigned long
4821290001Sglebius	    iiCaseSerialNumber,
4822290001Sglebius	    iiProdNumber;
4823106424Sroberto
4824290001Sglebius	if (!rpt_0x8F42(rpt,
4825290001Sglebius			&bProdOptionsPre,
4826290001Sglebius			&bProdNumberExt,
4827290001Sglebius			&iCaseSerialNumberPre,
4828290001Sglebius			&iiCaseSerialNumber,
4829290001Sglebius			&iiProdNumber,
4830290001Sglebius			&iPremiumOptions,
4831290001Sglebius			&iMachineID,
4832290001Sglebius			&iKey))
4833290001Sglebius	{
4834106424Sroberto		parsed = BADLEN_PARSE;
4835290001Sglebius		return;
4836290001Sglebius	}
4837106424Sroberto
4838106424Sroberto	pbuf += sprintf(pbuf, "\nProduct ID 8F42");
4839290001Sglebius	pbuf += sprintf(pbuf, "\n   extension:            %d", bProdNumberExt);
4840290001Sglebius	pbuf += sprintf(pbuf, "\n   case serial # prefix: %d", iCaseSerialNumberPre);
4841290001Sglebius	pbuf += sprintf(pbuf, "\n   case serial #:        %ld", iiCaseSerialNumber);
4842290001Sglebius	pbuf += sprintf(pbuf, "\n   prod. #:              %ld", iiProdNumber);
4843106424Sroberto	pbuf += sprintf(pbuf, "\n   premium options:      %Xh", iPremiumOptions);
4844290001Sglebius	pbuf += sprintf(pbuf, "\n   machine ID:           %d", iMachineID);
4845290001Sglebius	pbuf += sprintf(pbuf, "\n   key:                  %Xh", iKey);
4846106424Sroberto}
4847106424Sroberto
4848106424Sroberto/* 0x8F45 */
4849290001Sglebiusstatic void
4850290001Sglebiusrpt_8F45(
4851290001Sglebius	 TSIPPKT *rpt
4852290001Sglebius	 )
4853106424Sroberto{
4854290001Sglebius	unsigned char bSegMask;
4855106424Sroberto
4856290001Sglebius	if (!rpt_0x8F45(rpt,
4857290001Sglebius			&bSegMask))
4858290001Sglebius	{
4859106424Sroberto		parsed = BADLEN_PARSE;
4860106424Sroberto		return;
4861106424Sroberto	}
4862106424Sroberto	pbuf += sprintf(pbuf, "\nCleared Segment Mask: %Xh", bSegMask);
4863106424Sroberto}
4864106424Sroberto
4865106424Sroberto/* Stinger PPS def */
4866290001Sglebiusstatic void
4867290001Sglebiusrpt_8F4A(
4868290001Sglebius	 TSIPPKT *rpt
4869290001Sglebius	 )
4870106424Sroberto{
4871106424Sroberto	unsigned char
4872290001Sglebius	    pps_enabled,
4873290001Sglebius	    pps_timebase,
4874290001Sglebius	    pps_polarity;
4875290001Sglebius	float
4876290001Sglebius	    bias_unc_threshold;
4877290001Sglebius	double
4878290001Sglebius	    pps_offset;
4879106424Sroberto
4880106424Sroberto  	if (rpt_0x8F4A_16 (rpt,
4881290001Sglebius			   &pps_enabled,
4882290001Sglebius			   &pps_timebase,
4883290001Sglebius			   &pps_polarity,
4884290001Sglebius			   &pps_offset,
4885290001Sglebius			   &bias_unc_threshold))
4886290001Sglebius	{
4887290001Sglebius		parsed = BADLEN_PARSE;
4888290001Sglebius		return;
4889290001Sglebius	}
4890106424Sroberto
4891106424Sroberto	pbuf += sprintf(pbuf, "\nPPS is         %s",	pps_enabled?"enabled":"disabled");
4892290001Sglebius	pbuf += sprintf(pbuf, "\n   timebase:   %s", PPSTimeBaseText[pps_timebase]);
4893290001Sglebius	pbuf += sprintf(pbuf, "\n   polarity:   %s", PPSPolarityText[pps_polarity]);
4894290001Sglebius	pbuf += sprintf(pbuf, "\n   offset:     %.1f ns, ", pps_offset*1.e9);
4895290001Sglebius	pbuf += sprintf(pbuf, "\n   biasunc:    %.1f ns", bias_unc_threshold/GPS_C*1.e9);
4896106424Sroberto}
4897106424Sroberto
4898106424Sroberto/* fast-SA decorrolation time for self-survey */
4899290001Sglebiusstatic void
4900290001Sglebiusrpt_8F4B(
4901290001Sglebius	 TSIPPKT *rpt
4902290001Sglebius	 )
4903106424Sroberto{
4904106424Sroberto	unsigned long
4905290001Sglebius	    decorr_max;
4906106424Sroberto
4907290001Sglebius	if (rpt_0x8F4B(rpt, &decorr_max))
4908290001Sglebius	{
4909106424Sroberto		parsed = BADLEN_PARSE;
4910290001Sglebius		return;
4911290001Sglebius	}
4912106424Sroberto
4913290001Sglebius	pbuf += sprintf(pbuf,
4914290001Sglebius			"\nMax # of position fixes for self-survey : %ld",
4915290001Sglebius			decorr_max);
4916106424Sroberto}
4917106424Sroberto
4918290001Sglebiusstatic void
4919290001Sglebiusrpt_8F4D(
4920290001Sglebius	 TSIPPKT *rpt
4921290001Sglebius	 )
4922106424Sroberto{
4923106424Sroberto	static char
4924290001Sglebius	    *linestart;
4925106424Sroberto	unsigned long
4926290001Sglebius	    OutputMask;
4927290001Sglebius	static unsigned long
4928290001Sglebius	    MaskBit[] = {
4929290001Sglebius		0x00000001, 0x00000002, 0x00000004, 0x00000008, 0x00000010,
4930290001Sglebius		0x00000020,
4931290001Sglebius		0x00000100L, 0x00000800L, 0x00001000L,
4932290001Sglebius		0x40000000L, 0x80000000L};
4933290001Sglebius	int
4934290001Sglebius	    ichoice,
4935290001Sglebius	    numchoices;
4936106424Sroberto
4937290001Sglebius	if (rpt_0x8F4D(rpt, &OutputMask))
4938290001Sglebius	{
4939106424Sroberto		parsed = BADLEN_PARSE;
4940290001Sglebius		return;
4941290001Sglebius	}
4942106424Sroberto
4943290001Sglebius	pbuf += sprintf(pbuf, "\nAuto-Report Mask: %02X %02X %02X %02X",
4944290001Sglebius			(unsigned char)(OutputMask>>24),
4945290001Sglebius			(unsigned char)(OutputMask>>16),
4946290001Sglebius			(unsigned char)(OutputMask>>8),
4947290001Sglebius			(unsigned char)OutputMask);
4948106424Sroberto
4949290001Sglebius	numchoices = sizeof(MaskText)/sizeof(char*);
4950290001Sglebius	pbuf += sprintf(pbuf, "\nAuto-Reports scheduled for Output:");
4951290001Sglebius	linestart = pbuf;
4952290001Sglebius	for (ichoice = 0; ichoice < numchoices; ichoice++)
4953290001Sglebius	{
4954290001Sglebius		if (OutputMask&MaskBit[ichoice])
4955290001Sglebius		{
4956290001Sglebius			pbuf += sprintf(pbuf, "%s %s",
4957290001Sglebius					(pbuf==linestart)?"\n     ":",",
4958290001Sglebius					MaskText[ichoice]);
4959106424Sroberto			if (pbuf-linestart > 60) linestart = pbuf;
4960290001Sglebius		}
4961290001Sglebius	}
4962106424Sroberto
4963290001Sglebius	pbuf += sprintf(pbuf, "\nAuto-Reports NOT scheduled for Output:");
4964290001Sglebius	linestart = pbuf;
4965290001Sglebius	for (ichoice = 0; ichoice < numchoices; ichoice++)
4966290001Sglebius	{
4967290001Sglebius		if (OutputMask&MaskBit[ichoice]) continue;
4968106424Sroberto	     	pbuf += sprintf(pbuf, "%s %s",
4969290001Sglebius				(pbuf==linestart)?"\n     ":",",
4970290001Sglebius				MaskText[ichoice]);
4971106424Sroberto		if (pbuf-linestart > 60) linestart = pbuf;
4972290001Sglebius	}
4973106424Sroberto}
4974106424Sroberto
4975290001Sglebiusstatic void
4976290001Sglebiusrpt_8FA5(
4977290001Sglebius	 TSIPPKT *rpt
4978290001Sglebius	 )
4979106424Sroberto{
4980106424Sroberto	unsigned char
4981290001Sglebius	    spktmask[4];
4982106424Sroberto
4983290001Sglebius	if (rpt_0x8FA5(rpt, spktmask))
4984290001Sglebius	{
4985106424Sroberto		parsed = BADLEN_PARSE;
4986290001Sglebius		return;
4987290001Sglebius	}
4988106424Sroberto
4989290001Sglebius	pbuf += sprintf(pbuf, "\nSuperpacket auto-output mask: %02X %02X %02X %02X",
4990290001Sglebius			spktmask[0], spktmask[1], spktmask[2], spktmask[3]);
4991106424Sroberto
4992290001Sglebius	if (spktmask[0]&0x01) pbuf+= sprintf (pbuf, "\n    PPS   8F-0B");
4993290001Sglebius	if (spktmask[0]&0x02) pbuf+= sprintf (pbuf, "\n    Event 8F-0B");
4994290001Sglebius	if (spktmask[0]&0x10) pbuf+= sprintf (pbuf, "\n    PPS   8F-AD");
4995290001Sglebius	if (spktmask[0]&0x20) pbuf+= sprintf (pbuf, "\n    Event 8F-AD");
4996290001Sglebius	if (spktmask[2]&0x01) pbuf+= sprintf (pbuf, "\n    ppos Fix 8F-20");
4997106424Sroberto}
4998106424Sroberto
4999290001Sglebiusstatic void
5000290001Sglebiusrpt_8FAD(
5001290001Sglebius	 TSIPPKT *rpt
5002290001Sglebius	 )
5003106424Sroberto{
5004290001Sglebius	unsigned short
5005290001Sglebius	    Count,
5006290001Sglebius	    Year;
5007290001Sglebius	double
5008290001Sglebius	    FracSec;
5009290001Sglebius	unsigned char
5010290001Sglebius	    Hour,
5011290001Sglebius	    Minute,
5012290001Sglebius	    Second,
5013290001Sglebius	    Day,
5014290001Sglebius	    Month,
5015290001Sglebius	    Status,
5016290001Sglebius	    Flags;
5017106424Sroberto	static char* Status8FADText[] = {
5018290001Sglebius		"CODE_DOING_FIXES",
5019290001Sglebius		"CODE_GOOD_1_SV",
5020290001Sglebius		"CODE_APPX_1SV",
5021290001Sglebius		"CODE_NEED_TIME",
5022290001Sglebius		"CODE_NEED_INITIALIZATION",
5023290001Sglebius		"CODE_PDOP_HIGH",
5024290001Sglebius		"CODE_BAD_1SV",
5025290001Sglebius		"CODE_0SVS",
5026290001Sglebius		"CODE_1SV",
5027290001Sglebius		"CODE_2SVS",
5028290001Sglebius		"CODE_3SVS",
5029290001Sglebius		"CODE_NO_INTEGRITY",
5030290001Sglebius		"CODE_DCORR_GEN",
5031290001Sglebius		"CODE_OVERDET_CLK",
5032290001Sglebius		"Invalid Status"},
5033290001Sglebius	    *LeapStatusText[] = {
5034290001Sglebius		    " UTC Avail", " ", " ", " ",
5035290001Sglebius		    " Scheduled", " Pending", " Warning", " In Progress"};
5036290001Sglebius	int i;
5037106424Sroberto
5038106424Sroberto	if (rpt_0x8FAD (rpt,
5039290001Sglebius			&Count,
5040290001Sglebius			&FracSec,
5041290001Sglebius			&Hour,
5042290001Sglebius			&Minute,
5043290001Sglebius			&Second,
5044290001Sglebius			&Day,
5045290001Sglebius			&Month,
5046290001Sglebius			&Year,
5047290001Sglebius			&Status,
5048290001Sglebius			&Flags))
5049290001Sglebius	{
5050106424Sroberto		parsed = BADLEN_PARSE;
5051106424Sroberto		return;
5052290001Sglebius	}
5053106424Sroberto
5054106424Sroberto	pbuf += sprintf(pbuf,    "\n8FAD   Count: %d   Status: %s",
5055290001Sglebius			Count, Status8FADText[Status]);
5056106424Sroberto
5057290001Sglebius	pbuf += sprintf(pbuf, "\n   Leap Flags:");
5058290001Sglebius	if (Flags)
5059290001Sglebius	{
5060290001Sglebius		for (i=0; i<8; i++)
5061290001Sglebius		{
5062290001Sglebius			if (Flags&(1<<i)) pbuf += sprintf(pbuf, LeapStatusText[i]);
5063290001Sglebius		}
5064290001Sglebius	}
5065290001Sglebius	else
5066290001Sglebius	{
5067290001Sglebius		pbuf += sprintf(pbuf, "  UTC info not available");
5068290001Sglebius	}
5069106424Sroberto
5070106424Sroberto	pbuf += sprintf(pbuf,     "\n      %02d/%02d/%04d (DMY)  %02d:%02d:%02d.%09ld UTC",
5071290001Sglebius			Day, Month, Year, Hour, Minute, Second, (long)(FracSec*1.e9));
5072106424Sroberto}
5073106424Sroberto
5074106424Sroberto
5075290001Sglebiusint
5076290001Sglebiusprint_msg_table_header(
5077290001Sglebius		       int rptcode,
5078290001Sglebius		       char *HdrStr,
5079290001Sglebius		       int force
5080290001Sglebius		       )
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
5086290001Sglebius	    last_rptcode = 0;
5087290001Sglebius	int
5088290001Sglebius	    numchars;
5089106424Sroberto
5090290001Sglebius	numchars = 0;
5091106424Sroberto	if (force || rptcode!=last_rptcode)
5092290001Sglebius	{
5093106424Sroberto		/* supply a header in console output */
5094290001Sglebius		switch (rptcode)
5095106424Sroberto		{
5096290001Sglebius		    case 0x5A:
5097106424Sroberto			numchars = sprintf(HdrStr, "\nRaw Measurement Data");
5098106424Sroberto			numchars += sprintf(HdrStr+numchars,
5099290001Sglebius					    "\n   SV  Sample   SNR  Code Phase   Doppler    Seconds     Time of Meas");
5100106424Sroberto			break;
5101106424Sroberto
5102290001Sglebius		    case 0x5B:
5103106424Sroberto			numchars = sprintf(HdrStr, "\nEphemeris Status");
5104106424Sroberto			numchars += sprintf(HdrStr+numchars,
5105290001Sglebius					    "\n    SV     Time collected     Health  IODE        t oe         Fit   URA");
5106106424Sroberto			break;
5107106424Sroberto
5108290001Sglebius		    case 0x5C:
5109106424Sroberto			numchars = sprintf(HdrStr, "\nTracking Info");
5110106424Sroberto			numchars += sprintf(HdrStr+numchars,
5111290001Sglebius					    "\n   SV  C Acq Eph   SNR     Time of Meas       Elev  Azim   ");
5112106424Sroberto			break;
5113106424Sroberto
5114290001Sglebius		}
5115106424Sroberto	}
5116106424Sroberto	last_rptcode = rptcode;
5117290001Sglebius	return (short)numchars;
5118106424Sroberto}
5119106424Sroberto
5120290001Sglebiusstatic void
5121290001Sglebiusunknown_rpt(
5122290001Sglebius	    TSIPPKT *rpt
5123290001Sglebius	    )
5124106424Sroberto{
5125106424Sroberto	int i;
5126106424Sroberto
5127106424Sroberto	/* app-specific rpt packets */
5128106424Sroberto	if (parsed == BADLEN_PARSE)
5129290001Sglebius	{
5130106424Sroberto		pbuf += sprintf(pbuf, "\nTSIP report packet ID %2Xh, length %d: Bad length",
5131290001Sglebius				rpt->code, rpt->len);
5132290001Sglebius	}
5133106424Sroberto	if (parsed == BADID_PARSE)
5134290001Sglebius	{
5135106424Sroberto		pbuf += sprintf(pbuf,
5136290001Sglebius				"\nTSIP report packet ID %2Xh, length %d: translation not supported",
5137290001Sglebius				rpt->code, rpt->len);
5138290001Sglebius	}
5139106424Sroberto
5140106424Sroberto	if (parsed == BADDATA_PARSE)
5141290001Sglebius	{
5142106424Sroberto		pbuf += sprintf(pbuf,
5143290001Sglebius				"\nTSIP report packet ID %2Xh, length %d: data content incorrect",
5144290001Sglebius				rpt->code, rpt->len);
5145290001Sglebius	}
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/**/
5153290001Sglebius
5154106424Sroberto/*
5155106424Sroberto** main subroutine, called from ProcessInputBytesWhileWaitingForKBHit()
5156106424Sroberto*/
5157290001Sglebiusvoid
5158290001SglebiusTranslateTSIPReportToText(
5159290001Sglebius			  TSIPPKT *rpt,
5160290001Sglebius			  char *TextOutputBuffer
5161290001Sglebius			  )
5162106424Sroberto{
5163106424Sroberto
5164106424Sroberto	/* pbuf is the pointer to the current location of the text output */
5165106424Sroberto	pbuf = TextOutputBuffer;
5166106424Sroberto
5167290001Sglebius	/* 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
5173290001Sglebius	/* process incoming TSIP report according to code */
5174106424Sroberto	switch (rpt->code)
5175290001Sglebius	{
5176290001Sglebius	    case 0x3D: rpt_chan_A_config (rpt); break;
5177290001Sglebius	    case 0x40: rpt_almanac_data_page (rpt); break;
5178290001Sglebius	    case 0x41: rpt_GPS_time (rpt); break;
5179290001Sglebius	    case 0x42: rpt_single_ECEF_position (rpt); break;
5180290001Sglebius	    case 0x43: rpt_single_ECEF_velocity (rpt); break;
5181290001Sglebius	    case 0x45: rpt_SW_version (rpt); break;
5182290001Sglebius	    case 0x46: rpt_rcvr_health (rpt); break;
5183290001Sglebius	    case 0x47: rpt_SNR_all_SVs (rpt); break;
5184290001Sglebius	    case 0x48: rpt_GPS_system_message (rpt); break;
5185290001Sglebius	    case 0x49: rpt_almanac_health_page (rpt); break;
5186290001Sglebius	    case 0x4A: switch (rpt->len) {
5187290001Sglebius			/*
5188290001Sglebius			** special case (=slip-up) in the TSIP protocol;
5189290001Sglebius			** parsing method depends on length
5190290001Sglebius			*/
5191290001Sglebius		    case 20: rpt_single_lla_position (rpt); break;
5192290001Sglebius		    case  9: rpt_ref_alt (rpt); break;
5193106424Sroberto		} break;
5194290001Sglebius	    case 0x4B: rpt_rcvr_id_and_status (rpt);break;
5195290001Sglebius	    case 0x4C: rpt_operating_parameters (rpt); break;
5196290001Sglebius	    case 0x4D: rpt_oscillator_offset (rpt); break;
5197290001Sglebius	    case 0x4E: rpt_GPS_time_set_response (rpt); break;
5198290001Sglebius	    case 0x4F: rpt_UTC_offset (rpt); break;
5199290001Sglebius	    case 0x54: rpt_1SV_bias (rpt); break;
5200290001Sglebius	    case 0x55: rpt_io_opt (rpt); break;
5201290001Sglebius	    case 0x56: rpt_ENU_velocity (rpt); break;
5202290001Sglebius	    case 0x57: rpt_last_fix_info (rpt); break;
5203290001Sglebius	    case 0x58: rpt_GPS_system_data (rpt); break;
5204290001Sglebius	    case 0x59: rpt_SVs_enabled (rpt); break;
5205290001Sglebius	    case 0x5A: rpt_raw_msmt (rpt); break;
5206290001Sglebius	    case 0x5B: rpt_SV_ephemeris_status (rpt); break;
5207290001Sglebius	    case 0x5C: rpt_SV_tracking_status (rpt); break;
5208290001Sglebius	    case 0x6D: rpt_allSV_selection (rpt); break;
5209290001Sglebius	    case 0x82: rpt_DGPS_position_mode (rpt); break;
5210290001Sglebius	    case 0x83: rpt_double_ECEF_position (rpt); break;
5211290001Sglebius	    case 0x84: rpt_double_lla_position (rpt); break;
5212290001Sglebius	    case 0xBB: rpt_complete_rcvr_config (rpt); break;
5213290001Sglebius	    case 0xBC: rpt_rcvr_serial_port_config (rpt); break;
5214106424Sroberto
5215290001Sglebius	    case 0x8F: switch (rpt->buf[0])
5216290001Sglebius		{
5217290001Sglebius			/* superpackets; parsed according to subcodes */
5218290001Sglebius		    case 0x0B: rpt_8F0B(rpt); break;
5219290001Sglebius		    case 0x14: rpt_8F14(rpt); break;
5220290001Sglebius		    case 0x15: rpt_8F15(rpt); break;
5221290001Sglebius		    case 0x20: rpt_8F20(rpt); break;
5222290001Sglebius		    case 0x41: rpt_8F41(rpt); break;
5223290001Sglebius		    case 0x42: rpt_8F42(rpt); break;
5224290001Sglebius		    case 0x45: rpt_8F45(rpt); break;
5225290001Sglebius		    case 0x4A: rpt_8F4A(rpt); break;
5226290001Sglebius		    case 0x4B: rpt_8F4B(rpt); break;
5227290001Sglebius		    case 0x4D: rpt_8F4D(rpt); break;
5228290001Sglebius		    case 0xA5: rpt_8FA5(rpt); break;
5229290001Sglebius		    case 0xAD: rpt_8FAD(rpt); break;
5230290001Sglebius		    default: parsed = BADID_PARSE; break;
5231106424Sroberto		}
5232106424Sroberto		break;
5233106424Sroberto
5234290001Sglebius	    default: parsed = BADID_PARSE; break;
5235106424Sroberto	}
5236106424Sroberto
5237106424Sroberto	if (parsed != GOOD_PARSE)
5238106424Sroberto	{
5239290001Sglebius		/*
5240290001Sglebius		**The message has TSIP structure (DLEs, etc.)
5241290001Sglebius		** but could not be parsed by above routines
5242290001Sglebius		*/
5243106424Sroberto		unknown_rpt (rpt);
5244106424Sroberto	}
5245106424Sroberto
5246290001Sglebius	/* close TextOutputBuffer */
5247290001Sglebius	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