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