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