xref: /freebsd/contrib/ntp/ntpd/refclock_ripencc.c (revision f5f40dd63bc7acbb5312b26ac1ea1103c12352a6)
1 /*
2  * $Id: refclock_ripencc.c,v 1.13 2002/06/18 14:20:55 marks Exp marks $
3  *
4  * Copyright (c) 2002  RIPE NCC
5  *
6  * All Rights Reserved
7  *
8  * Permission to use, copy, modify, and distribute this software and its
9  * documentation for any purpose and without fee is hereby granted,
10  * provided that the above copyright notice appear in all copies and that
11  * both that copyright notice and this permission notice appear in
12  * supporting documentation, and that the name of the author not be
13  * used in advertising or publicity pertaining to distribution of the
14  * software without specific, written prior permission.
15  *
16  * THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
17  * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
18  * AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
19  * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
20  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
21  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  *
23  *
24  *
25  * This driver was developed for use with the RIPE NCC TTM project.
26  *
27  *
28  * The initial driver was developed by Daniel Karrenberg <dfk@ripe.net>
29  * using the code made available by Trimble. This was for xntpd-3.x.x
30  *
31  * Rewrite of the driver for ntpd-4.x.x by Mark Santcroos <marks@ripe.net>
32  *
33  */
34 
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif /* HAVE_CONFIG_H */
38 
39 #if defined(REFCLOCK) && defined(CLOCK_RIPENCC)
40 
41 #include "ntp_stdlib.h"
42 #include "ntpd.h"
43 #include "ntp_refclock.h"
44 #include "ntp_unixtime.h"
45 #include "ntp_io.h"
46 
47 #ifdef HAVE_PPSAPI
48 # include "ppsapi_timepps.h"
49 #endif
50 
51 /*
52  * Definitions
53  */
54 
55 /* we are on little endian */
56 #define BYTESWAP
57 
58 /*
59  * DEBUG statements: uncomment if necessary
60  */
61 /* #define DEBUG_NCC */ /* general debug statements */
62 /* #define DEBUG_PPS */ /* debug pps */
63 /* #define DEBUG_RAW */ /* print raw packets */
64 
65 #define TRIMBLE_OUTPUT_FUNC
66 #define TSIP_VERNUM "7.12a"
67 
68 #ifndef FALSE
69 #define FALSE 	(0)
70 #define TRUE 	(!FALSE)
71 #endif /* FALSE */
72 
73 #define GPS_PI 	(3.1415926535898)
74 #define GPS_C 		(299792458.)
75 #define	D2R		(GPS_PI/180.0)
76 #define	R2D		(180.0/GPS_PI)
77 #define WEEK 	(604800.)
78 #define MAXCHAN  (8)
79 
80 /* control characters for TSIP packets */
81 #define DLE 	(0x10)
82 #define ETX 	(0x03)
83 
84 #define MAX_RPTBUF (256)
85 
86 /* values of TSIPPKT.status */
87 #define TSIP_PARSED_EMPTY 	0
88 #define TSIP_PARSED_FULL 	1
89 #define TSIP_PARSED_DLE_1 	2
90 #define TSIP_PARSED_DATA 	3
91 #define TSIP_PARSED_DLE_2 	4
92 
93 #define UTCF_UTC_AVAIL  (unsigned char) (1)     /* UTC available */
94 #define UTCF_LEAP_SCHD  (unsigned char) (1<<4)  /* Leap scheduled */
95 #define UTCF_LEAP_PNDG  (unsigned char) (1<<5)  /* Leap pending, will occur at end of day */
96 
97 #define DEVICE  "/dev/gps%d"	/* name of radio device */
98 #define PRECISION       (-9)    /* precision assumed (about 2 ms) */
99 #define PPS_PRECISION   (-20)	/* precision assumed (about 1 us) */
100 #define REFID           "GPS\0" /* reference id */
101 #define REFID_LEN	4
102 #define DESCRIPTION     "RIPE NCC GPS (Palisade)"	/* Description */
103 #define SPEED232        B9600   /* 9600 baud */
104 
105 #define NSAMPLES        3       /* stages of median filter */
106 
107 /* Structures */
108 
109 /* TSIP packets have the following structure, whether report or command. */
110 typedef struct {
111 	short
112 	    counter,		/* counter */
113 	    len;		/* size of buf; < MAX_RPTBUF unsigned chars */
114 	unsigned char
115 	    status,		/* TSIP packet format/parse status */
116 	    code,		/* TSIP code */
117 	    buf[MAX_RPTBUF];	/* report or command string */
118 } TSIPPKT;
119 
120 /* TSIP binary data structures */
121 typedef struct {
122 	unsigned char
123 	    t_oa_raw, SV_health;
124 	float
125 	    e, t_oa, i_0, OMEGADOT, sqrt_A,
126 	    OMEGA_0, omega, M_0, a_f0, a_f1,
127 	    Axis, n, OMEGA_n, ODOT_n, t_zc;
128 	short
129 	    weeknum, wn_oa;
130 } ALM_INFO;
131 
132 typedef struct {		/*  Almanac health page (25) parameters  */
133 	unsigned char
134 	    WN_a, SV_health[32], t_oa;
135 } ALH_PARMS;
136 
137 typedef struct {		/*  Universal Coordinated Time (UTC) parms */
138 	double
139 	    A_0;
140 	float
141 	    A_1;
142 	short
143 	    delta_t_LS;
144 	float
145 	    t_ot;
146 	short
147 	    WN_t, WN_LSF, DN, delta_t_LSF;
148 } UTC_INFO;
149 
150 typedef struct {		/*  Ionospheric info (float)  */
151 	float
152 	    alpha_0, alpha_1, alpha_2, alpha_3,
153 	    beta_0, beta_1, beta_2, beta_3;
154 } ION_INFO;
155 
156 typedef struct {		/*  Subframe 1 info (float)  */
157 	short
158 	    weeknum;
159 	unsigned char
160 	    codeL2, L2Pdata, SVacc_raw, SV_health;
161 	short
162 	    IODC;
163 	float
164 	    T_GD, t_oc, a_f2, a_f1, a_f0, SVacc;
165 } EPHEM_CLOCK;
166 
167 typedef	struct {		/*  Ephemeris info (float)  */
168 	unsigned char
169 	    IODE, fit_interval;
170 	float
171 	    C_rs, delta_n;
172 	double
173 	    M_0;
174 	float
175 	    C_uc;
176 	double
177 	    e;
178 	float
179 	    C_us;
180 	double
181 	    sqrt_A;
182 	float
183 	    t_oe, C_ic;
184 	double
185 	    OMEGA_0;
186 	float
187 	    C_is;
188 	double
189 	    i_0;
190 	float
191 	    C_rc;
192 	double
193 	    omega;
194 	float
195 	    OMEGADOT, IDOT;
196 	double
197 	    Axis, n, r1me2, OMEGA_n, ODOT_n;
198 } EPHEM_ORBIT;
199 
200 typedef struct {		/* Navigation data structure */
201 	short
202 	    sv_number;		/* SV number (0 = no entry) */
203 	float
204 	    t_ephem;		/* time of ephemeris collection */
205 	EPHEM_CLOCK
206 	    ephclk;		/* subframe 1 data */
207 	EPHEM_ORBIT
208 	    ephorb;		/* ephemeris data */
209 } NAV_INFO;
210 
211 typedef struct {
212 	unsigned char
213 	    bSubcode,
214 	    operating_mode,
215 	    dgps_mode,
216 	    dyn_code,
217 	    trackmode;
218 	float
219 	    elev_mask,
220 	    cno_mask,
221 	    dop_mask,
222 	    dop_switch;
223 	unsigned char
224 	    dgps_age_limit;
225 } TSIP_RCVR_CFG;
226 
227 
228 #ifdef TRIMBLE_OUTPUT_FUNC
229 static char
230         *dayname[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"},
231 	old_baudnum[] = {0, 1, 4, 5, 6, 8, 9, 11, 28, 12},
232         *st_baud_text_app [] = {"", "", "  300", "  600", " 1200", " 2400",
233 				" 4800", " 9600", "19200", "38400"},
234 	*old_parity_text[] = {"EVEN", "ODD", "", "", "NONE"},
235 	*parity_text [] = {"NONE", "ODD", "EVEN"},
236 	*old_input_ch[] = { "TSIP", "RTCM (6 of 8 bits)"},
237 	*old_output_ch[] = { "TSIP", "No output", "", "", "", "NMEA 0183"},
238 	*protocols_in_text[] = { "", "TSIP", "", ""},
239 	*protocols_out_text[] =	{ "", "TSIP", "NMEA"},
240 	*rcvr_port_text [] = { "Port A      ", "Port B      ", "Current Port"},
241 	*dyn_text [] = {"Unchanged", "Land", "Sea", "Air", "Static"},
242 	*NavModeText0xBB[] = {"automatic", "time only (0-D)", "", "2-D",
243 			      "3-D", "", "", "OverDetermined Time"},
244 	*PPSTimeBaseText[] = {"GPS", "UTC", "USER"},
245 	*PPSPolarityText[] = {"Positive", "Negative"},
246   	*MaskText[] = { "Almanac  ", "Ephemeris", "UTC      ", "Iono     ",
247 			"GPS Msg  ", "Alm Hlth ", "Time Fix ", "SV Select",
248 			"Ext Event", "Pos Fix  ", "Raw Meas "};
249 
250 #endif /* TRIMBLE_OUTPUT_FUNC */
251 
252 /*
253  * Unit control structure
254  */
255 struct ripencc_unit {
256         int unit;                       /* unit number */
257         int     pollcnt;                /* poll message counter */
258         int     polled;                 /* Hand in a sample? */
259         char leapdelta;                 /* delta of next leap event */
260         unsigned char utcflags;         /* delta of next leap event */
261         l_fp    tstamp;                 /* timestamp of last poll */
262 
263         struct timespec ts;             /* last timestamp */
264         pps_params_t pps_params;        /* pps parameters */
265         pps_info_t pps_info;            /* last pps data */
266         pps_handle_t handle;            /* pps handlebars */
267 
268 };
269 
270 
271 /*******************        PROTOYPES            *****************/
272 
273 /*  prototypes for report parsing primitives */
274 short rpt_0x3D (TSIPPKT *rpt, unsigned char *tx_baud_index,
275 		unsigned char *rx_baud_index, unsigned char *char_format_index,
276 		unsigned char *stop_bits, unsigned char *tx_mode_index,
277 		unsigned char *rx_mode_index);
278 short rpt_0x40 (TSIPPKT *rpt, unsigned char *sv_prn, short *week_num,
279 		float *t_zc, float *eccentricity, float *t_oa, float *i_0,
280 		float *OMEGA_dot, float *sqrt_A, float *OMEGA_0, float *omega,
281 		float *M_0);
282 short rpt_0x41 (TSIPPKT *rpt, float *time_of_week, float *UTC_offset,
283 		short *week_num);
284 short rpt_0x42 (TSIPPKT *rpt, float ECEF_pos[3], float *time_of_fix);
285 short rpt_0x43 (TSIPPKT *rpt, float ECEF_vel[3], float *freq_offset,
286 		float *time_of_fix);
287 short rpt_0x45 (TSIPPKT *rpt, unsigned char *major_nav_version,
288 		unsigned char *minor_nav_version, unsigned char *nav_day,
289 		unsigned char *nav_month, unsigned char *nav_year,
290 		unsigned char *major_dsp_version, unsigned char *minor_dsp_version,
291 		unsigned char *dsp_day, unsigned char *dsp_month,
292 		unsigned char *dsp_year);
293 short rpt_0x46 (TSIPPKT *rpt, unsigned char *status1, unsigned char *status2);
294 short rpt_0x47 (TSIPPKT *rpt, unsigned char *nsvs, unsigned char *sv_prn,
295 		float *snr);
296 short rpt_0x48 (TSIPPKT *rpt, unsigned char *message);
297 short rpt_0x49 (TSIPPKT *rpt, unsigned char *sv_health);
298 short rpt_0x4A (TSIPPKT *rpt, float *lat, float *lon, float *alt,
299 		float *clock_bias, float *time_of_fix);
300 short rpt_0x4A_2 (TSIPPKT *rpt, float *alt, float *dummy,
301 		  unsigned char *alt_flag);
302 short rpt_0x4B (TSIPPKT *rpt, unsigned char *machine_id,
303 		unsigned char *status3, unsigned char *status4);
304 short rpt_0x4C (TSIPPKT *rpt, unsigned char *dyn_code, float *el_mask,
305 		float *snr_mask, float *dop_mask, float *dop_switch);
306 short rpt_0x4D (TSIPPKT *rpt, float *osc_offset);
307 short rpt_0x4E (TSIPPKT *rpt, unsigned char *response);
308 short rpt_0x4F (TSIPPKT *rpt, double *a0, float *a1, float *time_of_data,
309 		short *dt_ls, short *wn_t, short *wn_lsf, short *dn, short *dt_lsf);
310 short rpt_0x54 (TSIPPKT *rpt, float *clock_bias, float *freq_offset,
311 		float *time_of_fix);
312 short rpt_0x55 (TSIPPKT *rpt, unsigned char *pos_code, unsigned char *vel_code,
313 		unsigned char *time_code, unsigned char *aux_code);
314 short rpt_0x56 (TSIPPKT *rpt, float vel_ENU[3], float *freq_offset,
315 		float *time_of_fix);
316 short rpt_0x57 (TSIPPKT *rpt, unsigned char *source_code,
317 		unsigned char *diag_code, short *week_num, float *time_of_fix);
318 short rpt_0x58 (TSIPPKT *rpt, unsigned char *op_code, unsigned char *data_type,
319 		unsigned char *sv_prn, unsigned char *data_length,
320 		unsigned char *data_packet);
321 short rpt_0x59 (TSIPPKT *rpt, unsigned char *code_type,
322 		unsigned char status_code[32]);
323 short rpt_0x5A (TSIPPKT *rpt, unsigned char *sv_prn, float *sample_length,
324 		float *signal_level, float *code_phase, float *Doppler,
325 		double *time_of_fix);
326 short rpt_0x5B (TSIPPKT *rpt, unsigned char *sv_prn, unsigned char *sv_health,
327 		unsigned char *sv_iode, unsigned char *fit_interval_flag,
328 		float *time_of_collection, float *time_of_eph, float *sv_accy);
329 short rpt_0x5C (TSIPPKT *rpt, unsigned char *sv_prn, unsigned char *slot,
330 		unsigned char *chan, unsigned char *acq_flag, unsigned char *eph_flag,
331 		float *signal_level, float *time_of_last_msmt, float *elev,
332 		float *azim, unsigned char *old_msmt_flag,
333 		unsigned char *integer_msec_flag, unsigned char *bad_data_flag,
334 		unsigned char *data_collect_flag);
335 short rpt_0x6D (TSIPPKT *rpt, unsigned char *manual_mode, unsigned char *nsvs,
336 		unsigned char *ndim, unsigned char sv_prn[], float *pdop,
337 		float *hdop, float *vdop, float *tdop);
338 short rpt_0x82 (TSIPPKT *rpt, unsigned char *diff_mode);
339 short rpt_0x83 (TSIPPKT *rpt, double ECEF_pos[3], double *clock_bias,
340 		float *time_of_fix);
341 short rpt_0x84 (TSIPPKT *rpt, double *lat, double *lon, double *alt,
342 		double *clock_bias, float *time_of_fix);
343 short rpt_Paly0xBB(TSIPPKT *rpt, TSIP_RCVR_CFG *TsipxBB);
344 short rpt_0xBC   (TSIPPKT *rpt, unsigned char *port_num,
345 		  unsigned char *in_baud, unsigned char *out_baud,
346 		  unsigned char *data_bits, unsigned char *parity,
347 		  unsigned char *stop_bits, unsigned char *flow_control,
348 		  unsigned char *protocols_in, unsigned char *protocols_out,
349 		  unsigned char *reserved);
350 
351 /* prototypes for superpacket parsers */
352 
353 short rpt_0x8F0B (TSIPPKT *rpt, unsigned short *event, double *tow,
354 		  unsigned char *date, unsigned char *month, short *year,
355 		  unsigned char *dim_mode, short *utc_offset, double *bias, double *drift,
356 		  float *bias_unc, float *dr_unc, double *lat, double *lon, double *alt,
357 		  char sv_id[8]);
358 short rpt_0x8F14 (TSIPPKT *rpt, short *datum_idx, double datum_coeffs[5]);
359 short rpt_0x8F15 (TSIPPKT *rpt, short *datum_idx, double datum_coeffs[5]);
360 short rpt_0x8F20 (TSIPPKT *rpt, unsigned char *info, double *lat,
361 		  double *lon, double *alt, double vel_enu[], double *time_of_fix,
362 		  short *week_num, unsigned char *nsvs, unsigned char sv_prn[],
363 		  short sv_IODC[], short *datum_index);
364 short rpt_0x8F41 (TSIPPKT *rpt, unsigned char *bSearchRange,
365 		  unsigned char *bBoardOptions, unsigned long *iiSerialNumber,
366 		  unsigned char *bBuildYear, unsigned char *bBuildMonth,
367 		  unsigned char *bBuildDay, unsigned char *bBuildHour,
368 		  float *fOscOffset, unsigned short *iTestCodeId);
369 short rpt_0x8F42 (TSIPPKT *rpt, unsigned char *bProdOptionsPre,
370 		  unsigned char *bProdNumberExt, unsigned short *iCaseSerialNumberPre,
371 		  unsigned long *iiCaseSerialNumber, unsigned long *iiProdNumber,
372 		  unsigned short *iPremiumOptions, unsigned short *iMachineID,
373 		  unsigned short *iKey);
374 short rpt_0x8F45 (TSIPPKT *rpt, unsigned char *bSegMask);
375 short rpt_0x8F4A_16 (TSIPPKT *rpt, unsigned char *pps_enabled,
376 		     unsigned char *pps_timebase, unsigned char *pos_polarity,
377 		     double *pps_offset, float *bias_unc_threshold);
378 short rpt_0x8F4B (TSIPPKT *rpt, unsigned long *decorr_max);
379 short rpt_0x8F4D (TSIPPKT *rpt, unsigned long *event_mask);
380 short rpt_0x8FA5 (TSIPPKT *rpt, unsigned char *spktmask);
381 short rpt_0x8FAD (TSIPPKT *rpt, unsigned short *COUNT, double *FracSec,
382 		  unsigned char *Hour, unsigned char *Minute, unsigned char *Second,
383 		  unsigned char *Day, unsigned char *Month, unsigned short *Year,
384 		  unsigned char *Status, unsigned char *Flags);
385 
386 /**/
387 /* prototypes for command-encode primitives with suffix convention:  */
388 /* c = clear, s = set, q = query, e = enable, d = disable            */
389 void cmd_0x1F  (TSIPPKT *cmd);
390 void cmd_0x26  (TSIPPKT *cmd);
391 void cmd_0x2F  (TSIPPKT *cmd);
392 void cmd_0x35s (TSIPPKT *cmd, unsigned char pos_code, unsigned char vel_code,
393 		unsigned char time_code, unsigned char opts_code);
394 void cmd_0x3C  (TSIPPKT *cmd, unsigned char sv_prn);
395 void cmd_0x3Ds (TSIPPKT *cmd, unsigned char baud_out, unsigned char baud_inp,
396 		unsigned char char_code, unsigned char stopbitcode,
397 		unsigned char output_mode, unsigned char input_mode);
398 void cmd_0xBBq (TSIPPKT *cmd, unsigned char subcode) ;
399 
400 /* prototypes 8E commands */
401 void cmd_0x8E0Bq (TSIPPKT *cmd);
402 void cmd_0x8E41q (TSIPPKT *cmd);
403 void cmd_0x8E42q (TSIPPKT *cmd);
404 void cmd_0x8E4Aq (TSIPPKT *cmd);
405 void cmd_0x8E4As (TSIPPKT *cmd, unsigned char PPSOnOff, unsigned char TimeBase,
406 		  unsigned char Polarity, double PPSOffset, float Uncertainty);
407 void cmd_0x8E4Bq (TSIPPKT *cmd);
408 void cmd_0x8E4Ds (TSIPPKT *cmd, unsigned long AutoOutputMask);
409 void cmd_0x8EADq (TSIPPKT *cmd);
410 
411 /* header/source border XXXXXXXXXXXXXXXXXXXXXXXXXX */
412 
413 /* Trimble parse functions */
414 static 	int	parse0x8FAD	(TSIPPKT *, struct peer *);
415 static 	int	parse0x8F0B	(TSIPPKT *, struct peer *);
416 #ifdef TRIMBLE_OUTPUT_FUNC
417 static 	int	parseany	(TSIPPKT *, struct peer *);
418 static 	void	TranslateTSIPReportToText	(TSIPPKT *, char *);
419 #endif /* TRIMBLE_OUTPUT_FUNC */
420 static 	int	parse0x5C	(TSIPPKT *, struct peer *);
421 static 	int	parse0x4F	(TSIPPKT *, struct peer *);
422 static	void	tsip_input_proc	(TSIPPKT *, int);
423 
424 /* Trimble helper functions */
425 static	void	bPutFloat 	(float *, unsigned char *);
426 static	void	bPutDouble 	(double *, unsigned char *);
427 static	void	bPutULong 	(unsigned long *, unsigned char *);
428 static	int	print_msg_table_header	(int rptcode, char *HdrStr, int force);
429 static	char *	show_time	(float time_of_week);
430 
431 /* RIPE NCC functions */
432 static	void	ripencc_control	(int, const struct refclockstat *,
433 				 struct refclockstat *, struct peer *);
434 static	int	ripencc_ppsapi	(struct peer *, int, int);
435 static	int	ripencc_get_pps_ts	(struct ripencc_unit *, l_fp *);
436 static	int	ripencc_start	(int, struct peer *);
437 static 	void	ripencc_shutdown	(int, struct peer *);
438 static 	void	ripencc_poll	(int, struct peer *);
439 static 	void	ripencc_send	(struct peer *, TSIPPKT spt);
440 static 	void	ripencc_receive	(struct recvbuf *);
441 
442 /* fill in reflock structure for our clock */
443 struct refclock refclock_ripencc = {
444 	ripencc_start,		/* start up driver */
445 	ripencc_shutdown,	/* shut down driver */
446 	ripencc_poll,		/* transmit poll message */
447 	ripencc_control,	/* control function */
448 	noentry,		/* initialize driver */
449 	noentry,		/* debug info */
450 	NOFLAGS			/* clock flags */
451 };
452 
453 /*
454  *  Tables to compute the ddd of year form icky dd/mm timecode. Viva la
455  *  leap.
456  */
457 static int day1tab[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
458 static int day2tab[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
459 
460 
461 /*
462  * ripencc_start - open the GPS devices and initialize data for processing
463  */
464 static int
465 ripencc_start(int unit, struct peer *peer)
466 {
467 	register struct ripencc_unit *up;
468 	struct refclockproc *pp;
469 	char device[40];
470 	int fd;
471 	struct termios tio;
472 	TSIPPKT spt;
473 
474 	pp = peer->procptr;
475 
476 	/*
477 	 * Open serial port
478 	 */
479 	(void)snprintf(device, sizeof(device), DEVICE, unit);
480 	fd = refclock_open(&peer->srcadr, device, SPEED232, LDISC_RAW);
481 	if (fd <= 0) {
482 		pp->io.fd = -1;
483 		return (0);
484 	}
485 
486 	pp->io.fd = fd;
487 
488 	/* from refclock_palisade.c */
489 	if (tcgetattr(fd, &tio) < 0) {
490 		msyslog(LOG_ERR, "Palisade(%d) tcgetattr(fd, &tio): %m",unit);
491 		return (0);
492 	}
493 
494 	/*
495 	 * set flags
496 	 */
497 	tio.c_cflag |= (PARENB|PARODD);
498 	tio.c_iflag &= ~ICRNL;
499 	if (tcsetattr(fd, TCSANOW, &tio) == -1) {
500 		msyslog(LOG_ERR, "Palisade(%d) tcsetattr(fd, &tio): %m",unit);
501 		return (0);
502 	}
503 
504 	/*
505 	 * Allocate and initialize unit structure
506 	 */
507 	up = emalloc_zero(sizeof(*up));
508 
509 	pp->io.clock_recv = ripencc_receive;
510 	pp->io.srcclock = peer;
511 	pp->io.datalen = 0;
512 	if (!io_addclock(&pp->io)) {
513 		pp->io.fd = -1;
514 		close(fd);
515 		free(up);
516 		return (0);
517 	}
518 	pp->unitptr = up;
519 
520 	/*
521 	 * Initialize miscellaneous variables
522 	 */
523 	peer->precision = PRECISION;
524 	pp->clockdesc = DESCRIPTION;
525 	memcpy((char *)&pp->refid, REFID, REFID_LEN);
526 	up->pollcnt = 2;
527 	up->unit = unit;
528 	up->leapdelta = 0;
529 	up->utcflags = 0;
530 
531 	/*
532 	 * Initialize the Clock
533 	 */
534 
535 	/* query software versions */
536 	cmd_0x1F(&spt);
537 	ripencc_send(peer, spt);
538 
539 	/* query receiver health */
540 	cmd_0x26(&spt);
541 	ripencc_send(peer, spt);
542 
543 	/* query serial numbers */
544 	cmd_0x8E42q(&spt);
545 	ripencc_send(peer, spt);
546 
547 	/* query manuf params */
548 	cmd_0x8E41q(&spt);
549 	ripencc_send(peer, spt);
550 
551 	/* i/o opts */ /* trimble manual page A30 */
552 	cmd_0x35s(&spt,
553 		  0x1C, 	/* position */
554 		  0x00, 	/* velocity */
555 		  0x05, 	/* timing */
556 		  0x0a); 	/* auxilary */
557 	ripencc_send(peer, spt);
558 
559 	/* turn off port A */
560 	cmd_0x3Ds (&spt,
561 		   0x0B,	/* baud_out */
562 		   0x0B,	/* baud_inp */
563 		   0x07,	/* char_code */
564 		   0x07,	/* stopbitcode */
565 		   0x01,	/* output_mode */
566 		   0x00);	/* input_mode */
567 	ripencc_send(peer, spt);
568 
569 	/* set i/o options */
570 	cmd_0x8E4As (&spt,
571 		     0x01,	/* PPS on */
572 		     0x01,	/* Timebase UTC */
573 		     0x00,	/* polarity positive */
574 		     0.,	/* 100 ft. cable XXX make flag */
575 		     1e-6 * GPS_C); 	/* turn of biasuncert. > (1us) */
576 	ripencc_send(peer,spt);
577 
578 	/* all outomatic packet output off */
579 	cmd_0x8E4Ds(&spt,
580 		    0x00000000); /* AutoOutputMask */
581 	ripencc_send(peer, spt);
582 
583 	cmd_0xBBq (&spt,
584 		   0x00);	/* query primary configuration */
585 	ripencc_send(peer,spt);
586 
587 
588 	/* query PPS parameters */
589 	cmd_0x8E4Aq (&spt);	/* query PPS params */
590 	ripencc_send(peer,spt);
591 
592 	/* query survey limit */
593 	cmd_0x8E4Bq (&spt);	/* query survey limit */
594 	ripencc_send(peer,spt);
595 
596 #ifdef DEBUG_NCC
597 	if (debug)
598 		printf("ripencc_start: success\n");
599 #endif /* DEBUG_NCC */
600 
601 	/*
602 	 * Start the PPSAPI interface if it is there. Default to use
603 	 * the assert edge and do not enable the kernel hardpps.
604 	 */
605 	if (time_pps_create(fd, &up->handle) < 0) {
606 		up->handle = 0;
607 		msyslog(LOG_ERR, "refclock_ripencc: time_pps_create failed: %m");
608 		return (1);
609 	}
610 
611 	return(ripencc_ppsapi(peer, 0, 0));
612 }
613 
614 /*
615  * ripencc_control - fudge control
616  */
617 static void
618 ripencc_control(
619 	int unit,		/* unit (not used) */
620 	const struct refclockstat *in, /* input parameters (not used) */
621 	struct refclockstat *out, /* output parameters (not used) */
622 	struct peer *peer	/* peer structure pointer */
623 	)
624 {
625 	struct refclockproc *pp;
626 
627 #ifdef DEBUG_NCC
628 	msyslog(LOG_INFO,"%s()",__FUNCTION__);
629 #endif /* DEBUG_NCC */
630 
631 	pp = peer->procptr;
632 	ripencc_ppsapi(peer, pp->sloppyclockflag & CLK_FLAG2,
633 		       pp->sloppyclockflag & CLK_FLAG3);
634 }
635 
636 
637 /*
638  * Initialize PPSAPI
639  */
640 int
641 ripencc_ppsapi(
642 	struct peer *peer,	/* peer structure pointer */
643 	int enb_clear,		/* clear enable */
644 	int enb_hardpps		/* hardpps enable */
645 	)
646 {
647 	struct refclockproc *pp;
648 	struct ripencc_unit *up;
649 	int capability;
650 
651 	pp = peer->procptr;
652 	up = pp->unitptr;
653 	if (time_pps_getcap(up->handle, &capability) < 0) {
654 		msyslog(LOG_ERR,
655 			"refclock_ripencc: time_pps_getcap failed: %m");
656 		return (0);
657 	}
658 	memset(&up->pps_params, 0, sizeof(pps_params_t));
659 	if (enb_clear)
660 		up->pps_params.mode = capability & PPS_CAPTURECLEAR;
661 	else
662 		up->pps_params.mode = capability & PPS_CAPTUREASSERT;
663 	if (!up->pps_params.mode) {
664 		msyslog(LOG_ERR,
665 			"refclock_ripencc: invalid capture edge %d",
666 			!enb_clear);
667 		return (0);
668 	}
669 	up->pps_params.mode |= PPS_TSFMT_TSPEC;
670 	if (time_pps_setparams(up->handle, &up->pps_params) < 0) {
671 		msyslog(LOG_ERR,
672 			"refclock_ripencc: time_pps_setparams failed: %m");
673 		return (0);
674 	}
675 	if (enb_hardpps) {
676 		if (time_pps_kcbind(up->handle, PPS_KC_HARDPPS,
677 				    up->pps_params.mode & ~PPS_TSFMT_TSPEC,
678 				    PPS_TSFMT_TSPEC) < 0) {
679 			msyslog(LOG_ERR,
680 				"refclock_ripencc: time_pps_kcbind failed: %m");
681 			return (0);
682 		}
683 		hardpps_enable = 1;
684 	}
685 	peer->precision = PPS_PRECISION;
686 
687 #if DEBUG_NCC
688 	if (debug) {
689 		time_pps_getparams(up->handle, &up->pps_params);
690 		printf(
691 			"refclock_ripencc: capability 0x%x version %d mode 0x%x kern %d\n",
692 			capability, up->pps_params.api_version,
693 			up->pps_params.mode, enb_hardpps);
694 	}
695 #endif /* DEBUG_NCC */
696 
697 	return (1);
698 }
699 
700 /*
701  * This function is called every 64 seconds from ripencc_receive
702  * It will fetch the pps time
703  *
704  * Return 0 on failure and 1 on success.
705  */
706 static int
707 ripencc_get_pps_ts(
708 	struct ripencc_unit *up,
709 	l_fp *tsptr
710 	)
711 {
712 	pps_info_t pps_info;
713 	struct timespec timeout, ts;
714 	double dtemp;
715 	l_fp tstmp;
716 
717 #ifdef DEBUG_PPS
718 	msyslog(LOG_INFO,"ripencc_get_pps_ts");
719 #endif /* DEBUG_PPS */
720 
721 
722 	/*
723 	 * Convert the timespec nanoseconds field to ntp l_fp units.
724 	 */
725 	if (up->handle == 0)
726 		return (0);
727 	timeout.tv_sec = 0;
728 	timeout.tv_nsec = 0;
729 	memcpy(&pps_info, &up->pps_info, sizeof(pps_info_t));
730 	if (time_pps_fetch(up->handle, PPS_TSFMT_TSPEC, &up->pps_info,
731 			   &timeout) < 0)
732 		return (0);
733 	if (up->pps_params.mode & PPS_CAPTUREASSERT) {
734 		if (pps_info.assert_sequence ==
735 		    up->pps_info.assert_sequence)
736 			return (0);
737 		ts = up->pps_info.assert_timestamp;
738 	} else if (up->pps_params.mode & PPS_CAPTURECLEAR) {
739 		if (pps_info.clear_sequence ==
740 		    up->pps_info.clear_sequence)
741 			return (0);
742 		ts = up->pps_info.clear_timestamp;
743 	} else {
744 		return (0);
745 	}
746 	if ((up->ts.tv_sec == ts.tv_sec) && (up->ts.tv_nsec == ts.tv_nsec))
747 		return (0);
748 	up->ts = ts;
749 
750 	tstmp.l_ui = ts.tv_sec + JAN_1970;
751 	dtemp = ts.tv_nsec * FRAC / 1e9;
752 	tstmp.l_uf = (u_int32)dtemp;
753 
754 #ifdef DEBUG_PPS
755 	msyslog(LOG_INFO,"ts.tv_sec: %d",(int)ts.tv_sec);
756 	msyslog(LOG_INFO,"ts.tv_nsec: %ld",ts.tv_nsec);
757 #endif /* DEBUG_PPS */
758 
759 	*tsptr = tstmp;
760 	return (1);
761 }
762 
763 /*
764  * ripencc_shutdown - shut down a GPS clock
765  */
766 static void
767 ripencc_shutdown(int unit, struct peer *peer)
768 {
769 	register struct ripencc_unit *up;
770 	struct refclockproc *pp;
771 
772 	pp = peer->procptr;
773 	up = pp->unitptr;
774 
775 	if (up != NULL) {
776 		if (up->handle != 0)
777 			time_pps_destroy(up->handle);
778 		free(up);
779 	}
780 	if (-1 != pp->io.fd)
781 		io_closeclock(&pp->io);
782 
783 	return;
784 }
785 
786 /*
787  * ripencc_poll - called by the transmit procedure
788  */
789 static void
790 ripencc_poll(int unit, struct peer *peer)
791 {
792 	register struct ripencc_unit *up;
793 	struct refclockproc *pp;
794 	TSIPPKT spt;
795 
796 #ifdef DEBUG_NCC
797 	if (debug)
798 		fprintf(stderr, "ripencc_poll(%d)\n", unit);
799 #endif /* DEBUG_NCC */
800 	pp = peer->procptr;
801 	up = pp->unitptr;
802 	if (up->pollcnt == 0)
803 		refclock_report(peer, CEVNT_TIMEOUT);
804 	else
805 		up->pollcnt--;
806 
807 	pp->polls++;
808 	up->polled = 1;
809 
810 	/* poll for UTC superpacket */
811 	cmd_0x8EADq (&spt);
812 	ripencc_send(peer,spt);
813 }
814 
815 /*
816  * ripencc_send - send message to clock
817  * use the structures being created by the trimble functions!
818  * makes the code more readable/clean
819  */
820 static void
821 ripencc_send(struct peer *peer, TSIPPKT spt)
822 {
823 	unsigned char *ip, *op;
824 	unsigned char obuf[512];
825 
826 #ifdef DEBUG_RAW
827 	{
828 		register struct ripencc_unit *up;
829 		register struct refclockproc *pp;
830 
831 		pp = peer->procptr;
832 		up = pp->unitptr;
833 		if (debug)
834 			printf("ripencc_send(%d, %02X)\n", up->unit, cmd);
835 	}
836 #endif /* DEBUG_RAW */
837 
838 	ip = spt.buf;
839 	op = obuf;
840 
841 	*op++ = 0x10;
842 	*op++ = spt.code;
843 
844 	while (spt.len--) {
845 		if (op-obuf > sizeof(obuf)-5) {
846 			msyslog(LOG_ERR, "ripencc_send obuf overflow!");
847 			refclock_report(peer, CEVNT_FAULT);
848 			return;
849 		}
850 
851 		if (*ip == 0x10) /* byte stuffing */
852 			*op++ = 0x10;
853 		*op++ = *ip++;
854 	}
855 
856 	*op++ = 0x10;
857 	*op++ = 0x03;
858 
859 #ifdef DEBUG_RAW
860 	if (debug) { /* print raw packet */
861 		unsigned char *cp;
862 		int i;
863 
864 		printf("ripencc_send: len %d\n", op-obuf);
865 		for (i=1, cp=obuf; cp<op; i++, cp++) {
866 			printf(" %02X", *cp);
867 			if (i%10 == 0)
868 				printf("\n");
869 		}
870 		printf("\n");
871 	}
872 #endif /* DEBUG_RAW */
873 
874 	if (write(peer->procptr->io.fd, obuf, op-obuf) == -1) {
875 		refclock_report(peer, CEVNT_FAULT);
876 	}
877 }
878 
879 /*
880  * ripencc_receive()
881  *
882  * called when a packet is received on the serial port
883  * takes care of further processing
884  *
885  */
886 static void
887 ripencc_receive(struct recvbuf *rbufp)
888 {
889 	register struct ripencc_unit *up;
890 	register struct refclockproc *pp;
891 	struct peer *peer;
892 	static TSIPPKT rpt;	/* for current incoming TSIP report */
893 	TSIPPKT spt;		/* send packet */
894 	int ns_since_pps;
895 	int i;
896 	char *cp;
897 	/* these variables hold data until we decide it's worth keeping */
898 	char    rd_lastcode[BMAX];
899 	l_fp    rd_tmp;
900 	u_short rd_lencode;
901 
902 	/* msyslog(LOG_INFO, "%s",__FUNCTION__); */
903 
904 	/*
905 	 * Initialize pointers and read the timecode and timestamp
906 	 */
907 	peer = rbufp->recv_peer;
908 	pp = peer->procptr;
909 	up = pp->unitptr;
910 	rd_lencode = refclock_gtlin(rbufp, rd_lastcode, BMAX, &rd_tmp);
911 
912 #ifdef DEBUG_RAW
913 	if (debug)
914 		fprintf(stderr, "ripencc_receive(%d)\n", up->unit);
915 #endif /* DEBUG_RAW */
916 
917 #ifdef DEBUG_RAW
918 	if (debug) {		/* print raw packet */
919 		int i;
920 		unsigned char *cp;
921 
922 		printf("ripencc_receive: len %d\n", rbufp->recv_length);
923 		for (i=1, cp=(char*)&rbufp->recv_space;
924 		     i <= rbufp->recv_length;
925 		     i++, cp++) {
926 			printf(" %02X", *cp);
927 			if (i%10 == 0)
928 				printf("\n");
929 		}
930 		printf("\n");
931 	}
932 #endif /* DEBUG_RAW */
933 
934 	cp = (char*) &rbufp->recv_space;
935 	i=rbufp->recv_length;
936 
937 	while (i--) {		/* loop over received chars */
938 
939 		tsip_input_proc(&rpt, (unsigned char) *cp++);
940 
941 		if (rpt.status != TSIP_PARSED_FULL)
942 			continue;
943 
944 		switch (rpt.code) {
945 
946 		    case 0x8F:	/* superpacket */
947 
948 			switch (rpt.buf[0]) {
949 
950 			    case 0xAD:	/* UTC Time */
951 				/*
952 				** When polling on port B the timecode is
953 				** the time of the previous PPS.  If we
954 				** completed receiving the packet less than
955 				** 150ms after the turn of the second, it
956 				** may have the code of the previous second.
957 				** We do not trust that and simply poll
958 				** again without even parsing it.
959 				**
960 				** More elegant would be to re-schedule the
961 				** poll, but I do not know (yet) how to do
962 				** that cleanly.
963 				**
964 				*/
965 				/* BLA ns_since_pps = ncc_tstmp(rbufp, &trtmp); */
966 /*   if (up->polled && ns_since_pps > -1 && ns_since_pps < 150) { */
967 
968 				ns_since_pps = 200;
969 				if (up->polled && ns_since_pps < 150) {
970 					msyslog(LOG_INFO, "%s(): up->polled",
971 						__FUNCTION__);
972 					ripencc_poll(up->unit, peer);
973 					break;
974 				}
975 
976 			        /*
977  				 * Parse primary utc time packet
978 				 * and fill refclock structure
979 				 * from results.
980 				 */
981 				if (parse0x8FAD(&rpt, peer) < 0) {
982 					msyslog(LOG_INFO, "%s(): parse0x8FAD < 0",__FUNCTION__);
983 					refclock_report(peer, CEVNT_BADREPLY);
984 					break;
985 				}
986 				/*
987 				 * If the PPSAPI is working, rather use its
988 				 * timestamps.
989 				 * assume that the PPS occurs on the second
990 				 * so blow any msec
991 				 */
992 				if (ripencc_get_pps_ts(up, &rd_tmp) == 1) {
993 					pp->lastrec = up->tstamp = rd_tmp;
994 					pp->nsec = 0;
995 				}
996 				else
997 					msyslog(LOG_INFO, "%s(): ripencc_get_pps_ts returns failure",__FUNCTION__);
998 
999 
1000 				if (!up->polled) {
1001 					msyslog(LOG_INFO, "%s(): unrequested packet",__FUNCTION__);
1002 					/* unrequested packet */
1003 					break;
1004 				}
1005 
1006 				/* we have been polled ! */
1007 				up->polled = 0;
1008 				up->pollcnt = 2;
1009 
1010 				/* poll for next packet */
1011 				cmd_0x8E0Bq(&spt);
1012 				ripencc_send(peer,spt);
1013 
1014 				if (ns_since_pps < 0) { /* no PPS */
1015 					msyslog(LOG_INFO, "%s(): ns_since_pps < 0",__FUNCTION__);
1016 					refclock_report(peer, CEVNT_BADTIME);
1017 					break;
1018 				}
1019 
1020 				/*
1021 				** Process the new sample in the median
1022 				** filter and determine the reference clock
1023 				** offset and dispersion.
1024 				*/
1025 				if (!refclock_process(pp)) {
1026 					msyslog(LOG_INFO, "%s(): !refclock_process",__FUNCTION__);
1027 					refclock_report(peer, CEVNT_BADTIME);
1028 					break;
1029 				}
1030 
1031 				refclock_receive(peer);
1032 				break;
1033 
1034 			    case 0x0B: /* comprehensive time packet */
1035 				parse0x8F0B(&rpt, peer);
1036 				break;
1037 
1038 			    default: /* other superpackets */
1039 #ifdef DEBUG_NCC
1040 				msyslog(LOG_INFO, "%s(): calling parseany",
1041 					__FUNCTION__);
1042 #endif /* DEBUG_NCC */
1043 #ifdef TRIMBLE_OUTPUT_FUNC
1044 				parseany(&rpt, peer);
1045 #endif /* TRIMBLE_OUTPUT_FUNC */
1046 				break;
1047 			}
1048 			break;
1049 
1050 		    case 0x4F:	/* UTC parameters, for leap info */
1051 			parse0x4F(&rpt, peer);
1052 			break;
1053 
1054 		    case 0x5C:	/* sat tracking data */
1055 			parse0x5C(&rpt, peer);
1056 			break;
1057 
1058 		    default:	/* other packets */
1059 #ifdef TRIMBLE_OUTPUT_FUNC
1060 			parseany(&rpt, peer);
1061 #endif /* TRIMBLE_OUTPUT_FUNC */
1062 			break;
1063 		}
1064    		rpt.status = TSIP_PARSED_EMPTY;
1065 	}
1066 }
1067 
1068 /*
1069  * All trimble functions that are directly referenced from driver code
1070  * (so not from parseany)
1071  */
1072 
1073 /* request software versions */
1074 void
1075 cmd_0x1F(
1076 	 TSIPPKT *cmd
1077 	 )
1078 {
1079 	cmd->len = 0;
1080 	cmd->code = 0x1F;
1081 }
1082 
1083 /* request receiver health */
1084 void
1085 cmd_0x26(
1086 	 TSIPPKT *cmd
1087 	 )
1088 {
1089 	cmd->len = 0;
1090 	cmd->code = 0x26;
1091 }
1092 
1093 /* request UTC params */
1094 void
1095 cmd_0x2F(
1096 	 TSIPPKT *cmd
1097 	 )
1098 {
1099 	cmd->len = 0;
1100 	cmd->code = 0x2F;
1101 }
1102 
1103 /* set serial I/O options */
1104 void
1105 cmd_0x35s(
1106 	 TSIPPKT *cmd,
1107 	 unsigned char pos_code,
1108 	 unsigned char vel_code,
1109 	 unsigned char time_code,
1110 	 unsigned char opts_code
1111 	 )
1112 {
1113 	cmd->buf[0] = pos_code;
1114 	cmd->buf[1] = vel_code;
1115 	cmd->buf[2] = time_code;
1116 	cmd->buf[3] = opts_code;
1117 	cmd->len = 4;
1118 	cmd->code = 0x35;
1119 }
1120 
1121 /* request tracking status */
1122 void
1123 cmd_0x3C(
1124 	 TSIPPKT *cmd,
1125 	 unsigned char sv_prn
1126 	 )
1127 {
1128 	cmd->buf[0] = sv_prn;
1129 	cmd->len = 1;
1130 	cmd->code = 0x3C;
1131 }
1132 
1133 /* set Channel A configuration for dual-port operation */
1134 void
1135 cmd_0x3Ds(
1136 	  TSIPPKT *cmd,
1137 	  unsigned char baud_out,
1138 	  unsigned char baud_inp,
1139 	  unsigned char char_code,
1140 	  unsigned char stopbitcode,
1141 	  unsigned char output_mode,
1142 	  unsigned char input_mode
1143 	  )
1144 {
1145 	cmd->buf[0] = baud_out;		/* XMT baud rate */
1146 	cmd->buf[1] = baud_inp;		/* RCV baud rate */
1147 	cmd->buf[2] = char_code;	/* parity and #bits per byte */
1148 	cmd->buf[3] = stopbitcode;	/* number of stop bits code */
1149 	cmd->buf[4] = output_mode;	/* Ch. A transmission mode */
1150 	cmd->buf[5] = input_mode;	/* Ch. A reception mode */
1151 	cmd->len = 6;
1152 	cmd->code = 0x3D;
1153 }
1154 
1155 
1156 /* query primary configuration */
1157 void
1158 cmd_0xBBq(
1159 	  TSIPPKT *cmd,
1160 	  unsigned char subcode
1161 	  )
1162 {
1163 	cmd->len = 1;
1164 	cmd->code = 0xBB;
1165 	cmd->buf[0] = subcode;
1166 }
1167 
1168 
1169 /**** Superpackets ****/
1170 /* 8E-0B to query 8F-0B controls */
1171 void
1172 cmd_0x8E0Bq(
1173 	    TSIPPKT *cmd
1174 	    )
1175 {
1176 	cmd->len = 1;
1177 	cmd->code = 0x8E;
1178 	cmd->buf[0] = 0x0B;
1179 }
1180 
1181 
1182 /* 8F-41 to query board serial number */
1183 void
1184 cmd_0x8E41q(
1185 	    TSIPPKT *cmd
1186 	    )
1187 {
1188 	cmd->len = 1;
1189 	cmd->code = 0x8E;
1190 	cmd->buf[0] = 0x41;
1191 }
1192 
1193 
1194 /* 8F-42 to query product serial number */
1195 void
1196 cmd_0x8E42q(
1197 	    TSIPPKT *cmd
1198 	    )
1199 {
1200 	cmd->len = 1;
1201 	cmd->code = 0x8E;
1202 	cmd->buf[0] = 0x42;
1203 }
1204 
1205 
1206 /* 8F-4A to query PPS parameters */
1207 void
1208 cmd_0x8E4Aq(
1209 	    TSIPPKT *cmd
1210 	    )
1211 {
1212 	cmd->len = 1;
1213 	cmd->code = 0x8E;
1214 	cmd->buf[0] = 0x4A;
1215 }
1216 
1217 
1218 /* set i/o options */
1219 void
1220 cmd_0x8E4As(
1221 	    TSIPPKT *cmd,
1222 	    unsigned char PPSOnOff,
1223 	    unsigned char TimeBase,
1224 	    unsigned char Polarity,
1225 	    double PPSOffset,
1226 	    float Uncertainty
1227 	    )
1228 {
1229 	cmd->len = 16;
1230 	cmd->code = 0x8E;
1231 	cmd->buf[0] = 0x4A;
1232 	cmd->buf[1] = PPSOnOff;
1233 	cmd->buf[2] = TimeBase;
1234 	cmd->buf[3] = Polarity;
1235 	bPutDouble (&PPSOffset, &cmd->buf[4]);
1236 	bPutFloat (&Uncertainty, &cmd->buf[12]);
1237 }
1238 
1239 /* 8F-4B query survey limit */
1240 void
1241 cmd_0x8E4Bq(
1242 	    TSIPPKT *cmd
1243 	    )
1244 {
1245 	cmd->len = 1;
1246 	cmd->code = 0x8E;
1247 	cmd->buf[0] = 0x4B;
1248 }
1249 
1250 /* poll for UTC superpacket */
1251 /* 8E-AD to query 8F-AD controls */
1252 void
1253 cmd_0x8EADq(
1254 	    TSIPPKT *cmd
1255 	    )
1256 {
1257 	cmd->len = 1;
1258 	cmd->code = 0x8E;
1259 	cmd->buf[0] = 0xAD;
1260 }
1261 
1262 /* all outomatic packet output off */
1263 void
1264 cmd_0x8E4Ds(
1265 	    TSIPPKT *cmd,
1266 	    unsigned long AutoOutputMask
1267 	    )
1268 {
1269 	cmd->len = 5;
1270 	cmd->code = 0x8E;
1271 	cmd->buf[0] = 0x4D;
1272 	bPutULong (&AutoOutputMask, &cmd->buf[1]);
1273 }
1274 
1275 
1276 /*
1277  * for DOS machines, reverse order of bytes as they come through the
1278  * serial port.
1279  */
1280 #ifdef BYTESWAP
1281 static short
1282 bGetShort(
1283 	  unsigned char *bp
1284 	  )
1285 {
1286 	short outval;
1287 	unsigned char *optr;
1288 
1289 	optr = (unsigned char*)&outval + 1;
1290 	*optr-- = *bp++;
1291 	*optr = *bp;
1292 	return outval;
1293 }
1294 
1295 #ifdef TRIMBLE_OUTPUT_FUNC
1296 static unsigned short
1297 bGetUShort(
1298 	   unsigned char *bp
1299 	   )
1300 {
1301 	unsigned short outval;
1302 	unsigned char *optr;
1303 
1304 	optr = (unsigned char*)&outval + 1;
1305 	*optr-- = *bp++;
1306 	*optr = *bp;
1307 	return outval;
1308 }
1309 
1310 static long
1311 bGetLong(
1312 	 unsigned char *bp
1313 	 )
1314 {
1315 	long outval;
1316 	unsigned char *optr;
1317 
1318 	optr = (unsigned char*)&outval + 3;
1319 	*optr-- = *bp++;
1320 	*optr-- = *bp++;
1321 	*optr-- = *bp++;
1322 	*optr = *bp;
1323 	return outval;
1324 }
1325 
1326 static unsigned long
1327 bGetULong(
1328 	  unsigned char *bp
1329 	  )
1330 {
1331 	unsigned long outval;
1332 	unsigned char *optr;
1333 
1334 	optr = (unsigned char*)&outval + 3;
1335 	*optr-- = *bp++;
1336 	*optr-- = *bp++;
1337 	*optr-- = *bp++;
1338 	*optr = *bp;
1339 	return outval;
1340 }
1341 #endif /* TRIMBLE_OUTPUT_FUNC */
1342 
1343 static float
1344 bGetSingle(
1345 	   unsigned char *bp
1346 	   )
1347 {
1348 	float outval;
1349 	unsigned char *optr;
1350 
1351 	optr = (unsigned char*)&outval + 3;
1352 	*optr-- = *bp++;
1353 	*optr-- = *bp++;
1354 	*optr-- = *bp++;
1355 	*optr = *bp;
1356 	return outval;
1357 }
1358 
1359 static double
1360 bGetDouble(
1361 	   unsigned char *bp
1362 	   )
1363 {
1364 	double outval;
1365 	unsigned char *optr;
1366 
1367 	optr = (unsigned char*)&outval + 7;
1368 	*optr-- = *bp++;
1369 	*optr-- = *bp++;
1370 	*optr-- = *bp++;
1371 	*optr-- = *bp++;
1372 	*optr-- = *bp++;
1373 	*optr-- = *bp++;
1374 	*optr-- = *bp++;
1375 	*optr = *bp;
1376 	return outval;
1377 }
1378 
1379 #else /* not BYTESWAP */
1380 
1381 #define bGetShort(bp) 	(*(short*)(bp))
1382 #define bGetLong(bp) 	(*(long*)(bp))
1383 #define bGetULong(bp) 	(*(unsigned long*)(bp))
1384 #define bGetSingle(bp) 	(*(float*)(bp))
1385 #define bGetDouble(bp)	(*(double*)(bp))
1386 
1387 #endif /* BYTESWAP */
1388 /*
1389  * Byte-reversal is necessary for little-endian (Intel-based) machines.
1390  * TSIP streams are Big-endian (Motorola-based).
1391  */
1392 #ifdef BYTESWAP
1393 
1394 void
1395 bPutFloat(
1396 	  float *in,
1397 	  unsigned char *out
1398 	  )
1399 {
1400 	unsigned char *inptr;
1401 
1402 	inptr = (unsigned char*)in + 3;
1403 	*out++ = *inptr--;
1404 	*out++ = *inptr--;
1405 	*out++ = *inptr--;
1406 	*out = *inptr;
1407 }
1408 
1409 static void
1410 bPutULong(
1411 	  unsigned long *in,
1412 	  unsigned char *out
1413 	  )
1414 {
1415 	unsigned char *inptr;
1416 
1417 	inptr = (unsigned char*)in + 3;
1418 	*out++ = *inptr--;
1419 	*out++ = *inptr--;
1420 	*out++ = *inptr--;
1421 	*out = *inptr;
1422 }
1423 
1424 static void
1425 bPutDouble(
1426 	   double *in,
1427 	   unsigned char *out
1428 	   )
1429 {
1430 	unsigned char *inptr;
1431 
1432 	inptr = (unsigned char*)in + 7;
1433 	*out++ = *inptr--;
1434 	*out++ = *inptr--;
1435 	*out++ = *inptr--;
1436 	*out++ = *inptr--;
1437 	*out++ = *inptr--;
1438 	*out++ = *inptr--;
1439 	*out++ = *inptr--;
1440 	*out = *inptr;
1441 }
1442 
1443 #else	/* not BYTESWAP */
1444 
1445 void bPutShort (short a, unsigned char *cmdbuf) {*(short*) cmdbuf = a;}
1446 void bPutULong (long a, unsigned char *cmdbuf) 	{*(long*) cmdbuf = a;}
1447 void bPutFloat (float a, unsigned char *cmdbuf) {*(float*) cmdbuf = a;}
1448 void bPutDouble (double a, unsigned char *cmdbuf){*(double*) cmdbuf = a;}
1449 
1450 #endif /* BYTESWAP */
1451 
1452 /*
1453  * Parse primary utc time packet
1454  * and fill refclock structure
1455  * from results.
1456  *
1457  * 0 = success
1458  * -1 = errors
1459  */
1460 
1461 static int
1462 parse0x8FAD(
1463 	    TSIPPKT *rpt,
1464 	    struct peer *peer
1465 	    )
1466 {
1467 	register struct refclockproc *pp;
1468 	register struct ripencc_unit *up;
1469 
1470 	unsigned day, month, year;	/* data derived from received timecode */
1471 	unsigned hour, minute, second;
1472 	unsigned char trackstat, utcflags;
1473 
1474    	static char logbuf[1024];	/* logging string buffer */
1475 	int i;
1476 	unsigned char *buf;
1477 
1478 	buf = rpt->buf;
1479 	pp = peer->procptr;
1480 
1481 	if (rpt->len != 22)
1482 		return (-1);
1483 
1484 	if (bGetShort(&buf[1]) != 0) {
1485 #ifdef DEBUG_NCC
1486 		if (debug)
1487 			printf("parse0x8FAD: event count != 0\n");
1488 #endif /* DEBUG_NCC */
1489 		return(-1);
1490 	}
1491 
1492 	if (bGetDouble(&buf[3]) != 0.0) {
1493 #ifdef DEBUG_NCC
1494 		if (debug)
1495 			printf("parse0x8FAD: fracsecs != 0\n");
1496 #endif /* DEBUG_NCC */
1497 		return(-1);
1498 	}
1499 
1500 	hour =		(unsigned int) buf[11];
1501 	minute =	(unsigned int) buf[12];
1502 	second =	(unsigned int) buf[13];
1503 	day =		(unsigned int) buf[14];
1504 	month =		(unsigned int) buf[15];
1505 	year =		bGetShort(&buf[16]);
1506 	trackstat =	buf[18];
1507 	utcflags =	buf[19];
1508 
1509 
1510 	sprintf(logbuf, "U1 %d.%d.%d %02d:%02d:%02d %d %02x",
1511 		day, month, year, hour, minute, second, trackstat, utcflags);
1512 
1513 #ifdef DEBUG_NCC
1514 	if (debug)
1515    		puts(logbuf);
1516 #endif /* DEBUG_NCC */
1517 
1518 	record_clock_stats(&peer->srcadr, logbuf);
1519 
1520 	if (!utcflags & UTCF_UTC_AVAIL)
1521 		return(-1);
1522 
1523 	/* poll for UTC parameters once and then if UTC flag changed */
1524 	up = (struct ripencc_unit *) pp->unitptr;
1525 	if (utcflags != up->utcflags) {
1526 		TSIPPKT spt;	/* local structure for send packet */
1527 		cmd_0x2F (&spt); /* request UTC params */
1528 		ripencc_send(peer,spt);
1529 		up->utcflags = utcflags;
1530 	}
1531 
1532 	/*
1533 	 * If we hit the leap second, we choose to skip this sample
1534 	 * rather than rely on other code to be perfectly correct.
1535 	 * No offense, just defense ;-).
1536 	 */
1537 	if (second == 60)
1538 		return(-1);
1539 
1540 	/* now check and convert the time we received */
1541 
1542 	pp->year = year;
1543 	if (month < 1 || month > 12 || day < 1 || day > 31)
1544 		return(-1);
1545 
1546 	if (pp->year % 4) {	/* XXX: use is_leapyear() ? */
1547 		if (day > day1tab[month - 1])
1548 			return(-1);
1549 		for (i = 0; i < month - 1; i++)
1550 			day += day1tab[i];
1551 	} else {
1552 		if (day > day2tab[month - 1])
1553 			return(-1);
1554 		for (i = 0; i < month - 1; i++)
1555 			day += day2tab[i];
1556 	}
1557 	pp->day = day;
1558 	pp->hour = hour;
1559 	pp->minute = minute;
1560 	pp-> second = second;
1561 	pp->nsec = 0;
1562 
1563 	if ((utcflags&UTCF_LEAP_PNDG) && up->leapdelta != 0)
1564 		pp-> leap = (up->leapdelta > 0)
1565 		    ? LEAP_ADDSECOND
1566 		    : LEAP_DELSECOND;
1567 	else
1568 		pp-> leap = LEAP_NOWARNING;
1569 
1570 	return (0);
1571 }
1572 
1573 /*
1574  * Parse comprehensive time packet
1575  *
1576  *  0 = success
1577  * -1 = errors
1578  */
1579 
1580 int
1581 parse0x8F0B(
1582 	    TSIPPKT *rpt,
1583 	    struct peer *peer
1584 	    )
1585 {
1586 	register struct refclockproc *pp;
1587 
1588 	unsigned day, month, year;	/* data derived from received timecode */
1589 	unsigned hour, minute, second;
1590 	unsigned utcoff;
1591 	unsigned char mode;
1592 	double  bias, rate;
1593 	float biasunc, rateunc;
1594 	double lat, lon, alt;
1595 	short lat_deg, lon_deg;
1596 	float lat_min, lon_min;
1597 	unsigned char north_south, east_west;
1598 	char sv[9];
1599 
1600    	static char logbuf[1024];	/* logging string buffer */
1601 	unsigned char b;
1602 	int i;
1603 	unsigned char *buf;
1604 	double tow;
1605 
1606 	buf = rpt->buf;
1607 	pp = peer->procptr;
1608 
1609 	if (rpt->len != 74)
1610 		return (-1);
1611 
1612 	if (bGetShort(&buf[1]) != 0)
1613 		return(-1);;
1614 
1615 	tow =  bGetDouble(&buf[3]);
1616 
1617 	if (tow == -1.0) {
1618 		return(-1);
1619 	}
1620 	else if ((tow >= 604800.0) || (tow < 0.0)) {
1621 		return(-1);
1622 	}
1623 	else
1624 	{
1625 		if (tow < 604799.9) tow = tow + .00000001;
1626 		second = (unsigned int) fmod(tow, 60.);
1627 		minute =  (unsigned int) fmod(tow/60., 60.);
1628 		hour = (unsigned int )fmod(tow / 3600., 24.);
1629 	}
1630 
1631 	day =		(unsigned int) buf[11];
1632 	month =		(unsigned int) buf[12];
1633 	year =		bGetShort(&buf[13]);
1634 	mode =		buf[15];
1635 	utcoff =	bGetShort(&buf[16]);
1636 	bias = 		bGetDouble(&buf[18]) / GPS_C * 1e9;	/* ns */
1637 	rate = 		bGetDouble(&buf[26]) / GPS_C * 1e9;	/* ppb */
1638 	biasunc = 	bGetSingle(&buf[34]) / GPS_C * 1e9;	/* ns */
1639 	rateunc = 	bGetSingle(&buf[38]) / GPS_C * 1e9;	/* ppb */
1640 	lat = 		bGetDouble(&buf[42]) * R2D;
1641 	lon = 		bGetDouble(&buf[50]) * R2D;
1642 	alt = 		bGetDouble(&buf[58]);
1643 
1644 	if (lat < 0.0) {
1645 		north_south = 'S';
1646 		lat = -lat;
1647 	}
1648 	else {
1649 		north_south = 'N';
1650 	}
1651 	lat_deg = (short)lat;
1652 	lat_min = (lat - lat_deg) * 60.0;
1653 
1654 	if (lon < 0.0) {
1655 		east_west = 'W';
1656 		lon = -lon;
1657 	}
1658 	else {
1659 		east_west = 'E';
1660 	}
1661 
1662 	lon_deg = (short)lon;
1663 	lon_min = (lon - lon_deg) * 60.0;
1664 
1665 	for (i=0; i<8; i++) {
1666 		sv[i] = buf[i + 66];
1667 		if (sv[i]) {
1668 			TSIPPKT spt; /* local structure for sendpacket */
1669 			b = (unsigned char) (sv[i]<0 ? -sv[i] : sv[i]);
1670 			/* request tracking status */
1671 			cmd_0x3C  (&spt, b);
1672 			ripencc_send(peer,spt);
1673 		}
1674 	}
1675 
1676 
1677 	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",
1678 		day, month, year, hour, minute, second, mode, bias, biasunc,
1679 		rate, rateunc, utcoff, lat_deg, lat_min, north_south, lon_deg,
1680 		lon_min, east_west, alt, sv[0], sv[1], sv[2], sv[3], sv[4],
1681 		sv[5], sv[6], sv[7]);
1682 
1683 #ifdef DEBUG_NCC
1684 	if (debug)
1685    		puts(logbuf);
1686 #endif /* DEBUG_NCC */
1687 
1688 	record_clock_stats(&peer->srcadr, logbuf);
1689 
1690 	return (0);
1691 }
1692 
1693 #ifdef TRIMBLE_OUTPUT_FUNC
1694 /*
1695  * Parse any packet using Trimble machinery
1696  */
1697 int
1698 parseany(
1699 	 TSIPPKT *rpt,
1700 	 struct peer *peer
1701 	 )
1702 {
1703    	static char logbuf[1024];	/* logging string buffer */
1704 
1705    	TranslateTSIPReportToText (rpt, logbuf);	/* anything else */
1706 #ifdef DEBUG_NCC
1707 	if (debug)
1708    		puts(&logbuf[1]);
1709 #endif /* DEBUG_NCC */
1710 	record_clock_stats(&peer->srcadr, &logbuf[1]);
1711 	return(0);
1712 }
1713 #endif /* TRIMBLE_OUTPUT_FUNC */
1714 
1715 
1716 /*
1717  * Parse UTC Parameter Packet
1718  *
1719  * See the IDE for documentation!
1720  *
1721  * 0 = success
1722  * -1 = errors
1723  */
1724 
1725 int
1726 parse0x4F(
1727 	  TSIPPKT *rpt,
1728 	  struct peer *peer
1729 	  )
1730 {
1731 	register struct ripencc_unit *up;
1732 
1733 	double a0;
1734 	float a1, tot;
1735 	int dt_ls, wn_t, wn_lsf, dn, dt_lsf;
1736 
1737    	static char logbuf[1024];	/* logging string buffer */
1738 	unsigned char *buf;
1739 
1740 	buf = rpt->buf;
1741 
1742 	if (rpt->len != 26)
1743 		return (-1);
1744 	a0 = bGetDouble (buf);
1745 	a1 = bGetSingle (&buf[8]);
1746 	dt_ls = bGetShort (&buf[12]);
1747 	tot = bGetSingle (&buf[14]);
1748 	wn_t = bGetShort (&buf[18]);
1749 	wn_lsf = bGetShort (&buf[20]);
1750 	dn = bGetShort (&buf[22]);
1751 	dt_lsf = bGetShort (&buf[24]);
1752 
1753 	sprintf(logbuf, "L1 %d %d %d %g %g %g %d %d %d",
1754 		dt_lsf - dt_ls, dt_ls, dt_lsf, a0, a1, tot, wn_t, wn_lsf, dn);
1755 
1756 #ifdef DEBUG_NCC
1757 	if (debug)
1758    		puts(logbuf);
1759 #endif /* DEBUG_NCC */
1760 
1761 	record_clock_stats(&peer->srcadr, logbuf);
1762 
1763 	up = (struct ripencc_unit *) peer->procptr->unitptr;
1764 	up->leapdelta = dt_lsf - dt_ls;
1765 
1766 	return (0);
1767 }
1768 
1769 /*
1770  * Parse Tracking Status packet
1771  *
1772  * 0 = success
1773  * -1 = errors
1774  */
1775 
1776 int
1777 parse0x5C(
1778 	  TSIPPKT *rpt,
1779 	  struct peer *peer
1780 	  )
1781 {
1782 	unsigned char prn, channel, aqflag, ephstat;
1783 	float snr, azinuth, elevation;
1784 
1785    	static char logbuf[1024];	/* logging string buffer */
1786 	unsigned char *buf;
1787 
1788 	buf = rpt->buf;
1789 
1790 	if (rpt->len != 24)
1791 		return(-1);
1792 
1793 	prn = buf[0];
1794 	channel = (unsigned char)(buf[1] >> 3);
1795 	if (channel == 0x10)
1796 		channel = 2;
1797 	else
1798 		channel++;
1799 	aqflag = buf[2];
1800 	ephstat = buf[3];
1801 	snr = bGetSingle(&buf[4]);
1802 	elevation = bGetSingle(&buf[12]) * R2D;
1803 	azinuth = bGetSingle(&buf[16]) * R2D;
1804 
1805 	sprintf(logbuf, "S1 %02d %d %d %02x %4.1f %5.1f %4.1f",
1806 		prn, channel, aqflag, ephstat, snr, azinuth, elevation);
1807 
1808 #ifdef DEBUG_NCC
1809 	if (debug)
1810    		puts(logbuf);
1811 #endif /* DEBUG_NCC */
1812 
1813 	record_clock_stats(&peer->srcadr, logbuf);
1814 
1815 	return (0);
1816 }
1817 
1818 /******* Code below is from Trimble Tsipchat *************/
1819 
1820 /*
1821  * *************************************************************************
1822  *
1823  * Trimble Navigation, Ltd.
1824  * OEM Products Development Group
1825  * P.O. Box 3642
1826  * 645 North Mary Avenue
1827  * Sunnyvale, California 94088-3642
1828  *
1829  * Corporate Headquarter:
1830  *    Telephone:  (408) 481-8000
1831  *    Fax:        (408) 481-6005
1832  *
1833  * Technical Support Center:
1834  *    Telephone:  (800) 767-4822	(U.S. and Canada)
1835  *                (408) 481-6940    (outside U.S. and Canada)
1836  *    Fax:        (408) 481-6020
1837  *    BBS:        (408) 481-7800
1838  *    e-mail:     trimble_support@trimble.com
1839  *		ftp://ftp.trimble.com/pub/sct/embedded/bin
1840  *
1841  * *************************************************************************
1842  *
1843  * -------  BYTE-SWAPPING  -------
1844  * TSIP is big-endian (Motorola) protocol.  To use on little-endian (Intel)
1845  * systems, the bytes of all multi-byte types (shorts, floats, doubles, etc.)
1846  * must be reversed.  This is controlled by the MACRO BYTESWAP; if defined, it
1847  * assumes little-endian protocol.
1848  * --------------------------------
1849  *
1850  * T_PARSER.C and T_PARSER.H contains primitive functions that interpret
1851  * reports received from the receiver.  A second source file pair,
1852  * T_FORMAT.C and T_FORMAT.H, contin the matching TSIP command formatters.
1853  *
1854  * The module is in very portable, basic C language.  It can be used as is, or
1855  * with minimal changes if a TSIP communications application is needed separate
1856  * from TSIPCHAT. The construction of most argument lists avoid the use of
1857  * structures, but the developer is encouraged to reconstruct them using such
1858  * definitions to meet project requirements.  Declarations of T_PARSER.C
1859  * functions are included in T_PARSER.H to provide prototyping definitions.
1860  *
1861  * There are two types of functions: a serial input processing routine,
1862  *                            tsip_input_proc()
1863  * which assembles incoming bytes into a TSIPPKT structure, and the
1864  * report parsers, rpt_0x??().
1865  *
1866  * 1) The function tsip_input_proc() accumulates bytes from the receiver,
1867  * strips control bytes (DLE), and checks if the report end sequence (DLE ETX)
1868  * has been received.  rpt.status is defined as TSIP_PARSED_FULL (== 1)
1869  * if a complete packet is available.
1870  *
1871  * 2) The functions rpt_0x??() are report string interpreters patterned after
1872  * the document called "Trimble Standard Interface Protocol".  It should be
1873  * noted that if the report buffer is sent into the receiver with the wrong
1874  * length (byte count), the rpt_0x??() returns the Boolean equivalence for
1875  * TRUE.
1876  *
1877  * *************************************************************************
1878  *
1879  */
1880 
1881 
1882 /*
1883  * reads bytes until serial buffer is empty or a complete report
1884  * has been received; end of report is signified by DLE ETX.
1885  */
1886 static void
1887 tsip_input_proc(
1888 		TSIPPKT *rpt,
1889 		int inbyte
1890 		)
1891 {
1892 	unsigned char newbyte;
1893 
1894 	if (inbyte < 0 || inbyte > 0xFF) return;
1895 
1896 	newbyte = (unsigned char)(inbyte);
1897 	switch (rpt->status)
1898 	{
1899 	    case TSIP_PARSED_DLE_1:
1900 		switch (newbyte)
1901 		{
1902 		    case 0:
1903 		    case ETX:
1904 			/* illegal TSIP IDs */
1905 			rpt->len = 0;
1906 			rpt->status = TSIP_PARSED_EMPTY;
1907 			break;
1908 		    case DLE:
1909 			/* try normal message start again */
1910 			rpt->len = 0;
1911 			rpt->status = TSIP_PARSED_DLE_1;
1912 			break;
1913 		    default:
1914 			/* legal TSIP ID; start message */
1915 			rpt->code = newbyte;
1916 			rpt->len = 0;
1917 			rpt->status = TSIP_PARSED_DATA;
1918 			break;
1919 		}
1920 		break;
1921 	    case TSIP_PARSED_DATA:
1922 		switch (newbyte) {
1923 		    case DLE:
1924 			/* expect DLE or ETX next */
1925 			rpt->status = TSIP_PARSED_DLE_2;
1926 			break;
1927 		    default:
1928 			/* normal data byte  */
1929 			rpt->buf[rpt->len] = newbyte;
1930 			rpt->len++;
1931 			/* no change in rpt->status */
1932 			break;
1933 		}
1934 		break;
1935 	    case TSIP_PARSED_DLE_2:
1936 		switch (newbyte) {
1937 		    case DLE:
1938 			/* normal data byte */
1939 			rpt->buf[rpt->len] = newbyte;
1940 			rpt->len++;
1941 			rpt->status = TSIP_PARSED_DATA;
1942 			break;
1943 		    case ETX:
1944 			/* end of message; return TRUE here. */
1945 			rpt->status = TSIP_PARSED_FULL;
1946 			break;
1947 		    default:
1948 			/* error: treat as TSIP_PARSED_DLE_1; start new report packet */
1949 			rpt->code = newbyte;
1950 			rpt->len = 0;
1951 			rpt->status = TSIP_PARSED_DATA;
1952 		}
1953 		break;
1954 	    case TSIP_PARSED_FULL:
1955 	    case TSIP_PARSED_EMPTY:
1956 	    default:
1957 		switch (newbyte) {
1958 		    case DLE:
1959 			/* normal message start */
1960 			rpt->len = 0;
1961 			rpt->status = TSIP_PARSED_DLE_1;
1962 			break;
1963 		    default:
1964 			/* error: ignore newbyte */
1965 			rpt->len = 0;
1966 			rpt->status = TSIP_PARSED_EMPTY;
1967 		}
1968 		break;
1969 	}
1970 	if (rpt->len > MAX_RPTBUF) {
1971 		/* error: start new report packet */
1972 		rpt->status = TSIP_PARSED_EMPTY;
1973 		rpt->len = 0;
1974 	}
1975 }
1976 
1977 #ifdef TRIMBLE_OUTPUT_FUNC
1978 
1979 /**/
1980 /* Channel A configuration for dual port operation */
1981 short
1982 rpt_0x3D(
1983 	 TSIPPKT *rpt,
1984 	 unsigned char *tx_baud_index,
1985 	 unsigned char *rx_baud_index,
1986 	 unsigned char *char_format_index,
1987 	 unsigned char *stop_bits,
1988 	 unsigned char *tx_mode_index,
1989 	 unsigned char *rx_mode_index
1990 	 )
1991 {
1992 	unsigned char *buf;
1993 	buf = rpt->buf;
1994 
1995 	if (rpt->len != 6) return TRUE;
1996 	*tx_baud_index = buf[0];
1997 	*rx_baud_index = buf[1];
1998 	*char_format_index = buf[2];
1999 	*stop_bits = (unsigned char)((buf[3] == 0x07) ? 1 : 2);
2000 	*tx_mode_index = buf[4];
2001 	*rx_mode_index = buf[5];
2002 	return FALSE;
2003 }
2004 
2005 /**/
2006 /* almanac data for specified satellite */
2007 short
2008 rpt_0x40(
2009 	 TSIPPKT *rpt,
2010 	 unsigned char *sv_prn,
2011 	 short *week_num,
2012 	 float *t_zc,
2013 	 float *eccentricity,
2014 	 float *t_oa,
2015 	 float *i_0,
2016 	 float *OMEGA_dot,
2017 	 float *sqrt_A,
2018 	 float *OMEGA_0,
2019 	 float *omega,
2020 	 float *M_0
2021 	 )
2022 {
2023 	unsigned char *buf;
2024 	buf = rpt->buf;
2025 
2026 	if (rpt->len != 39) return TRUE;
2027 	*sv_prn = buf[0];
2028 	*t_zc = bGetSingle (&buf[1]);
2029 	*week_num = bGetShort (&buf[5]);
2030 	*eccentricity = bGetSingle (&buf[7]);
2031 	*t_oa = bGetSingle (&buf[11]);
2032 	*i_0 = bGetSingle (&buf[15]);
2033 	*OMEGA_dot = bGetSingle (&buf[19]);
2034 	*sqrt_A = bGetSingle (&buf[23]);
2035 	*OMEGA_0 = bGetSingle (&buf[27]);
2036 	*omega = bGetSingle (&buf[31]);
2037 	*M_0 = bGetSingle (&buf[35]);
2038 	return FALSE;
2039 }
2040 
2041 /* GPS time */
2042 short
2043 rpt_0x41(
2044 	 TSIPPKT *rpt,
2045 	 float *time_of_week,
2046 	 float *UTC_offset,
2047 	 short *week_num
2048 	 )
2049 {
2050 	unsigned char *buf;
2051 	buf = rpt->buf;
2052 
2053 	if (rpt->len != 10) return TRUE;
2054 	*time_of_week = bGetSingle (buf);
2055 	*week_num = bGetShort (&buf[4]);
2056 	*UTC_offset = bGetSingle (&buf[6]);
2057 	return FALSE;
2058 }
2059 
2060 /* position in ECEF, single precision */
2061 short
2062 rpt_0x42(
2063 	 TSIPPKT *rpt,
2064 	 float pos_ECEF[3],
2065 	 float *time_of_fix
2066 	 )
2067 {
2068 	unsigned char *buf;
2069 	buf = rpt->buf;
2070 
2071 	if (rpt->len != 16) return TRUE;
2072 	pos_ECEF[0] = bGetSingle (buf);
2073 	pos_ECEF[1]= bGetSingle (&buf[4]);
2074 	pos_ECEF[2]= bGetSingle (&buf[8]);
2075 	*time_of_fix = bGetSingle (&buf[12]);
2076 	return FALSE;
2077 }
2078 
2079 /* velocity in ECEF, single precision */
2080 short
2081 rpt_0x43(
2082 	 TSIPPKT *rpt,
2083 	 float ECEF_vel[3],
2084 	 float *freq_offset,
2085 	 float *time_of_fix
2086 	 )
2087 {
2088 	unsigned char *buf;
2089 	buf = rpt->buf;
2090 
2091 	if (rpt->len != 20) return TRUE;
2092 	ECEF_vel[0] = bGetSingle (buf);
2093 	ECEF_vel[1] = bGetSingle (&buf[4]);
2094 	ECEF_vel[2] = bGetSingle (&buf[8]);
2095 	*freq_offset = bGetSingle (&buf[12]);
2096 	*time_of_fix = bGetSingle (&buf[16]);
2097 	return FALSE;
2098 }
2099 
2100 /* software versions */
2101 short
2102 rpt_0x45(
2103 	 TSIPPKT *rpt,
2104 	 unsigned char *major_nav_version,
2105 	 unsigned char *minor_nav_version,
2106 	 unsigned char *nav_day,
2107 	 unsigned char *nav_month,
2108 	 unsigned char *nav_year,
2109 	 unsigned char *major_dsp_version,
2110 	 unsigned char *minor_dsp_version,
2111 	 unsigned char *dsp_day,
2112 	 unsigned char *dsp_month,
2113 	 unsigned char *dsp_year
2114 	 )
2115 {
2116 	unsigned char *buf;
2117 	buf = rpt->buf;
2118 
2119 	if (rpt->len != 10) return TRUE;
2120 	*major_nav_version = buf[0];
2121 	*minor_nav_version = buf[1];
2122 	*nav_day = buf[2];
2123 	*nav_month = buf[3];
2124 	*nav_year = buf[4];
2125 	*major_dsp_version = buf[5];
2126 	*minor_dsp_version = buf[6];
2127 	*dsp_day = buf[7];
2128 	*dsp_month = buf[8];
2129 	*dsp_year = buf[9];
2130 	return FALSE;
2131 }
2132 
2133 /* receiver health and status */
2134 short
2135 rpt_0x46(
2136 	 TSIPPKT *rpt,
2137 	 unsigned char *status1,
2138 	 unsigned char *status2
2139 	 )
2140 {
2141 	unsigned char *buf;
2142 	buf = rpt->buf;
2143 
2144 	if (rpt->len != 2) return TRUE;
2145 	*status1 = buf[0];
2146 	*status2 = buf[1];
2147 	return FALSE;
2148 }
2149 
2150 /* signal levels for all satellites tracked */
2151 short
2152 rpt_0x47(
2153 	 TSIPPKT *rpt,
2154 	 unsigned char *nsvs,
2155 	 unsigned char *sv_prn,
2156 	 float *snr
2157 	 )
2158 {
2159 	short isv;
2160 	unsigned char *buf;
2161 	buf = rpt->buf;
2162 
2163 	if (rpt->len != 1 + 5*buf[0]) return TRUE;
2164 	*nsvs = buf[0];
2165 	for (isv = 0; isv < (*nsvs); isv++) {
2166 		sv_prn[isv] = buf[5*isv + 1];
2167 		snr[isv] = bGetSingle (&buf[5*isv + 2]);
2168 	}
2169 	return FALSE;
2170 }
2171 
2172 /* GPS system message */
2173 short
2174 rpt_0x48(
2175 	 TSIPPKT *rpt,
2176 	 unsigned char *message
2177 	 )
2178 {
2179 	unsigned char *buf;
2180 	buf = rpt->buf;
2181 
2182 	if (rpt->len != 22) return TRUE;
2183 	memcpy (message, buf, 22);
2184 	message[22] = 0;
2185 	return FALSE;
2186 }
2187 
2188 /* health for all satellites from almanac health page */
2189 short
2190 rpt_0x49(
2191 	 TSIPPKT *rpt,
2192 	 unsigned char *sv_health
2193 	 )
2194 {
2195 	short i;
2196 	unsigned char *buf;
2197 	buf = rpt->buf;
2198 
2199 	if (rpt->len != 32) return TRUE;
2200 	for (i = 0; i < 32; i++) sv_health [i]= buf[i];
2201 	return FALSE;
2202 }
2203 
2204 /* position in lat-lon-alt, single precision */
2205 short
2206 rpt_0x4A(
2207 	 TSIPPKT *rpt,
2208 	 float *lat,
2209 	 float *lon,
2210 	 float *alt,
2211 	 float *clock_bias,
2212 	 float *time_of_fix
2213 	 )
2214 {
2215 	unsigned char *buf;
2216 	buf = rpt->buf;
2217 
2218 	if (rpt->len != 20) return TRUE;
2219 	*lat = bGetSingle (buf);
2220 	*lon = bGetSingle (&buf[4]);
2221 	*alt = bGetSingle (&buf[8]);
2222 	*clock_bias = bGetSingle (&buf[12]);
2223 	*time_of_fix = bGetSingle (&buf[16]);
2224 	return FALSE;
2225 }
2226 
2227 /* reference altitude parameters */
2228 short
2229 rpt_0x4A_2(
2230 	   TSIPPKT *rpt,
2231 	   float *alt,
2232 	   float *dummy,
2233 	   unsigned char *alt_flag
2234 	   )
2235 {
2236 	unsigned char *buf;
2237 
2238 	buf = rpt->buf;
2239 
2240 	if (rpt->len != 9) return TRUE;
2241 	*alt = bGetSingle (buf);
2242 	*dummy = bGetSingle (&buf[4]);
2243 	*alt_flag = buf[8];
2244 	return FALSE;
2245 }
2246 
2247 /* machine ID code, status */
2248 short
2249 rpt_0x4B(
2250 	 TSIPPKT *rpt,
2251 	 unsigned char *machine_id,
2252 	 unsigned char *status3,
2253 	 unsigned char *status4
2254 	 )
2255 {
2256 	unsigned char *buf;
2257 	buf = rpt->buf;
2258 
2259 	if (rpt->len != 3) return TRUE;
2260 	*machine_id = buf[0];
2261 	*status3 = buf[1];
2262 	*status4 = buf[2];
2263 	return FALSE;
2264 }
2265 
2266 /* operating parameters and masks */
2267 short
2268 rpt_0x4C(
2269 	 TSIPPKT *rpt,
2270 	 unsigned char *dyn_code,
2271 	 float *el_mask,
2272 	 float *snr_mask,
2273 	 float *dop_mask,
2274 	 float *dop_switch
2275 	 )
2276 {
2277 	unsigned char *buf;
2278 	buf = rpt->buf;
2279 
2280 	if (rpt->len != 17) return TRUE;
2281 	*dyn_code = buf[0];
2282 	*el_mask = bGetSingle (&buf[1]);
2283 	*snr_mask = bGetSingle (&buf[5]);
2284 	*dop_mask = bGetSingle (&buf[9]);
2285 	*dop_switch = bGetSingle (&buf[13]);
2286 	return FALSE;
2287 }
2288 
2289 /* oscillator offset */
2290 short
2291 rpt_0x4D(
2292 	 TSIPPKT *rpt,
2293 	 float *osc_offset
2294 	 )
2295 {
2296 	unsigned char *buf;
2297 	buf = rpt->buf;
2298 
2299 	if (rpt->len != 4) return TRUE;
2300 	*osc_offset = bGetSingle (buf);
2301 	return FALSE;
2302 }
2303 
2304 /* yes/no response to command to set GPS time */
2305 short
2306 rpt_0x4E(
2307 	 TSIPPKT *rpt,
2308 	 unsigned char *response
2309 	 )
2310 {
2311 	unsigned char *buf;
2312 	buf = rpt->buf;
2313 
2314 	if (rpt->len != 1) return TRUE;
2315 	*response = buf[0];
2316 	return FALSE;
2317 }
2318 
2319 /* UTC data */
2320 short
2321 rpt_0x4F(
2322 	 TSIPPKT *rpt,
2323 	 double *a0,
2324 	 float *a1,
2325 	 float *time_of_data,
2326 	 short *dt_ls,
2327 	 short *wn_t,
2328 	 short *wn_lsf,
2329 	 short *dn,
2330 	 short *dt_lsf
2331 	 )
2332 {
2333 	unsigned char *buf;
2334 	buf = rpt->buf;
2335 
2336 	if (rpt->len != 26) return TRUE;
2337 	*a0 = bGetDouble (buf);
2338 	*a1 = bGetSingle (&buf[8]);
2339 	*dt_ls = bGetShort (&buf[12]);
2340 	*time_of_data = bGetSingle (&buf[14]);
2341 	*wn_t = bGetShort (&buf[18]);
2342 	*wn_lsf = bGetShort (&buf[20]);
2343 	*dn = bGetShort (&buf[22]);
2344 	*dt_lsf = bGetShort (&buf[24]);
2345 	return FALSE;
2346 }
2347 
2348 /**/
2349 /* clock offset and frequency offset in 1-SV (0-D) mode */
2350 short
2351 rpt_0x54(
2352 	 TSIPPKT *rpt,
2353 	 float *clock_bias,
2354 	 float *freq_offset,
2355 	 float *time_of_fix
2356 	 )
2357 {
2358 	unsigned char *buf;
2359 	buf = rpt->buf;
2360 
2361 	if (rpt->len != 12) return TRUE;
2362 	*clock_bias = bGetSingle (buf);
2363 	*freq_offset = bGetSingle (&buf[4]);
2364 	*time_of_fix = bGetSingle (&buf[8]);
2365 	return FALSE;
2366 }
2367 
2368 /* I/O serial options */
2369 short
2370 rpt_0x55(
2371 	 TSIPPKT *rpt,
2372 	 unsigned char *pos_code,
2373 	 unsigned char *vel_code,
2374 	 unsigned char *time_code,
2375 	 unsigned char *aux_code
2376 	 )
2377 {
2378 	unsigned char *buf;
2379 	buf = rpt->buf;
2380 
2381 	if (rpt->len != 4) return TRUE;
2382 	*pos_code = buf[0];
2383 	*vel_code = buf[1];
2384 	*time_code = buf[2];
2385 	*aux_code = buf[3];
2386 	return FALSE;
2387 }
2388 
2389 /* velocity in east-north-up coordinates */
2390 short
2391 rpt_0x56(
2392 	 TSIPPKT *rpt,
2393 	 float vel_ENU[3],
2394 	 float *freq_offset,
2395 	 float *time_of_fix
2396 	 )
2397 {
2398 	unsigned char *buf;
2399 	buf = rpt->buf;
2400 
2401 	if (rpt->len != 20) return TRUE;
2402 	/* east */
2403 	vel_ENU[0] = bGetSingle (buf);
2404 	/* north */
2405 	vel_ENU[1] = bGetSingle (&buf[4]);
2406 	/* up */
2407 	vel_ENU[2] = bGetSingle (&buf[8]);
2408 	*freq_offset = bGetSingle (&buf[12]);
2409 	*time_of_fix = bGetSingle (&buf[16]);
2410 	return FALSE;
2411 }
2412 
2413 /* info about last computed fix */
2414 short
2415 rpt_0x57(
2416 	 TSIPPKT *rpt,
2417 	 unsigned char *source_code,
2418 	 unsigned char *diag_code,
2419 	 short *week_num,
2420 	 float *time_of_fix
2421 	 )
2422 {
2423 	unsigned char *buf;
2424 	buf = rpt->buf;
2425 
2426 	if (rpt->len != 8) return TRUE;
2427 	*source_code = buf[0];
2428 	*diag_code = buf[1];
2429 	*time_of_fix = bGetSingle (&buf[2]);
2430 	*week_num = bGetShort (&buf[6]);
2431 	return FALSE;
2432 }
2433 
2434 /* GPS system data or acknowledgment of GPS system data load */
2435 short
2436 rpt_0x58(
2437 	 TSIPPKT *rpt,
2438 	 unsigned char *op_code,
2439 	 unsigned char *data_type,
2440 	 unsigned char *sv_prn,
2441 	 unsigned char *data_length,
2442 	 unsigned char *data_packet
2443 	 )
2444 {
2445 	unsigned char *buf, *buf4;
2446 	short dl;
2447 	ALM_INFO* alminfo;
2448 	ION_INFO* ioninfo;
2449 	UTC_INFO* utcinfo;
2450 	NAV_INFO* navinfo;
2451 
2452 	buf = rpt->buf;
2453 
2454 	if (buf[0] == 2) {
2455 		if (rpt->len < 4) return TRUE;
2456 		if (rpt->len != 4+buf[3]) return TRUE;
2457 	}
2458 	else if (rpt->len != 3) {
2459 		return TRUE;
2460 	}
2461 	*op_code = buf[0];
2462 	*data_type = buf[1];
2463 	*sv_prn = buf[2];
2464 	if (*op_code == 2) {
2465 		dl = buf[3];
2466 		*data_length = (unsigned char)dl;
2467 		buf4 = &buf[4];
2468 		switch (*data_type) {
2469 		    case 2:
2470 			/* Almanac */
2471 			if (*data_length != sizeof (ALM_INFO)) return TRUE;
2472 			alminfo = (ALM_INFO*)data_packet;
2473 			alminfo->t_oa_raw  = buf4[0];
2474 			alminfo->SV_health = buf4[1];
2475 			alminfo->e         = bGetSingle(&buf4[2]);
2476 			alminfo->t_oa      = bGetSingle(&buf4[6]);
2477 			alminfo->i_0       = bGetSingle(&buf4[10]);
2478 			alminfo->OMEGADOT  = bGetSingle(&buf4[14]);
2479 			alminfo->sqrt_A    = bGetSingle(&buf4[18]);
2480 			alminfo->OMEGA_0   = bGetSingle(&buf4[22]);
2481 			alminfo->omega     = bGetSingle(&buf4[26]);
2482 			alminfo->M_0       = bGetSingle(&buf4[30]);
2483 			alminfo->a_f0      = bGetSingle(&buf4[34]);
2484 			alminfo->a_f1      = bGetSingle(&buf4[38]);
2485 			alminfo->Axis      = bGetSingle(&buf4[42]);
2486 			alminfo->n         = bGetSingle(&buf4[46]);
2487 			alminfo->OMEGA_n   = bGetSingle(&buf4[50]);
2488 			alminfo->ODOT_n    = bGetSingle(&buf4[54]);
2489 			alminfo->t_zc      = bGetSingle(&buf4[58]);
2490 			alminfo->weeknum   = bGetShort(&buf4[62]);
2491 			alminfo->wn_oa     = bGetShort(&buf4[64]);
2492 			break;
2493 
2494 		    case 3:
2495 			/* Almanac health page */
2496 			if (*data_length != sizeof (ALH_PARMS) + 3) return TRUE;
2497 
2498 			/* this record is returned raw */
2499 			memcpy (data_packet, buf4, dl);
2500 			break;
2501 
2502 		    case 4:
2503 			/* Ionosphere */
2504 			if (*data_length != sizeof (ION_INFO) + 8) return TRUE;
2505 			ioninfo = (ION_INFO*)data_packet;
2506 			ioninfo->alpha_0   = bGetSingle (&buf4[8]);
2507 			ioninfo->alpha_1   = bGetSingle (&buf4[12]);
2508 			ioninfo->alpha_2   = bGetSingle (&buf4[16]);
2509 			ioninfo->alpha_3   = bGetSingle (&buf4[20]);
2510 			ioninfo->beta_0    = bGetSingle (&buf4[24]);
2511 			ioninfo->beta_1    = bGetSingle (&buf4[28]);
2512 			ioninfo->beta_2    = bGetSingle (&buf4[32]);
2513 			ioninfo->beta_3    = bGetSingle (&buf4[36]);
2514 			break;
2515 
2516 		    case 5:
2517 			/* UTC */
2518 			if (*data_length != sizeof (UTC_INFO) + 13) return TRUE;
2519 			utcinfo = (UTC_INFO*)data_packet;
2520 			utcinfo->A_0       = bGetDouble (&buf4[13]);
2521 			utcinfo->A_1       = bGetSingle (&buf4[21]);
2522 			utcinfo->delta_t_LS = bGetShort (&buf4[25]);
2523 			utcinfo->t_ot      = bGetSingle(&buf4[27]);
2524 			utcinfo->WN_t      = bGetShort (&buf4[31]);
2525 			utcinfo->WN_LSF    = bGetShort (&buf4[33]);
2526 			utcinfo->DN        = bGetShort (&buf4[35]);
2527 			utcinfo->delta_t_LSF = bGetShort (&buf4[37]);
2528 			break;
2529 
2530 		    case 6:
2531 			/* Ephemeris */
2532 			if (*data_length != sizeof (NAV_INFO) - 1) return TRUE;
2533 
2534 			navinfo = (NAV_INFO*)data_packet;
2535 
2536 			navinfo->sv_number = buf4[0];
2537 			navinfo->t_ephem = bGetSingle (&buf4[1]);
2538 			navinfo->ephclk.weeknum = bGetShort (&buf4[5]);
2539 
2540 			navinfo->ephclk.codeL2 = buf4[7];
2541 			navinfo->ephclk.L2Pdata = buf4[8];
2542 			navinfo->ephclk.SVacc_raw = buf4[9];
2543 			navinfo->ephclk.SV_health = buf4[10];
2544 			navinfo->ephclk.IODC = bGetShort (&buf4[11]);
2545 			navinfo->ephclk.T_GD = bGetSingle (&buf4[13]);
2546 			navinfo->ephclk.t_oc = bGetSingle (&buf4[17]);
2547 			navinfo->ephclk.a_f2 = bGetSingle (&buf4[21]);
2548 			navinfo->ephclk.a_f1 = bGetSingle (&buf4[25]);
2549 			navinfo->ephclk.a_f0 = bGetSingle (&buf4[29]);
2550 			navinfo->ephclk.SVacc = bGetSingle (&buf4[33]);
2551 
2552 			navinfo->ephorb.IODE = buf4[37];
2553 			navinfo->ephorb.fit_interval = buf4[38];
2554 			navinfo->ephorb.C_rs = bGetSingle (&buf4[39]);
2555 			navinfo->ephorb.delta_n = bGetSingle (&buf4[43]);
2556 			navinfo->ephorb.M_0 = bGetDouble (&buf4[47]);
2557 			navinfo->ephorb.C_uc = bGetSingle (&buf4[55]);
2558 			navinfo->ephorb.e = bGetDouble (&buf4[59]);
2559 			navinfo->ephorb.C_us = bGetSingle (&buf4[67]);
2560 			navinfo->ephorb.sqrt_A = bGetDouble (&buf4[71]);
2561 			navinfo->ephorb.t_oe = bGetSingle (&buf4[79]);
2562 			navinfo->ephorb.C_ic = bGetSingle (&buf4[83]);
2563 			navinfo->ephorb.OMEGA_0 = bGetDouble (&buf4[87]);
2564 			navinfo->ephorb.C_is = bGetSingle (&buf4[95]);
2565 			navinfo->ephorb.i_0 = bGetDouble (&buf4[99]);
2566 			navinfo->ephorb.C_rc = bGetSingle (&buf4[107]);
2567 			navinfo->ephorb.omega = bGetDouble (&buf4[111]);
2568 			navinfo->ephorb.OMEGADOT=bGetSingle (&buf4[119]);
2569 			navinfo->ephorb.IDOT = bGetSingle (&buf4[123]);
2570 			navinfo->ephorb.Axis = bGetDouble (&buf4[127]);
2571 			navinfo->ephorb.n = bGetDouble (&buf4[135]);
2572 			navinfo->ephorb.r1me2 = bGetDouble (&buf4[143]);
2573 			navinfo->ephorb.OMEGA_n=bGetDouble (&buf4[151]);
2574 			navinfo->ephorb.ODOT_n = bGetDouble (&buf4[159]);
2575 			break;
2576 		}
2577 	}
2578 	return FALSE;
2579 }
2580 
2581 /* satellite enable/disable or health heed/ignore list */
2582 short
2583 rpt_0x59(
2584 	 TSIPPKT *rpt,
2585 	 unsigned char *code_type,
2586 	 unsigned char status_code[32]
2587 	 )
2588 {
2589 	short iprn;
2590 	unsigned char *buf;
2591 	buf = rpt->buf;
2592 
2593 	if (rpt->len != 33) return TRUE;
2594 	*code_type = buf[0];
2595 	for (iprn = 0; iprn < 32; iprn++)
2596 		status_code[iprn] = buf[iprn + 1];
2597 	return FALSE;
2598 }
2599 
2600 /* raw measurement data - code phase/Doppler */
2601 short
2602 rpt_0x5A(
2603 	 TSIPPKT *rpt,
2604 	 unsigned char *sv_prn,
2605 	 float *sample_length,
2606 	 float *signal_level,
2607 	 float *code_phase,
2608 	 float *Doppler,
2609 	 double *time_of_fix
2610 	 )
2611 {
2612 	unsigned char *buf;
2613 	buf = rpt->buf;
2614 
2615 	if (rpt->len != 25) return TRUE;
2616 	*sv_prn = buf[0];
2617 	*sample_length = bGetSingle (&buf[1]);
2618 	*signal_level = bGetSingle (&buf[5]);
2619 	*code_phase = bGetSingle (&buf[9]);
2620 	*Doppler = bGetSingle (&buf[13]);
2621 	*time_of_fix = bGetDouble (&buf[17]);
2622 	return FALSE;
2623 }
2624 
2625 /* satellite ephorb status */
2626 short
2627 rpt_0x5B(
2628 	 TSIPPKT *rpt,
2629 	 unsigned char *sv_prn,
2630 	 unsigned char *sv_health,
2631 	 unsigned char *sv_iode,
2632 	 unsigned char *fit_interval_flag,
2633 	 float *time_of_collection,
2634 	 float *time_of_eph,
2635 	 float *sv_accy
2636 	 )
2637 {
2638 	unsigned char *buf;
2639 	buf = rpt->buf;
2640 
2641 	if (rpt->len != 16) return TRUE;
2642 	*sv_prn = buf[0];
2643 	*time_of_collection = bGetSingle (&buf[1]);
2644 	*sv_health = buf[5];
2645 	*sv_iode = buf[6];
2646 	*time_of_eph = bGetSingle (&buf[7]);
2647 	*fit_interval_flag = buf[11];
2648 	*sv_accy = bGetSingle (&buf[12]);
2649 	return FALSE;
2650 }
2651 
2652 /* satellite tracking status */
2653 short
2654 rpt_0x5C(
2655 	 TSIPPKT *rpt,
2656 	 unsigned char *sv_prn,
2657 	 unsigned char *slot,
2658 	 unsigned char *chan,
2659 	 unsigned char *acq_flag,
2660 	 unsigned char *eph_flag,
2661 	 float *signal_level,
2662 	 float *time_of_last_msmt,
2663 	 float *elev,
2664 	 float *azim,
2665 	 unsigned char *old_msmt_flag,
2666 	 unsigned char *integer_msec_flag,
2667 	 unsigned char *bad_data_flag,
2668 	 unsigned char *data_collect_flag
2669 	 )
2670 {
2671 	unsigned char *buf;
2672 	buf = rpt->buf;
2673 
2674 	if (rpt->len != 24) return TRUE;
2675 	*sv_prn = buf[0];
2676 	*slot = (unsigned char)((buf[1] & 0x07) + 1);
2677 	*chan = (unsigned char)(buf[1] >> 3);
2678 	if (*chan == 0x10) *chan = 2;
2679 	else (*chan)++;
2680 	*acq_flag = buf[2];
2681 	*eph_flag = buf[3];
2682 	*signal_level = bGetSingle (&buf[4]);
2683 	*time_of_last_msmt = bGetSingle (&buf[8]);
2684 	*elev = bGetSingle (&buf[12]);
2685 	*azim = bGetSingle (&buf[16]);
2686 	*old_msmt_flag = buf[20];
2687 	*integer_msec_flag = buf[21];
2688 	*bad_data_flag = buf[22];
2689 	*data_collect_flag = buf[23];
2690 	return FALSE;
2691 }
2692 
2693 /**/
2694 /* over-determined satellite selection for position fixes, PDOP, fix mode */
2695 short
2696 rpt_0x6D(
2697 	 TSIPPKT *rpt,
2698 	 unsigned char *manual_mode,
2699 	 unsigned char *nsvs,
2700 	 unsigned char *ndim,
2701 	 unsigned char sv_prn[],
2702 	 float *pdop,
2703 	 float *hdop,
2704 	 float *vdop,
2705 	 float *tdop
2706 	 )
2707 {
2708 	short islot;
2709 	unsigned char *buf;
2710 	buf = rpt->buf;
2711 
2712 	*nsvs = (unsigned char)((buf[0] & 0xF0) >> 4);
2713 	if ((*nsvs)>8) return TRUE;
2714 	if (rpt->len != 17 + (*nsvs) ) return TRUE;
2715 
2716 	*manual_mode = (unsigned char)(buf[0] & 0x08);
2717 	*ndim  = (unsigned char)((buf[0] & 0x07));
2718 	*pdop = bGetSingle (&buf[1]);
2719 	*hdop = bGetSingle (&buf[5]);
2720 	*vdop = bGetSingle (&buf[9]);
2721 	*tdop = bGetSingle (&buf[13]);
2722 	for (islot = 0; islot < (*nsvs); islot++)
2723 		sv_prn[islot] = buf[islot + 17];
2724 	return FALSE;
2725 }
2726 
2727 /**/
2728 /* differential fix mode */
2729 short
2730 rpt_0x82(
2731 	 TSIPPKT *rpt,
2732 	 unsigned char *diff_mode
2733 	 )
2734 {
2735 	unsigned char *buf;
2736 	buf = rpt->buf;
2737 
2738 	if (rpt->len != 1) return TRUE;
2739 	*diff_mode = buf[0];
2740 	return FALSE;
2741 }
2742 
2743 /* position, ECEF double precision */
2744 short
2745 rpt_0x83(
2746 	 TSIPPKT *rpt,
2747 	 double ECEF_pos[3],
2748 	 double *clock_bias,
2749 	 float *time_of_fix
2750 	 )
2751 {
2752 	unsigned char *buf;
2753 	buf = rpt->buf;
2754 
2755 	if (rpt->len != 36) return TRUE;
2756 	ECEF_pos[0] = bGetDouble (buf);
2757 	ECEF_pos[1] = bGetDouble (&buf[8]);
2758 	ECEF_pos[2] = bGetDouble (&buf[16]);
2759 	*clock_bias  = bGetDouble (&buf[24]);
2760 	*time_of_fix = bGetSingle (&buf[32]);
2761 	return FALSE;
2762 }
2763 
2764 /* position, lat-lon-alt double precision */
2765 short
2766 rpt_0x84(
2767 	 TSIPPKT *rpt,
2768 	 double *lat,
2769 	 double *lon,
2770 	 double *alt,
2771 	 double *clock_bias,
2772 	 float *time_of_fix
2773 	 )
2774 {
2775 	unsigned char *buf;
2776 	buf = rpt->buf;
2777 
2778 	if (rpt->len != 36) return TRUE;
2779 	*lat = bGetDouble (buf);
2780 	*lon = bGetDouble (&buf[8]);
2781 	*alt = bGetDouble (&buf[16]);
2782 	*clock_bias = bGetDouble (&buf[24]);
2783 	*time_of_fix = bGetSingle (&buf[32]);
2784 	return FALSE;
2785 }
2786 
2787 short
2788 rpt_Paly0xBB(
2789 	     TSIPPKT *rpt,
2790 	     TSIP_RCVR_CFG *TsipxBB
2791 	     )
2792 {
2793 	unsigned char *buf;
2794 	buf = rpt->buf;
2795 
2796 	/* Palisade is inconsistent with other TSIP, which has a length of 40 */
2797 	/* if (rpt->len != 40) return TRUE; */
2798 	if (rpt->len != 43) return TRUE;
2799 
2800 	TsipxBB->bSubcode	=  buf[0];
2801 	TsipxBB->operating_mode	=  buf[1];
2802 	TsipxBB->dyn_code	=  buf[3];
2803 	TsipxBB->elev_mask	=  bGetSingle (&buf[5]);
2804 	TsipxBB->cno_mask	=  bGetSingle (&buf[9]);
2805 	TsipxBB->dop_mask 	=  bGetSingle (&buf[13]);
2806 	TsipxBB->dop_switch 	=  bGetSingle (&buf[17]);
2807 	return FALSE;
2808 }
2809 
2810 /* Receiver serial port configuration */
2811 short
2812 rpt_0xBC(
2813 	 TSIPPKT *rpt,
2814 	 unsigned char *port_num,
2815 	 unsigned char *in_baud,
2816 	 unsigned char *out_baud,
2817 	 unsigned char *data_bits,
2818 	 unsigned char *parity,
2819 	 unsigned char *stop_bits,
2820 	 unsigned char *flow_control,
2821 	 unsigned char *protocols_in,
2822 	 unsigned char *protocols_out,
2823 	 unsigned char *reserved
2824 	 )
2825 {
2826 	unsigned char *buf;
2827 	buf = rpt->buf;
2828 
2829 	if (rpt->len != 10) return TRUE;
2830 	*port_num = buf[0];
2831 	*in_baud = buf[1];
2832 	*out_baud = buf[2];
2833 	*data_bits = buf[3];
2834 	*parity = buf[4];
2835 	*stop_bits = buf[5];
2836 	*flow_control = buf[6];
2837 	*protocols_in = buf[7];
2838 	*protocols_out = buf[8];
2839 	*reserved = buf[9];
2840 
2841 	return FALSE;
2842 }
2843 
2844 /**** Superpackets ****/
2845 
2846 short
2847 rpt_0x8F0B(
2848 	   TSIPPKT *rpt,
2849 	   unsigned short *event,
2850 	   double *tow,
2851 	   unsigned char *date,
2852 	   unsigned char *month,
2853 	   short *year,
2854 	   unsigned char *dim_mode,
2855 	   short *utc_offset,
2856 	   double *bias,
2857 	   double *drift,
2858 	   float *bias_unc,
2859 	   float *dr_unc,
2860 	   double *lat,
2861 	   double *lon,
2862 	   double *alt,
2863 	   char sv_id[8]
2864 	   )
2865 {
2866 	short local_index;
2867 	unsigned char *buf;
2868 
2869 	buf = rpt->buf;
2870 	if (rpt->len != 74) return TRUE;
2871 	*event = bGetShort(&buf[1]);
2872 	*tow = bGetDouble(&buf[3]);
2873 	*date = buf[11];
2874 	*month = buf[12];
2875 	*year = bGetShort(&buf[13]);
2876 	*dim_mode = buf[15];
2877 	*utc_offset = bGetShort(&buf[16]);
2878 	*bias = bGetDouble(&buf[18]);
2879 	*drift = bGetDouble(&buf[26]);
2880 	*bias_unc = bGetSingle(&buf[34]);
2881 	*dr_unc = bGetSingle(&buf[38]);
2882 	*lat = bGetDouble(&buf[42]);
2883 	*lon = bGetDouble(&buf[50]);
2884 	*alt = bGetDouble(&buf[58]);
2885 
2886 	for (local_index=0; local_index<8; local_index++) sv_id[local_index] = buf[local_index + 66];
2887 	return FALSE;
2888 }
2889 
2890 /* datum index and coefficients  */
2891 short
2892 rpt_0x8F14(
2893 	   TSIPPKT *rpt,
2894 	   short *datum_idx,
2895 	   double datum_coeffs[5]
2896 	   )
2897 {
2898 	unsigned char *buf;
2899 	buf = rpt->buf;
2900 
2901 	if (rpt->len != 43) return TRUE;
2902 	*datum_idx = bGetShort(&buf[1]);
2903 	datum_coeffs[0] = bGetDouble (&buf[3]);
2904 	datum_coeffs[1] = bGetDouble (&buf[11]);
2905 	datum_coeffs[2] = bGetDouble (&buf[19]);
2906 	datum_coeffs[3] = bGetDouble (&buf[27]);
2907 	datum_coeffs[4] = bGetDouble (&buf[35]);
2908 	return FALSE;
2909 }
2910 
2911 
2912 /* datum index and coefficients  */
2913 short
2914 rpt_0x8F15(
2915 	   TSIPPKT *rpt,
2916 	   short *datum_idx,
2917 	   double datum_coeffs[5]
2918 	   )
2919 {
2920 	unsigned char *buf;
2921 	buf = rpt->buf;
2922 
2923 	if (rpt->len != 43) return TRUE;
2924 	*datum_idx = bGetShort(&buf[1]);
2925 	datum_coeffs[0] = bGetDouble (&buf[3]);
2926 	datum_coeffs[1] = bGetDouble (&buf[11]);
2927 	datum_coeffs[2] = bGetDouble (&buf[19]);
2928 	datum_coeffs[3] = bGetDouble (&buf[27]);
2929 	datum_coeffs[4] = bGetDouble (&buf[35]);
2930 	return FALSE;
2931 }
2932 
2933 
2934 #define MAX_LONG  (2147483648.)   /* 2**31 */
2935 
2936 short
2937 rpt_0x8F20(
2938 	   TSIPPKT *rpt,
2939 	   unsigned char *info,
2940 	   double *lat,
2941 	   double *lon,
2942 	   double *alt,
2943 	   double vel_enu[],
2944 	   double *time_of_fix,
2945 	   short *week_num,
2946 	   unsigned char *nsvs,
2947 	   unsigned char sv_prn[],
2948 	   short sv_IODC[],
2949 	   short *datum_index
2950 	   )
2951 {
2952 	short
2953 	    isv;
2954 	unsigned char
2955 	    *buf, prnx, iode;
2956 	unsigned long
2957 	    ulongtemp;
2958 	long
2959 	    longtemp;
2960 	double
2961 	    vel_scale;
2962 
2963 	buf = rpt->buf;
2964 
2965 	if (rpt->len != 56) return TRUE;
2966 
2967 	vel_scale = (buf[24]&1)? 0.020 : 0.005;
2968 	vel_enu[0] = bGetShort (buf+2)*vel_scale;
2969 	vel_enu[1] = bGetShort (buf+4)*vel_scale;
2970 	vel_enu[2] = bGetShort (buf+6)*vel_scale;
2971 
2972 	*time_of_fix = bGetULong (buf+8)*.001;
2973 
2974 	longtemp = bGetLong (buf+12);
2975 	*lat = longtemp*(GPS_PI/MAX_LONG);
2976 
2977 	ulongtemp = bGetULong (buf+16);
2978 	*lon = ulongtemp*(GPS_PI/MAX_LONG);
2979 	if (*lon > GPS_PI) *lon -= 2.0*GPS_PI;
2980 
2981 	*alt = bGetLong (buf+20)*.001;
2982 	/* 25 blank; 29 = UTC */
2983 	(*datum_index) = (short)((short)buf[26]-1);
2984 	*info = buf[27];
2985 	*nsvs = buf[28];
2986 	*week_num = bGetShort (&buf[30]);
2987 	for (isv = 0; isv < 8; isv++) {
2988 		prnx = buf[32+2*isv];
2989 		sv_prn[isv] = (unsigned char)(prnx&0x3F);
2990 		iode = buf[33+2*isv];
2991 		sv_IODC[isv] = (short)(iode | ((prnx>>6)<<8));
2992 	}
2993 	return FALSE;
2994 }
2995 
2996 short
2997 rpt_0x8F41(
2998 	   TSIPPKT *rpt,
2999 	   unsigned char *bSearchRange,
3000 	   unsigned char *bBoardOptions,
3001 	   unsigned long *iiSerialNumber,
3002 	   unsigned char *bBuildYear,
3003 	   unsigned char *bBuildMonth,
3004 	   unsigned char *bBuildDay,
3005 	   unsigned char *bBuildHour,
3006 	   float *fOscOffset,
3007 	   unsigned short *iTestCodeId
3008 	   )
3009 {
3010 	if (rpt->len != 17) return FALSE;
3011 	*bSearchRange = rpt->buf[1];
3012 	*bBoardOptions = rpt->buf[2];
3013 	*iiSerialNumber = bGetLong(&rpt->buf[3]);
3014 	*bBuildYear = rpt->buf[7];
3015 	*bBuildMonth = rpt->buf[8];
3016 	*bBuildDay = rpt->buf[9];
3017 	*bBuildHour =	rpt->buf[10];
3018 	*fOscOffset = bGetSingle(&rpt->buf[11]);
3019 	*iTestCodeId = bGetShort(&rpt->buf[15]);
3020 /*	Tsipx8E41Data = *Tsipx8E41; */
3021 	return TRUE;
3022 }
3023 
3024 short
3025 rpt_0x8F42(
3026 	   TSIPPKT *rpt,
3027 	   unsigned char *bProdOptionsPre,
3028 	   unsigned char *bProdNumberExt,
3029 	   unsigned short *iCaseSerialNumberPre,
3030 	   unsigned long *iiCaseSerialNumber,
3031 	   unsigned long *iiProdNumber,
3032 	   unsigned short *iPremiumOptions,
3033 	   unsigned short *iMachineID,
3034 	   unsigned short *iKey
3035 	   )
3036 {
3037 	if (rpt->len != 19) return FALSE;
3038 	*bProdOptionsPre = rpt->buf[1];
3039 	*bProdNumberExt = rpt->buf[2];
3040 	*iCaseSerialNumberPre = bGetShort(&rpt->buf[3]);
3041 	*iiCaseSerialNumber = bGetLong(&rpt->buf[5]);
3042 	*iiProdNumber = bGetLong(&rpt->buf[9]);
3043 	*iPremiumOptions = bGetShort(&rpt->buf[13]);
3044 	*iMachineID = bGetShort(&rpt->buf[15]);
3045 	*iKey = bGetShort(&rpt->buf[17]);
3046 	return TRUE;
3047 }
3048 
3049 short
3050 rpt_0x8F45(
3051 	   TSIPPKT *rpt,
3052 	   unsigned char *bSegMask
3053 	   )
3054 {
3055 	if (rpt->len != 2) return FALSE;
3056 	*bSegMask = rpt->buf[1];
3057 	return TRUE;
3058 }
3059 
3060 /* Stinger PPS definition */
3061 short
3062 rpt_0x8F4A_16(
3063 	      TSIPPKT *rpt,
3064 	      unsigned char *pps_enabled,
3065 	      unsigned char *pps_timebase,
3066 	      unsigned char *pos_polarity,
3067 	      double *pps_offset,
3068 	      float *bias_unc_threshold
3069 	      )
3070 {
3071 	unsigned char
3072 	    *buf;
3073 
3074 	buf = rpt->buf;
3075 	if (rpt->len != 16) return TRUE;
3076 	*pps_enabled = buf[1];
3077 	*pps_timebase = buf[2];
3078 	*pos_polarity = buf[3];
3079 	*pps_offset = bGetDouble(&buf[4]);
3080 	*bias_unc_threshold = bGetSingle(&buf[12]);
3081 	return FALSE;
3082 }
3083 
3084 short
3085 rpt_0x8F4B(
3086 	   TSIPPKT *rpt,
3087 	   unsigned long *decorr_max
3088 	   )
3089 {
3090 	unsigned char
3091 	    *buf;
3092 
3093 	buf = rpt->buf;
3094 	if (rpt->len != 5) return TRUE;
3095 	*decorr_max = bGetLong(&buf[1]);
3096 	return FALSE;
3097 }
3098 
3099 short
3100 rpt_0x8F4D(
3101 	   TSIPPKT *rpt,
3102 	   unsigned long *event_mask
3103 	   )
3104 {
3105 	unsigned char
3106 	    *buf;
3107 
3108 	buf = rpt->buf;
3109 	if (rpt->len != 5) return TRUE;
3110 	*event_mask = bGetULong (&buf[1]);
3111 	return FALSE;
3112 }
3113 
3114 short
3115 rpt_0x8FA5(
3116 	   TSIPPKT *rpt,
3117 	   unsigned char *spktmask
3118 	   )
3119 {
3120 	unsigned char
3121 	    *buf;
3122 
3123 	buf = rpt->buf;
3124 	if (rpt->len != 5) return TRUE;
3125 	spktmask[0] = buf[1];
3126 	spktmask[1] = buf[2];
3127 	spktmask[2] = buf[3];
3128 	spktmask[3] = buf[4];
3129 	return FALSE;
3130 }
3131 
3132 short
3133 rpt_0x8FAD(
3134 	   TSIPPKT *rpt,
3135 	   unsigned short *COUNT,
3136 	   double *FracSec,
3137 	   unsigned char *Hour,
3138 	   unsigned char *Minute,
3139 	   unsigned char *Second,
3140 	   unsigned char *Day,
3141 	   unsigned char *Month,
3142 	   unsigned short *Year,
3143 	   unsigned char *Status,
3144 	   unsigned char *Flags
3145 	   )
3146 {
3147 	if (rpt->len != 22) return TRUE;
3148 
3149 	*COUNT = bGetUShort(&rpt->buf[1]);
3150 	*FracSec = bGetDouble(&rpt->buf[3]);
3151 	*Hour = rpt->buf[11];
3152 	*Minute = rpt->buf[12];
3153 	*Second = rpt->buf[13];
3154 	*Day = rpt->buf[14];
3155 	*Month = rpt->buf[15];
3156 	*Year = bGetUShort(&rpt->buf[16]);
3157 	*Status = rpt->buf[18];
3158 	*Flags = rpt->buf[19];
3159 	return FALSE;
3160 }
3161 
3162 
3163 /*
3164  * *************************************************************************
3165  *
3166  * Trimble Navigation, Ltd.
3167  * OEM Products Development Group
3168  * P.O. Box 3642
3169  * 645 North Mary Avenue
3170  * Sunnyvale, California 94088-3642
3171  *
3172  * Corporate Headquarter:
3173  *    Telephone:  (408) 481-8000
3174  *    Fax:        (408) 481-6005
3175  *
3176  * Technical Support Center:
3177  *    Telephone:  (800) 767-4822	(U.S. and Canada)
3178  *                (408) 481-6940    (outside U.S. and Canada)
3179  *    Fax:        (408) 481-6020
3180  *    BBS:        (408) 481-7800
3181  *    e-mail:     trimble_support@trimble.com
3182  *		ftp://ftp.trimble.com/pub/sct/embedded/bin
3183  *
3184  * *************************************************************************
3185  *
3186  * T_REPORT.C consists of a primary function TranslateTSIPReportToText()
3187  * called by main().
3188  *
3189  * This function takes a character buffer that has been received as a report
3190  * from a TSIP device and interprets it.  The character buffer has been
3191  * assembled using tsip_input_proc() in T_PARSER.C.
3192  *
3193  * A large case statement directs processing to one of many mid-level
3194  * functions.  The mid-level functions specific to the current report
3195  * code passes the report buffer to the appropriate report decoder
3196  * rpt_0x?? () in T_PARSER.C, which converts the byte stream in rpt.buf
3197  * to data values approporaite for use.
3198  *
3199  * *************************************************************************
3200  *
3201  */
3202 
3203 
3204 #define GOOD_PARSE 0
3205 #define BADID_PARSE 1
3206 #define BADLEN_PARSE 2
3207 #define BADDATA_PARSE 3
3208 
3209 #define B_TSIP	0x02
3210 #define B_NMEA	0x04
3211 
3212 
3213 /* pbuf is the pointer to the current location of the text output */
3214 static char
3215 *pbuf;
3216 
3217 /* keep track of whether the message has been successfully parsed */
3218 static short
3219 parsed;
3220 
3221 
3222 /* convert time of week into day-hour-minute-second and print */
3223 char *
3224 show_time(
3225 	  float time_of_week
3226 	  )
3227 {
3228 	short	days, hours, minutes;
3229 	float seconds;
3230 	double tow = 0;
3231 	static char timestring [80];
3232 
3233 	if (time_of_week == -1.0)
3234 	{
3235 		sprintf(timestring, "   <No time yet>   ");
3236 	}
3237 	else if ((time_of_week >= 604800.0) || (time_of_week < 0.0))
3238 	{
3239 		sprintf(timestring, "     <Bad time>     ");
3240 	}
3241 	else
3242 	{
3243 		if (time_of_week < 604799.9)
3244 			tow = time_of_week + .00000001;
3245 		seconds = (float)fmod(tow, 60.);
3246 		minutes =  (short) fmod(tow/60., 60.);
3247 		hours = (short)fmod(tow / 3600., 24.);
3248 		days = (short)(tow / 86400.0);
3249 		sprintf(timestring, " %s %02d:%02d:%05.2f   ",
3250 			dayname[days], hours, minutes, seconds);
3251 	}
3252 	return timestring;
3253 }
3254 
3255 /**/
3256 /* 0x3D */
3257 static void
3258 rpt_chan_A_config(
3259 		  TSIPPKT *rpt
3260 		  )
3261 {
3262 	unsigned char
3263 	    tx_baud_index, rx_baud_index,
3264 	    char_format_index, stop_bits,
3265 	    tx_mode_index, rx_mode_index,
3266 	    databits, parity;
3267 	int
3268 	    i, nbaud;
3269 
3270 	/* unload rptbuf */
3271 	if (rpt_0x3D (rpt,
3272 		      &tx_baud_index, &rx_baud_index, &char_format_index,
3273 		      &stop_bits, &tx_mode_index, &rx_mode_index)) {
3274 		parsed = BADLEN_PARSE;
3275 		return;
3276 	}
3277 
3278 	pbuf += sprintf(pbuf, "\nChannel A Configuration");
3279 
3280 	nbaud = sizeof(old_baudnum);
3281 
3282 	for (i = 0; i < nbaud; ++i) if (tx_baud_index == old_baudnum[i]) break;
3283 	pbuf += sprintf(pbuf, "\n   Transmit speed: %s at %s",
3284 			old_output_ch[tx_mode_index], st_baud_text_app[i]);
3285 
3286 	for (i = 0; i < nbaud; ++i) if (rx_baud_index == old_baudnum[i]) break;
3287 	pbuf += sprintf(pbuf, "\n   Receive speed: %s at %s",
3288 			old_input_ch[rx_mode_index], st_baud_text_app[i]);
3289 
3290 	databits = (unsigned char)((char_format_index & 0x03) + 5);
3291 
3292 	parity = (unsigned char)(char_format_index >> 2);
3293 	if (parity > 4) parity = 2;
3294 
3295 	pbuf += sprintf(pbuf, "\n   Character format (bits/char, parity, stop bits): %d-%s-%d",
3296 			databits, old_parity_text[parity], stop_bits);
3297 }
3298 
3299 /**/
3300 /* 0x40 */
3301 static void
3302 rpt_almanac_data_page(
3303 		      TSIPPKT *rpt
3304 		      )
3305 {
3306 	unsigned char
3307 	    sv_prn;
3308 	short
3309 	    week_num;
3310 	float
3311 	    t_zc,
3312 	    eccentricity,
3313 	    t_oa,
3314 	    i_0,
3315 	    OMEGA_dot,
3316 	    sqrt_A,
3317 	    OMEGA_0,
3318 	    omega,
3319 	    M_0;
3320 
3321 	/* unload rptbuf */
3322 	if (rpt_0x40 (rpt,
3323 		      &sv_prn, &week_num, &t_zc, &eccentricity, &t_oa,
3324 		      &i_0, &OMEGA_dot, &sqrt_A, &OMEGA_0, &omega, &M_0)) {
3325 		parsed = BADLEN_PARSE;
3326 		return;
3327 	}
3328 
3329 	pbuf += sprintf(pbuf, "\nAlmanac for SV %02d", sv_prn);
3330 	pbuf += sprintf(pbuf, "\n       Captured:%15.0f %s",
3331 			t_zc, show_time (t_zc));
3332 	pbuf += sprintf(pbuf, "\n           week:%15d", week_num);
3333 	pbuf += sprintf(pbuf, "\n   Eccentricity:%15g", eccentricity);
3334 	pbuf += sprintf(pbuf, "\n           T_oa:%15.0f %s",
3335 			t_oa, show_time (t_oa));
3336 	pbuf += sprintf(pbuf, "\n            i 0:%15g", i_0);
3337 	pbuf += sprintf(pbuf, "\n      OMEGA dot:%15g", OMEGA_dot);
3338 	pbuf += sprintf(pbuf, "\n         sqrt A:%15g", sqrt_A);
3339 	pbuf += sprintf(pbuf, "\n        OMEGA 0:%15g", OMEGA_0);
3340 	pbuf += sprintf(pbuf, "\n          omega:%15g", omega);
3341 	pbuf += sprintf(pbuf, "\n            M 0:%15g", M_0);
3342 }
3343 
3344 /* 0x41 */
3345 static void
3346 rpt_GPS_time(
3347 	     TSIPPKT *rpt
3348 	     )
3349 {
3350 	float
3351 	    time_of_week, UTC_offset;
3352 	short
3353 	    week_num;
3354 
3355 	/* unload rptbuf */
3356 	if (rpt_0x41 (rpt, &time_of_week, &UTC_offset, &week_num)) {
3357 		parsed = BADLEN_PARSE;
3358 		return;
3359 	}
3360 
3361 	pbuf += sprintf(pbuf, "\nGPS time:%s GPS week: %d   UTC offset %.1f",
3362 			show_time(time_of_week), week_num, UTC_offset);
3363 
3364 }
3365 
3366 /* 0x42 */
3367 static void
3368 rpt_single_ECEF_position(
3369 			 TSIPPKT *rpt
3370 			 )
3371 {
3372 	float
3373 	    ECEF_pos[3], time_of_fix;
3374 
3375 	/* unload rptbuf */
3376 	if (rpt_0x42 (rpt, ECEF_pos, &time_of_fix)) {
3377 		parsed = BADLEN_PARSE;
3378 		return;
3379 	}
3380 
3381 	pbuf += sprintf(pbuf, "\nSXYZ:  %15.0f  %15.0f  %15.0f    %s",
3382 			ECEF_pos[0], ECEF_pos[1], ECEF_pos[2],
3383 			show_time(time_of_fix));
3384 }
3385 
3386 /* 0x43 */
3387 static void
3388 rpt_single_ECEF_velocity(
3389 			 TSIPPKT *rpt
3390 			 )
3391 {
3392 
3393 	float
3394 	    ECEF_vel[3], freq_offset, time_of_fix;
3395 
3396 	/* unload rptbuf */
3397 	if (rpt_0x43 (rpt, ECEF_vel, &freq_offset, &time_of_fix)) {
3398 		parsed = BADLEN_PARSE;
3399 		return;
3400 	}
3401 
3402 	pbuf += sprintf(pbuf, "\nVelECEF: %11.3f  %11.3f  %11.3f  %12.3f%s",
3403 			ECEF_vel[0], ECEF_vel[1], ECEF_vel[2], freq_offset,
3404 			show_time(time_of_fix));
3405 }
3406 
3407 /*  0x45  */
3408 static void
3409 rpt_SW_version(
3410 	       TSIPPKT *rpt
3411 	       )
3412 {
3413 	unsigned char
3414 	    major_nav_version, minor_nav_version,
3415 	    nav_day, nav_month, nav_year,
3416 	    major_dsp_version, minor_dsp_version,
3417 	    dsp_day, dsp_month, dsp_year;
3418 
3419 	/* unload rptbuf */
3420 	if (rpt_0x45 (rpt,
3421 		      &major_nav_version, &minor_nav_version,
3422 		      &nav_day, &nav_month, &nav_year,
3423 		      &major_dsp_version, &minor_dsp_version,
3424 		      &dsp_day, &dsp_month, &dsp_year)) {
3425 		parsed = BADLEN_PARSE;
3426 		return;
3427 	}
3428 
3429 	pbuf += sprintf(pbuf,
3430 			"\nFW Versions:  Nav Proc %2d.%02d  %2d/%2d/%2d  Sig Proc %2d.%02d  %2d/%2d/%2d",
3431 			major_nav_version, minor_nav_version, nav_day, nav_month, nav_year,
3432 			major_dsp_version, minor_dsp_version, dsp_day, dsp_month, dsp_year);
3433 }
3434 
3435 /* 0x46 */
3436 static void
3437 rpt_rcvr_health(
3438 		TSIPPKT *rpt
3439 		)
3440 {
3441 	unsigned char
3442 	    status1, status2;
3443 	const char
3444 	    *text;
3445 	static const char const
3446 	    *sc_text[] = {
3447 		"Doing position fixes",
3448 		"Don't have GPS time yet",
3449 		"Waiting for almanac collection",
3450 		"DOP too high          ",
3451 		"No satellites available",
3452 		"Only 1 satellite available",
3453 		"Only 2 satellites available",
3454 		"Only 3 satellites available",
3455 		"No satellites usable   ",
3456 		"Only 1 satellite usable",
3457 		"Only 2 satellites usable",
3458 		"Only 3 satellites usable",
3459 		"Chosen satellite unusable"};
3460 
3461 
3462 	/* unload rptbuf */
3463 	if (rpt_0x46 (rpt, &status1, &status2))
3464 	{
3465 		parsed = BADLEN_PARSE;
3466 		return;
3467 	}
3468 
3469 	text = (status1 < COUNTOF(sc_text))
3470 	    ? sc_text[status1]
3471 	    : "(out of range)";
3472 	pbuf += sprintf(pbuf, "\nRcvr status1: %s (%02Xh); ",
3473 			text, status1);
3474 
3475 	pbuf += sprintf(pbuf, "status2: %s, %s (%02Xh)",
3476 			(status2 & 0x01)?"No BBRAM":"BBRAM OK",
3477 			(status2 & 0x10)?"No Ant":"Ant OK",
3478 			status2);
3479 }
3480 
3481 /* 0x47 */
3482 static void
3483 rpt_SNR_all_SVs(
3484 		TSIPPKT *rpt
3485 		)
3486 {
3487 	unsigned char
3488 	    nsvs, sv_prn[12];
3489 	short
3490 	    isv;
3491 	float
3492 	    snr[12];
3493 
3494 	/* unload rptbuf */
3495 	if (rpt_0x47 (rpt, &nsvs, sv_prn, snr))
3496 	{
3497 		parsed = BADLEN_PARSE;
3498 		return;
3499 	}
3500 
3501 	pbuf += sprintf(pbuf, "\nSNR for satellites: %d", nsvs);
3502 	for (isv = 0; isv < nsvs; isv++)
3503 	{
3504 		pbuf += sprintf(pbuf, "\n    SV %02d   %6.2f",
3505 				sv_prn[isv], snr[isv]);
3506 	}
3507 }
3508 
3509 /* 0x48 */
3510 static void
3511 rpt_GPS_system_message(
3512 		       TSIPPKT *rpt
3513 		       )
3514 {
3515 	unsigned char
3516 	    message[23];
3517 
3518 	/* unload rptbuf */
3519 	if (rpt_0x48 (rpt, message))
3520 	{
3521 		parsed = BADLEN_PARSE;
3522 		return;
3523 	}
3524 
3525 	pbuf += sprintf(pbuf, "\nGPS message: %s", message);
3526 }
3527 
3528 /* 0x49 */
3529 static void
3530 rpt_almanac_health_page(
3531 			TSIPPKT *rpt
3532 			)
3533 {
3534 	short
3535 	    iprn;
3536 	unsigned char
3537 	    sv_health [32];
3538 
3539 	/* unload rptbuf */
3540 	if (rpt_0x49 (rpt, sv_health))
3541 	{
3542 		parsed = BADLEN_PARSE;
3543 		return;
3544 	}
3545 
3546 	pbuf += sprintf(pbuf, "\nAlmanac health page:");
3547 	for (iprn = 0; iprn < 32; iprn++)
3548 	{
3549 		if (!(iprn%5)) *pbuf++ = '\n';
3550 		pbuf += sprintf(pbuf, "    SV%02d  %2X",
3551 				(iprn+1) , sv_health[iprn]);
3552 	}
3553 }
3554 
3555 /* 0x4A */
3556 static void
3557 rpt_single_lla_position(
3558 			TSIPPKT *rpt
3559 			)
3560 {
3561 	short
3562 	    lat_deg, lon_deg;
3563 	float
3564 	    lat, lon,
3565 	    alt, clock_bias, time_of_fix;
3566 	double lat_min, lon_min;
3567 	unsigned char
3568 	    north_south, east_west;
3569 
3570 	if (rpt_0x4A (rpt,
3571 		      &lat, &lon, &alt, &clock_bias, &time_of_fix))
3572 	{
3573 		parsed = BADLEN_PARSE;
3574 		return;
3575 	}
3576 
3577 	/* convert from radians to degrees */
3578 	lat *= (float)R2D;
3579 	north_south = 'N';
3580 	if (lat < 0.0)
3581 	{
3582 		north_south = 'S';
3583 		lat = -lat;
3584 	}
3585 	lat_deg = (short)lat;
3586 	lat_min = (lat - lat_deg) * 60.0;
3587 
3588 	lon *= (float)R2D;
3589 	east_west = 'E';
3590 	if (lon < 0.0)
3591 	{
3592 		east_west = 'W';
3593 		lon = -lon;
3594 	}
3595 	lon_deg = (short)lon;
3596 	lon_min = (lon - lon_deg) * 60.0;
3597 
3598 	pbuf += sprintf(pbuf, "\nSLLA: %4d: %06.3f  %c%5d:%06.3f  %c%10.2f  %12.2f%s",
3599 			lat_deg, lat_min, north_south,
3600 			lon_deg, lon_min, east_west,
3601 			alt, clock_bias,
3602 			show_time(time_of_fix));
3603 }
3604 
3605 /* 0x4A */
3606 static void
3607 rpt_ref_alt(
3608 	    TSIPPKT *rpt
3609 	    )
3610 {
3611 	float
3612 	    alt, dummy;
3613 	unsigned char
3614 	    alt_flag;
3615 
3616 	if (rpt_0x4A_2 (rpt, &alt, &dummy, &alt_flag))
3617 	{
3618 		parsed = BADLEN_PARSE;
3619 		return;
3620 	}
3621 
3622 	pbuf += sprintf(pbuf, "\nReference Alt:   %.1f m;    %s",
3623 			alt, alt_flag?"ON":"OFF");
3624 }
3625 
3626 /* 0x4B */
3627 static void
3628 rpt_rcvr_id_and_status(
3629 		       TSIPPKT *rpt
3630 		       )
3631 {
3632 
3633 	unsigned char
3634 	    machine_id, status3, status4;
3635 
3636 	/* unload rptbuf */
3637 	if (rpt_0x4B (rpt, &machine_id, &status3, &status4))
3638 	{
3639 		parsed = BADLEN_PARSE;
3640 		return;
3641 	}
3642 
3643 	pbuf += sprintf(pbuf, "\nRcvr Machine ID: %d; Status3 = %s, %s (%02Xh)",
3644 			machine_id,
3645 			(status3 & 0x02)?"No RTC":"RTC OK",
3646 			(status3 & 0x08)?"No Alm":"Alm OK",
3647 			status3);
3648 }
3649 
3650 /* 0x4C */
3651 static void
3652 rpt_operating_parameters(
3653 			 TSIPPKT *rpt
3654 			 )
3655 {
3656 	unsigned char
3657 	    dyn_code;
3658 	float
3659 	    el_mask, snr_mask, dop_mask, dop_switch;
3660 
3661 	/* unload rptbuf */
3662 	if (rpt_0x4C (rpt, &dyn_code, &el_mask,
3663 		      &snr_mask, &dop_mask, &dop_switch))
3664 	{
3665 		parsed = BADLEN_PARSE;
3666 		return;
3667 	}
3668 
3669 	pbuf += sprintf(pbuf, "\nOperating Parameters:");
3670 	pbuf += sprintf(pbuf, "\n     Dynamics code = %d %s",
3671 			dyn_code, dyn_text[dyn_code]);
3672 	pbuf += sprintf(pbuf, "\n     Elevation mask = %.2f", el_mask * R2D);
3673 	pbuf += sprintf(pbuf, "\n     SNR mask = %.2f", snr_mask);
3674 	pbuf += sprintf(pbuf, "\n     DOP mask = %.2f", dop_mask);
3675 	pbuf += sprintf(pbuf, "\n     DOP switch = %.2f", dop_switch);
3676 }
3677 
3678 /* 0x4D */
3679 static void
3680 rpt_oscillator_offset(
3681 		      TSIPPKT *rpt
3682 		      )
3683 {
3684 	float
3685 	    osc_offset;
3686 
3687 	/* unload rptbuf */
3688 	if (rpt_0x4D (rpt, &osc_offset))
3689 	{
3690 		parsed = BADLEN_PARSE;
3691 		return;
3692 	}
3693 
3694 	pbuf += sprintf(pbuf, "\nOscillator offset: %.2f Hz = %.3f PPM",
3695 			osc_offset, osc_offset/1575.42);
3696 }
3697 
3698 /* 0x4E */
3699 static void
3700 rpt_GPS_time_set_response(
3701 			  TSIPPKT *rpt
3702 			  )
3703 {
3704 	unsigned char
3705 	    response;
3706 
3707 	/* unload rptbuf */
3708 	if (rpt_0x4E (rpt, &response))
3709 	{
3710 		parsed = BADLEN_PARSE;
3711 		return;
3712 	}
3713 
3714 	switch (response)
3715 	{
3716 	    case 'Y':
3717 		pbuf += sprintf(pbuf, "\nTime set accepted");
3718 		break;
3719 
3720 	    case 'N':
3721 		pbuf += sprintf(pbuf, "\nTime set rejected or not required");
3722 		break;
3723 
3724 	    default:
3725 		parsed = BADDATA_PARSE;
3726 	}
3727 }
3728 
3729 /* 0x4F */
3730 static void
3731 rpt_UTC_offset(
3732 	       TSIPPKT *rpt
3733 	       )
3734 {
3735 	double
3736 	    a0;
3737 	float
3738 	    a1, time_of_data;
3739 	short
3740 	    dt_ls, wn_t, wn_lsf, dn, dt_lsf;
3741 
3742 	/* unload rptbuf */
3743 	if (rpt_0x4F (rpt, &a0, &a1, &time_of_data,
3744 		      &dt_ls, &wn_t, &wn_lsf, &dn, &dt_lsf)) {
3745 		parsed = BADLEN_PARSE;
3746 		return;
3747 	}
3748 
3749 	pbuf += sprintf(pbuf, "\nUTC Correction Data");
3750 	pbuf += sprintf(pbuf, "\n   A_0         = %g  ", a0);
3751 	pbuf += sprintf(pbuf, "\n   A_1         = %g  ", a1);
3752 	pbuf += sprintf(pbuf, "\n   delta_t_LS  = %d  ", dt_ls);
3753 	pbuf += sprintf(pbuf, "\n   t_ot        = %.0f  ", time_of_data);
3754 	pbuf += sprintf(pbuf, "\n   WN_t        = %d  ", wn_t );
3755 	pbuf += sprintf(pbuf, "\n   WN_LSF      = %d  ", wn_lsf );
3756 	pbuf += sprintf(pbuf, "\n   DN          = %d  ", dn );
3757 	pbuf += sprintf(pbuf, "\n   delta_t_LSF = %d  ", dt_lsf );
3758 }
3759 
3760 /**/
3761 /* 0x54 */
3762 static void
3763 rpt_1SV_bias(
3764 	     TSIPPKT *rpt
3765 	     )
3766 {
3767 	float
3768 	    clock_bias, freq_offset, time_of_fix;
3769 
3770 	/* unload rptbuf */
3771 	if (rpt_0x54 (rpt, &clock_bias, &freq_offset, &time_of_fix)) {
3772 		parsed = BADLEN_PARSE;
3773 		return;
3774 	}
3775 
3776 	pbuf += sprintf (pbuf, "\nTime Fix   Clock Bias: %6.2f m  Freq Bias: %6.2f m/s%s",
3777 			 clock_bias, freq_offset, show_time (time_of_fix));
3778 }
3779 
3780 /* 0x55 */
3781 static void
3782 rpt_io_opt(
3783 	   TSIPPKT *rpt
3784 	   )
3785 {
3786 	unsigned char
3787 	    pos_code, vel_code, time_code, aux_code;
3788 
3789 	/* unload rptbuf */
3790 	if (rpt_0x55 (rpt,
3791 		      &pos_code, &vel_code, &time_code, &aux_code)) {
3792 		parsed = BADLEN_PARSE;
3793 		return;
3794 	}
3795 	/* rptbuf unloaded */
3796 
3797 	pbuf += sprintf(pbuf, "\nI/O Options: %2X %2X %2X %2X",
3798 			pos_code, vel_code, time_code, aux_code);
3799 
3800 	if (pos_code & 0x01) {
3801 		pbuf += sprintf(pbuf, "\n    ECEF XYZ position output");
3802 	}
3803 
3804 	if (pos_code & 0x02) {
3805 		pbuf += sprintf(pbuf, "\n    LLA position output");
3806 	}
3807 
3808 	pbuf += sprintf(pbuf, (pos_code & 0x04)?
3809 			"\n    MSL altitude output (Geoid height) ":
3810 			"\n    WGS-84 altitude output");
3811 
3812 	pbuf += sprintf(pbuf, (pos_code & 0x08)?
3813 			"\n    MSL altitude input":
3814 			"\n    WGS-84 altitude input");
3815 
3816 	pbuf += sprintf(pbuf, (pos_code & 0x10)?
3817 			"\n    Double precision":
3818 			"\n    Single precision");
3819 
3820 	if (pos_code & 0x20) {
3821 		pbuf += sprintf(pbuf, "\n    All Enabled Superpackets");
3822 	}
3823 
3824 	if (vel_code & 0x01) {
3825 		pbuf += sprintf(pbuf, "\n    ECEF XYZ velocity output");
3826 	}
3827 
3828 	if (vel_code & 0x02) {
3829 		pbuf += sprintf(pbuf, "\n    ENU velocity output");
3830 	}
3831 
3832 	pbuf += sprintf(pbuf, (time_code & 0x01)?
3833 			"\n    Time tags in UTC":
3834 			"\n    Time tags in GPS time");
3835 
3836 	if (time_code & 0x02) {
3837 		pbuf += sprintf(pbuf, "\n    Fixes delayed to integer seconds");
3838 	}
3839 
3840 	if (time_code & 0x04) {
3841 		pbuf += sprintf(pbuf, "\n    Fixes sent only on request");
3842 	}
3843 
3844 	if (time_code & 0x08) {
3845 		pbuf += sprintf(pbuf, "\n    Synchronized measurements");
3846 	}
3847 
3848 	if (time_code & 0x10) {
3849 		pbuf += sprintf(pbuf, "\n    Minimize measurement propagation");
3850 	}
3851 
3852 	pbuf += sprintf(pbuf, (time_code & 0x20) ?
3853 			"\n    PPS output at all times" :
3854 			"\n    PPS output during fixes");
3855 
3856 	if (aux_code & 0x01) {
3857 		pbuf += sprintf(pbuf, "\n    Raw measurement output");
3858 	}
3859 
3860 	if (aux_code & 0x02) {
3861 		pbuf += sprintf(pbuf, "\n    Code-phase smoothed before output");
3862 	}
3863 
3864 	if (aux_code & 0x04) {
3865 		pbuf += sprintf(pbuf, "\n    Additional fix status");
3866 	}
3867 
3868 	pbuf += sprintf(pbuf, (aux_code & 0x08)?
3869 			"\n    Signal Strength Output as dBHz" :
3870 			"\n    Signal Strength Output as AMU");
3871 }
3872 
3873 /* 0x56 */
3874 static void
3875 rpt_ENU_velocity(
3876 		 TSIPPKT *rpt
3877 		 )
3878 {
3879 	float
3880 	    vel_ENU[3], freq_offset, time_of_fix;
3881 
3882 	/* unload rptbuf */
3883 	if (rpt_0x56 (rpt, vel_ENU, &freq_offset, &time_of_fix)) {
3884 		parsed = BADLEN_PARSE;
3885 		return;
3886 	}
3887 
3888 	pbuf += sprintf(pbuf, "\nVel ENU: %11.3f  %11.3f  %11.3f  %12.3f%s",
3889 			vel_ENU[0], vel_ENU[1], vel_ENU[2], freq_offset,
3890 			show_time (time_of_fix));
3891 }
3892 
3893 /* 0x57 */
3894 static void
3895 rpt_last_fix_info(
3896 		  TSIPPKT *rpt
3897 		  )
3898 {
3899 	unsigned char
3900 	    source_code, diag_code;
3901 	short
3902 	    week_num;
3903 	float
3904 	    time_of_fix;
3905 
3906 	/* unload rptbuf */
3907 	if (rpt_0x57 (rpt, &source_code, &diag_code, &week_num, &time_of_fix)) {
3908 		parsed = BADLEN_PARSE;
3909 		return;
3910 	}
3911 
3912 	pbuf += sprintf(pbuf, "\n source code %d;   diag code: %2Xh",
3913 			source_code, diag_code);
3914 	pbuf += sprintf(pbuf, "\n    Time of last fix:%s", show_time(time_of_fix));
3915 	pbuf += sprintf(pbuf, "\n    Week of last fix: %d", week_num);
3916 }
3917 
3918 /* 0x58 */
3919 static void
3920 rpt_GPS_system_data(
3921 		    TSIPPKT *rpt
3922 		    )
3923 {
3924 	unsigned char
3925 	    iprn,
3926 	    op_code, data_type, sv_prn,
3927 	    data_length, data_packet[250];
3928 	ALM_INFO
3929 	    *almanac;
3930 	ALH_PARMS
3931 	    *almh;
3932 	UTC_INFO
3933 	    *utc;
3934 	ION_INFO
3935 	    *ionosphere;
3936 	EPHEM_CLOCK
3937 	    *cdata;
3938 	EPHEM_ORBIT
3939 	    *edata;
3940 	NAV_INFO
3941 	    *nav_data;
3942 	unsigned char
3943 	    curr_t_oa;
3944 	unsigned short
3945 	    curr_wn_oa;
3946 	static char
3947 	    *datname[] =
3948 	    {"", "", "Almanac Orbit",
3949 	     "Health Page & Ref Time", "Ionosphere", "UTC ",
3950 	     "Ephemeris"};
3951 
3952 	/* unload rptbuf */
3953 	if (rpt_0x58 (rpt, &op_code, &data_type, &sv_prn,
3954 		      &data_length, data_packet))
3955 	{
3956 		parsed = BADLEN_PARSE;
3957 		return;
3958 	}
3959 
3960 	pbuf += sprintf(pbuf, "\nSystem data [%d]:  %s  SV%02d",
3961 			data_type, datname[data_type], sv_prn);
3962 	switch (op_code)
3963 	{
3964 	    case 1:
3965 		pbuf += sprintf(pbuf, "  Acknowledgment");
3966 		break;
3967 	    case 2:
3968 		pbuf += sprintf(pbuf, "  length = %d bytes", data_length);
3969 		switch (data_type) {
3970 		    case 2:
3971 			/* Almanac */
3972 			if (sv_prn == 0 || sv_prn > 32) {
3973 				pbuf += sprintf(pbuf, "  Binary PRN invalid");
3974 				return;
3975 			}
3976 			almanac = (ALM_INFO*)data_packet;
3977 			pbuf += sprintf(pbuf, "\n   t_oa_raw = % -12d    SV_hlth  = % -12d  ",
3978 					almanac->t_oa_raw , almanac->SV_health );
3979 			pbuf += sprintf(pbuf, "\n   e        = % -12g    t_oa     = % -12g  ",
3980 					almanac->e        , almanac->t_oa     );
3981 			pbuf += sprintf(pbuf, "\n   i_0      = % -12g    OMEGADOT = % -12g  ",
3982 					almanac->i_0      , almanac->OMEGADOT );
3983 			pbuf += sprintf(pbuf, "\n   sqrt_A   = % -12g    OMEGA_0  = % -12g  ",
3984 					almanac->sqrt_A   , almanac->OMEGA_0  );
3985 			pbuf += sprintf(pbuf, "\n   omega    = % -12g    M_0      = % -12g  ",
3986 					almanac->omega    , almanac->M_0      );
3987 			pbuf += sprintf(pbuf, "\n   a_f0     = % -12g    a_f1     = % -12g  ",
3988 					almanac->a_f0     , almanac->a_f1     );
3989 			pbuf += sprintf(pbuf, "\n   Axis     = % -12g    n        = % -12g  ",
3990 					almanac->Axis     , almanac->n        );
3991 			pbuf += sprintf(pbuf, "\n   OMEGA_n  = % -12g    ODOT_n   = % -12g  ",
3992 					almanac->OMEGA_n  , almanac->ODOT_n   );
3993 			pbuf += sprintf(pbuf, "\n   t_zc     = % -12g    weeknum  = % -12d  ",
3994 					almanac->t_zc     , almanac->weeknum  );
3995 			pbuf += sprintf(pbuf, "\n   wn_oa    = % -12d", almanac->wn_oa    );
3996 			break;
3997 
3998 		    case 3:
3999 			/* Almanac health page */
4000 			almh = (ALH_PARMS*)data_packet;
4001 			pbuf += sprintf(pbuf, "\n   t_oa = %d, wn_oa&0xFF = %d  ",
4002 					almh->t_oa, almh->WN_a);
4003 			pbuf += sprintf(pbuf, "\nAlmanac health page:");
4004 			for (iprn = 0; iprn < 32; iprn++) {
4005 				if (!(iprn%5)) *pbuf++ = '\n';
4006 				pbuf += sprintf(pbuf, "    SV%02d  %2X",
4007 						(iprn+1) , almh->SV_health[iprn]);
4008 			}
4009 			curr_t_oa = data_packet[34];
4010 			curr_wn_oa = (unsigned short)((data_packet[35]<<8) + data_packet[36]);
4011 			pbuf += sprintf(pbuf, "\n   current t_oa = %d, wn_oa = %d  ",
4012 					curr_t_oa, curr_wn_oa);
4013 			break;
4014 
4015 		    case 4:
4016 			/* Ionosphere */
4017 			ionosphere = (ION_INFO*)data_packet;
4018 			pbuf += sprintf(pbuf, "\n   alpha_0 = % -12g  alpha_1 = % -12g ",
4019 					ionosphere->alpha_0, ionosphere->alpha_1);
4020 			pbuf += sprintf(pbuf, "\n   alpha_2 = % -12g  alpha_3 = % -12g ",
4021 					ionosphere->alpha_2, ionosphere->alpha_3);
4022 			pbuf += sprintf(pbuf, "\n   beta_0  = % -12g  beta_1  = % -12g  ",
4023 					ionosphere->beta_0, ionosphere->beta_1);
4024 			pbuf += sprintf(pbuf, "\n   beta_2  = % -12g  beta_3  = % -12g  ",
4025 					ionosphere->beta_2, ionosphere->beta_3);
4026 			break;
4027 
4028 		    case 5:
4029 			/* UTC */
4030 			utc = (UTC_INFO*)data_packet;
4031 			pbuf += sprintf(pbuf, "\n   A_0         = %g  ", utc->A_0);
4032 			pbuf += sprintf(pbuf, "\n   A_1         = %g  ", utc->A_1);
4033 			pbuf += sprintf(pbuf, "\n   delta_t_LS  = %d  ", utc->delta_t_LS);
4034 			pbuf += sprintf(pbuf, "\n   t_ot        = %.0f  ", utc->t_ot );
4035 			pbuf += sprintf(pbuf, "\n   WN_t        = %d  ", utc->WN_t );
4036 			pbuf += sprintf(pbuf, "\n   WN_LSF      = %d  ", utc->WN_LSF );
4037 			pbuf += sprintf(pbuf, "\n   DN          = %d  ", utc->DN );
4038 			pbuf += sprintf(pbuf, "\n   delta_t_LSF = %d  ", utc->delta_t_LSF );
4039 			break;
4040 
4041 		    case 6: /* Ephemeris */
4042 			if (sv_prn == 0 || sv_prn > 32) {
4043 				pbuf += sprintf(pbuf, "  Binary PRN invalid");
4044 				return;
4045 			}
4046 			nav_data = (NAV_INFO*)data_packet;
4047 
4048 			pbuf += sprintf(pbuf, "\n     SV_PRN = % -12d .  t_ephem = % -12g . ",
4049 					nav_data->sv_number , nav_data->t_ephem );
4050 			cdata = &(nav_data->ephclk);
4051 			pbuf += sprintf(pbuf,
4052 					"\n    weeknum = % -12d .   codeL2 = % -12d .  L2Pdata = % -12d",
4053 					cdata->weeknum , cdata->codeL2 , cdata->L2Pdata );
4054 			pbuf += sprintf(pbuf,
4055 					"\n  SVacc_raw = % -12d .SV_health = % -12d .     IODC = % -12d",
4056 					cdata->SVacc_raw, cdata->SV_health, cdata->IODC );
4057 			pbuf += sprintf(pbuf,
4058 					"\n       T_GD = % -12g .     t_oc = % -12g .     a_f2 = % -12g",
4059 					cdata->T_GD, cdata->t_oc, cdata->a_f2 );
4060 			pbuf += sprintf(pbuf,
4061 					"\n       a_f1 = % -12g .     a_f0 = % -12g .    SVacc = % -12g",
4062 					cdata->a_f1, cdata->a_f0, cdata->SVacc );
4063 			edata = &(nav_data->ephorb);
4064 			pbuf += sprintf(pbuf,
4065 					"\n       IODE = % -12d .fit_intvl = % -12d .     C_rs = % -12g",
4066 					edata->IODE, edata->fit_interval, edata->C_rs );
4067 			pbuf += sprintf(pbuf,
4068 					"\n    delta_n = % -12g .      M_0 = % -12g .     C_uc = % -12g",
4069 					edata->delta_n, edata->M_0, edata->C_uc );
4070 			pbuf += sprintf(pbuf,
4071 					"\n        ecc = % -12g .     C_us = % -12g .   sqrt_A = % -12g",
4072 					edata->e, edata->C_us, edata->sqrt_A );
4073 			pbuf += sprintf(pbuf,
4074 					"\n       t_oe = % -12g .     C_ic = % -12g .  OMEGA_0 = % -12g",
4075 					edata->t_oe, edata->C_ic, edata->OMEGA_0 );
4076 			pbuf += sprintf(pbuf,
4077 					"\n       C_is = % -12g .      i_0 = % -12g .     C_rc = % -12g",
4078 					edata->C_is, edata->i_0, edata->C_rc );
4079 			pbuf += sprintf(pbuf,
4080 					"\n      omega = % -12g . OMEGADOT = % -12g .     IDOT = % -12g",
4081 					edata->omega, edata->OMEGADOT, edata->IDOT );
4082 			pbuf += sprintf(pbuf,
4083 					"\n       Axis = % -12g .        n = % -12g .    r1me2 = % -12g",
4084 					edata->Axis, edata->n, edata->r1me2 );
4085 			pbuf += sprintf(pbuf,
4086 					"\n    OMEGA_n = % -12g .   ODOT_n = % -12g",
4087 					edata->OMEGA_n, edata->ODOT_n );
4088 			break;
4089 		}
4090 	}
4091 }
4092 
4093 
4094 /* 0x59: */
4095 static void
4096 rpt_SVs_enabled(
4097 		TSIPPKT *rpt
4098 		)
4099 {
4100 	unsigned char
4101 	    numsvs,
4102 	    code_type,
4103 	    status_code[32];
4104 	short
4105 	    iprn;
4106 
4107 	/* unload rptbuf */
4108 	if (rpt_0x59 (rpt, &code_type, status_code))
4109 	{
4110 		parsed = BADLEN_PARSE;
4111 		return;
4112 	}
4113 	switch (code_type)
4114 	{
4115 	    case 3: pbuf += sprintf(pbuf, "\nSVs Disabled:\n"); break;
4116 	    case 6: pbuf += sprintf(pbuf, "\nSVs with Health Ignored:\n"); break;
4117 	    default: return;
4118 	}
4119 	numsvs = 0;
4120 	for (iprn = 0; iprn < 32; iprn++)
4121 	{
4122 		if (status_code[iprn])
4123 		{
4124 			pbuf += sprintf(pbuf, " %02d", iprn+1);
4125 			numsvs++;
4126 		}
4127 	}
4128 	if (numsvs == 0) pbuf += sprintf(pbuf, "None");
4129 }
4130 
4131 
4132 /* 0x5A */
4133 static void
4134 rpt_raw_msmt(
4135 	     TSIPPKT *rpt
4136 	     )
4137 {
4138 	unsigned char
4139 	    sv_prn;
4140 	float
4141 	    sample_length, signal_level, code_phase, Doppler;
4142 	double
4143 	    time_of_fix;
4144 
4145 	/* unload rptbuf */
4146 	if (rpt_0x5A (rpt, &sv_prn, &sample_length, &signal_level,
4147 		      &code_phase, &Doppler, &time_of_fix))
4148 	{
4149 		parsed = BADLEN_PARSE;
4150 		return;
4151 	}
4152 
4153 	pbuf += sprintf(pbuf, "\n   %02d %5.0f %7.1f %10.2f %10.2f %12.3f %s",
4154 			sv_prn, sample_length, signal_level, code_phase, Doppler, time_of_fix,
4155 			show_time ((float)time_of_fix));
4156 }
4157 
4158 /* 0x5B */
4159 static void
4160 rpt_SV_ephemeris_status(
4161 			TSIPPKT *rpt
4162 			)
4163 {
4164 	unsigned char
4165 	    sv_prn, sv_health, sv_iode, fit_interval_flag;
4166 	float
4167 	    time_of_collection, time_of_eph, sv_accy;
4168 
4169 	/* unload rptbuf */
4170 	if (rpt_0x5B (rpt, &sv_prn, &sv_health, &sv_iode, &fit_interval_flag,
4171 		      &time_of_collection, &time_of_eph, &sv_accy))
4172 	{
4173 		parsed = BADLEN_PARSE;
4174 		return;
4175 	}
4176 
4177 	pbuf += sprintf(pbuf, "\n  SV%02d  %s   %2Xh     %2Xh ",
4178 			sv_prn, show_time (time_of_collection), sv_health, sv_iode);
4179 	/* note: cannot use show_time twice in same call */
4180 	pbuf += sprintf(pbuf, "%s   %1d   %4.1f",
4181 			show_time (time_of_eph), fit_interval_flag, sv_accy);
4182 }
4183 
4184 /* 0x5C */
4185 static void
4186 rpt_SV_tracking_status(
4187 		       TSIPPKT *rpt
4188 		       )
4189 {
4190 	unsigned char
4191 	    sv_prn, chan, slot, acq_flag, eph_flag,
4192 	    old_msmt_flag, integer_msec_flag, bad_data_flag,
4193 	    data_collect_flag;
4194 	float
4195 	    signal_level, time_of_last_msmt,
4196 	    elev, azim;
4197 
4198 	/* unload rptbuf */
4199 	if (rpt_0x5C (rpt,
4200 		      &sv_prn, &slot, &chan, &acq_flag, &eph_flag,
4201 		      &signal_level, &time_of_last_msmt, &elev, &azim,
4202 		      &old_msmt_flag, &integer_msec_flag, &bad_data_flag,
4203 		      &data_collect_flag))
4204 	{
4205 		parsed = BADLEN_PARSE;
4206 		return;
4207 	}
4208 
4209 	pbuf += sprintf(pbuf,
4210 			"\n SV%2d  %1d   %1d   %1d   %4.1f  %s  %5.1f  %5.1f",
4211 			sv_prn, chan,
4212 			acq_flag, eph_flag, signal_level,
4213 			show_time(time_of_last_msmt),
4214 			elev*R2D, azim*R2D);
4215 }
4216 
4217 /**/
4218 /* 0x6D */
4219 static void
4220 rpt_allSV_selection(
4221 		    TSIPPKT *rpt
4222 		    )
4223 {
4224 	unsigned char
4225 	    manual_mode, nsvs, sv_prn[8], ndim;
4226 	short
4227 	    islot;
4228 	float
4229 	    pdop, hdop, vdop, tdop;
4230 
4231 	/* unload rptbuf */
4232 	if (rpt_0x6D (rpt,
4233 		      &manual_mode, &nsvs, &ndim, sv_prn,
4234 		      &pdop, &hdop, &vdop, &tdop))
4235 	{
4236 		parsed = BADLEN_PARSE;
4237 		return;
4238 	}
4239 
4240 	switch (ndim)
4241 	{
4242 	    case 0:
4243 		pbuf += sprintf(pbuf, "\nMode: Searching, %d-SV:", nsvs);
4244 		break;
4245 	    case 1:
4246 		pbuf += sprintf(pbuf, "\nMode: One-SV Timing:");
4247 		break;
4248 	    case 3: case 4:
4249 		pbuf += sprintf(pbuf, "\nMode: %c-%dD, %d-SV:",
4250 				manual_mode ? 'M' : 'A', ndim - 1,  nsvs);
4251 		break;
4252 	    case 5:
4253 		pbuf += sprintf(pbuf, "\nMode: Timing, %d-SV:", nsvs);
4254 		break;
4255 	    default:
4256 		pbuf += sprintf(pbuf, "\nMode: Unknown = %d:", ndim);
4257 		break;
4258 	}
4259 
4260 	for (islot = 0; islot < nsvs; islot++)
4261 	{
4262 		if (sv_prn[islot]) pbuf += sprintf(pbuf, " %02d", sv_prn[islot]);
4263 	}
4264 	if (ndim == 3 || ndim == 4)
4265 	{
4266 		pbuf += sprintf(pbuf, ";  DOPs: P %.1f H %.1f V %.1f T %.1f",
4267 				pdop, hdop, vdop, tdop);
4268 	}
4269 }
4270 
4271 /**/
4272 /* 0x82 */
4273 static void
4274 rpt_DGPS_position_mode(
4275 		       TSIPPKT *rpt
4276 		       )
4277 {
4278 	unsigned char
4279 	    diff_mode;
4280 
4281 	/* unload rptbuf */
4282 	if (rpt_0x82 (rpt, &diff_mode)) {
4283 		parsed = BADLEN_PARSE;
4284 		return;
4285 	}
4286 
4287 	pbuf += sprintf(pbuf, "\nFix is%s DGPS-corrected (%s mode)  (%d)",
4288 			(diff_mode&1) ? "" : " not",
4289 			(diff_mode&2) ? "auto" : "manual",
4290 			diff_mode);
4291 }
4292 
4293 /* 0x83 */
4294 static void
4295 rpt_double_ECEF_position(
4296 			 TSIPPKT *rpt
4297 			 )
4298 {
4299 	double
4300 	    ECEF_pos[3], clock_bias;
4301 	float
4302 	    time_of_fix;
4303 
4304 	/* unload rptbuf */
4305 	if (rpt_0x83 (rpt, ECEF_pos, &clock_bias, &time_of_fix))
4306 	{
4307 		parsed = BADLEN_PARSE;
4308 		return;
4309 	}
4310 
4311 	pbuf += sprintf(pbuf, "\nDXYZ:%12.2f  %13.2f  %13.2f %12.2f%s",
4312 			ECEF_pos[0], ECEF_pos[1], ECEF_pos[2], clock_bias,
4313 			show_time(time_of_fix));
4314 }
4315 
4316 /* 0x84 */
4317 static void
4318 rpt_double_lla_position(
4319 			TSIPPKT *rpt
4320 			)
4321 {
4322 	short
4323 	    lat_deg, lon_deg;
4324 	double
4325 	    lat, lon, lat_min, lon_min,
4326 	    alt, clock_bias;
4327 	float
4328 	    time_of_fix;
4329 	unsigned char
4330 	    north_south, east_west;
4331 
4332 	/* unload rptbuf */
4333 	if (rpt_0x84 (rpt,
4334 		      &lat, &lon, &alt, &clock_bias, &time_of_fix))
4335 	{
4336 		parsed = BADLEN_PARSE;
4337 		return;
4338 	}
4339 
4340 	lat *= R2D;
4341 	lon *= R2D;
4342 	if (lat < 0.0) {
4343 		north_south = 'S';
4344 		lat = -lat;
4345 	} else {
4346 		north_south = 'N';
4347 	}
4348 	lat_deg = (short)lat;
4349 	lat_min = (lat - lat_deg) * 60.0;
4350 
4351 	if (lon < 0.0) {
4352 		east_west = 'W';
4353 		lon = -lon;
4354 	} else {
4355 		east_west = 'E';
4356 	}
4357 	lon_deg = (short)lon;
4358 	lon_min = (lon - lon_deg) * 60.0;
4359 	pbuf += sprintf(pbuf, "\nDLLA: %2d:%08.5f %c; %3d:%08.5f %c; %10.2f %12.2f%s",
4360 			lat_deg, lat_min, north_south,
4361 			lon_deg, lon_min, east_west,
4362 			alt, clock_bias,
4363 			show_time(time_of_fix));
4364 }
4365 
4366 /* 0xBB */
4367 static void
4368 rpt_complete_rcvr_config(
4369 			 TSIPPKT *rpt
4370 			 )
4371 {
4372 	TSIP_RCVR_CFG TsipxBB ;
4373 	/* unload rptbuf */
4374 	if (rpt_Paly0xBB (rpt, &TsipxBB))
4375 	{
4376 		parsed = BADLEN_PARSE;
4377 		return;
4378 	}
4379 
4380 	pbuf += sprintf(pbuf, "\n   operating mode:      %s",
4381 			NavModeText0xBB[TsipxBB.operating_mode]);
4382 	pbuf += sprintf(pbuf, "\n   dynamics:            %s",
4383 			dyn_text[TsipxBB.dyn_code]);
4384 	pbuf += sprintf(pbuf, "\n   elev angle mask:     %g deg",
4385 			TsipxBB.elev_mask * R2D);
4386 	pbuf += sprintf(pbuf, "\n   SNR mask:            %g AMU",
4387 			TsipxBB.cno_mask);
4388 	pbuf += sprintf(pbuf, "\n   DOP mask:            %g",
4389 			TsipxBB.dop_mask);
4390 	pbuf += sprintf(pbuf, "\n   DOP switch:          %g",
4391 			TsipxBB.dop_switch);
4392 	return ;
4393 }
4394 
4395 /* 0xBC */
4396 static void
4397 rpt_rcvr_serial_port_config(
4398 			    TSIPPKT *rpt
4399 			    )
4400 {
4401 	unsigned char
4402 	    port_num, in_baud, out_baud, data_bits, parity, stop_bits, flow_control,
4403 	    protocols_in, protocols_out, reserved;
4404 	unsigned char known;
4405 
4406 	/* unload rptbuf */
4407 	if (rpt_0xBC (rpt, &port_num, &in_baud, &out_baud, &data_bits, &parity,
4408 		      &stop_bits, &flow_control, &protocols_in, &protocols_out, &reserved)) {
4409 		parsed = BADLEN_PARSE;
4410 		return;
4411 	}
4412 	/* rptbuf unloaded */
4413 
4414 	pbuf += sprintf(pbuf, "\n   RECEIVER serial port %s config:",
4415 			rcvr_port_text[port_num]);
4416 
4417 	pbuf += sprintf(pbuf, "\n             I/O Baud %s/%s, %d - %s - %d",
4418 			st_baud_text_app[in_baud],
4419 			st_baud_text_app[out_baud],
4420 			data_bits+5,
4421 			parity_text[parity],
4422 			stop_bits=1);
4423 	pbuf += sprintf(pbuf, "\n             Input protocols: ");
4424 	known = FALSE;
4425 	if (protocols_in&B_TSIP)
4426 	{
4427 		pbuf += sprintf(pbuf, "%s ", protocols_in_text[1]);
4428 		known = TRUE;
4429 	}
4430 	if (known == FALSE) pbuf += sprintf(pbuf, "No known");
4431 
4432 	pbuf += sprintf(pbuf, "\n             Output protocols: ");
4433 	known = FALSE;
4434 	if (protocols_out&B_TSIP)
4435 	{
4436 		pbuf += sprintf(pbuf, "%s ", protocols_out_text[1]);
4437 		known = TRUE;
4438 	}
4439 	if (protocols_out&B_NMEA)
4440 	{
4441 		pbuf += sprintf(pbuf, "%s ", protocols_out_text[2]);
4442 		known = TRUE;
4443 	}
4444 	if (known == FALSE) pbuf += sprintf(pbuf, "No known");
4445 	reserved = reserved;
4446 
4447 }
4448 
4449 /* 0x8F */
4450 /* 8F0B */
4451 static void
4452 rpt_8F0B(
4453 	 TSIPPKT *rpt
4454 	 )
4455 {
4456 	const char
4457 	    *oprtng_dim[7] = {
4458 		"horizontal (2-D)",
4459 		"full position (3-D)",
4460 		"single satellite (0-D)",
4461 		"automatic",
4462 		"N/A",
4463 		"N/A",
4464 		"overdetermined clock"};
4465 	char
4466 	    sv_id[8];
4467 	unsigned char
4468 	    month,
4469 	    date,
4470 	    dim_mode,
4471 	    north_south,
4472 	    east_west;
4473 	unsigned short
4474 	    event;
4475 	short
4476 	    utc_offset,
4477 	    year,
4478 	    local_index;
4479 	short
4480 	    lat_deg,
4481 	    lon_deg;
4482 	float
4483 	    bias_unc,
4484 	    dr_unc;
4485 	double
4486 	    tow,
4487 	    bias,
4488 	    drift,
4489 	    lat,
4490 	    lon,
4491 	    alt,
4492 	    lat_min,
4493 	    lon_min;
4494 	int
4495 	    numfix,
4496 	    numnotfix;
4497 
4498 	if (rpt_0x8F0B(rpt,
4499 		       &event,
4500 		       &tow,
4501 		       &date,
4502 		       &month,
4503 		       &year,
4504 		       &dim_mode,
4505 		       &utc_offset,
4506 		       &bias,
4507 		       &drift,
4508 		       &bias_unc,
4509 		       &dr_unc,
4510 		       &lat,
4511 		       &lon,
4512 		       &alt,
4513 		       sv_id))
4514 	{
4515 		parsed = BADLEN_PARSE;
4516 		return;
4517 	}
4518 
4519 	if (event == 0)
4520 	{
4521 		pbuf += sprintf(pbuf, "\nNew partial+full meas");
4522 	}
4523 	else
4524 	{
4525 		pbuf += sprintf(pbuf, "\nEvent count: %5d", event);
4526 	}
4527 
4528 	pbuf += sprintf(pbuf, "\nGPS time  : %s %2d/%2d/%2d (DMY)",
4529 			show_time(tow), date, month, year);
4530 	pbuf += sprintf(pbuf, "\nMode      : %s", oprtng_dim[dim_mode]);
4531 	pbuf += sprintf(pbuf, "\nUTC offset: %2d", utc_offset);
4532 	pbuf += sprintf(pbuf, "\nClock Bias: %6.2f m", bias);
4533 	pbuf += sprintf(pbuf, "\nFreq bias : %6.2f m/s", drift);
4534 	pbuf += sprintf(pbuf, "\nBias unc  : %6.2f m", bias_unc);
4535 	pbuf += sprintf(pbuf, "\nFreq unc  : %6.2f m/s", dr_unc);
4536 
4537 	lat *= R2D; /* convert from radians to degrees */
4538 	lon *= R2D;
4539 	if (lat < 0.0)
4540 	{
4541 		north_south = 'S';
4542 		lat = -lat;
4543 	}
4544 	else
4545 	{
4546 		north_south = 'N';
4547 	}
4548 
4549 	lat_deg = (short)lat;
4550 	lat_min = (lat - lat_deg) * 60.0;
4551 	if (lon < 0.0)
4552 	{
4553 		east_west = 'W';
4554 		lon = -lon;
4555 	}
4556 	else
4557 	{
4558 		east_west = 'E';
4559 	}
4560 
4561 	lon_deg = (short)lon;
4562 	lon_min = (lon - lon_deg) * 60.0;
4563 	pbuf += sprintf(pbuf, "\nPosition  :");
4564 	pbuf += sprintf(pbuf, " %4d %6.3f %c", lat_deg, lat_min, north_south);
4565 	pbuf += sprintf(pbuf, " %5d %6.3f %c", lon_deg, lon_min, east_west);
4566 	pbuf += sprintf(pbuf, " %10.2f", alt);
4567 
4568 	numfix = numnotfix = 0;
4569 	for (local_index=0; local_index<8; local_index++)
4570 	{
4571 		if (sv_id[local_index] < 0) numnotfix++;
4572 		if (sv_id[local_index] > 0) numfix++;
4573 	}
4574 	if (numfix > 0)
4575 	{
4576 		pbuf += sprintf(pbuf, "\nSVs used in fix  : ");
4577 		for (local_index=0; local_index<8; local_index++)
4578 		{
4579 			if (sv_id[local_index] > 0)
4580 			{
4581 				pbuf += sprintf(pbuf, "%2d ", sv_id[local_index]);
4582 			}
4583 		}
4584 	}
4585 	if (numnotfix > 0)
4586 	{
4587 		pbuf += sprintf(pbuf, "\nOther SVs tracked: ");
4588 		for (local_index=0; local_index<8; local_index++)
4589 		{
4590 			if (sv_id[local_index] < 0)
4591 			{
4592 				pbuf += sprintf(pbuf, "%2d ", sv_id[local_index]);
4593 			}
4594 		}
4595 	}
4596 }
4597 
4598 /* 0x8F14 */
4599 /* Datum parameters */
4600 static void
4601 rpt_8F14(
4602 	 TSIPPKT *rpt
4603 	 )
4604 {
4605 	double
4606 	    datum_coeffs[5];
4607 	short
4608 	    datum_idx;
4609 
4610 	/* unload rptbuf */
4611 	if (rpt_0x8F14 (rpt, &datum_idx, datum_coeffs))
4612 	{
4613 		parsed = BADLEN_PARSE;
4614 		return;
4615 	}
4616 
4617 	if (datum_idx == -1)
4618 	{
4619 		pbuf += sprintf(pbuf, "\nUser-Entered Datum:");
4620 		pbuf += sprintf(pbuf, "\n   dx        = %6.1f", datum_coeffs[0]);
4621 		pbuf += sprintf(pbuf, "\n   dy        = %6.1f", datum_coeffs[1]);
4622 		pbuf += sprintf(pbuf, "\n   dz        = %6.1f", datum_coeffs[2]);
4623 		pbuf += sprintf(pbuf, "\n   a-axis    = %10.3f", datum_coeffs[3]);
4624 		pbuf += sprintf(pbuf, "\n   e-squared = %16.14f", datum_coeffs[4]);
4625 	}
4626 	else if (datum_idx == 0)
4627 	{
4628 		pbuf += sprintf(pbuf, "\nWGS-84 datum, Index 0 ");
4629 	}
4630 	else
4631 	{
4632 		pbuf += sprintf(pbuf, "\nStandard Datum, Index %3d ", datum_idx);
4633 	}
4634 }
4635 
4636 /* 0x8F15 */
4637 /* Datum parameters */
4638 static void
4639 rpt_8F15(
4640 	 TSIPPKT *rpt
4641 	 )
4642 {
4643 	double
4644 	    datum_coeffs[5];
4645 	short
4646 	    datum_idx;
4647 
4648 	/* unload rptbuf */
4649 	if (rpt_0x8F15 (rpt, &datum_idx, datum_coeffs)) {
4650 		parsed = BADLEN_PARSE;
4651 		return;
4652 	}
4653 
4654 	if (datum_idx == -1)
4655 	{
4656 		pbuf += sprintf(pbuf, "\nUser-Entered Datum:");
4657 		pbuf += sprintf(pbuf, "\n   dx        = %6.1f", datum_coeffs[0]);
4658 		pbuf += sprintf(pbuf, "\n   dy        = %6.1f", datum_coeffs[1]);
4659 		pbuf += sprintf(pbuf, "\n   dz        = %6.1f", datum_coeffs[2]);
4660 		pbuf += sprintf(pbuf, "\n   a-axis    = %10.3f", datum_coeffs[3]);
4661 		pbuf += sprintf(pbuf, "\n   e-squared = %16.14f", datum_coeffs[4]);
4662 	}
4663 	else if (datum_idx == 0)
4664 	{
4665 		pbuf += sprintf(pbuf, "\nWGS-84 datum, Index 0 ");
4666 	}
4667 	else
4668 	{
4669 		pbuf += sprintf(pbuf, "\nStandard Datum, Index %3d ", datum_idx);
4670 	}
4671 }
4672 
4673 /* 0x8F20 */
4674 #define INFO_DGPS       0x02
4675 #define INFO_2D         0x04
4676 #define INFO_ALTSET     0x08
4677 #define INFO_FILTERED   0x10
4678 static void
4679 rpt_8F20(
4680 	 TSIPPKT *rpt
4681 	 )
4682 {
4683 	unsigned char
4684 	    info, nsvs, sv_prn[32];
4685 	short
4686 	    week_num, datum_index, sv_IODC[32];
4687 	double
4688 	    lat, lon, alt, time_of_fix;
4689 	double
4690 	    londeg, latdeg, vel[3];
4691 	short
4692 	    isv;
4693 	char
4694 	    datum_string[20];
4695 
4696 	/* unload rptbuf */
4697 	if (rpt_0x8F20 (rpt,
4698 			&info, &lat, &lon, &alt, vel,
4699 			&time_of_fix,
4700 			&week_num, &nsvs, sv_prn, sv_IODC, &datum_index))
4701 	{
4702 		parsed = BADLEN_PARSE;
4703 		return;
4704 	}
4705 	pbuf += sprintf(pbuf,
4706 			"\nFix at: %04d:%3s:%02d:%02d:%06.3f GPS (=UTC+%2ds)  FixType: %s%s%s",
4707 			week_num,
4708 			dayname[(short)(time_of_fix/86400.0)],
4709 			(short)fmod(time_of_fix/3600., 24.),
4710 			(short)fmod(time_of_fix/60., 60.),
4711 			fmod(time_of_fix, 60.),
4712 			(char)rpt->buf[29],		/* UTC offset */
4713 			(info & INFO_DGPS)?"Diff":"",
4714 			(info & INFO_2D)?"2D":"3D",
4715 			(info & INFO_FILTERED)?"-Filtrd":"");
4716 
4717 	if (datum_index > 0)
4718 	{
4719 		sprintf(datum_string, "Datum%3d", datum_index);
4720 	}
4721 	else if (datum_index)
4722 	{
4723 		sprintf(datum_string, "Unknown ");
4724 	}
4725 	else
4726 	{
4727 		sprintf(datum_string, "WGS-84");
4728 	}
4729 
4730 	/* convert from radians to degrees */
4731 	latdeg = R2D * fabs(lat);
4732 	londeg = R2D * fabs(lon);
4733 	pbuf += sprintf(pbuf,
4734 			"\n   Pos: %4d:%09.6f %c %5d:%09.6f %c %10.2f m HAE (%s)",
4735 			(short)latdeg, fmod (latdeg, 1.)*60.0,
4736 			(lat<0.0)?'S':'N',
4737 			(short)londeg, fmod (londeg, 1.)*60.0,
4738 			(lon<0.0)?'W':'E',
4739 			alt,
4740 			datum_string);
4741 	pbuf += sprintf(pbuf,
4742 			"\n   Vel:    %9.3f E       %9.3f N      %9.3f U   (m/sec)",
4743 			vel[0], vel[1], vel[2]);
4744 
4745 	pbuf += sprintf(pbuf,
4746 			"\n   SVs: ");
4747 	for (isv = 0; isv < nsvs; isv++) {
4748 		pbuf += sprintf(pbuf, " %02d", sv_prn[isv]);
4749 	}
4750 	pbuf += sprintf(pbuf, "     (IODEs:");
4751 	for (isv = 0; isv < nsvs; isv++) {
4752 		pbuf += sprintf(pbuf, " %02X", sv_IODC[isv]&0xFF);
4753 	}
4754 	pbuf += sprintf(pbuf, ")");
4755 }
4756 
4757 /* 0x8F41 */
4758 static void
4759 rpt_8F41(
4760 	 TSIPPKT *rpt
4761 	 )
4762 {
4763 	unsigned char
4764 	    bSearchRange,
4765 	    bBoardOptions,
4766 	    bBuildYear,
4767 	    bBuildMonth,
4768 	    bBuildDay,
4769 	    bBuildHour;
4770 	float
4771 	    fOscOffset;
4772 	unsigned short
4773 	    iTestCodeId;
4774 	unsigned long
4775 	    iiSerialNumber;
4776 
4777 	if (!rpt_0x8F41(rpt,
4778 			&bSearchRange,
4779 			&bBoardOptions,
4780 			&iiSerialNumber,
4781 			&bBuildYear,
4782 			&bBuildMonth,
4783 			&bBuildDay,
4784 			&bBuildHour,
4785 			&fOscOffset,
4786 			&iTestCodeId))
4787 	{
4788 		parsed = BADLEN_PARSE;
4789 		return;
4790 	}
4791 
4792 	pbuf += sprintf(pbuf, "\n  search range:          %d",
4793 			bSearchRange);
4794 	pbuf += sprintf(pbuf, "\n  board options:         %d",
4795 			bBoardOptions);
4796 	pbuf += sprintf(pbuf, "\n  board serial #:        %ld",
4797 			iiSerialNumber);
4798 	pbuf += sprintf(pbuf, "\n  build date/hour:       %02d/%02d/%02d %02d:00",
4799 			bBuildDay, bBuildMonth, bBuildYear, bBuildHour);
4800 	pbuf += sprintf(pbuf, "\n  osc offset:            %.3f PPM (%.0f Hz)",
4801 			fOscOffset/1575.42, fOscOffset);
4802 	pbuf += sprintf(pbuf, "\n  test code:             %d",
4803 			iTestCodeId);
4804 }
4805 
4806 /* 0x8F42 */
4807 static void
4808 rpt_8F42(
4809 	 TSIPPKT *rpt
4810 	 )
4811 {
4812 	unsigned char
4813 	    bProdOptionsPre,
4814 	    bProdNumberExt;
4815 	unsigned short
4816 	    iCaseSerialNumberPre,
4817 	    iPremiumOptions,
4818 	    iMachineID,
4819 	    iKey;
4820 	unsigned long
4821 	    iiCaseSerialNumber,
4822 	    iiProdNumber;
4823 
4824 	if (!rpt_0x8F42(rpt,
4825 			&bProdOptionsPre,
4826 			&bProdNumberExt,
4827 			&iCaseSerialNumberPre,
4828 			&iiCaseSerialNumber,
4829 			&iiProdNumber,
4830 			&iPremiumOptions,
4831 			&iMachineID,
4832 			&iKey))
4833 	{
4834 		parsed = BADLEN_PARSE;
4835 		return;
4836 	}
4837 
4838 	pbuf += sprintf(pbuf, "\nProduct ID 8F42");
4839 	pbuf += sprintf(pbuf, "\n   extension:            %d", bProdNumberExt);
4840 	pbuf += sprintf(pbuf, "\n   case serial # prefix: %d", iCaseSerialNumberPre);
4841 	pbuf += sprintf(pbuf, "\n   case serial #:        %ld", iiCaseSerialNumber);
4842 	pbuf += sprintf(pbuf, "\n   prod. #:              %ld", iiProdNumber);
4843 	pbuf += sprintf(pbuf, "\n   premium options:      %Xh", iPremiumOptions);
4844 	pbuf += sprintf(pbuf, "\n   machine ID:           %d", iMachineID);
4845 	pbuf += sprintf(pbuf, "\n   key:                  %Xh", iKey);
4846 }
4847 
4848 /* 0x8F45 */
4849 static void
4850 rpt_8F45(
4851 	 TSIPPKT *rpt
4852 	 )
4853 {
4854 	unsigned char bSegMask;
4855 
4856 	if (!rpt_0x8F45(rpt,
4857 			&bSegMask))
4858 	{
4859 		parsed = BADLEN_PARSE;
4860 		return;
4861 	}
4862 	pbuf += sprintf(pbuf, "\nCleared Segment Mask: %Xh", bSegMask);
4863 }
4864 
4865 /* Stinger PPS def */
4866 static void
4867 rpt_8F4A(
4868 	 TSIPPKT *rpt
4869 	 )
4870 {
4871 	unsigned char
4872 	    pps_enabled,
4873 	    pps_timebase,
4874 	    pps_polarity;
4875 	float
4876 	    bias_unc_threshold;
4877 	double
4878 	    pps_offset;
4879 
4880   	if (rpt_0x8F4A_16 (rpt,
4881 			   &pps_enabled,
4882 			   &pps_timebase,
4883 			   &pps_polarity,
4884 			   &pps_offset,
4885 			   &bias_unc_threshold))
4886 	{
4887 		parsed = BADLEN_PARSE;
4888 		return;
4889 	}
4890 
4891 	pbuf += sprintf(pbuf, "\nPPS is         %s",	pps_enabled?"enabled":"disabled");
4892 	pbuf += sprintf(pbuf, "\n   timebase:   %s", PPSTimeBaseText[pps_timebase]);
4893 	pbuf += sprintf(pbuf, "\n   polarity:   %s", PPSPolarityText[pps_polarity]);
4894 	pbuf += sprintf(pbuf, "\n   offset:     %.1f ns, ", pps_offset*1.e9);
4895 	pbuf += sprintf(pbuf, "\n   biasunc:    %.1f ns", bias_unc_threshold/GPS_C*1.e9);
4896 }
4897 
4898 /* fast-SA decorrolation time for self-survey */
4899 static void
4900 rpt_8F4B(
4901 	 TSIPPKT *rpt
4902 	 )
4903 {
4904 	unsigned long
4905 	    decorr_max;
4906 
4907 	if (rpt_0x8F4B(rpt, &decorr_max))
4908 	{
4909 		parsed = BADLEN_PARSE;
4910 		return;
4911 	}
4912 
4913 	pbuf += sprintf(pbuf,
4914 			"\nMax # of position fixes for self-survey : %ld",
4915 			decorr_max);
4916 }
4917 
4918 static void
4919 rpt_8F4D(
4920 	 TSIPPKT *rpt
4921 	 )
4922 {
4923 	static char
4924 	    *linestart;
4925 	unsigned long
4926 	    OutputMask;
4927 	static unsigned long
4928 	    MaskBit[] = {
4929 		0x00000001, 0x00000002, 0x00000004, 0x00000008, 0x00000010,
4930 		0x00000020,
4931 		0x00000100L, 0x00000800L, 0x00001000L,
4932 		0x40000000L, 0x80000000L};
4933 	int
4934 	    ichoice,
4935 	    numchoices;
4936 
4937 	if (rpt_0x8F4D(rpt, &OutputMask))
4938 	{
4939 		parsed = BADLEN_PARSE;
4940 		return;
4941 	}
4942 
4943 	pbuf += sprintf(pbuf, "\nAuto-Report Mask: %02X %02X %02X %02X",
4944 			(unsigned char)(OutputMask>>24),
4945 			(unsigned char)(OutputMask>>16),
4946 			(unsigned char)(OutputMask>>8),
4947 			(unsigned char)OutputMask);
4948 
4949 	numchoices = sizeof(MaskText)/sizeof(char*);
4950 	pbuf += sprintf(pbuf, "\nAuto-Reports scheduled for Output:");
4951 	linestart = pbuf;
4952 	for (ichoice = 0; ichoice < numchoices; ichoice++)
4953 	{
4954 		if (OutputMask&MaskBit[ichoice])
4955 		{
4956 			pbuf += sprintf(pbuf, "%s %s",
4957 					(pbuf==linestart)?"\n     ":",",
4958 					MaskText[ichoice]);
4959 			if (pbuf-linestart > 60) linestart = pbuf;
4960 		}
4961 	}
4962 
4963 	pbuf += sprintf(pbuf, "\nAuto-Reports NOT scheduled for Output:");
4964 	linestart = pbuf;
4965 	for (ichoice = 0; ichoice < numchoices; ichoice++)
4966 	{
4967 		if (OutputMask&MaskBit[ichoice]) continue;
4968 	     	pbuf += sprintf(pbuf, "%s %s",
4969 				(pbuf==linestart)?"\n     ":",",
4970 				MaskText[ichoice]);
4971 		if (pbuf-linestart > 60) linestart = pbuf;
4972 	}
4973 }
4974 
4975 static void
4976 rpt_8FA5(
4977 	 TSIPPKT *rpt
4978 	 )
4979 {
4980 	unsigned char
4981 	    spktmask[4];
4982 
4983 	if (rpt_0x8FA5(rpt, spktmask))
4984 	{
4985 		parsed = BADLEN_PARSE;
4986 		return;
4987 	}
4988 
4989 	pbuf += sprintf(pbuf, "\nSuperpacket auto-output mask: %02X %02X %02X %02X",
4990 			spktmask[0], spktmask[1], spktmask[2], spktmask[3]);
4991 
4992 	if (spktmask[0]&0x01) pbuf+= sprintf (pbuf, "\n    PPS   8F-0B");
4993 	if (spktmask[0]&0x02) pbuf+= sprintf (pbuf, "\n    Event 8F-0B");
4994 	if (spktmask[0]&0x10) pbuf+= sprintf (pbuf, "\n    PPS   8F-AD");
4995 	if (spktmask[0]&0x20) pbuf+= sprintf (pbuf, "\n    Event 8F-AD");
4996 	if (spktmask[2]&0x01) pbuf+= sprintf (pbuf, "\n    ppos Fix 8F-20");
4997 }
4998 
4999 static void
5000 rpt_8FAD(
5001 	 TSIPPKT *rpt
5002 	 )
5003 {
5004 	unsigned short
5005 	    Count,
5006 	    Year;
5007 	double
5008 	    FracSec;
5009 	unsigned char
5010 	    Hour,
5011 	    Minute,
5012 	    Second,
5013 	    Day,
5014 	    Month,
5015 	    Status,
5016 	    Flags;
5017 	static char* Status8FADText[] = {
5018 		"CODE_DOING_FIXES",
5019 		"CODE_GOOD_1_SV",
5020 		"CODE_APPX_1SV",
5021 		"CODE_NEED_TIME",
5022 		"CODE_NEED_INITIALIZATION",
5023 		"CODE_PDOP_HIGH",
5024 		"CODE_BAD_1SV",
5025 		"CODE_0SVS",
5026 		"CODE_1SV",
5027 		"CODE_2SVS",
5028 		"CODE_3SVS",
5029 		"CODE_NO_INTEGRITY",
5030 		"CODE_DCORR_GEN",
5031 		"CODE_OVERDET_CLK",
5032 		"Invalid Status"},
5033 	    *LeapStatusText[] = {
5034 		    " UTC Avail", " ", " ", " ",
5035 		    " Scheduled", " Pending", " Warning", " In Progress"};
5036 	int i;
5037 
5038 	if (rpt_0x8FAD (rpt,
5039 			&Count,
5040 			&FracSec,
5041 			&Hour,
5042 			&Minute,
5043 			&Second,
5044 			&Day,
5045 			&Month,
5046 			&Year,
5047 			&Status,
5048 			&Flags))
5049 	{
5050 		parsed = BADLEN_PARSE;
5051 		return;
5052 	}
5053 
5054 	pbuf += sprintf(pbuf,    "\n8FAD   Count: %d   Status: %s",
5055 			Count, Status8FADText[Status]);
5056 
5057 	pbuf += sprintf(pbuf, "\n   Leap Flags:");
5058 	if (Flags)
5059 	{
5060 		for (i=0; i<8; i++)
5061 		{
5062 			if (Flags&(1<<i)) pbuf += sprintf(pbuf, LeapStatusText[i]);
5063 		}
5064 	}
5065 	else
5066 	{
5067 		pbuf += sprintf(pbuf, "  UTC info not available");
5068 	}
5069 
5070 	pbuf += sprintf(pbuf,     "\n      %02d/%02d/%04d (DMY)  %02d:%02d:%02d.%09ld UTC",
5071 			Day, Month, Year, Hour, Minute, Second, (long)(FracSec*1.e9));
5072 }
5073 
5074 
5075 int
5076 print_msg_table_header(
5077 		       int rptcode,
5078 		       char *HdrStr,
5079 		       int force
5080 		       )
5081 {
5082 	/* force header is to help auto-output function */
5083 	/* last_rptcode is to determine whether to print a header */
5084 	/* for the first occurrence of a series of reports */
5085 	static int
5086 	    last_rptcode = 0;
5087 	int
5088 	    numchars;
5089 
5090 	numchars = 0;
5091 	if (force || rptcode!=last_rptcode)
5092 	{
5093 		/* supply a header in console output */
5094 		switch (rptcode)
5095 		{
5096 		    case 0x5A:
5097 			numchars = sprintf(HdrStr, "\nRaw Measurement Data");
5098 			numchars += sprintf(HdrStr+numchars,
5099 					    "\n   SV  Sample   SNR  Code Phase   Doppler    Seconds     Time of Meas");
5100 			break;
5101 
5102 		    case 0x5B:
5103 			numchars = sprintf(HdrStr, "\nEphemeris Status");
5104 			numchars += sprintf(HdrStr+numchars,
5105 					    "\n    SV     Time collected     Health  IODE        t oe         Fit   URA");
5106 			break;
5107 
5108 		    case 0x5C:
5109 			numchars = sprintf(HdrStr, "\nTracking Info");
5110 			numchars += sprintf(HdrStr+numchars,
5111 					    "\n   SV  C Acq Eph   SNR     Time of Meas       Elev  Azim   ");
5112 			break;
5113 
5114 		}
5115 	}
5116 	last_rptcode = rptcode;
5117 	return (short)numchars;
5118 }
5119 
5120 static void
5121 unknown_rpt(
5122 	    TSIPPKT *rpt
5123 	    )
5124 {
5125 	int i;
5126 
5127 	/* app-specific rpt packets */
5128 	if (parsed == BADLEN_PARSE)
5129 	{
5130 		pbuf += sprintf(pbuf, "\nTSIP report packet ID %2Xh, length %d: Bad length",
5131 				rpt->code, rpt->len);
5132 	}
5133 	if (parsed == BADID_PARSE)
5134 	{
5135 		pbuf += sprintf(pbuf,
5136 				"\nTSIP report packet ID %2Xh, length %d: translation not supported",
5137 				rpt->code, rpt->len);
5138 	}
5139 
5140 	if (parsed == BADDATA_PARSE)
5141 	{
5142 		pbuf += sprintf(pbuf,
5143 				"\nTSIP report packet ID %2Xh, length %d: data content incorrect",
5144 				rpt->code, rpt->len);
5145 	}
5146 
5147 	for (i = 0; i < rpt->len; i++) {
5148 		if ((i % 20) == 0) *pbuf++ = '\n';
5149 		pbuf += sprintf(pbuf, " %02X", rpt->buf[i]);
5150 	}
5151 }
5152 /**/
5153 
5154 /*
5155 ** main subroutine, called from ProcessInputBytesWhileWaitingForKBHit()
5156 */
5157 void
5158 TranslateTSIPReportToText(
5159 			  TSIPPKT *rpt,
5160 			  char *TextOutputBuffer
5161 			  )
5162 {
5163 
5164 	/* pbuf is the pointer to the current location of the text output */
5165 	pbuf = TextOutputBuffer;
5166 
5167 	/* keep track of whether the message has been successfully parsed */
5168 	parsed = GOOD_PARSE;
5169 
5170 	/* print a header if this is the first of a series of messages */
5171 	pbuf += print_msg_table_header (rpt->code, pbuf, FALSE);
5172 
5173 	/* process incoming TSIP report according to code */
5174 	switch (rpt->code)
5175 	{
5176 	    case 0x3D: rpt_chan_A_config (rpt); break;
5177 	    case 0x40: rpt_almanac_data_page (rpt); break;
5178 	    case 0x41: rpt_GPS_time (rpt); break;
5179 	    case 0x42: rpt_single_ECEF_position (rpt); break;
5180 	    case 0x43: rpt_single_ECEF_velocity (rpt); break;
5181 	    case 0x45: rpt_SW_version (rpt); break;
5182 	    case 0x46: rpt_rcvr_health (rpt); break;
5183 	    case 0x47: rpt_SNR_all_SVs (rpt); break;
5184 	    case 0x48: rpt_GPS_system_message (rpt); break;
5185 	    case 0x49: rpt_almanac_health_page (rpt); break;
5186 	    case 0x4A: switch (rpt->len) {
5187 			/*
5188 			** special case (=slip-up) in the TSIP protocol;
5189 			** parsing method depends on length
5190 			*/
5191 		    case 20: rpt_single_lla_position (rpt); break;
5192 		    case  9: rpt_ref_alt (rpt); break;
5193 		} break;
5194 	    case 0x4B: rpt_rcvr_id_and_status (rpt);break;
5195 	    case 0x4C: rpt_operating_parameters (rpt); break;
5196 	    case 0x4D: rpt_oscillator_offset (rpt); break;
5197 	    case 0x4E: rpt_GPS_time_set_response (rpt); break;
5198 	    case 0x4F: rpt_UTC_offset (rpt); break;
5199 	    case 0x54: rpt_1SV_bias (rpt); break;
5200 	    case 0x55: rpt_io_opt (rpt); break;
5201 	    case 0x56: rpt_ENU_velocity (rpt); break;
5202 	    case 0x57: rpt_last_fix_info (rpt); break;
5203 	    case 0x58: rpt_GPS_system_data (rpt); break;
5204 	    case 0x59: rpt_SVs_enabled (rpt); break;
5205 	    case 0x5A: rpt_raw_msmt (rpt); break;
5206 	    case 0x5B: rpt_SV_ephemeris_status (rpt); break;
5207 	    case 0x5C: rpt_SV_tracking_status (rpt); break;
5208 	    case 0x6D: rpt_allSV_selection (rpt); break;
5209 	    case 0x82: rpt_DGPS_position_mode (rpt); break;
5210 	    case 0x83: rpt_double_ECEF_position (rpt); break;
5211 	    case 0x84: rpt_double_lla_position (rpt); break;
5212 	    case 0xBB: rpt_complete_rcvr_config (rpt); break;
5213 	    case 0xBC: rpt_rcvr_serial_port_config (rpt); break;
5214 
5215 	    case 0x8F: switch (rpt->buf[0])
5216 		{
5217 			/* superpackets; parsed according to subcodes */
5218 		    case 0x0B: rpt_8F0B(rpt); break;
5219 		    case 0x14: rpt_8F14(rpt); break;
5220 		    case 0x15: rpt_8F15(rpt); break;
5221 		    case 0x20: rpt_8F20(rpt); break;
5222 		    case 0x41: rpt_8F41(rpt); break;
5223 		    case 0x42: rpt_8F42(rpt); break;
5224 		    case 0x45: rpt_8F45(rpt); break;
5225 		    case 0x4A: rpt_8F4A(rpt); break;
5226 		    case 0x4B: rpt_8F4B(rpt); break;
5227 		    case 0x4D: rpt_8F4D(rpt); break;
5228 		    case 0xA5: rpt_8FA5(rpt); break;
5229 		    case 0xAD: rpt_8FAD(rpt); break;
5230 		    default: parsed = BADID_PARSE; break;
5231 		}
5232 		break;
5233 
5234 	    default: parsed = BADID_PARSE; break;
5235 	}
5236 
5237 	if (parsed != GOOD_PARSE)
5238 	{
5239 		/*
5240 		**The message has TSIP structure (DLEs, etc.)
5241 		** but could not be parsed by above routines
5242 		*/
5243 		unknown_rpt (rpt);
5244 	}
5245 
5246 	/* close TextOutputBuffer */
5247 	pbuf = '\0';
5248 }
5249 
5250 #endif /* TRIMBLE_OUTPUT_FUNC */
5251 
5252 #else  /* defined(REFCLOCK) && defined(CLOCK_RIPENCC) */
5253 NONEMPTY_TRANSLATION_UNIT
5254 #endif /* defined(REFCLOCK) && defined(CLOCK_RIPENCC) */
5255 
5256