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