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