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