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