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