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