/contrib/ntp/ntpd/refclock_ripencc.c
C | 4866 lines | 3751 code | 591 blank | 524 comment | 411 complexity | 262eb696cb696d14c100f9b876355fbe MD5 | raw file
Large files files are truncated, but you can click here to view the full file
1/* 2 * $Id: refclock_ripencc.c,v 1.13 2002/06/18 14:20:55 marks Exp marks $ 3 * 4 * Copyright (c) 2002 RIPE NCC 5 * 6 * All Rights Reserved 7 * 8 * Permission to use, copy, modify, and distribute this software and its 9 * documentation for any purpose and without fee is hereby granted, 10 * provided that the above copyright notice appear in all copies and that 11 * both that copyright notice and this permission notice appear in 12 * supporting documentation, and that the name of the author not be 13 * used in advertising or publicity pertaining to distribution of the 14 * software without specific, written prior permission. 15 * 16 * THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 17 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL 18 * AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY 19 * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 20 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 21 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 22 * 23 * 24 * 25 * This driver was developed for use with the RIPE NCC TTM project. 26 * 27 * 28 * The initial driver was developed by Daniel Karrenberg <dfk@ripe.net> 29 * using the code made available by Trimble. This was for xntpd-3.x.x 30 * 31 * Rewrite of the driver for ntpd-4.x.x by Mark Santcroos <marks@ripe.net> 32 * 33 */ 34 35#ifdef HAVE_CONFIG_H 36#include <config.h> 37#endif /* HAVE_CONFIG_H */ 38 39#if defined(REFCLOCK) && defined(CLOCK_RIPENCC) 40 41#include "ntp_stdlib.h" 42#include "ntpd.h" 43#include "ntp_refclock.h" 44#include "ntp_unixtime.h" 45#include "ntp_io.h" 46 47#ifdef HAVE_PPSAPI 48# include "ppsapi_timepps.h" 49#endif 50 51/* 52 * Definitions 53 */ 54 55/* we are on little endian */ 56#define BYTESWAP 57 58/* 59 * DEBUG statements: uncomment if necessary 60 */ 61/* #define DEBUG_NCC */ /* general debug statements */ 62/* #define DEBUG_PPS */ /* debug pps */ 63/* #define DEBUG_RAW */ /* print raw packets */ 64 65#define TRIMBLE_OUTPUT_FUNC 66#define TSIP_VERNUM "7.12a" 67 68#ifndef FALSE 69#define FALSE (0) 70#define TRUE (!FALSE) 71#endif /* FALSE */ 72 73#define GPS_PI (3.1415926535898) 74#define GPS_C (299792458.) 75#define D2R (GPS_PI/180.0) 76#define R2D (180.0/GPS_PI) 77#define WEEK (604800.) 78#define MAXCHAN (8) 79 80/* control characters for TSIP packets */ 81#define DLE (0x10) 82#define ETX (0x03) 83 84#define MAX_RPTBUF (256) 85 86/* values of TSIPPKT.status */ 87#define TSIP_PARSED_EMPTY 0 88#define TSIP_PARSED_FULL 1 89#define TSIP_PARSED_DLE_1 2 90#define TSIP_PARSED_DATA 3 91#define TSIP_PARSED_DLE_2 4 92 93#define UTCF_UTC_AVAIL (unsigned char) (1) /* UTC available */ 94#define UTCF_LEAP_SCHD (unsigned char) (1<<4) /* Leap scheduled */ 95#define UTCF_LEAP_PNDG (unsigned char) (1<<5) /* Leap pending, will occur at end of day */ 96 97#define DEVICE "/dev/gps%d" /* name of radio device */ 98#define PRECISION (-9) /* precision assumed (about 2 ms) */ 99#define PPS_PRECISION (-20) /* precision assumed (about 1 us) */ 100#define REFID "GPS\0" /* reference id */ 101#define REFID_LEN 4 102#define DESCRIPTION "RIPE NCC GPS (Palisade)" /* Description */ 103#define SPEED232 B9600 /* 9600 baud */ 104 105#define NSAMPLES 3 /* stages of median filter */ 106 107/* Structures */ 108 109/* TSIP packets have the following structure, whether report or command. */ 110typedef struct { 111 short 112 counter, /* counter */ 113 len; /* size of buf; < MAX_RPTBUF unsigned chars */ 114 unsigned char 115 status, /* TSIP packet format/parse status */ 116 code, /* TSIP code */ 117 buf[MAX_RPTBUF];/* report or command string */ 118} TSIPPKT; 119 120/* TSIP binary data structures */ 121typedef struct { 122 unsigned char 123 t_oa_raw, SV_health; 124 float 125 e, t_oa, i_0, OMEGADOT, sqrt_A, 126 OMEGA_0, omega, M_0, a_f0, a_f1, 127 Axis, n, OMEGA_n, ODOT_n, t_zc; 128 short 129 weeknum, wn_oa; 130} ALM_INFO; 131 132typedef struct { /* Almanac health page (25) parameters */ 133 unsigned char 134 WN_a, SV_health[32], t_oa; 135} ALH_PARMS; 136 137typedef struct { /* Universal Coordinated Time (UTC) parms */ 138 double 139 A_0; 140 float 141 A_1; 142 short 143 delta_t_LS; 144 float 145 t_ot; 146 short 147 WN_t, WN_LSF, DN, delta_t_LSF; 148} UTC_INFO; 149 150typedef struct { /* Ionospheric info (float) */ 151 float 152 alpha_0, alpha_1, alpha_2, alpha_3, 153 beta_0, beta_1, beta_2, beta_3; 154} ION_INFO; 155 156typedef struct { /* Subframe 1 info (float) */ 157 short 158 weeknum; 159 unsigned char 160 codeL2, L2Pdata, SVacc_raw, SV_health; 161 short 162 IODC; 163 float 164 T_GD, t_oc, a_f2, a_f1, a_f0, SVacc; 165} EPHEM_CLOCK; 166 167typedef struct { /* Ephemeris info (float) */ 168 unsigned char 169 IODE, fit_interval; 170 float 171 C_rs, delta_n; 172 double 173 M_0; 174 float 175 C_uc; 176 double 177 e; 178 float 179 C_us; 180 double 181 sqrt_A; 182 float 183 t_oe, C_ic; 184 double 185 OMEGA_0; 186 float 187 C_is; 188 double 189 i_0; 190 float 191 C_rc; 192 double 193 omega; 194 float 195 OMEGADOT, IDOT; 196 double 197 Axis, n, r1me2, OMEGA_n, ODOT_n; 198} EPHEM_ORBIT; 199 200typedef struct { /* Navigation data structure */ 201 short 202 sv_number; /* SV number (0 = no entry) */ 203 float 204 t_ephem; /* time of ephemeris collection */ 205 EPHEM_CLOCK 206 ephclk; /* subframe 1 data */ 207 EPHEM_ORBIT 208 ephorb; /* ephemeris data */ 209} NAV_INFO; 210 211typedef struct { 212 unsigned char 213 bSubcode, 214 operating_mode, 215 dgps_mode, 216 dyn_code, 217 trackmode; 218 float 219 elev_mask, 220 cno_mask, 221 dop_mask, 222 dop_switch; 223 unsigned char 224 dgps_age_limit; 225} TSIP_RCVR_CFG; 226 227 228#ifdef TRIMBLE_OUTPUT_FUNC 229static char 230 *dayname[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}, 231 old_baudnum[] = {0, 1, 4, 5, 6, 8, 9, 11, 28, 12}, 232 *st_baud_text_app [] = {"", "", " 300", " 600", " 1200", " 2400", 233 " 4800", " 9600", "19200", "38400"}, 234 *old_parity_text[] = {"EVEN", "ODD", "", "", "NONE"}, 235 *parity_text [] = {"NONE", "ODD", "EVEN"}, 236 *old_input_ch[] = { "TSIP", "RTCM (6 of 8 bits)"}, 237 *old_output_ch[] = { "TSIP", "No output", "", "", "", "NMEA 0183"}, 238 *protocols_in_text[] = { "", "TSIP", "", ""}, 239 *protocols_out_text[] = { "", "TSIP", "NMEA"}, 240 *rcvr_port_text [] = { "Port A ", "Port B ", "Current Port"}, 241 *dyn_text [] = {"Unchanged", "Land", "Sea", "Air", "Static"}, 242 *NavModeText0xBB[] = {"automatic", "time only (0-D)", "", "2-D", 243 "3-D", "", "", "OverDetermined Time"}, 244 *PPSTimeBaseText[] = {"GPS", "UTC", "USER"}, 245 *PPSPolarityText[] = {"Positive", "Negative"}, 246 *MaskText[] = { "Almanac ", "Ephemeris", "UTC ", "Iono ", 247 "GPS Msg ", "Alm Hlth ", "Time Fix ", "SV Select", 248 "Ext Event", "Pos Fix ", "Raw Meas "}; 249 250#endif /* TRIMBLE_OUTPUT_FUNC */ 251 252/* 253 * Unit control structure 254 */ 255struct ripencc_unit { 256 int unit; /* unit number */ 257 int pollcnt; /* poll message counter */ 258 int polled; /* Hand in a sample? */ 259 char leapdelta; /* delta of next leap event */ 260 unsigned char utcflags; /* delta of next leap event */ 261 l_fp tstamp; /* timestamp of last poll */ 262 263 struct timespec ts; /* last timestamp */ 264 pps_params_t pps_params; /* pps parameters */ 265 pps_info_t pps_info; /* last pps data */ 266 pps_handle_t handle; /* pps handlebars */ 267 268}; 269 270 271/******************* PROTOYPES *****************/ 272 273/* prototypes for report parsing primitives */ 274short rpt_0x3D (TSIPPKT *rpt, unsigned char *tx_baud_index, 275 unsigned char *rx_baud_index, unsigned char *char_format_index, 276 unsigned char *stop_bits, unsigned char *tx_mode_index, 277 unsigned char *rx_mode_index); 278short rpt_0x40 (TSIPPKT *rpt, unsigned char *sv_prn, short *week_num, 279 float *t_zc, float *eccentricity, float *t_oa, float *i_0, 280 float *OMEGA_dot, float *sqrt_A, float *OMEGA_0, float *omega, 281 float *M_0); 282short rpt_0x41 (TSIPPKT *rpt, float *time_of_week, float *UTC_offset, 283 short *week_num); 284short rpt_0x42 (TSIPPKT *rpt, float ECEF_pos[3], float *time_of_fix); 285short rpt_0x43 (TSIPPKT *rpt, float ECEF_vel[3], float *freq_offset, 286 float *time_of_fix); 287short rpt_0x45 (TSIPPKT *rpt, unsigned char *major_nav_version, 288 unsigned char *minor_nav_version, unsigned char *nav_day, 289 unsigned char *nav_month, unsigned char *nav_year, 290 unsigned char *major_dsp_version, unsigned char *minor_dsp_version, 291 unsigned char *dsp_day, unsigned char *dsp_month, 292 unsigned char *dsp_year); 293short rpt_0x46 (TSIPPKT *rpt, unsigned char *status1, unsigned char *status2); 294short rpt_0x47 (TSIPPKT *rpt, unsigned char *nsvs, unsigned char *sv_prn, 295 float *snr); 296short rpt_0x48 (TSIPPKT *rpt, unsigned char *message); 297short rpt_0x49 (TSIPPKT *rpt, unsigned char *sv_health); 298short rpt_0x4A (TSIPPKT *rpt, float *lat, float *lon, float *alt, 299 float *clock_bias, float *time_of_fix); 300short rpt_0x4A_2 (TSIPPKT *rpt, float *alt, float *dummy, 301 unsigned char *alt_flag); 302short rpt_0x4B (TSIPPKT *rpt, unsigned char *machine_id, 303 unsigned char *status3, unsigned char *status4); 304short rpt_0x4C (TSIPPKT *rpt, unsigned char *dyn_code, float *el_mask, 305 float *snr_mask, float *dop_mask, float *dop_switch); 306short rpt_0x4D (TSIPPKT *rpt, float *osc_offset); 307short rpt_0x4E (TSIPPKT *rpt, unsigned char *response); 308short rpt_0x4F (TSIPPKT *rpt, double *a0, float *a1, float *time_of_data, 309 short *dt_ls, short *wn_t, short *wn_lsf, short *dn, short *dt_lsf); 310short rpt_0x54 (TSIPPKT *rpt, float *clock_bias, float *freq_offset, 311 float *time_of_fix); 312short rpt_0x55 (TSIPPKT *rpt, unsigned char *pos_code, unsigned char *vel_code, 313 unsigned char *time_code, unsigned char *aux_code); 314short rpt_0x56 (TSIPPKT *rpt, float vel_ENU[3], float *freq_offset, 315 float *time_of_fix); 316short rpt_0x57 (TSIPPKT *rpt, unsigned char *source_code, 317 unsigned char *diag_code, short *week_num, float *time_of_fix); 318short rpt_0x58 (TSIPPKT *rpt, unsigned char *op_code, unsigned char *data_type, 319 unsigned char *sv_prn, unsigned char *data_length, 320 unsigned char *data_packet); 321short rpt_0x59 (TSIPPKT *rpt, unsigned char *code_type, 322 unsigned char status_code[32]); 323short rpt_0x5A (TSIPPKT *rpt, unsigned char *sv_prn, float *sample_length, 324 float *signal_level, float *code_phase, float *Doppler, 325 double *time_of_fix); 326short rpt_0x5B (TSIPPKT *rpt, unsigned char *sv_prn, unsigned char *sv_health, 327 unsigned char *sv_iode, unsigned char *fit_interval_flag, 328 float *time_of_collection, float *time_of_eph, float *sv_accy); 329short rpt_0x5C (TSIPPKT *rpt, unsigned char *sv_prn, unsigned char *slot, 330 unsigned char *chan, unsigned char *acq_flag, unsigned char *eph_flag, 331 float *signal_level, float *time_of_last_msmt, float *elev, 332 float *azim, unsigned char *old_msmt_flag, 333 unsigned char *integer_msec_flag, unsigned char *bad_data_flag, 334 unsigned char *data_collect_flag); 335short rpt_0x6D (TSIPPKT *rpt, unsigned char *manual_mode, unsigned char *nsvs, 336 unsigned char *ndim, unsigned char sv_prn[], float *pdop, 337 float *hdop, float *vdop, float *tdop); 338short rpt_0x82 (TSIPPKT *rpt, unsigned char *diff_mode); 339short rpt_0x83 (TSIPPKT *rpt, double ECEF_pos[3], double *clock_bias, 340 float *time_of_fix); 341short rpt_0x84 (TSIPPKT *rpt, double *lat, double *lon, double *alt, 342 double *clock_bias, float *time_of_fix); 343short rpt_Paly0xBB(TSIPPKT *rpt, TSIP_RCVR_CFG *TsipxBB); 344short rpt_0xBC (TSIPPKT *rpt, unsigned char *port_num, 345 unsigned char *in_baud, unsigned char *out_baud, 346 unsigned char *data_bits, unsigned char *parity, 347 unsigned char *stop_bits, unsigned char *flow_control, 348 unsigned char *protocols_in, unsigned char *protocols_out, 349 unsigned char *reserved); 350 351/* prototypes for superpacket parsers */ 352 353short rpt_0x8F0B (TSIPPKT *rpt, unsigned short *event, double *tow, 354 unsigned char *date, unsigned char *month, short *year, 355 unsigned char *dim_mode, short *utc_offset, double *bias, double *drift, 356 float *bias_unc, float *dr_unc, double *lat, double *lon, double *alt, 357 char sv_id[8]); 358short rpt_0x8F14 (TSIPPKT *rpt, short *datum_idx, double datum_coeffs[5]); 359short rpt_0x8F15 (TSIPPKT *rpt, short *datum_idx, double datum_coeffs[5]); 360short rpt_0x8F20 (TSIPPKT *rpt, unsigned char *info, double *lat, 361 double *lon, double *alt, double vel_enu[], double *time_of_fix, 362 short *week_num, unsigned char *nsvs, unsigned char sv_prn[], 363 short sv_IODC[], short *datum_index); 364short rpt_0x8F41 (TSIPPKT *rpt, unsigned char *bSearchRange, 365 unsigned char *bBoardOptions, unsigned long *iiSerialNumber, 366 unsigned char *bBuildYear, unsigned char *bBuildMonth, 367 unsigned char *bBuildDay, unsigned char *bBuildHour, 368 float *fOscOffset, unsigned short *iTestCodeId); 369short rpt_0x8F42 (TSIPPKT *rpt, unsigned char *bProdOptionsPre, 370 unsigned char *bProdNumberExt, unsigned short *iCaseSerialNumberPre, 371 unsigned long *iiCaseSerialNumber, unsigned long *iiProdNumber, 372 unsigned short *iPremiumOptions, unsigned short *iMachineID, 373 unsigned short *iKey); 374short rpt_0x8F45 (TSIPPKT *rpt, unsigned char *bSegMask); 375short rpt_0x8F4A_16 (TSIPPKT *rpt, unsigned char *pps_enabled, 376 unsigned char *pps_timebase, unsigned char *pos_polarity, 377 double *pps_offset, float *bias_unc_threshold); 378short rpt_0x8F4B (TSIPPKT *rpt, unsigned long *decorr_max); 379short rpt_0x8F4D (TSIPPKT *rpt, unsigned long *event_mask); 380short rpt_0x8FA5 (TSIPPKT *rpt, unsigned char *spktmask); 381short rpt_0x8FAD (TSIPPKT *rpt, unsigned short *COUNT, double *FracSec, 382 unsigned char *Hour, unsigned char *Minute, unsigned char *Second, 383 unsigned char *Day, unsigned char *Month, unsigned short *Year, 384 unsigned char *Status, unsigned char *Flags); 385 386/**/ 387/* prototypes for command-encode primitives with suffix convention: */ 388/* c = clear, s = set, q = query, e = enable, d = disable */ 389void cmd_0x1F (TSIPPKT *cmd); 390void cmd_0x26 (TSIPPKT *cmd); 391void cmd_0x2F (TSIPPKT *cmd); 392void cmd_0x35s (TSIPPKT *cmd, unsigned char pos_code, unsigned char vel_code, 393 unsigned char time_code, unsigned char opts_code); 394void cmd_0x3C (TSIPPKT *cmd, unsigned char sv_prn); 395void cmd_0x3Ds (TSIPPKT *cmd, unsigned char baud_out, unsigned char baud_inp, 396 unsigned char char_code, unsigned char stopbitcode, 397 unsigned char output_mode, unsigned char input_mode); 398void cmd_0xBBq (TSIPPKT *cmd, unsigned char subcode) ; 399 400/* prototypes 8E commands */ 401void cmd_0x8E0Bq (TSIPPKT *cmd); 402void cmd_0x8E41q (TSIPPKT *cmd); 403void cmd_0x8E42q (TSIPPKT *cmd); 404void cmd_0x8E4Aq (TSIPPKT *cmd); 405void cmd_0x8E4As (TSIPPKT *cmd, unsigned char PPSOnOff, unsigned char TimeBase, 406 unsigned char Polarity, double PPSOffset, float Uncertainty); 407void cmd_0x8E4Bq (TSIPPKT *cmd); 408void cmd_0x8E4Ds (TSIPPKT *cmd, unsigned long AutoOutputMask); 409void cmd_0x8EADq (TSIPPKT *cmd); 410 411/* header/source border XXXXXXXXXXXXXXXXXXXXXXXXXX */ 412 413/* Trimble parse functions */ 414static int parse0x8FAD P((TSIPPKT *, struct peer *)); 415static int parse0x8F0B P((TSIPPKT *, struct peer *)); 416#ifdef TRIMBLE_OUTPUT_FUNC 417static int parseany P((TSIPPKT *, struct peer *)); 418static void TranslateTSIPReportToText P((TSIPPKT *, char *)); 419#endif /* TRIMBLE_OUTPUT_FUNC */ 420static int parse0x5C P((TSIPPKT *, struct peer *)); 421static int parse0x4F P((TSIPPKT *, struct peer *)); 422static void tsip_input_proc P((TSIPPKT *, int)); 423 424/* Trimble helper functions */ 425static void bPutFloat P((float *, unsigned char *)); 426static void bPutDouble P((double *, unsigned char *)); 427static void bPutULong P((unsigned long *, unsigned char *)); 428static int print_msg_table_header P((int rptcode, char *HdrStr, int force)); 429static char * show_time P((float time_of_week)); 430 431/* RIPE NCC functions */ 432static void ripencc_control P((int, struct refclockstat *, struct 433 refclockstat *, struct peer *)); 434static int ripencc_ppsapi P((struct peer *, int, int)); 435static int ripencc_get_pps_ts P((struct ripencc_unit *, l_fp *)); 436static int ripencc_start P((int, struct peer *)); 437static void ripencc_shutdown P((int, struct peer *)); 438static void ripencc_poll P((int, struct peer *)); 439static void ripencc_send P((struct peer *, TSIPPKT spt)); 440static void ripencc_receive P((struct recvbuf *)); 441 442/* fill in reflock structure for our clock */ 443struct refclock refclock_ripencc = { 444 ripencc_start, /* start up driver */ 445 ripencc_shutdown, /* shut down driver */ 446 ripencc_poll, /* transmit poll message */ 447 ripencc_control, /* control function */ 448 noentry, /* initialize driver */ 449 noentry, /* debug info */ 450 NOFLAGS /* clock flags */ 451}; 452 453/* 454 * Tables to compute the ddd of year form icky dd/mm timecode. Viva la 455 * leap. 456 */ 457static int day1tab[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 458static int day2tab[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 459 460 461/* 462 * ripencc_start - open the GPS devices and initialize data for processing 463 */ 464static int 465ripencc_start(int unit, struct peer *peer) 466{ 467 register struct ripencc_unit *up; 468 struct refclockproc *pp; 469 char device[40]; 470 int fd; 471 struct termios tio; 472 TSIPPKT spt; 473 474 /* 475 * Open serial port 476 */ 477 (void)snprintf(device, sizeof(device), DEVICE, unit); 478 if (!(fd = refclock_open(device, SPEED232, LDISC_RAW))) 479 return (0); 480 481 /* from refclock_palisade.c */ 482 if (tcgetattr(fd, &tio) < 0) { 483 msyslog(LOG_ERR, "Palisade(%d) tcgetattr(fd, &tio): %m",unit); 484 return (0); 485 } 486 487 /* 488 * set flags 489 */ 490 tio.c_cflag |= (PARENB|PARODD); 491 tio.c_iflag &= ~ICRNL; 492 if (tcsetattr(fd, TCSANOW, &tio) == -1) { 493 msyslog(LOG_ERR, "Palisade(%d) tcsetattr(fd, &tio): %m",unit); 494 return (0); 495 } 496 497 /* 498 * Allocate and initialize unit structure 499 */ 500 if (!(up = (struct ripencc_unit *) 501 emalloc(sizeof(struct ripencc_unit)))) { 502 (void) close(fd); 503 return (0); 504 } 505 memset((char *)up, 0, sizeof(struct ripencc_unit)); 506 pp = peer->procptr; 507 pp->io.clock_recv = ripencc_receive; 508 pp->io.srcclock = (caddr_t)peer; 509 pp->io.datalen = 0; 510 pp->io.fd = fd; 511 if (!io_addclock(&pp->io)) { 512 (void) close(fd); 513 free(up); 514 return (0); 515 } 516 pp->unitptr = (caddr_t)up; 517 518 /* 519 * Initialize miscellaneous variables 520 */ 521 peer->precision = PRECISION; 522 pp->clockdesc = DESCRIPTION; 523 memcpy((char *)&pp->refid, REFID, REFID_LEN); 524 up->pollcnt = 2; 525 up->unit = unit; 526 up->leapdelta = 0; 527 up->utcflags = 0; 528 529 /* 530 * Initialize the Clock 531 */ 532 533 /* query software versions */ 534 cmd_0x1F(&spt); 535 ripencc_send(peer, spt); 536 537 /* query receiver health */ 538 cmd_0x26(&spt); 539 ripencc_send(peer, spt); 540 541 /* query serial numbers */ 542 cmd_0x8E42q(&spt); 543 ripencc_send(peer, spt); 544 545 /* query manuf params */ 546 cmd_0x8E41q(&spt); 547 ripencc_send(peer, spt); 548 549 /* i/o opts */ /* trimble manual page A30 */ 550 cmd_0x35s(&spt, 551 0x1C, /* position */ 552 0x00, /* velocity */ 553 0x05, /* timing */ 554 0x0a); /* auxilary */ 555 ripencc_send(peer, spt); 556 557 /* turn off port A */ 558 cmd_0x3Ds (&spt, 559 0x0B, /* baud_out */ 560 0x0B, /* baud_inp */ 561 0x07, /* char_code */ 562 0x07, /* stopbitcode */ 563 0x01, /* output_mode */ 564 0x00); /* input_mode */ 565 ripencc_send(peer, spt); 566 567 /* set i/o options */ 568 cmd_0x8E4As (&spt, 569 0x01, /* PPS on */ 570 0x01, /* Timebase UTC */ 571 0x00, /* polarity positive */ 572 0., /* 100 ft. cable XXX make flag */ 573 1e-6 * GPS_C); /* turn of biasuncert. > (1us) */ 574 ripencc_send(peer,spt); 575 576 /* all outomatic packet output off */ 577 cmd_0x8E4Ds(&spt, 578 0x00000000); /* AutoOutputMask */ 579 ripencc_send(peer, spt); 580 581 cmd_0xBBq (&spt, 582 0x00); /* query primary configuration */ 583 ripencc_send(peer,spt); 584 585 586 /* query PPS parameters */ 587 cmd_0x8E4Aq (&spt); /* query PPS params */ 588 ripencc_send(peer,spt); 589 590 /* query survey limit */ 591 cmd_0x8E4Bq (&spt); /* query survey limit */ 592 ripencc_send(peer,spt); 593 594#ifdef DEBUG_NCC 595 if (debug) 596 printf("ripencc_start: success\n"); 597#endif /* DEBUG_NCC */ 598 599 /* 600 * Start the PPSAPI interface if it is there. Default to use 601 * the assert edge and do not enable the kernel hardpps. 602 */ 603 if (time_pps_create(fd, &up->handle) < 0) { 604 up->handle = 0; 605 msyslog(LOG_ERR, "refclock_ripencc: time_pps_create failed: %m"); 606 return (1); 607 } 608 609 return(ripencc_ppsapi(peer, 0, 0)); 610} 611 612/* 613 * ripencc_control - fudge control 614 */ 615static void 616ripencc_control( 617 int unit, /* unit (not used) */ 618 struct refclockstat *in, /* input parameters (not used) */ 619 struct refclockstat *out, /* output parameters (not used) */ 620 struct peer *peer /* peer structure pointer */ 621 ) 622{ 623 struct refclockproc *pp; 624 625#ifdef DEBUG_NCC 626 msyslog(LOG_INFO,"%s()",__FUNCTION__); 627#endif /* DEBUG_NCC */ 628 629 pp = peer->procptr; 630 ripencc_ppsapi(peer, pp->sloppyclockflag & CLK_FLAG2, 631 pp->sloppyclockflag & CLK_FLAG3); 632} 633 634 635/* 636 * Initialize PPSAPI 637 */ 638int 639ripencc_ppsapi( 640 struct peer *peer, /* peer structure pointer */ 641 int enb_clear, /* clear enable */ 642 int enb_hardpps /* hardpps enable */ 643 ) 644{ 645 struct refclockproc *pp; 646 struct ripencc_unit *up; 647 int capability; 648 649 pp = peer->procptr; 650 up = (struct ripencc_unit *)pp->unitptr; 651 if (time_pps_getcap(up->handle, &capability) < 0) { 652 msyslog(LOG_ERR, 653 "refclock_ripencc: time_pps_getcap failed: %m"); 654 return (0); 655 } 656 memset(&up->pps_params, 0, sizeof(pps_params_t)); 657 if (enb_clear) 658 up->pps_params.mode = capability & PPS_CAPTURECLEAR; 659 else 660 up->pps_params.mode = capability & PPS_CAPTUREASSERT; 661 if (!up->pps_params.mode) { 662 msyslog(LOG_ERR, 663 "refclock_ripencc: invalid capture edge %d", 664 !enb_clear); 665 return (0); 666 } 667 up->pps_params.mode |= PPS_TSFMT_TSPEC; 668 if (time_pps_setparams(up->handle, &up->pps_params) < 0) { 669 msyslog(LOG_ERR, 670 "refclock_ripencc: time_pps_setparams failed: %m"); 671 return (0); 672 } 673 if (enb_hardpps) { 674 if (time_pps_kcbind(up->handle, PPS_KC_HARDPPS, 675 up->pps_params.mode & ~PPS_TSFMT_TSPEC, 676 PPS_TSFMT_TSPEC) < 0) { 677 msyslog(LOG_ERR, 678 "refclock_ripencc: time_pps_kcbind failed: %m"); 679 return (0); 680 } 681 pps_enable = 1; 682 } 683 peer->precision = PPS_PRECISION; 684 685#if DEBUG_NCC 686 if (debug) { 687 time_pps_getparams(up->handle, &up->pps_params); 688 printf( 689 "refclock_ripencc: capability 0x%x version %d mode 0x%x kern %d\n", 690 capability, up->pps_params.api_version, 691 up->pps_params.mode, enb_hardpps); 692 } 693#endif /* DEBUG_NCC */ 694 695 return (1); 696} 697 698/* 699 * This function is called every 64 seconds from ripencc_receive 700 * It will fetch the pps time 701 * 702 * Return 0 on failure and 1 on success. 703 */ 704static int 705ripencc_get_pps_ts( 706 struct ripencc_unit *up, 707 l_fp *tsptr 708 ) 709{ 710 pps_info_t pps_info; 711 struct timespec timeout, ts; 712 double dtemp; 713 l_fp tstmp; 714 715#ifdef DEBUG_PPS 716 msyslog(LOG_INFO,"ripencc_get_pps_ts\n"); 717#endif /* DEBUG_PPS */ 718 719 720 /* 721 * Convert the timespec nanoseconds field to ntp l_fp units. 722 */ 723 if (up->handle == 0) 724 return (0); 725 timeout.tv_sec = 0; 726 timeout.tv_nsec = 0; 727 memcpy(&pps_info, &up->pps_info, sizeof(pps_info_t)); 728 if (time_pps_fetch(up->handle, PPS_TSFMT_TSPEC, &up->pps_info, 729 &timeout) < 0) 730 return (0); 731 if (up->pps_params.mode & PPS_CAPTUREASSERT) { 732 if (pps_info.assert_sequence == 733 up->pps_info.assert_sequence) 734 return (0); 735 ts = up->pps_info.assert_timestamp; 736 } else if (up->pps_params.mode & PPS_CAPTURECLEAR) { 737 if (pps_info.clear_sequence == 738 up->pps_info.clear_sequence) 739 return (0); 740 ts = up->pps_info.clear_timestamp; 741 } else { 742 return (0); 743 } 744 if ((up->ts.tv_sec == ts.tv_sec) && (up->ts.tv_nsec == ts.tv_nsec)) 745 return (0); 746 up->ts = ts; 747 748 tstmp.l_ui = ts.tv_sec + JAN_1970; 749 dtemp = ts.tv_nsec * FRAC / 1e9; 750 tstmp.l_uf = (u_int32)dtemp; 751 752#ifdef DEBUG_PPS 753 msyslog(LOG_INFO,"ts.tv_sec: %d\n",(int)ts.tv_sec); 754 msyslog(LOG_INFO,"ts.tv_nsec: %ld\n",ts.tv_nsec); 755#endif /* DEBUG_PPS */ 756 757 *tsptr = tstmp; 758 return (1); 759} 760 761/* 762 * ripencc_shutdown - shut down a GPS clock 763 */ 764static void 765ripencc_shutdown(int unit, struct peer *peer) 766{ 767 register struct ripencc_unit *up; 768 struct refclockproc *pp; 769 770 pp = peer->procptr; 771 up = (struct ripencc_unit *)pp->unitptr; 772 773 if (up->handle != 0) 774 time_pps_destroy(up->handle); 775 776 io_closeclock(&pp->io); 777 778 free(up); 779} 780 781/* 782 * ripencc_poll - called by the transmit procedure 783 */ 784static void 785ripencc_poll(int unit, struct peer *peer) 786{ 787 register struct ripencc_unit *up; 788 struct refclockproc *pp; 789 TSIPPKT spt; 790 791#ifdef DEBUG_NCC 792 if (debug) 793 fprintf(stderr, "ripencc_poll(%d)\n", unit); 794#endif /* DEBUG_NCC */ 795 pp = peer->procptr; 796 up = (struct ripencc_unit *)pp->unitptr; 797 if (up->pollcnt == 0) 798 refclock_report(peer, CEVNT_TIMEOUT); 799 else 800 up->pollcnt--; 801 802 pp->polls++; 803 up->polled = 1; 804 805 /* poll for UTC superpacket */ 806 cmd_0x8EADq (&spt); 807 ripencc_send(peer,spt); 808} 809 810/* 811 * ripencc_send - send message to clock 812 * use the structures being created by the trimble functions! 813 * makes the code more readable/clean 814 */ 815static void 816ripencc_send(struct peer *peer, TSIPPKT spt) 817{ 818 unsigned char *ip, *op; 819 unsigned char obuf[512]; 820 821#ifdef DEBUG_RAW 822 { 823 register struct ripencc_unit *up; 824 register struct refclockproc *pp; 825 826 pp = peer->procptr; 827 up = (struct ripencc_unit *)pp->unitptr; 828 if (debug) 829 printf("ripencc_send(%d, %02X)\n", up->unit, cmd); 830 } 831#endif /* DEBUG_RAW */ 832 833 ip = spt.buf; 834 op = obuf; 835 836 *op++ = 0x10; 837 *op++ = spt.code; 838 839 while (spt.len--) { 840 if (op-obuf > sizeof(obuf)-5) { 841 msyslog(LOG_ERR, "ripencc_send obuf overflow!"); 842 refclock_report(peer, CEVNT_FAULT); 843 return; 844 } 845 846 if (*ip == 0x10) /* byte stuffing */ 847 *op++ = 0x10; 848 *op++ = *ip++; 849 } 850 851 *op++ = 0x10; 852 *op++ = 0x03; 853 854#ifdef DEBUG_RAW 855 if (debug) { /* print raw packet */ 856 unsigned char *cp; 857 int i; 858 859 printf("ripencc_send: len %d\n", op-obuf); 860 for (i=1, cp=obuf; cp<op; i++, cp++) { 861 printf(" %02X", *cp); 862 if (i%10 == 0) 863 printf("\n"); 864 } 865 printf("\n"); 866 } 867#endif /* DEBUG_RAW */ 868 869 if (write(peer->procptr->io.fd, obuf, op-obuf) == -1) { 870 refclock_report(peer, CEVNT_FAULT); 871 } 872} 873 874/* 875 * ripencc_receive() 876 * 877 * called when a packet is received on the serial port 878 * takes care of further processing 879 * 880 */ 881static void 882ripencc_receive(struct recvbuf *rbufp) 883{ 884 register struct ripencc_unit *up; 885 register struct refclockproc *pp; 886 struct peer *peer; 887 static TSIPPKT rpt; /* structure for current incoming TSIP report */ 888 TSIPPKT spt; /* send packet */ 889 int ns_since_pps; 890 int i; 891 char *cp; 892 /* Use these variables to hold data until we decide its worth keeping */ 893 char rd_lastcode[BMAX]; 894 l_fp rd_tmp; 895 u_short rd_lencode; 896 897 /* msyslog(LOG_INFO, "%s",__FUNCTION__); */ 898 899 /* 900 * Initialize pointers and read the timecode and timestamp 901 */ 902 peer = (struct peer *)rbufp->recv_srcclock; 903 pp = peer->procptr; 904 up = (struct ripencc_unit *)pp->unitptr; 905 rd_lencode = refclock_gtlin(rbufp, rd_lastcode, BMAX, &rd_tmp); 906 907#ifdef DEBUG_RAW 908 if (debug) 909 fprintf(stderr, "ripencc_receive(%d)\n", up->unit); 910#endif /* DEBUG_RAW */ 911 912#ifdef DEBUG_RAW 913 if (debug) { /* print raw packet */ 914 int i; 915 unsigned char *cp; 916 917 printf("ripencc_receive: len %d\n", rbufp->recv_length); 918 for (i=1, cp=(char*)&rbufp->recv_space; i <= rbufp->recv_length; i++, cp++) { 919 printf(" %02X", *cp); 920 if (i%10 == 0) 921 printf("\n"); 922 } 923 printf("\n"); 924 } 925#endif /* DEBUG_RAW */ 926 927 cp = (char*) &rbufp->recv_space; 928 i=rbufp->recv_length; 929 930 while (i--) { /* loop over received chars */ 931 932 tsip_input_proc(&rpt, (unsigned char) *cp++); 933 934 if (rpt.status != TSIP_PARSED_FULL) 935 continue; 936 937 switch (rpt.code) { 938 939 case 0x8F: /* superpacket */ 940 941 switch (rpt.buf[0]) { 942 943 case 0xAD: /* UTC Time */ 944 /* 945 * When polling on port B the timecode 946 * is the time of the previous PPS. 947 * If we completed receiving the packet 948 * less than 150ms after the turn of the second, 949 * it may have the code of the previous second. 950 * We do not trust that and simply poll again 951 * without even parsing it. 952 * 953 * More elegant would be to re-schedule the poll, 954 * but I do not know (yet) how to do that cleanly. 955 * 956 */ 957 /* BLA ns_since_pps = ncc_tstmp(rbufp, &trtmp); */ 958/* if (up->polled && ns_since_pps > -1 && ns_since_pps < 150) { */ 959 960 ns_since_pps=200; 961 if (up->polled && ns_since_pps < 150) { 962 msyslog(LOG_INFO, "%s(): up->polled",__FUNCTION__); 963 ripencc_poll(up->unit, peer); 964 break; 965 } 966 967 /* 968 * Parse primary utc time packet 969 * and fill refclock structure 970 * from results. 971 */ 972 if (parse0x8FAD(&rpt, peer) < 0) { 973 msyslog(LOG_INFO, "%s(): parse0x8FAD < 0",__FUNCTION__); 974 refclock_report(peer, CEVNT_BADREPLY); 975 break; 976 } 977 /* 978 * If the PPSAPI is working, rather use its 979 * timestamps. 980 * assume that the PPS occurs on the second 981 * so blow any msec 982 */ 983 if (ripencc_get_pps_ts(up, &rd_tmp) == 1) { 984 pp->lastrec = up->tstamp = rd_tmp; 985 pp->nsec = 0; 986 } 987 else 988 msyslog(LOG_INFO, "%s(): ripencc_get_pps_ts returns failure\n",__FUNCTION__); 989 990 991 if (!up->polled) { 992 msyslog(LOG_INFO, "%s(): unrequested packet\n",__FUNCTION__); 993 /* unrequested packet */ 994 break; 995 } 996 997 /* we have been polled ! */ 998 up->polled = 0; 999 up->pollcnt = 2; 1000 1001 /* poll for next packet */ 1002 cmd_0x8E0Bq(&spt); 1003 ripencc_send(peer,spt); 1004 1005 if (ns_since_pps < 0) { /* no PPS */ 1006 msyslog(LOG_INFO, "%s(): ns_since_pps < 0",__FUNCTION__); 1007 refclock_report(peer, CEVNT_BADTIME); 1008 break; 1009 } 1010 1011 /* 1012 * Process the new sample in the median filter and determine the 1013 * reference clock offset and dispersion. 1014 */ 1015 if (!refclock_process(pp)) { 1016 msyslog(LOG_INFO, "%s(): !refclock_process",__FUNCTION__); 1017 refclock_report(peer, CEVNT_BADTIME); 1018 break; 1019 } 1020 1021 refclock_receive(peer); 1022 break; 1023 1024 case 0x0B: /* comprehensive time packet */ 1025 parse0x8F0B(&rpt, peer); 1026 break; 1027 1028 default: /* other superpackets */ 1029#ifdef DEBUG_NCC 1030 msyslog(LOG_INFO, "%s(): calling parseany",__FUNCTION__); 1031#endif /* DEBUG_NCC */ 1032#ifdef TRIMBLE_OUTPUT_FUNC 1033 parseany(&rpt, peer); 1034#endif /* TRIMBLE_OUTPUT_FUNC */ 1035 break; 1036 } 1037 break; 1038 1039 case 0x4F: /* UTC parameters, for leap info */ 1040 parse0x4F(&rpt, peer); 1041 break; 1042 1043 case 0x5C: /* sat tracking data */ 1044 parse0x5C(&rpt, peer); 1045 break; 1046 1047 default: /* other packets */ 1048#ifdef TRIMBLE_OUTPUT_FUNC 1049 parseany(&rpt, peer); 1050#endif /* TRIMBLE_OUTPUT_FUNC */ 1051 break; 1052 } 1053 rpt.status = TSIP_PARSED_EMPTY; 1054 } 1055} 1056 1057/* 1058 * All trimble functions that are directly referenced from driver code 1059 * (so not from parseany) 1060 */ 1061 1062void cmd_0x1F (TSIPPKT *cmd) 1063/* request software versions */ 1064{ 1065 cmd->len = 0; 1066 cmd->code = 0x1F; 1067} 1068 1069void cmd_0x26 (TSIPPKT *cmd) 1070/* request receiver health */ 1071{ 1072 cmd->len = 0; 1073 cmd->code = 0x26; 1074} 1075 1076 1077 1078 1079void cmd_0x2F (TSIPPKT *cmd) 1080/* request UTC params */ 1081{ 1082 cmd->len = 0; 1083 cmd->code = 0x2F; 1084} 1085 1086void cmd_0x35s (TSIPPKT *cmd, unsigned char pos_code, unsigned char vel_code, 1087 unsigned char time_code, unsigned char opts_code) 1088/* set serial I/O options */ 1089{ 1090 cmd->buf[0] = pos_code; 1091 cmd->buf[1] = vel_code; 1092 cmd->buf[2] = time_code; 1093 cmd->buf[3] = opts_code; 1094 cmd->len = 4; 1095 cmd->code = 0x35; 1096} 1097void cmd_0x3C (TSIPPKT *cmd, unsigned char sv_prn) 1098/* request tracking status */ 1099{ 1100 cmd->buf[0] = sv_prn; 1101 cmd->len = 1; 1102 cmd->code = 0x3C; 1103} 1104 1105 1106void cmd_0x3Ds (TSIPPKT *cmd, 1107 unsigned char baud_out, unsigned char baud_inp, 1108 unsigned char char_code, unsigned char stopbitcode, 1109 unsigned char output_mode, unsigned char input_mode) 1110/* set Channel A configuration for dual-port operation */ 1111{ 1112 cmd->buf[0] = baud_out; /* XMT baud rate */ 1113 cmd->buf[1] = baud_inp; /* RCV baud rate */ 1114 cmd->buf[2] = char_code; /* parity and #bits per byte */ 1115 cmd->buf[3] = stopbitcode; /* number of stop bits code */ 1116 cmd->buf[4] = output_mode; /* Ch. A transmission mode */ 1117 cmd->buf[5] = input_mode; /* Ch. A reception mode */ 1118 cmd->len = 6; 1119 cmd->code = 0x3D; 1120} 1121 1122 1123/* query primary configuration */ 1124void cmd_0xBBq (TSIPPKT *cmd, 1125 unsigned char subcode) 1126{ 1127 1128 cmd->len = 1; 1129 cmd->code = 0xBB; 1130 cmd->buf[0] = subcode; 1131} 1132 1133 1134/**** Superpackets ****/ 1135void cmd_0x8E0Bq (TSIPPKT *cmd) 1136/* 8E-0B to query 8F-0B controls */ 1137{ 1138 1139 cmd->len = 1; 1140 cmd->code = 0x8E; 1141 cmd->buf[0] = 0x0B; 1142} 1143 1144 1145void cmd_0x8E41q (TSIPPKT *cmd) 1146/* 8F-41 to query board serial number */ 1147{ 1148 1149 cmd->len = 1; 1150 cmd->code = 0x8E; 1151 cmd->buf[0] = 0x41; 1152} 1153 1154 1155void cmd_0x8E42q (TSIPPKT *cmd) 1156/* 8F-42 to query product serial number */ 1157{ 1158 1159 cmd->len = 1; 1160 cmd->code = 0x8E; 1161 cmd->buf[0] = 0x42; 1162} 1163void cmd_0x8E4Aq (TSIPPKT *cmd) 1164/* 8F-4A to query PPS parameters */ 1165{ 1166 cmd->len = 1; 1167 cmd->code = 0x8E; 1168 cmd->buf[0] = 0x4A; 1169} 1170 1171 1172/* set i/o options */ 1173void cmd_0x8E4As (TSIPPKT *cmd, 1174 unsigned char PPSOnOff, 1175 unsigned char TimeBase, 1176 unsigned char Polarity, 1177 double PPSOffset, 1178 float Uncertainty) 1179{ 1180 cmd->len = 16; 1181 cmd->code = 0x8E; 1182 cmd->buf[0] = 0x4A; 1183 cmd->buf[1] = PPSOnOff; 1184 cmd->buf[2] = TimeBase; 1185 cmd->buf[3] = Polarity; 1186 bPutDouble (&PPSOffset, &cmd->buf[4]); 1187 bPutFloat (&Uncertainty, &cmd->buf[12]); 1188} 1189void cmd_0x8E4Bq (TSIPPKT *cmd) 1190/* 8F-4B query survey limit */ 1191{ 1192 cmd->len = 1; 1193 cmd->code = 0x8E; 1194 cmd->buf[0] = 0x4B; 1195} 1196 1197 1198/* poll for UTC superpacket */ 1199void cmd_0x8EADq (TSIPPKT *cmd) 1200/* 8E-AD to query 8F-AD controls */ 1201{ 1202 cmd->len = 1; 1203 cmd->code = 0x8E; 1204 cmd->buf[0] = 0xAD; 1205} 1206 1207/* all outomatic packet output off */ 1208void cmd_0x8E4Ds (TSIPPKT *cmd, 1209 unsigned long AutoOutputMask) 1210{ 1211 cmd->len = 5; 1212 cmd->code = 0x8E; 1213 cmd->buf[0] = 0x4D; 1214 bPutULong (&AutoOutputMask, &cmd->buf[1]); 1215} 1216 1217 1218 1219 1220/* for DOS machines, reverse order of bytes as they come through the 1221 * serial port. */ 1222#ifdef BYTESWAP 1223static short bGetShort (unsigned char *bp) 1224{ 1225 short outval; 1226 unsigned char *optr; 1227 1228 optr = (unsigned char*)&outval + 1; 1229 *optr-- = *bp++; 1230 *optr = *bp; 1231 return outval; 1232} 1233 1234#ifdef TRIMBLE_OUTPUT_FUNC 1235static unsigned short bGetUShort (unsigned char *bp) 1236{ 1237 unsigned short outval; 1238 unsigned char *optr; 1239 1240 optr = (unsigned char*)&outval + 1; 1241 *optr-- = *bp++; 1242 *optr = *bp; 1243 return outval; 1244} 1245 1246static long bGetLong (unsigned char *bp) 1247{ 1248 long outval; 1249 unsigned char *optr; 1250 1251 optr = (unsigned char*)&outval + 3; 1252 *optr-- = *bp++; 1253 *optr-- = *bp++; 1254 *optr-- = *bp++; 1255 *optr = *bp; 1256 return outval; 1257} 1258 1259static unsigned long bGetULong (unsigned char *bp) 1260{ 1261 unsigned long outval; 1262 unsigned char *optr; 1263 1264 optr = (unsigned char*)&outval + 3; 1265 *optr-- = *bp++; 1266 *optr-- = *bp++; 1267 *optr-- = *bp++; 1268 *optr = *bp; 1269 return outval; 1270} 1271#endif /* TRIMBLE_OUTPUT_FUNC */ 1272 1273static float bGetSingle (unsigned char *bp) 1274{ 1275 float outval; 1276 unsigned char *optr; 1277 1278 optr = (unsigned char*)&outval + 3; 1279 *optr-- = *bp++; 1280 *optr-- = *bp++; 1281 *optr-- = *bp++; 1282 *optr = *bp; 1283 return outval; 1284} 1285 1286static double bGetDouble (unsigned char *bp) 1287{ 1288 double outval; 1289 unsigned char *optr; 1290 1291 optr = (unsigned char*)&outval + 7; 1292 *optr-- = *bp++; 1293 *optr-- = *bp++; 1294 *optr-- = *bp++; 1295 *optr-- = *bp++; 1296 *optr-- = *bp++; 1297 *optr-- = *bp++; 1298 *optr-- = *bp++; 1299 *optr = *bp; 1300 return outval; 1301} 1302 1303#else /* not BYTESWAP */ 1304 1305#define bGetShort(bp) (*(short*)(bp)) 1306#define bGetLong(bp) (*(long*)(bp)) 1307#define bGetULong(bp) (*(unsigned long*)(bp)) 1308#define bGetSingle(bp) (*(float*)(bp)) 1309#define bGetDouble(bp) (*(double*)(bp)) 1310 1311#endif /* BYTESWAP */ 1312/* 1313 * Byte-reversal is necessary for little-endian (Intel-based) machines. 1314 * TSIP streams are Big-endian (Motorola-based). 1315 */ 1316#ifdef BYTESWAP 1317 1318void 1319bPutFloat (float *in, unsigned char *out) 1320{ 1321 unsigned char *inptr; 1322 1323 inptr = (unsigned char*)in + 3; 1324 *out++ = *inptr--; 1325 *out++ = *inptr--; 1326 *out++ = *inptr--; 1327 *out = *inptr; 1328} 1329 1330static void 1331bPutULong (unsigned long *in, unsigned char *out) 1332{ 1333 unsigned char *inptr; 1334 1335 inptr = (unsigned char*)in + 3; 1336 *out++ = *inptr--; 1337 *out++ = *inptr--; 1338 *out++ = *inptr--; 1339 *out = *inptr; 1340} 1341 1342static void 1343bPutDouble (double *in, unsigned char *out) 1344{ 1345 unsigned char *inptr; 1346 1347 inptr = (unsigned char*)in + 7; 1348 *out++ = *inptr--; 1349 *out++ = *inptr--; 1350 *out++ = *inptr--; 1351 *out++ = *inptr--; 1352 *out++ = *inptr--; 1353 *out++ = *inptr--; 1354 *out++ = *inptr--; 1355 *out = *inptr; 1356} 1357 1358#else /* not BYTESWAP */ 1359 1360void bPutShort (short a, unsigned char *cmdbuf) {*(short*) cmdbuf = a;} 1361void bPutULong (long a, unsigned char *cmdbuf) {*(long*) cmdbuf = a;} 1362void bPutFloat (float a, unsigned char *cmdbuf) {*(float*) cmdbuf = a;} 1363void bPutDouble (double a, unsigned char *cmdbuf){*(double*) cmdbuf = a;} 1364 1365#endif /* BYTESWAP */ 1366 1367/* 1368 * Parse primary utc time packet 1369 * and fill refclock structure 1370 * from results. 1371 * 1372 * 0 = success 1373 * -1 = errors 1374 */ 1375 1376static int 1377parse0x8FAD(rpt, peer) 1378 TSIPPKT *rpt; 1379 struct peer *peer; 1380{ 1381 register struct refclockproc *pp; 1382 register struct ripencc_unit *up; 1383 1384 unsigned day, month, year; /* data derived from received timecode */ 1385 unsigned hour, minute, second; 1386 unsigned char trackstat, utcflags; 1387 1388 static char logbuf[1024]; /* logging string buffer */ 1389 int i; 1390 unsigned char *buf; 1391 1392 buf = rpt->buf; 1393 pp = peer->procptr; 1394 1395 if (rpt->len != 22) 1396 return (-1); 1397 1398 if (bGetShort(&buf[1]) != 0) { 1399#ifdef DEBUG_NCC 1400 if (debug) 1401 printf("parse0x8FAD: event count != 0\n"); 1402#endif /* DEBUG_NCC */ 1403 return(-1); 1404 } 1405 1406 1407 if (bGetDouble(&buf[3]) != 0.0) { 1408#ifdef DEBUG_NCC 1409 if (debug) 1410 printf("parse0x8FAD: fracsecs != 0\n"); 1411#endif /* DEBUG_NCC */ 1412 return(-1); 1413 } 1414 1415 hour = (unsigned int) buf[11]; 1416 minute = (unsigned int) buf[12]; 1417 second = (unsigned int) buf[13]; 1418 day = (unsigned int) buf[14]; 1419 month = (unsigned int) buf[15]; 1420 year = bGetShort(&buf[16]); 1421 trackstat = buf[18]; 1422 utcflags = buf[19]; 1423 1424 1425 sprintf(logbuf, "U1 %d.%d.%d %02d:%02d:%02d %d %02x", 1426 day, month, year, hour, minute, second, trackstat, utcflags); 1427 1428#ifdef DEBUG_NCC 1429 if (debug) 1430 puts(logbuf); 1431#endif /* DEBUG_NCC */ 1432 1433 record_clock_stats(&peer->srcadr, logbuf); 1434 1435 if (!utcflags & UTCF_UTC_AVAIL) 1436 return(-1); 1437 1438 /* poll for UTC parameters once and then if UTC flag changed */ 1439 up = (struct ripencc_unit *) pp->unitptr; 1440 if (utcflags != up->utcflags) { 1441 TSIPPKT spt; /* local structure for send packet */ 1442 cmd_0x2F (&spt); /* request UTC params */ 1443 ripencc_send(peer,spt); 1444 up->utcflags = utcflags; 1445 } 1446 1447 /* 1448 * If we hit the leap second, we choose to skip this sample 1449 * rather than rely on other code to be perfectly correct. 1450 * No offense, just defense ;-). 1451 */ 1452 if (second == 60) 1453 return(-1); 1454 1455 /* now check and convert the time we received */ 1456 1457 pp->year = year; 1458 if (month < 1 || month > 12 || day < 1 || day > 31) 1459 return(-1); 1460 1461 if (pp->year % 4) { 1462 if (day > day1tab[month - 1]) 1463 return(-1); 1464 for (i = 0; i < month - 1; i++) 1465 day += day1tab[i]; 1466 } else { 1467 if (day > day2tab[month - 1]) 1468 return(-1); 1469 for (i = 0; i < month - 1; i++) 1470 day += day2tab[i]; 1471 } 1472 pp->day = day; 1473 pp->hour = hour; 1474 pp->minute = minute; 1475 pp-> second = second; 1476 pp->nsec = 0; 1477 1478 if ((utcflags&UTCF_LEAP_PNDG) && up->leapdelta != 0) 1479 pp-> leap = (up->leapdelta > 0 ? LEAP_ADDSECOND : LEAP_DELSECOND); 1480 else 1481 pp-> leap = LEAP_NOWARNING; 1482 1483 return (0); 1484} 1485 1486/* 1487 * Parse comprehensive time packet 1488 * 1489 * 0 = success 1490 * -1 = errors 1491 */ 1492 1493int parse0x8F0B(rpt, peer) 1494 TSIPPKT *rpt; 1495 struct peer *peer; 1496{ 1497 register struct refclockproc *pp; 1498 1499 unsigned day, month, year; /* data derived from received timecode */ 1500 unsigned hour, minute, second; 1501 unsigned utcoff; 1502 unsigned char mode; 1503 double bias, rate; 1504 float biasunc, rateunc; 1505 double lat, lon, alt; 1506 short lat_deg, lon_deg; 1507 float lat_min, lon_min; 1508 unsigned char north_south, east_west; 1509 char sv[9]; 1510 1511 static char logbuf[1024]; /* logging string buffer */ 1512 unsigned char b; 1513 int i; 1514 unsigned char *buf; 1515 double tow; 1516 1517 buf = rpt->buf; 1518 pp = peer->procptr; 1519 1520 if (rpt->len != 74) 1521 return (-1); 1522 1523 if (bGetShort(&buf[1]) != 0) 1524 return(-1);; 1525 1526 tow = bGetDouble(&buf[3]); 1527 1528 if (tow == -1.0) { 1529 return(-1); 1530 } 1531 else if ((tow >= 604800.0) || (tow < 0.0)) { 1532 return(-1); 1533 } 1534 else 1535 { 1536 if (tow < 604799.9) tow = tow + .00000001; 1537 second = (unsigned int) fmod(tow, 60.); 1538 minute = (unsigned int) fmod(tow/60., 60.); 1539 hour = (unsigned int )fmod(tow / 3600., 24.); 1540 } 1541 1542 1543 day = (unsigned int) buf[11]; 1544 month = (unsigned int) buf[12]; 1545 year = bGetShort(&buf[13]); 1546 mode = buf[15]; 1547 utcoff = bGetShort(&buf[16]); 1548 bias = bGetDouble(&buf[18]) / GPS_C * 1e9; /* ns */ 1549 rate = bGetDouble(&buf[26]) / GPS_C * 1e9; /* ppb */ 1550 biasunc = bGetSingle(&buf[34]) / GPS_C * 1e9; /* ns */ 1551 rateunc = bGetSingle(&buf[38]) / GPS_C * 1e9; /* ppb */ 1552 lat = bGetDouble(&buf[42]) * R2D; 1553 lon = bGetDouble(&buf[50]) * R2D; 1554 alt = bGetDouble(&buf[58]); 1555 1556 if (lat < 0.0) { 1557 north_south = 'S'; 1558 lat = -lat; 1559 } 1560 else { 1561 north_south = 'N'; 1562 } 1563 lat_deg = (short)lat; 1564 lat_min = (lat - lat_deg) * 60.0; 1565 1566 if (lon < 0.0) { 1567 east_west = 'W'; 1568 lon = -lon; 1569 } 1570 else { 1571 east_west = 'E'; 1572 } 1573 1574 lon_deg = (short)lon; 1575 lon_min = (lon - lon_deg) * 60.0; 1576 1577 for (i=0; i<8; i++) { 1578 sv[i] = buf[i + 66]; 1579 if (sv[i]) { 1580 TSIPPKT spt; /* local structure for sendpacket */ 1581 b = (unsigned char) (sv[i]<0 ? -sv[i] : sv[i]); 1582 /* request tracking status */ 1583 cmd_0x3C (&spt, b); 1584 ripencc_send(peer,spt); 1585 } 1586 } 1587 1588 1589 sprintf(logbuf, "C1 %02d%02d%04d %02d%02d%02d %d %7.0f %.1f %.0f %.1f %d %02d%09.6f %c %02d%09.6f %c %.0f %d %d %d %d %d %d %d %d", 1590 day, month, year, hour, minute, second, mode, bias, biasunc, rate, rateunc, utcoff, 1591 lat_deg, lat_min, north_south, lon_deg, lon_min, east_west, alt, 1592 sv[0], sv[1], sv[2], sv[3], sv[4], sv[5], sv[6], sv[7]); 1593 1594#ifdef DEBUG_NCC 1595 if (debug) 1596 puts(logbuf); 1597#endif /* DEBUG_NCC */ 1598 1599 record_clock_stats(&peer->srcadr, logbuf); 1600 1601 return (0); 1602} 1603 1604#ifdef TRIMBLE_OUTPUT_FUNC 1605/* 1606 * Parse any packet using Trimble machinery 1607 */ 1608int parseany(rpt, peer) 1609 TSIPPKT *rpt; 1610 struct peer *peer; 1611{ 1612 static char logbuf[1024]; /* logging string buffer */ 1613 1614 TranslateTSIPReportToText (rpt, logbuf); /* anything else */ 1615#ifdef DEBUG_NCC 1616 if (debug) 1617 puts(&logbuf[1]); 1618#endif /* DEBUG_NCC */ 1619 record_clock_stats(&peer->srcadr, &logbuf[1]); 1620 return(0); 1621} 1622#endif /* TRIMBLE_OUTPUT_FUNC */ 1623 1624 1625/* 1626 * Parse UTC Parameter Packet 1627 * 1628 * See the IDE for documentation! 1629 * 1630 * 0 = success 1631 * -1 = errors 1632 */ 1633 1634int parse0x4F(rpt, peer) 1635 TSIPPKT *rpt; 1636 struct peer *peer; 1637{ 1638 register struct ripencc_unit *up; 1639 1640 double a0; 1641 float a1, tot; 1642 int dt_ls, wn_t, wn_lsf, dn, dt_lsf; 1643 1644 static char logbuf[1024]; /* logging string buffer */ 1645 unsigned char *buf; 1646 1647 buf = rpt->buf; 1648 1649 if (rpt->len != 26) 1650 return (-1); 1651 a0 = bGetDouble (buf); 1652 a1 = bGetSingle (&buf[8]); 1653 dt_ls = bGetShort (&buf[12]); 1654 tot = bGetSingle (&buf[14]); 1655 wn_t = bGetShort (&buf[18]); 1656 wn_lsf = bGetShort (&buf[20]); 1657 dn = bGetShort (&buf[22]); 1658 dt_lsf = bGetShort (&buf[24]); 1659 1660 sprintf(logbuf, "L1 %d %d %d %g %g %g %d %d %d", 1661 dt_lsf - dt_ls, dt_ls, dt_lsf, a0, a1, tot, wn_t, wn_lsf, dn); 1662 1663#ifdef DEBUG_NCC 1664 if (debug) 1665 puts(logbuf); 1666#endif /* DEBUG_NCC */ 1667 1668 record_clock_stats(&peer->srcadr, logbuf); 1669 1670 up = (struct ripencc_unit *) peer->procptr->unitptr; 1671 up->leapdelta = dt_lsf - dt_ls; 1672 1673 return (0); 1674} 1675 1676/* 1677 * Parse Tracking Status packet 1678 * 1679 * 0 = success 1680 * -1 = errors 1681 */ 1682 1683int parse0x5C(rpt, peer) 1684 TSIPPKT *rpt; 1685 struct peer *peer; 1686{ 1687 unsigned char prn, channel, aqflag, ephstat; 1688 float snr, azinuth, elevation; 1689 1690 static char logbuf[1024]; /* logging string buffer */ 1691 unsigned char *buf; 1692 1693 buf = rpt->buf; 1694 1695 if (rpt->len != 24) 1696 return(-1); 1697 1698 prn = buf[0]; 1699 channel = (unsigned char)(buf[1] >> 3); 1700 if (channel == 0x10) 1701 channel = 2; 1702 else 1703 channel++; 1704 aqflag = buf[2]; 1705 ephstat = buf[3]; 1706 snr = bGetSingle(&buf[4]); 1707 elevation = bGetSingle(&buf[12]) * R2D; 1708 azinuth = bGetSingle(&buf[16]) * R2D; 1709 1710 sprintf(logbuf, "S1 %02d %d %d %02x %4.1f %5.1f %4.1f", 1711 prn, channel, aqflag, ephstat, snr, azinuth, elevation); 1712 1713#ifdef DEBUG_NCC 1714 if (debug) 1715 puts(logbuf); 1716#endif /* DEBUG_NCC */ 1717 1718 record_clock_stats(&peer->srcadr, logbuf); 1719 1720 return (0); 1721} 1722 1723/******* Code below is from Trimble Tsipchat *************/ 1724 1725/* 1726 * ************************************************************************* 1727 * 1728 * Trimble Navigation, Ltd. 1729 * OEM Products Development Group 1730 * P.O. Box 3642 1731 * 645 North Mary Avenue 1732 * Sunnyvale, California 94088-3642 1733 * 1734 * Corporate Headquarter: 1735 * Telephone: (408) 481-8000 1736 * Fax: (408) 481-6005 1737 * 1738 * Technical Support Center: 1739 * Telephone: (800) 767-4822 (U.S. and Canada) 1740 * (408) 481-6940 (outside U.S. and Canada) 1741 * Fax: (408) 481-6020 1742 * BBS: (408) 481-7800 1743 * e-mail: trimble_support@trimble.com 1744 * ftp://ftp.trimble.com/pub/sct/embedded/bin 1745 * 1746 * ************************************************************************* 1747 * 1748 * ------- BYTE-SWAPPING ------- 1749 * TSIP is big-endian (Motorola) protocol. To use on little-endian (Intel) 1750 * systems, the bytes of all multi-byte types (shorts, floats, doubles, etc.) 1751 * must be reversed. This is controlled by the MACRO BYTESWAP; if defined, it 1752 * assumes little-endian protocol. 1753 * -------------------------------- 1754 * 1755 * T_PARSER.C and T_PARSER.H contains primitive functions that interpret 1756 * reports received from the receiver. A second source file pair, 1757 * T_FORMAT.C and T_FORMAT.H, contin the matching TSIP command formatters. 1758 * 1759 * The module is in very portable, basic C language. It can be used as is, or 1760 * with minimal changes if a TSIP communications application is needed separate 1761 * from TSIPCHAT. The construction of most argument lists avoid the use of 1762 * structures, but the developer is encouraged to reconstruct them using such 1763 * definitions to meet project requirements. Declarations of T_PARSER.C 1764 * functions are included in T_PARSER.H to provide prototyping definitions. 1765 * 1766 * There are two types of functions: a serial input processing routine, 1767 * tsip_input_proc() 1768 * which assembles incoming bytes into a TSIPPKT structure, and the 1769 * report parsers, rpt_0x??(). 1770 * 1771 * 1) The function tsip_input_proc() accumulates bytes from the receiver, 1772 * strips control bytes (DLE), and checks if the report end sequence (DLE ETX) 1773 * has been received. rpt.status is defined as TSIP_PARSED_FULL (== 1) 1774 * if a complete packet is available. 1775 * 1776 * 2) The functions rpt_0x??() are report string interpreters patterned after 1777 * the document called "Trimble Standard Interface Protocol". It should be 1778 * noted that if the report buffer is sent into the receiver with the wrong 1779 * length (byte count), the rpt_0x??() returns the Boolean equivalence for 1780 * TRUE. 1781 * 1782 * ************************************************************************* 1783 * 1784 */ 1785 1786 1787/**/ 1788static void tsip_input_proc ( 1789 TSIPPKT *rpt, 1790 int inbyte) 1791/* reads bytes until serial buffer is empty or a complete report 1792 * has been received; end of report is signified by DLE ETX. 1793 */ 1794{ 1795 unsigned char newbyte; 1796 1797 if (inbyte < 0 || inbyte > 0xFF) return; 1798 1799 newbyte = (unsigned char)(inbyte); 1800 switch (rpt->status) 1801 { 1802 case TSIP_PARSED_DLE_1: 1803 switch (newbyte) 1804 { 1805 case 0: 1806 case ETX: 1807 /* illegal TSIP IDs */ 1808 rpt->len = 0; 1809 rpt->status = TSIP_PARSED_EMPTY; 1810 break; 1811 case DLE: 1812 /* try normal message start again */ 1813 rpt->len = 0; 1814 rpt->status = TSIP_PARSED_DLE_1; 1815 break; 1816 default: 1817 /* legal TSIP ID; start message */ 1818 rpt->code = newbyte; 1819 rpt->len = 0; 1820 rpt->status = TSIP_PARSED_DATA; 1821 break; 1822 } 1823 break; 1824 case TSIP_PARSED_DATA: 1825 switch (newbyte) { 1826 case DLE: 1827 /* expect DLE or ETX next */ 1828 rpt->status = TSIP_PARSED_DLE_2; 1829 break; 1830 default: 1831 /* normal data byte */ 1832 rpt->buf[rpt->len] = newbyte; 1833 rpt->len++; 1834 /* no change in rpt->status */ 1835 break; 1836 } 1837 break; 1838 case TSIP_PARSED_DLE_2: 1839 switch (newbyte) { 1840 case DLE: 1841 /* normal data byte */ 1842 rpt->buf[rpt->len] = newbyte; 1843 rpt->len++; 1844 rpt->status = TSIP_PARSED_DATA; 1845 break; 1846 case ETX: 1847 /* end of message; return TRUE here. */ 1848 rpt->status = TSIP_PARSED_FULL; 1849 break; 1850 default: 1851 /* error: treat as TSIP_PARSED_DLE_1; start new report packet */ 1852 rpt->code = newbyte; 1853 rpt->len = 0; 1854 rpt->status = TSIP_PARSED_DATA; 1855 } 1856 break; 1857 case TSIP_PARSED_FULL: 1858 case TSIP_PARSED_EMPTY: 1859 default: 1860 switch (newbyte) { 1861 case DLE: 1862 /* normal message start */ 1863 rpt->len = 0; 1864 rpt->status = TSIP_PARSED_DLE_1; 1865 break; 1866 default: 1867 /* error: ignore newbyte */ 1868 rpt->len = 0; 1869 rpt->status = TSIP_PARSED_EMPTY; 1870 } 1871 break; 1872 } 1873 if (rpt->len > MAX_RPTBUF) { 1874 /* error: start new report packet */ 1875 rpt->status = TSIP_PARSED_EMPTY; 1876 rpt->len = 0; 1877 } 1878} 1879 1880#ifdef TRIMBLE_OUTPUT_FUNC 1881 1882/**/ 1883short rpt_0x3D (TSIPPKT *rpt, 1884 unsigned char *tx_baud_index, 1885 unsigned char *rx_baud_index, 1886 unsigned char *char_format_index, 1887 unsigned char *stop_bits, 1888 unsigned char *tx_mode_index, 1889 unsigned char *rx_mode_index) 1890/* Channel A configuration for dual port operation */ 1891{ 1892 unsigned char *buf; 1893 buf = rpt->buf; 1894 1895 if (rpt->len != 6) return TRUE; 1896 *tx_baud_index = buf[0]; 1897 *rx_baud_index = buf[1]; 1898 *char_format_index = buf[2]; 1899 *stop_bits = (unsigned char)((buf[3] == 0x07) ? 1 : 2); 1900 *tx_mode_index = buf[4]; 1901 *rx_mode_index = buf[5]; 1902 return FALSE; 1903} 1904 1905/**/ 1906short rpt_0x40 (TSIPPKT *rpt, 1907 unsigned char *sv_prn, 1908 short *week_num, 1909 float *t_zc, 1910 float *eccentricity, 1911 float *t_oa, 1912 float *i_0, 1913 float *OMEGA_dot, 1914 float *sqrt_A, 1915 float *OMEGA_0, 1916 float *omega, 1917 float *M_0) 1918/* almanac data for specified satellite */ 1919{ 1920 unsigned char *buf; 1921 buf = rpt->buf; 1922 1923 if (rpt->len != 39) return TRUE; 1924 *sv_prn = buf[0]; 1925 *t_zc = bGetSingle (&buf[1]); 1926 *week_num = bGetShort (&buf[5]); 1927 *eccentricity = bGetSingle (&buf[7]); 1928 *t_oa = bGetSingle (&buf[11]); 1929 *i_0 = bGetSingle (&buf[15]); 1930 *OMEGA_dot = bGetSingle (&buf[19]); 1931 *sqrt_A = bGetSingle (&buf[23]); 1932 *OMEGA_0 = bGetSingle (&buf[27]); 1933 *omega = bGetSingle (&buf[31]); 1934 *M_0 = bGetSingle (&buf[35]); 1935 return FALSE; 1936} 1937 1938short rpt_0x41 (TSIPPKT *rpt, 1939 float *time_of_week, 1940 float *UTC_offset, 1941 short *week_num) 1942/* GPS time */ 1943{ 1944 unsigned char *buf; 1945 buf = rpt->buf; 1946 1947 if (rpt->len != 10) return TRUE; 1948 *time_of_week = bGetSingle (buf); 1949 *week_num = bGetShort (&buf[4]); 1950 *UTC_offset = bGetSingle (&buf[6]); 1951 return FALSE; 1952} 1953 1954short rpt_0x42 (TSIPPKT *rpt, 1955 float pos_ECEF[3], 1956 float *time_of_fix) 1957/* position in ECEF, single precision */ 1958{ 1959 unsigned char *buf; 1960 buf = rpt->buf; 1961 1962 if (rpt->len != 16) return TRUE; 1963 pos_ECEF[0] = bGetSingle (buf); 1964 pos_ECEF[1]= bGetSingle (&buf[4]); 1965 pos_ECEF[2]= bGetSingle (&buf[8]); 1966 *time_of_fix = bGetSingle (&buf[12]); 1967 return FALSE; 1968} 1969 1970short rpt_0x43 (TSIPPKT *rpt, 1971 float ECEF_vel[3], 1972 float *freq_offset, 1973 float *time_of_fix) 1974/* velocity in ECEF, single precision */ 1975{ 1976 unsigned char *buf; 1977 buf = rpt->bu…
Large files files are truncated, but you can click here to view the full file