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