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