1 /* $NetBSD: refclock_ripencc.c,v 1.2 2003/12/04 16:23:37 drochner Exp $ */
4 * Id: refclock_ripencc.c,v 1.13 2002/06/18 14:20:55 marks Exp marks
6 * Copyright (c) 2002 RIPE NCC
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>
39 #endif /* HAVE_CONFIG_H */
41 #if defined(REFCLOCK) && defined(CLOCK_RIPENCC)
43 #include "ntp_stdlib.h"
45 #include "ntp_refclock.h"
46 #include "ntp_unixtime.h"
50 # include "ppsapi_timepps.h"
57 /* we are on little endian */
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"
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.)
82 /* control characters for TSIP packets */
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 */
104 #define DESCRIPTION "RIPE NCC GPS (Palisade)" /* Description */
105 #define SPEED232 B9600 /* 9600 baud */
107 #define NSAMPLES 3 /* stages of median filter */
111 /* TSIP packets have the following structure, whether report or command. */
114 counter
, /* counter */
115 len
; /* size of buf; < MAX_RPTBUF unsigned chars */
117 status
, /* TSIP packet format/parse status */
118 code
, /* TSIP code */
119 buf
[MAX_RPTBUF
];/* report or command string */
122 /* TSIP binary data structures */
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
;
134 typedef struct { /* Almanac health page (25) parameters */
136 WN_a
, SV_health
[32], t_oa
;
139 typedef struct { /* Universal Coordinated Time (UTC) parms */
149 WN_t
, WN_LSF
, DN
, delta_t_LSF
;
152 typedef struct { /* Ionospheric info (float) */
154 alpha_0
, alpha_1
, alpha_2
, alpha_3
,
155 beta_0
, beta_1
, beta_2
, beta_3
;
158 typedef struct { /* Subframe 1 info (float) */
162 codeL2
, L2Pdata
, SVacc_raw
, SV_health
;
166 T_GD
, t_oc
, a_f2
, a_f1
, a_f0
, SVacc
;
169 typedef struct { /* Ephemeris info (float) */
199 Axis
, n
, r1me2
, OMEGA_n
, ODOT_n
;
202 typedef struct { /* Navigation data structure */
204 sv_number
; /* SV number (0 = no entry) */
206 t_ephem
; /* time of ephemeris collection */
208 ephclk
; /* subframe 1 data */
210 ephorb
; /* ephemeris data */
230 #ifdef TRIMBLE_OUTPUT_FUNC
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
,
284 short rpt_0x41 (TSIPPKT
*rpt
, float *time_of_week
, float *UTC_offset
,
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
,
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
,
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
,
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
,
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
,
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
,
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
);
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
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
467 ripencc_start(int unit
, struct peer
*peer
)
469 register struct ripencc_unit
*up
;
470 struct refclockproc
*pp
;
479 (void)snprintf(device
, sizeof(device
), DEVICE
, unit
);
480 if (!(fd
= refclock_open(device
, SPEED232
, LDISC_RAW
)))
483 /* from refclock_palisade.c */
484 if (tcgetattr(fd
, &tio
) < 0) {
485 msyslog(LOG_ERR
, "Palisade(%d) tcgetattr(fd, &tio): %m",unit
);
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
);
500 * Allocate and initialize unit structure
502 if (!(up
= (struct ripencc_unit
*)
503 emalloc(sizeof(struct ripencc_unit
)))) {
507 memset((char *)up
, 0, sizeof(struct ripencc_unit
));
509 pp
->io
.clock_recv
= ripencc_receive
;
510 pp
->io
.srcclock
= (caddr_t
)peer
;
513 if (!io_addclock(&pp
->io
)) {
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
);
532 * Initialize the Clock
535 /* query software versions */
537 ripencc_send(peer
, spt
);
539 /* query receiver health */
541 ripencc_send(peer
, spt
);
543 /* query serial numbers */
545 ripencc_send(peer
, spt
);
547 /* query manuf params */
549 ripencc_send(peer
, spt
);
551 /* i/o opts */ /* trimble manual page A30 */
556 0x0a); /* auxilary */
557 ripencc_send(peer
, spt
);
559 /* turn off port A */
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 */
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 */
580 0x00000000); /* AutoOutputMask */
581 ripencc_send(peer
, 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
);
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) {
607 msyslog(LOG_ERR
, "refclock_ripencc: time_pps_create failed: %m");
611 return(ripencc_ppsapi(peer
, 0, 0));
615 * ripencc_control - fudge 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
;
628 msyslog(LOG_INFO
,"%s()",__FUNCTION__
);
629 #endif /* DEBUG_NCC */
632 ripencc_ppsapi(peer
, pp
->sloppyclockflag
& CLK_FLAG2
,
633 pp
->sloppyclockflag
& CLK_FLAG3
);
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
;
652 up
= (struct ripencc_unit
*)pp
->unitptr
;
653 if (time_pps_getcap(up
->handle
, &capability
) < 0) {
655 "refclock_ripencc: time_pps_getcap failed: %m");
658 memset(&up
->pps_params
, 0, sizeof(pps_params_t
));
660 up
->pps_params
.mode
= capability
& PPS_CAPTURECLEAR
;
662 up
->pps_params
.mode
= capability
& PPS_CAPTUREASSERT
;
663 if (!up
->pps_params
.mode
) {
665 "refclock_ripencc: invalid capture edge %d",
669 up
->pps_params
.mode
|= PPS_TSFMT_TSPEC
;
670 if (time_pps_setparams(up
->handle
, &up
->pps_params
) < 0) {
672 "refclock_ripencc: time_pps_setparams failed: %m");
676 if (time_pps_kcbind(up
->handle
, PPS_KC_HARDPPS
,
677 up
->pps_params
.mode
& ~PPS_TSFMT_TSPEC
,
678 PPS_TSFMT_TSPEC
) < 0) {
680 "refclock_ripencc: time_pps_kcbind failed: %m");
685 peer
->precision
= PPS_PRECISION
;
689 time_pps_getparams(up
->handle
, &up
->pps_params
);
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 */
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.
708 struct ripencc_unit
*up
,
713 struct timespec timeout
, ts
;
718 msyslog(LOG_INFO
,"ripencc_get_pps_ts\n");
719 #endif /* DEBUG_PPS */
723 * Convert the timespec nanoseconds field to ntp l_fp units.
729 memcpy(&pps_info
, &up
->pps_info
, sizeof(pps_info_t
));
730 if (time_pps_fetch(up
->handle
, PPS_TSFMT_TSPEC
, &up
->pps_info
,
733 if (up
->pps_params
.mode
& PPS_CAPTUREASSERT
) {
734 if (pps_info
.assert_sequence
==
735 up
->pps_info
.assert_sequence
)
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
)
742 ts
= up
->pps_info
.clear_timestamp
;
746 if ((up
->ts
.tv_sec
== ts
.tv_sec
) && (up
->ts
.tv_nsec
== ts
.tv_nsec
))
750 tstmp
.l_ui
= ts
.tv_sec
+ JAN_1970
;
751 dtemp
= ts
.tv_nsec
* FRAC
/ 1e9
;
752 tstmp
.l_uf
= (u_int32
)dtemp
;
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 */
764 * ripencc_shutdown - shut down a GPS clock
767 ripencc_shutdown(int unit
, struct peer
*peer
)
769 register struct ripencc_unit
*up
;
770 struct refclockproc
*pp
;
773 up
= (struct ripencc_unit
*)pp
->unitptr
;
776 time_pps_destroy(up
->handle
);
778 io_closeclock(&pp
->io
);
784 * ripencc_poll - called by the transmit procedure
787 ripencc_poll(int unit
, struct peer
*peer
)
789 register struct ripencc_unit
*up
;
790 struct refclockproc
*pp
;
795 fprintf(stderr
, "ripencc_poll(%d)\n", unit
);
796 #endif /* DEBUG_NCC */
798 up
= (struct ripencc_unit
*)pp
->unitptr
;
799 if (up
->pollcnt
== 0)
800 refclock_report(peer
, CEVNT_TIMEOUT
);
807 /* poll for UTC superpacket */
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
818 ripencc_send(struct peer
*peer
, TSIPPKT spt
)
820 unsigned char *ip
, *op
;
821 unsigned char obuf
[512];
825 register struct ripencc_unit
*up
;
826 register struct refclockproc
*pp
;
829 up
= (struct ripencc_unit
*)pp
->unitptr
;
831 printf("ripencc_send(%d, %02X)\n", up
->unit
, cmd
);
833 #endif /* DEBUG_RAW */
842 if (op
-obuf
> sizeof(obuf
)-5) {
843 msyslog(LOG_ERR
, "ripencc_send obuf overflow!");
844 refclock_report(peer
, CEVNT_FAULT
);
848 if (*ip
== 0x10) /* byte stuffing */
857 if (debug
) { /* print raw packet */
861 printf("ripencc_send: len %d\n", op
-obuf
);
862 for (i
=1, cp
=obuf
; cp
<op
; i
++, cp
++) {
863 printf(" %02X", *cp
);
869 #endif /* DEBUG_RAW */
871 if (write(peer
->procptr
->io
.fd
, obuf
, op
-obuf
) == -1) {
872 refclock_report(peer
, CEVNT_FAULT
);
879 * called when a packet is received on the serial port
880 * takes care of further processing
884 ripencc_receive(struct recvbuf
*rbufp
)
886 register struct ripencc_unit
*up
;
887 register struct refclockproc
*pp
;
889 static TSIPPKT rpt
; /* structure for current incoming TSIP report */
890 TSIPPKT spt
; /* send packet */
894 /* Use these variables to hold data until we decide its worth keeping */
895 char rd_lastcode
[BMAX
];
899 /* msyslog(LOG_INFO, "%s",__FUNCTION__); */
902 * Initialize pointers and read the timecode and timestamp
904 peer
= (struct peer
*)rbufp
->recv_srcclock
;
906 up
= (struct ripencc_unit
*)pp
->unitptr
;
907 rd_lencode
= refclock_gtlin(rbufp
, rd_lastcode
, BMAX
, &rd_tmp
);
911 fprintf(stderr
, "ripencc_receive(%d)\n", up
->unit
);
912 #endif /* DEBUG_RAW */
915 if (debug
) { /* print raw packet */
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
);
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
)
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) { */
963 if (up
->polled
&& ns_since_pps
< 150) {
964 msyslog(LOG_INFO
, "%s(): up->polled",__FUNCTION__
);
965 ripencc_poll(up
->unit
, peer
);
970 * Parse primary utc time packet
971 * and fill refclock structure
974 if (parse0x8FAD(&rpt
, peer
) < 0) {
975 msyslog(LOG_INFO
, "%s(): parse0x8FAD < 0",__FUNCTION__
);
976 refclock_report(peer
, CEVNT_BADREPLY
);
980 * If the PPSAPI is working, rather use its
982 * assume that the PPS occurs on the second
985 if (ripencc_get_pps_ts(up
, &rd_tmp
) == 1) {
986 pp
->lastrec
= up
->tstamp
= rd_tmp
;
990 msyslog(LOG_INFO
, "%s(): ripencc_get_pps_ts returns failure\n",__FUNCTION__
);
994 msyslog(LOG_INFO
, "%s(): unrequested packet\n",__FUNCTION__
);
995 /* unrequested packet */
999 /* we have been polled ! */
1003 /* poll for next packet */
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
);
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
);
1023 refclock_receive(peer
);
1026 case 0x0B: /* comprehensive time packet */
1027 parse0x8F0B(&rpt
, peer
);
1030 default: /* other superpackets */
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 */
1041 case 0x4F: /* UTC parameters, for leap info */
1042 parse0x4F(&rpt
, peer
);
1045 case 0x5C: /* sat tracking data */
1046 parse0x5C(&rpt
, peer
);
1049 default: /* other packets */
1050 #ifdef TRIMBLE_OUTPUT_FUNC
1051 parseany(&rpt
, peer
);
1052 #endif /* TRIMBLE_OUTPUT_FUNC */
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 */
1071 void cmd_0x26 (TSIPPKT
*cmd
)
1072 /* request receiver health */
1081 void cmd_0x2F (TSIPPKT
*cmd
)
1082 /* request UTC params */
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
;
1099 void cmd_0x3C (TSIPPKT
*cmd
, unsigned char sv_prn
)
1100 /* request tracking status */
1102 cmd
->buf
[0] = sv_prn
;
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 */
1125 /* query primary configuration */
1126 void cmd_0xBBq (TSIPPKT
*cmd
,
1127 unsigned char subcode
)
1132 cmd
->buf
[0] = subcode
;
1136 /**** Superpackets ****/
1137 void cmd_0x8E0Bq (TSIPPKT
*cmd
)
1138 /* 8E-0B to query 8F-0B controls */
1147 void cmd_0x8E41q (TSIPPKT
*cmd
)
1148 /* 8F-41 to query board serial number */
1157 void cmd_0x8E42q (TSIPPKT
*cmd
)
1158 /* 8F-42 to query product serial number */
1165 void cmd_0x8E4Aq (TSIPPKT
*cmd
)
1166 /* 8F-4A to query PPS parameters */
1174 /* set i/o options */
1175 void cmd_0x8E4As (TSIPPKT
*cmd
,
1176 unsigned char PPSOnOff
,
1177 unsigned char TimeBase
,
1178 unsigned char Polarity
,
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 */
1200 /* poll for UTC superpacket */
1201 void cmd_0x8EADq (TSIPPKT
*cmd
)
1202 /* 8E-AD to query 8F-AD controls */
1209 /* all outomatic packet output off */
1210 void cmd_0x8E4Ds (TSIPPKT
*cmd
,
1211 unsigned long AutoOutputMask
)
1216 bPutULong (&AutoOutputMask
, &cmd
->buf
[1]);
1222 /* for DOS machines, reverse order of bytes as they come through the
1225 static short bGetShort (unsigned char *bp
)
1228 unsigned char *optr
;
1230 optr
= (unsigned char*)&outval
+ 1;
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;
1248 static long bGetLong (unsigned char *bp
)
1251 unsigned char *optr
;
1253 optr
= (unsigned char*)&outval
+ 3;
1261 static unsigned long bGetULong (unsigned char *bp
)
1263 unsigned long outval
;
1264 unsigned char *optr
;
1266 optr
= (unsigned char*)&outval
+ 3;
1273 #endif /* TRIMBLE_OUTPUT_FUNC */
1275 static float bGetSingle (unsigned char *bp
)
1278 unsigned char *optr
;
1280 optr
= (unsigned char*)&outval
+ 3;
1288 static double bGetDouble (unsigned char *bp
)
1291 unsigned char *optr
;
1293 optr
= (unsigned char*)&outval
+ 7;
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).
1321 bPutFloat (float *in
, unsigned char *out
)
1323 unsigned char *inptr
;
1325 inptr
= (unsigned char*)in
+ 3;
1333 bPutULong (unsigned long *in
, unsigned char *out
)
1335 unsigned char *inptr
;
1337 inptr
= (unsigned char*)in
+ 3;
1345 bPutDouble (double *in
, unsigned char *out
)
1347 unsigned char *inptr
;
1349 inptr
= (unsigned char*)in
+ 7;
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
1379 parse0x8FAD(rpt
, 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 */
1400 if (bGetShort(&buf
[1]) != 0) {
1403 printf("parse0x8FAD: event count != 0\n");
1404 #endif /* DEBUG_NCC */
1409 if (bGetDouble(&buf
[3]) != 0.0) {
1412 printf("parse0x8FAD: fracsecs != 0\n");
1413 #endif /* DEBUG_NCC */
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];
1427 sprintf(logbuf
, "U1 %d.%d.%d %02d:%02d:%02d %d %02x",
1428 day
, month
, year
, hour
, minute
, second
, trackstat
, utcflags
);
1433 #endif /* DEBUG_NCC */
1435 record_clock_stats(&peer
->srcadr
, logbuf
);
1437 if (!utcflags
& UTCF_UTC_AVAIL
)
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 ;-).
1457 /* now check and convert the time we received */
1460 if (month
< 1 || month
> 12 || day
< 1 || day
> 31)
1464 if (day
> day1tab
[month
- 1])
1466 for (i
= 0; i
< month
- 1; i
++)
1469 if (day
> day2tab
[month
- 1])
1471 for (i
= 0; i
< month
- 1; i
++)
1476 pp
->minute
= minute
;
1477 pp
-> second
= second
;
1480 if ((utcflags
&UTCF_LEAP_PNDG
) && up
->leapdelta
!= 0)
1481 pp
-> leap
= (up
->leapdelta
> 0 ? LEAP_ADDSECOND
: LEAP_DELSECOND
);
1483 pp
-> leap
= LEAP_NOWARNING
;
1489 * Parse comprehensive time packet
1495 int parse0x8F0B(rpt
, peer
)
1499 register struct refclockproc
*pp
;
1501 unsigned day
, month
, year
; /* data derived from received timecode */
1502 unsigned hour
, minute
, second
;
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
;
1513 static char logbuf
[1024]; /* logging string buffer */
1525 if (bGetShort(&buf
[1]) != 0)
1528 tow
= bGetDouble(&buf
[3]);
1533 else if ((tow
>= 604800.0) || (tow
< 0.0)) {
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]);
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]);
1565 lat_deg
= (short)lat
;
1566 lat_min
= (lat
- lat_deg
) * 60.0;
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];
1582 TSIPPKT spt
; /* local structure for sendpacket */
1583 b
= (unsigned char) (sv
[i
]<0 ? -sv
[i
] : sv
[i
]);
1584 /* request tracking status */
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]);
1599 #endif /* DEBUG_NCC */
1601 record_clock_stats(&peer
->srcadr
, logbuf
);
1606 #ifdef TRIMBLE_OUTPUT_FUNC
1608 * Parse any packet using Trimble machinery
1610 int parseany(rpt
, peer
)
1614 static char logbuf
[1024]; /* logging string buffer */
1616 TranslateTSIPReportToText (rpt
, logbuf
); /* anything else */
1620 #endif /* DEBUG_NCC */
1621 record_clock_stats(&peer
->srcadr
, &logbuf
[1]);
1624 #endif /* TRIMBLE_OUTPUT_FUNC */
1628 * Parse UTC Parameter Packet
1630 * See the IDE for documentation!
1636 int parse0x4F(rpt
, peer
)
1640 register struct ripencc_unit
*up
;
1644 int dt_ls
, wn_t
, wn_lsf
, dn
, dt_lsf
;
1646 static char logbuf
[1024]; /* logging string buffer */
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
);
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
;
1679 * Parse Tracking Status packet
1685 int parse0x5C(rpt
, peer
)
1689 unsigned char prn
, channel
, aqflag
, ephstat
;
1690 float snr
, azinuth
, elevation
;
1692 static char logbuf
[1024]; /* logging string buffer */
1701 channel
= (unsigned char)(buf
[1] >> 3);
1702 if (channel
== 0x10)
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
);
1718 #endif /* DEBUG_NCC */
1720 record_clock_stats(&peer
->srcadr
, logbuf
);
1725 /******* Code below is from Trimble Tsipchat *************/
1728 * *************************************************************************
1730 * Trimble Navigation, Ltd.
1731 * OEM Products Development Group
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,
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
1784 * *************************************************************************
1790 static void tsip_input_proc (
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
:
1809 /* illegal TSIP IDs */
1811 rpt
->status
= TSIP_PARSED_EMPTY
;
1814 /* try normal message start again */
1816 rpt
->status
= TSIP_PARSED_DLE_1
;
1819 /* legal TSIP ID; start message */
1820 rpt
->code
= newbyte
;
1822 rpt
->status
= TSIP_PARSED_DATA
;
1826 case TSIP_PARSED_DATA
:
1829 /* expect DLE or ETX next */
1830 rpt
->status
= TSIP_PARSED_DLE_2
;
1833 /* normal data byte */
1834 rpt
->buf
[rpt
->len
] = newbyte
;
1836 /* no change in rpt->status */
1840 case TSIP_PARSED_DLE_2
:
1843 /* normal data byte */
1844 rpt
->buf
[rpt
->len
] = newbyte
;
1846 rpt
->status
= TSIP_PARSED_DATA
;
1849 /* end of message; return TRUE here. */
1850 rpt
->status
= TSIP_PARSED_FULL
;
1853 /* error: treat as TSIP_PARSED_DLE_1; start new report packet */
1854 rpt
->code
= newbyte
;
1856 rpt
->status
= TSIP_PARSED_DATA
;
1859 case TSIP_PARSED_FULL
:
1860 case TSIP_PARSED_EMPTY
:
1864 /* normal message start */
1866 rpt
->status
= TSIP_PARSED_DLE_1
;
1869 /* error: ignore newbyte */
1871 rpt
->status
= TSIP_PARSED_EMPTY
;
1875 if (rpt
->len
> MAX_RPTBUF
) {
1876 /* error: start new report packet */
1877 rpt
->status
= TSIP_PARSED_EMPTY
;
1882 #ifdef TRIMBLE_OUTPUT_FUNC
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 */
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];
1908 short rpt_0x40 (TSIPPKT
*rpt
,
1909 unsigned char *sv_prn
,
1912 float *eccentricity
,
1920 /* almanac data for specified satellite */
1925 if (rpt
->len
!= 39) return TRUE
;
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]);
1940 short rpt_0x41 (TSIPPKT
*rpt
,
1941 float *time_of_week
,
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]);
1956 short rpt_0x42 (TSIPPKT
*rpt
,
1959 /* position in ECEF, single precision */
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]);
1972 short rpt_0x43 (TSIPPKT
*rpt
,
1976 /* velocity in ECEF, single precision */
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]);
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 */
2006 if (rpt
->len
!= 10) return TRUE
;
2007 *major_nav_version
= buf
[0];
2008 *minor_nav_version
= buf
[1];
2010 *nav_month
= buf
[3];
2012 *major_dsp_version
= buf
[5];
2013 *minor_dsp_version
= buf
[6];
2015 *dsp_month
= buf
[8];
2020 short rpt_0x46 (TSIPPKT
*rpt
,
2021 unsigned char *status1
,
2022 unsigned char *status2
)
2023 /* receiver health and status */
2028 if (rpt
->len
!= 2) return TRUE
;
2034 short rpt_0x47 (TSIPPKT
*rpt
,
2035 unsigned char *nsvs
, unsigned char *sv_prn
,
2037 /* signal levels for all satellites tracked */
2043 if (rpt
->len
!= 1 + 5*buf
[0]) return TRUE
;
2045 for (isv
= 0; isv
< (*nsvs
); isv
++) {
2046 sv_prn
[isv
] = buf
[5*isv
+ 1];
2047 snr
[isv
] = bGetSingle (&buf
[5*isv
+ 2]);
2052 short rpt_0x48 (TSIPPKT
*rpt
,
2053 unsigned char *message
)
2054 /* GPS system message */
2059 if (rpt
->len
!= 22) return TRUE
;
2060 memcpy (message
, buf
, 22);
2065 short rpt_0x49 (TSIPPKT
*rpt
,
2066 unsigned char *sv_health
)
2067 /* health for all satellites from almanac health page */
2073 if (rpt
->len
!= 32) return TRUE
;
2074 for (i
= 0; i
< 32; i
++) sv_health
[i
]= buf
[i
];
2078 short rpt_0x4A (TSIPPKT
*rpt
,
2084 /* position in lat-lon-alt, single precision */
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]);
2098 short rpt_0x4A_2 (TSIPPKT
*rpt
,
2099 float *alt
, float *dummy
, unsigned char *alt_flag
)
2100 /* reference altitude parameters */
2106 if (rpt
->len
!= 9) return TRUE
;
2107 *alt
= bGetSingle (buf
);
2108 *dummy
= bGetSingle (&buf
[4]);
2113 short rpt_0x4B (TSIPPKT
*rpt
,
2114 unsigned char *machine_id
,
2115 unsigned char *status3
,
2116 unsigned char *status4
)
2117 /* machine ID code, status */
2122 if (rpt
->len
!= 3) return TRUE
;
2123 *machine_id
= buf
[0];
2129 short rpt_0x4C (TSIPPKT
*rpt
,
2130 unsigned char *dyn_code
,
2135 /* operating parameters and masks */
2140 if (rpt
->len
!= 17) return TRUE
;
2142 *el_mask
= bGetSingle (&buf
[1]);
2143 *snr_mask
= bGetSingle (&buf
[5]);
2144 *dop_mask
= bGetSingle (&buf
[9]);
2145 *dop_switch
= bGetSingle (&buf
[13]);
2149 short rpt_0x4D (TSIPPKT
*rpt
,
2151 /* oscillator offset */
2156 if (rpt
->len
!= 4) return TRUE
;
2157 *osc_offset
= bGetSingle (buf
);
2161 short rpt_0x4E (TSIPPKT
*rpt
,
2162 unsigned char *response
)
2163 /* yes/no response to command to set GPS time */
2168 if (rpt
->len
!= 1) return TRUE
;
2173 short rpt_0x4F (TSIPPKT
*rpt
,
2176 float *time_of_data
,
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]);
2200 short rpt_0x54 (TSIPPKT
*rpt
,
2204 /* clock offset and frequency offset in 1-SV (0-D) mode */
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]);
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 */
2226 if (rpt
->len
!= 4) return TRUE
;
2229 *time_code
= buf
[2];
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 */
2241 if (rpt
->len
!= 20) return TRUE
;
2243 vel_ENU
[0] = bGetSingle (buf
);
2245 vel_ENU
[1] = bGetSingle (&buf
[4]);
2247 vel_ENU
[2] = bGetSingle (&buf
[8]);
2248 *freq_offset
= bGetSingle (&buf
[12]);
2249 *time_of_fix
= bGetSingle (&buf
[16]);
2253 short rpt_0x57 (TSIPPKT
*rpt
,
2254 unsigned char *source_code
, unsigned char *diag_code
,
2257 /* info about last computed fix */
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]);
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
;
2285 if (rpt
->len
< 4) return TRUE
;
2286 if (rpt
->len
!= 4+buf
[3]) return TRUE
;
2288 else if (rpt
->len
!= 3) {
2292 *data_type
= buf
[1];
2294 if (*op_code
== 2) {
2296 *data_length
= (unsigned char)dl
;
2298 switch (*data_type
) {
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]);
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
);
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]);
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]);
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]);
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 */
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];
2427 short rpt_0x5A (TSIPPKT
*rpt
,
2428 unsigned char *sv_prn
,
2429 float *sample_length
,
2430 float *signal_level
,
2433 double *time_of_fix
)
2434 /* raw measurement data - code phase/Doppler */
2439 if (rpt
->len
!= 25) return TRUE
;
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]);
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
,
2457 /* satellite ephorb status */
2462 if (rpt
->len
!= 16) return TRUE
;
2464 *time_of_collection
= bGetSingle (&buf
[1]);
2465 *sv_health
= buf
[5];
2467 *time_of_eph
= bGetSingle (&buf
[7]);
2468 *fit_interval_flag
= buf
[11];
2469 *sv_accy
= bGetSingle (&buf
[12]);
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
,
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 */
2492 if (rpt
->len
!= 24) return TRUE
;
2494 *slot
= (unsigned char)((buf
[1] & 0x07) + 1);
2495 *chan
= (unsigned char)(buf
[1] >> 3);
2496 if (*chan
== 0x10) *chan
= 2;
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];
2512 short rpt_0x6D (TSIPPKT
*rpt
,
2513 unsigned char *manual_mode
,
2514 unsigned char *nsvs
,
2515 unsigned char *ndim
,
2516 unsigned char sv_prn
[],
2521 /* over-determined satellite selection for position fixes, PDOP, fix mode */
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];
2543 short rpt_0x82 (TSIPPKT
*rpt
,
2544 unsigned char *diff_mode
)
2545 /* differential fix mode */
2550 if (rpt
->len
!= 1) return TRUE
;
2551 *diff_mode
= buf
[0];
2555 short rpt_0x83 (TSIPPKT
*rpt
,
2559 /* position, ECEF double precision */
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]);
2573 short rpt_0x84 (TSIPPKT
*rpt
,
2579 /* position, lat-lon-alt double precision */
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]);
2593 short rpt_Paly0xBB(TSIPPKT
*rpt
,
2594 TSIP_RCVR_CFG
*TsipxBB
)
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]);
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 */
2630 if (rpt
->len
!= 10) return TRUE
;
2634 *data_bits
= buf
[3];
2636 *stop_bits
= buf
[5];
2637 *flow_control
= buf
[6];
2638 *protocols_in
= buf
[7];
2639 *protocols_out
= buf
[8];
2645 /**** Superpackets ****/
2647 short rpt_0x8F0B(TSIPPKT
*rpt
,
2648 unsigned short *event
,
2650 unsigned char *date
,
2651 unsigned char *month
,
2653 unsigned char *dim_mode
,
2668 if (rpt
->len
!= 74) return TRUE
;
2669 *event
= bGetShort(&buf
[1]);
2670 *tow
= bGetDouble(&buf
[3]);
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];
2688 short rpt_0x8F14 (TSIPPKT
*rpt
,
2690 double datum_coeffs
[5])
2691 /* datum index and coefficients */
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]);
2707 short rpt_0x8F15 (TSIPPKT
*rpt
,
2709 double datum_coeffs
[5])
2710 /* datum index and coefficients */
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]);
2726 #define MAX_LONG (2147483648.) /* 2**31 */
2728 short rpt_0x8F20 (TSIPPKT
*rpt
,
2729 unsigned char *info
,
2734 double *time_of_fix
,
2736 unsigned char *nsvs
,
2737 unsigned char sv_prn
[],
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);
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));
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
,
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; */
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]);
2832 short rpt_0x8F45(TSIPPKT
*rpt
,
2833 unsigned char *bSegMask
)
2835 if(rpt
->len
!= 2) return FALSE
;
2836 *bSegMask
= rpt
->buf
[1];
2840 short rpt_0x8F4A_16(TSIPPKT
*rpt
,
2841 unsigned char *pps_enabled
,
2842 unsigned char *pps_timebase
,
2843 unsigned char *pos_polarity
,
2845 float *bias_unc_threshold
)
2846 /* Stinger PPS definition */
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]);
2861 short rpt_0x8F4B(TSIPPKT
*rpt
,
2862 unsigned long *decorr_max
)
2868 if (rpt
->len
!= 5) return TRUE
;
2869 *decorr_max
= bGetLong(&buf
[1]);
2873 short rpt_0x8F4D(TSIPPKT
*rpt
,
2874 unsigned long *event_mask
)
2880 if (rpt
->len
!= 5) return TRUE
;
2881 *event_mask
= bGetULong (&buf
[1]);
2885 short rpt_0x8FA5(TSIPPKT
*rpt
,
2886 unsigned char *spktmask
)
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];
2900 short rpt_0x8FAD (TSIPPKT
*rpt
,
2901 unsigned short *COUNT
,
2903 unsigned char *Hour
,
2904 unsigned char *Minute
,
2905 unsigned char *Second
,
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];
2930 * *************************************************************************
2932 * Trimble Navigation, Ltd.
2933 * OEM Products Development Group
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()
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
2979 /* pbuf is the pointer to the current location of the text output */
2983 /* keep track of whether the message has been successfully 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
;
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> ");
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
);
3020 static void rpt_chan_A_config (TSIPPKT
*rpt
)
3023 tx_baud_index
, rx_baud_index
,
3024 char_format_index
, stop_bits
,
3025 tx_mode_index
, rx_mode_index
,
3032 &tx_baud_index
, &rx_baud_index
, &char_format_index
,
3033 &stop_bits
, &tx_mode_index
, &rx_mode_index
)) {
3034 parsed
= BADLEN_PARSE
;
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
);
3061 static void rpt_almanac_data_page (TSIPPKT
*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
;
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
);
3102 static void rpt_GPS_time (TSIPPKT
*rpt
)
3105 time_of_week
, UTC_offset
;
3110 if (rpt_0x41 (rpt
, &time_of_week
, &UTC_offset
, &week_num
)) {
3111 parsed
= BADLEN_PARSE
;
3115 pbuf
+= sprintf(pbuf
, "\nGPS time:%s GPS week: %d UTC offset %.1f",
3116 show_time(time_of_week
), week_num
, UTC_offset
);
3121 static void rpt_single_ECEF_position (TSIPPKT
*rpt
)
3124 ECEF_pos
[3], time_of_fix
;
3127 if (rpt_0x42 (rpt
, ECEF_pos
, &time_of_fix
)) {
3128 parsed
= BADLEN_PARSE
;
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
));
3138 static void rpt_single_ECEF_velocity (TSIPPKT
*rpt
)
3142 ECEF_vel
[3], freq_offset
, time_of_fix
;
3145 if (rpt_0x43 (rpt
, ECEF_vel
, &freq_offset
, &time_of_fix
)) {
3146 parsed
= BADLEN_PARSE
;
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
));
3156 static void rpt_SW_version (TSIPPKT
*rpt
) {
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
;
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
;
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
);
3180 static void rpt_rcvr_health (TSIPPKT
*rpt
)
3186 "Doing position fixes",
3187 "Don't have GPS time yet",
3188 "Waiting for almanac collection",
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"};
3202 if (rpt_0x46 (rpt
, &status1
, &status2
))
3204 parsed
= BADLEN_PARSE
;
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",
3218 static void rpt_SNR_all_SVs (TSIPPKT
*rpt
)
3228 if (rpt_0x47 (rpt
, &nsvs
, sv_prn
, snr
))
3230 parsed
= BADLEN_PARSE
;
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
]);
3243 static void rpt_GPS_system_message (TSIPPKT
*rpt
)
3249 if (rpt_0x48 (rpt
, message
))
3251 parsed
= BADLEN_PARSE
;
3255 pbuf
+= sprintf(pbuf
, "\nGPS message: %s", message
);
3259 static void rpt_almanac_health_page (TSIPPKT
*rpt
)
3267 if (rpt_0x49 (rpt
, sv_health
))
3269 parsed
= BADLEN_PARSE
;
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
]);
3283 static void rpt_single_lla_position (TSIPPKT
*rpt
) {
3288 alt
, clock_bias
, time_of_fix
;
3289 double lat_min
, lon_min
;
3291 north_south
, east_west
;
3294 &lat
, &lon
, &alt
, &clock_bias
, &time_of_fix
))
3296 parsed
= BADLEN_PARSE
;
3300 /* convert from radians to degrees */
3308 lat_deg
= (short)lat
;
3309 lat_min
= (lat
- lat_deg
) * 60.0;
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
,
3325 show_time(time_of_fix
));
3329 static void rpt_ref_alt (TSIPPKT
*rpt
) {
3336 if (rpt_0x4A_2 (rpt
,
3337 &alt
, &dummy
, &alt_flag
))
3339 parsed
= BADLEN_PARSE
;
3343 pbuf
+= sprintf(pbuf
, "\nReference Alt: %.1f m; %s",
3344 alt
, alt_flag
?"ON":"OFF");
3348 static void rpt_rcvr_id_and_status (TSIPPKT
*rpt
)
3352 machine_id
, status3
, status4
;
3355 if (rpt_0x4B (rpt
, &machine_id
, &status3
, &status4
))
3357 parsed
= BADLEN_PARSE
;
3361 pbuf
+= sprintf(pbuf
, "\nRcvr Machine ID: %d; Status3 = %s, %s (%02Xh)",
3363 (status3
& 0x02)?"No RTC":"RTC OK",
3364 (status3
& 0x08)?"No Alm":"Alm OK",
3369 static void rpt_operating_parameters (TSIPPKT
*rpt
)
3374 el_mask
, snr_mask
, dop_mask
, dop_switch
;
3377 if (rpt_0x4C (rpt
, &dyn_code
, &el_mask
,
3378 &snr_mask
, &dop_mask
, &dop_switch
))
3380 parsed
= BADLEN_PARSE
;
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
);
3394 static void rpt_oscillator_offset (TSIPPKT
*rpt
)
3400 if (rpt_0x4D (rpt
, &osc_offset
))
3402 parsed
= BADLEN_PARSE
;
3406 pbuf
+= sprintf(pbuf
, "\nOscillator offset: %.2f Hz = %.3f PPM",
3407 osc_offset
, osc_offset
/1575.42);
3411 static void rpt_GPS_time_set_response (TSIPPKT
*rpt
)
3418 if (rpt_0x4E (rpt
, &response
))
3420 parsed
= BADLEN_PARSE
;
3427 pbuf
+= sprintf(pbuf
, "\nTime set accepted");
3431 pbuf
+= sprintf(pbuf
, "\nTime set rejected or not required");
3435 parsed
= BADDATA_PARSE
;
3440 static void rpt_UTC_offset (TSIPPKT
*rpt
)
3447 dt_ls
, wn_t
, wn_lsf
, dn
, dt_lsf
;
3450 if (rpt_0x4F (rpt
, &a0
, &a1
, &time_of_data
,
3451 &dt_ls
, &wn_t
, &wn_lsf
, &dn
, &dt_lsf
)) {
3452 parsed
= BADLEN_PARSE
;
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
);
3469 static void rpt_1SV_bias (TSIPPKT
*rpt
)
3472 clock_bias
, freq_offset
, time_of_fix
;
3475 if (rpt_0x54 (rpt
, &clock_bias
, &freq_offset
, &time_of_fix
)) {
3476 parsed
= BADLEN_PARSE
;
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
));
3485 static void rpt_io_opt (TSIPPKT
*rpt
)
3488 pos_code
, vel_code
, time_code
, aux_code
;
3492 &pos_code
, &vel_code
, &time_code
, &aux_code
)) {
3493 parsed
= BADLEN_PARSE
;
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");
3575 static void rpt_ENU_velocity (TSIPPKT
*rpt
)
3578 vel_ENU
[3], freq_offset
, time_of_fix
;
3581 if (rpt_0x56 (rpt
, vel_ENU
, &freq_offset
, &time_of_fix
)) {
3582 parsed
= BADLEN_PARSE
;
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
));
3592 static void rpt_last_fix_info (TSIPPKT
*rpt
)
3595 source_code
, diag_code
;
3602 if (rpt_0x57 (rpt
, &source_code
, &diag_code
, &week_num
, &time_of_fix
)) {
3603 parsed
= BADLEN_PARSE
;
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
);
3614 static void rpt_GPS_system_data (TSIPPKT
*rpt
)
3618 op_code
, data_type
, sv_prn
,
3619 data_length
, data_packet
[250];
3640 {"", "", "Almanac Orbit",
3641 "Health Page & Ref Time", "Ionosphere", "UTC ",
3645 if (rpt_0x58 (rpt
, &op_code
, &data_type
, &sv_prn
,
3646 &data_length
, data_packet
))
3648 parsed
= BADLEN_PARSE
;
3652 pbuf
+= sprintf(pbuf
, "\nSystem data [%d]: %s SV%02d",
3653 data_type
, datname
[data_type
], sv_prn
);
3657 pbuf
+= sprintf(pbuf
, " Acknowledgment");
3660 pbuf
+= sprintf(pbuf
, " length = %d bytes", data_length
);
3661 switch (data_type
) {
3664 if (sv_prn
== 0 || sv_prn
> 32) {
3665 pbuf
+= sprintf(pbuf
, " Binary PRN invalid");
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
);
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
);
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
);
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
);
3733 case 6: /* Ephemeris */
3734 if (sv_prn
== 0 || sv_prn
> 32) {
3735 pbuf
+= sprintf(pbuf
, " Binary PRN invalid");
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
);
3787 static void rpt_SVs_enabled (TSIPPKT
*rpt
)
3797 if (rpt_0x59 (rpt
, &code_type
, status_code
))
3799 parsed
= BADLEN_PARSE
;
3804 case 3: pbuf
+= sprintf(pbuf
, "\nSVs Disabled:\n"); break;
3805 case 6: pbuf
+= sprintf(pbuf
, "\nSVs with Health Ignored:\n"); break;
3809 for (iprn
=0; iprn
<32; iprn
++)
3811 if (status_code
[iprn
])
3813 pbuf
+= sprintf(pbuf
, " %02d", iprn
+1);
3817 if (numsvs
== 0) pbuf
+= sprintf(pbuf
, "None");
3822 static void rpt_raw_msmt (TSIPPKT
*rpt
)
3827 sample_length
, signal_level
, code_phase
, Doppler
;
3832 if (rpt_0x5A (rpt
, &sv_prn
, &sample_length
, &signal_level
,
3833 &code_phase
, &Doppler
, &time_of_fix
))
3835 parsed
= BADLEN_PARSE
;
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
));
3845 static void rpt_SV_ephemeris_status (TSIPPKT
*rpt
)
3848 sv_prn
, sv_health
, sv_iode
, fit_interval_flag
;
3850 time_of_collection
, time_of_eph
, sv_accy
;
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
;
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
);
3868 static void rpt_SV_tracking_status (TSIPPKT
*rpt
)
3871 sv_prn
, chan
, slot
, acq_flag
, eph_flag
,
3872 old_msmt_flag
, integer_msec_flag
, bad_data_flag
,
3875 signal_level
, time_of_last_msmt
,
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
;
3889 pbuf
+= sprintf(pbuf
,
3890 "\n SV%2d %1d %1d %1d %4.1f %s %5.1f %5.1f",
3892 acq_flag
, eph_flag
, signal_level
,
3893 show_time(time_of_last_msmt
),
3894 elev
*R2D
, azim
*R2D
);
3899 static void rpt_allSV_selection (TSIPPKT
*rpt
)
3902 manual_mode
, nsvs
, sv_prn
[8], ndim
;
3906 pdop
, hdop
, vdop
, tdop
;
3910 &manual_mode
, &nsvs
, &ndim
, sv_prn
,
3911 &pdop
, &hdop
, &vdop
, &tdop
))
3913 parsed
= BADLEN_PARSE
;
3920 pbuf
+= sprintf(pbuf
, "\nMode: Searching, %d-SV:", nsvs
);
3923 pbuf
+= sprintf(pbuf
, "\nMode: One-SV Timing:");
3926 pbuf
+= sprintf(pbuf
, "\nMode: %c-%dD, %d-SV:",
3927 manual_mode
? 'M' : 'A', ndim
- 1, nsvs
);
3930 pbuf
+= sprintf(pbuf
, "\nMode: Timing, %d-SV:", nsvs
);
3933 pbuf
+= sprintf(pbuf
, "\nMode: Unknown = %d:", ndim
);
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
);
3950 static void rpt_DGPS_position_mode (TSIPPKT
*rpt
)
3956 if (rpt_0x82 (rpt
, &diff_mode
)) {
3957 parsed
= BADLEN_PARSE
;
3961 pbuf
+= sprintf(pbuf
, "\nFix is%s DGPS-corrected (%s mode) (%d)",
3962 (diff_mode
&1) ? "" : " not",
3963 (diff_mode
&2) ? "auto" : "manual",
3968 static void rpt_double_ECEF_position (TSIPPKT
*rpt
)
3972 ECEF_pos
[3], clock_bias
;
3977 if (rpt_0x83 (rpt
, ECEF_pos
, &clock_bias
, &time_of_fix
))
3979 parsed
= BADLEN_PARSE
;
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
));
3989 static void rpt_double_lla_position (TSIPPKT
*rpt
)
3994 lat
, lon
, lat_min
, lon_min
,
3999 north_south
, east_west
;
4003 &lat
, &lon
, &alt
, &clock_bias
, &time_of_fix
))
4005 parsed
= BADLEN_PARSE
;
4017 lat_deg
= (short)lat
;
4018 lat_min
= (lat
- lat_deg
) * 60.0;
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
,
4032 show_time(time_of_fix
));
4036 static void rpt_complete_rcvr_config (TSIPPKT
*rpt
)
4038 TSIP_RCVR_CFG TsipxBB
;
4040 if (rpt_Paly0xBB (rpt
, &TsipxBB
))
4042 parsed
= BADLEN_PARSE
;
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",
4054 pbuf
+= sprintf(pbuf
, "\n DOP mask: %g",
4056 pbuf
+= sprintf(pbuf
, "\n DOP switch: %g",
4057 TsipxBB
.dop_switch
);
4062 static void rpt_rcvr_serial_port_config (TSIPPKT
*rpt
)
4065 port_num
, in_baud
, out_baud
, data_bits
, parity
, stop_bits
, flow_control
,
4066 protocols_in
, protocols_out
, reserved
;
4067 unsigned char known
;
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
;
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
],
4084 parity_text
[parity
],
4086 pbuf
+= sprintf(pbuf
, "\n Input protocols: ");
4088 if (protocols_in
&B_TSIP
)
4090 pbuf
+= sprintf(pbuf
, "%s ", protocols_in_text
[1]);
4093 if (known
== FALSE
) pbuf
+= sprintf(pbuf
, "No known");
4095 pbuf
+= sprintf(pbuf
, "\n Output protocols: ");
4097 if (protocols_out
&B_TSIP
)
4099 pbuf
+= sprintf(pbuf
, "%s ", protocols_out_text
[1]);
4102 if (protocols_out
&B_NMEA
)
4104 pbuf
+= sprintf(pbuf
, "%s ", protocols_out_text
[2]);
4107 if (known
== FALSE
) pbuf
+= sprintf(pbuf
, "No known");
4108 reserved
= reserved
;
4114 static void rpt_8F0B(TSIPPKT
*rpt
)
4119 "full position (3-D)",
4120 "single satellite (0-D)",
4124 "overdetermined clock"};
4175 parsed
= BADLEN_PARSE
;
4181 pbuf
+= sprintf(pbuf
, "\nNew partial+full meas");
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 */
4209 lat_deg
= (short)lat
;
4210 lat_min
= (lat
- lat_deg
) * 60.0;
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
++;
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
]);
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
]);
4259 static void rpt_8F14 (TSIPPKT
*rpt
)
4260 /* Datum parameters */
4268 if (rpt_0x8F14 (rpt
, &datum_idx
, datum_coeffs
))
4270 parsed
= BADLEN_PARSE
;
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 ");
4289 pbuf
+= sprintf(pbuf
, "\nStandard Datum, Index %3d ", datum_idx
);
4294 static void rpt_8F15 (TSIPPKT
*rpt
)
4295 /* Datum parameters */
4303 if (rpt_0x8F15 (rpt
, &datum_idx
, datum_coeffs
)) {
4304 parsed
= BADLEN_PARSE
;
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 ");
4323 pbuf
+= sprintf(pbuf
, "\nStandard Datum, Index %3d ", datum_idx
);
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
)
4335 info
, nsvs
, sv_prn
[32];
4337 week_num
, datum_index
, sv_IODC
[32];
4339 lat
, lon
, alt
, time_of_fix
;
4341 londeg
, latdeg
, vel
[3];
4348 if (rpt_0x8F20 (rpt
,
4349 &info
, &lat
, &lon
, &alt
, vel
,
4351 &week_num
, &nsvs
, sv_prn
, sv_IODC
, &datum_index
))
4353 parsed
= BADLEN_PARSE
;
4356 pbuf
+= sprintf(pbuf
,
4357 "\nFix at: %04d:%3s:%02d:%02d:%06.3f GPS (=UTC+%2ds) FixType: %s%s%s",
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 ");
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,
4388 (short)londeg
, fmod (londeg
, 1.)*60.0,
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
,
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
, ")");
4409 static void rpt_8F41(TSIPPKT
*rpt
)
4425 if (!rpt_0x8F41(rpt
,
4436 parsed
= BADLEN_PARSE
;
4440 pbuf
+= sprintf(pbuf
, "\n search range: %d",
4442 pbuf
+= sprintf(pbuf
, "\n board options: %d",
4444 pbuf
+= sprintf(pbuf
, "\n board serial #: %ld",
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",
4455 static void rpt_8F42(TSIPPKT
*rpt
)
4461 iCaseSerialNumberPre
,
4469 if (!rpt_0x8F42(rpt
,
4472 &iCaseSerialNumberPre
,
4473 &iiCaseSerialNumber
,
4479 parsed
= BADLEN_PARSE
;
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
);
4494 static void rpt_8F45(TSIPPKT
*rpt
)
4496 unsigned char bSegMask
;
4498 if (!rpt_0x8F45(rpt
,
4501 parsed
= BADLEN_PARSE
;
4504 pbuf
+= sprintf(pbuf
, "\nCleared Segment Mask: %Xh", bSegMask
);
4507 static void rpt_8F4A(TSIPPKT
*rpt
)
4508 /* Stinger PPS def */
4519 if (rpt_0x8F4A_16 (rpt
,
4524 &bias_unc_threshold
))
4526 parsed
= BADLEN_PARSE
;
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 */
4543 if (rpt_0x8F4B(rpt
, &decorr_max
))
4545 parsed
= BADLEN_PARSE
;
4549 pbuf
+= sprintf(pbuf
,
4550 "\nMax # of position fixes for self-survey : %ld",
4554 static void rpt_8F4D(TSIPPKT
*rpt
)
4560 static unsigned long
4562 0x00000001, 0x00000002, 0x00000004, 0x00000008, 0x00000010, 0x00000020,
4563 0x00000100L
, 0x00000800L
, 0x00001000L
,
4564 0x40000000L
, 0x80000000L
};
4569 if (rpt_0x8F4D(rpt
, &OutputMask
))
4571 parsed
= BADLEN_PARSE
;
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:");
4584 for (ichoice
=0; ichoice
<numchoices
; ichoice
++)
4586 if (OutputMask
&MaskBit
[ichoice
])
4588 pbuf
+= sprintf(pbuf
, "%s %s",
4589 (pbuf
==linestart
)?"\n ":",",
4591 if (pbuf
-linestart
> 60) linestart
= pbuf
;
4595 pbuf
+= sprintf(pbuf
, "\nAuto-Reports NOT scheduled for Output:");
4597 for (ichoice
=0; ichoice
<numchoices
; ichoice
++)
4599 if (OutputMask
&MaskBit
[ichoice
]) continue;
4600 pbuf
+= sprintf(pbuf
, "%s %s",
4601 (pbuf
==linestart
)?"\n ":",",
4603 if (pbuf
-linestart
> 60) linestart
= pbuf
;
4607 static void rpt_8FA5(TSIPPKT
*rpt
)
4612 if (rpt_0x8FA5(rpt
, spktmask
))
4614 parsed
= BADLEN_PARSE
;
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
)
4643 static char* Status8FADText
[] = {
4648 "CODE_NEED_INITIALIZATION",
4655 "CODE_NO_INTEGRITY",
4659 *LeapStatusText
[] = {
4660 " UTC Avail", " ", " ", " ",
4661 " Scheduled", " Pending", " Warning", " In Progress"};
4664 if (rpt_0x8FAD (rpt
,
4676 parsed
= BADLEN_PARSE
;
4680 pbuf
+= sprintf(pbuf
, "\n8FAD Count: %d Status: %s",
4681 Count
, Status8FADText
[Status
]);
4683 pbuf
+= sprintf(pbuf
, "\n Leap Flags:");
4688 if (Flags
&(1<<i
)) pbuf
+= sprintf(pbuf
, LeapStatusText
[i
]);
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 */
4712 if (force
|| rptcode
!=last_rptcode
)
4714 /* supply a header in console output */
4718 numchars
= sprintf(HdrStr
, "\nRaw Measurement Data");
4719 numchars
+= sprintf(HdrStr
+numchars
,
4720 "\n SV Sample SNR Code Phase Doppler Seconds Time of Meas");
4724 numchars
= sprintf(HdrStr
, "\nEphemeris Status");
4725 numchars
+= sprintf(HdrStr
+numchars
,
4726 "\n SV Time collected Health IODE t oe Fit URA");
4730 numchars
= sprintf(HdrStr
, "\nTracking Info");
4731 numchars
+= sprintf(HdrStr
+numchars
,
4732 "\n SV C Acq Eph SNR Time of Meas Elev Azim ");
4737 last_rptcode
= rptcode
;
4738 return (short)numchars
;
4741 static void unknown_rpt (TSIPPKT
*rpt
)
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
]);
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 */
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;
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;
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
4859 /* close TextOutputBuffer */
4863 #endif /* TRIMBLE_OUTPUT_FUNC */
4865 #else /* defined(REFCLOCK) && defined(CLOCK_RIPENCC) */
4866 int refclock_ripencc_bs
;
4867 #endif /* defined(REFCLOCK) && defined(CLOCK_RIPENCC) */