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