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