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