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