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