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