/contrib/ntp/ntpd/refclock_ripencc.c
https://bitbucket.org/freebsd/freebsd-head/ · C · 4866 lines · 3751 code · 591 blank · 524 comment · 411 complexity · 262eb696cb696d14c100f9b876355fbe MD5 · raw file
Large files are truncated click here to view the full file
- /*
- * $Id: refclock_ripencc.c,v 1.13 2002/06/18 14:20:55 marks Exp marks $
- *
- * Copyright (c) 2002 RIPE NCC
- *
- * All Rights Reserved
- *
- * Permission to use, copy, modify, and distribute this software and its
- * documentation for any purpose and without fee is hereby granted,
- * provided that the above copyright notice appear in all copies and that
- * both that copyright notice and this permission notice appear in
- * supporting documentation, and that the name of the author not be
- * used in advertising or publicity pertaining to distribution of the
- * software without specific, written prior permission.
- *
- * THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
- * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
- * AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
- * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
- * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- *
- *
- * This driver was developed for use with the RIPE NCC TTM project.
- *
- *
- * The initial driver was developed by Daniel Karrenberg <dfk@ripe.net>
- * using the code made available by Trimble. This was for xntpd-3.x.x
- *
- * Rewrite of the driver for ntpd-4.x.x by Mark Santcroos <marks@ripe.net>
- *
- */
- #ifdef HAVE_CONFIG_H
- #include <config.h>
- #endif /* HAVE_CONFIG_H */
- #if defined(REFCLOCK) && defined(CLOCK_RIPENCC)
- #include "ntp_stdlib.h"
- #include "ntpd.h"
- #include "ntp_refclock.h"
- #include "ntp_unixtime.h"
- #include "ntp_io.h"
- #ifdef HAVE_PPSAPI
- # include "ppsapi_timepps.h"
- #endif
- /*
- * Definitions
- */
- /* we are on little endian */
- #define BYTESWAP
- /*
- * DEBUG statements: uncomment if necessary
- */
- /* #define DEBUG_NCC */ /* general debug statements */
- /* #define DEBUG_PPS */ /* debug pps */
- /* #define DEBUG_RAW */ /* print raw packets */
- #define TRIMBLE_OUTPUT_FUNC
- #define TSIP_VERNUM "7.12a"
- #ifndef FALSE
- #define FALSE (0)
- #define TRUE (!FALSE)
- #endif /* FALSE */
- #define GPS_PI (3.1415926535898)
- #define GPS_C (299792458.)
- #define D2R (GPS_PI/180.0)
- #define R2D (180.0/GPS_PI)
- #define WEEK (604800.)
- #define MAXCHAN (8)
- /* control characters for TSIP packets */
- #define DLE (0x10)
- #define ETX (0x03)
- #define MAX_RPTBUF (256)
- /* values of TSIPPKT.status */
- #define TSIP_PARSED_EMPTY 0
- #define TSIP_PARSED_FULL 1
- #define TSIP_PARSED_DLE_1 2
- #define TSIP_PARSED_DATA 3
- #define TSIP_PARSED_DLE_2 4
- #define UTCF_UTC_AVAIL (unsigned char) (1) /* UTC available */
- #define UTCF_LEAP_SCHD (unsigned char) (1<<4) /* Leap scheduled */
- #define UTCF_LEAP_PNDG (unsigned char) (1<<5) /* Leap pending, will occur at end of day */
- #define DEVICE "/dev/gps%d" /* name of radio device */
- #define PRECISION (-9) /* precision assumed (about 2 ms) */
- #define PPS_PRECISION (-20) /* precision assumed (about 1 us) */
- #define REFID "GPS\0" /* reference id */
- #define REFID_LEN 4
- #define DESCRIPTION "RIPE NCC GPS (Palisade)" /* Description */
- #define SPEED232 B9600 /* 9600 baud */
- #define NSAMPLES 3 /* stages of median filter */
- /* Structures */
- /* TSIP packets have the following structure, whether report or command. */
- typedef struct {
- short
- counter, /* counter */
- len; /* size of buf; < MAX_RPTBUF unsigned chars */
- unsigned char
- status, /* TSIP packet format/parse status */
- code, /* TSIP code */
- buf[MAX_RPTBUF];/* report or command string */
- } TSIPPKT;
- /* TSIP binary data structures */
- typedef struct {
- unsigned char
- t_oa_raw, SV_health;
- float
- e, t_oa, i_0, OMEGADOT, sqrt_A,
- OMEGA_0, omega, M_0, a_f0, a_f1,
- Axis, n, OMEGA_n, ODOT_n, t_zc;
- short
- weeknum, wn_oa;
- } ALM_INFO;
- typedef struct { /* Almanac health page (25) parameters */
- unsigned char
- WN_a, SV_health[32], t_oa;
- } ALH_PARMS;
- typedef struct { /* Universal Coordinated Time (UTC) parms */
- double
- A_0;
- float
- A_1;
- short
- delta_t_LS;
- float
- t_ot;
- short
- WN_t, WN_LSF, DN, delta_t_LSF;
- } UTC_INFO;
- typedef struct { /* Ionospheric info (float) */
- float
- alpha_0, alpha_1, alpha_2, alpha_3,
- beta_0, beta_1, beta_2, beta_3;
- } ION_INFO;
- typedef struct { /* Subframe 1 info (float) */
- short
- weeknum;
- unsigned char
- codeL2, L2Pdata, SVacc_raw, SV_health;
- short
- IODC;
- float
- T_GD, t_oc, a_f2, a_f1, a_f0, SVacc;
- } EPHEM_CLOCK;
- typedef struct { /* Ephemeris info (float) */
- unsigned char
- IODE, fit_interval;
- float
- C_rs, delta_n;
- double
- M_0;
- float
- C_uc;
- double
- e;
- float
- C_us;
- double
- sqrt_A;
- float
- t_oe, C_ic;
- double
- OMEGA_0;
- float
- C_is;
- double
- i_0;
- float
- C_rc;
- double
- omega;
- float
- OMEGADOT, IDOT;
- double
- Axis, n, r1me2, OMEGA_n, ODOT_n;
- } EPHEM_ORBIT;
- typedef struct { /* Navigation data structure */
- short
- sv_number; /* SV number (0 = no entry) */
- float
- t_ephem; /* time of ephemeris collection */
- EPHEM_CLOCK
- ephclk; /* subframe 1 data */
- EPHEM_ORBIT
- ephorb; /* ephemeris data */
- } NAV_INFO;
- typedef struct {
- unsigned char
- bSubcode,
- operating_mode,
- dgps_mode,
- dyn_code,
- trackmode;
- float
- elev_mask,
- cno_mask,
- dop_mask,
- dop_switch;
- unsigned char
- dgps_age_limit;
- } TSIP_RCVR_CFG;
- #ifdef TRIMBLE_OUTPUT_FUNC
- static char
- *dayname[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"},
- old_baudnum[] = {0, 1, 4, 5, 6, 8, 9, 11, 28, 12},
- *st_baud_text_app [] = {"", "", " 300", " 600", " 1200", " 2400",
- " 4800", " 9600", "19200", "38400"},
- *old_parity_text[] = {"EVEN", "ODD", "", "", "NONE"},
- *parity_text [] = {"NONE", "ODD", "EVEN"},
- *old_input_ch[] = { "TSIP", "RTCM (6 of 8 bits)"},
- *old_output_ch[] = { "TSIP", "No output", "", "", "", "NMEA 0183"},
- *protocols_in_text[] = { "", "TSIP", "", ""},
- *protocols_out_text[] = { "", "TSIP", "NMEA"},
- *rcvr_port_text [] = { "Port A ", "Port B ", "Current Port"},
- *dyn_text [] = {"Unchanged", "Land", "Sea", "Air", "Static"},
- *NavModeText0xBB[] = {"automatic", "time only (0-D)", "", "2-D",
- "3-D", "", "", "OverDetermined Time"},
- *PPSTimeBaseText[] = {"GPS", "UTC", "USER"},
- *PPSPolarityText[] = {"Positive", "Negative"},
- *MaskText[] = { "Almanac ", "Ephemeris", "UTC ", "Iono ",
- "GPS Msg ", "Alm Hlth ", "Time Fix ", "SV Select",
- "Ext Event", "Pos Fix ", "Raw Meas "};
- #endif /* TRIMBLE_OUTPUT_FUNC */
- /*
- * Unit control structure
- */
- struct ripencc_unit {
- int unit; /* unit number */
- int pollcnt; /* poll message counter */
- int polled; /* Hand in a sample? */
- char leapdelta; /* delta of next leap event */
- unsigned char utcflags; /* delta of next leap event */
- l_fp tstamp; /* timestamp of last poll */
-
- struct timespec ts; /* last timestamp */
- pps_params_t pps_params; /* pps parameters */
- pps_info_t pps_info; /* last pps data */
- pps_handle_t handle; /* pps handlebars */
- };
- /******************* PROTOYPES *****************/
- /* prototypes for report parsing primitives */
- short rpt_0x3D (TSIPPKT *rpt, unsigned char *tx_baud_index,
- unsigned char *rx_baud_index, unsigned char *char_format_index,
- unsigned char *stop_bits, unsigned char *tx_mode_index,
- unsigned char *rx_mode_index);
- short rpt_0x40 (TSIPPKT *rpt, unsigned char *sv_prn, short *week_num,
- float *t_zc, float *eccentricity, float *t_oa, float *i_0,
- float *OMEGA_dot, float *sqrt_A, float *OMEGA_0, float *omega,
- float *M_0);
- short rpt_0x41 (TSIPPKT *rpt, float *time_of_week, float *UTC_offset,
- short *week_num);
- short rpt_0x42 (TSIPPKT *rpt, float ECEF_pos[3], float *time_of_fix);
- short rpt_0x43 (TSIPPKT *rpt, float ECEF_vel[3], float *freq_offset,
- float *time_of_fix);
- short rpt_0x45 (TSIPPKT *rpt, unsigned char *major_nav_version,
- unsigned char *minor_nav_version, unsigned char *nav_day,
- unsigned char *nav_month, unsigned char *nav_year,
- unsigned char *major_dsp_version, unsigned char *minor_dsp_version,
- unsigned char *dsp_day, unsigned char *dsp_month,
- unsigned char *dsp_year);
- short rpt_0x46 (TSIPPKT *rpt, unsigned char *status1, unsigned char *status2);
- short rpt_0x47 (TSIPPKT *rpt, unsigned char *nsvs, unsigned char *sv_prn,
- float *snr);
- short rpt_0x48 (TSIPPKT *rpt, unsigned char *message);
- short rpt_0x49 (TSIPPKT *rpt, unsigned char *sv_health);
- short rpt_0x4A (TSIPPKT *rpt, float *lat, float *lon, float *alt,
- float *clock_bias, float *time_of_fix);
- short rpt_0x4A_2 (TSIPPKT *rpt, float *alt, float *dummy,
- unsigned char *alt_flag);
- short rpt_0x4B (TSIPPKT *rpt, unsigned char *machine_id,
- unsigned char *status3, unsigned char *status4);
- short rpt_0x4C (TSIPPKT *rpt, unsigned char *dyn_code, float *el_mask,
- float *snr_mask, float *dop_mask, float *dop_switch);
- short rpt_0x4D (TSIPPKT *rpt, float *osc_offset);
- short rpt_0x4E (TSIPPKT *rpt, unsigned char *response);
- short rpt_0x4F (TSIPPKT *rpt, double *a0, float *a1, float *time_of_data,
- short *dt_ls, short *wn_t, short *wn_lsf, short *dn, short *dt_lsf);
- short rpt_0x54 (TSIPPKT *rpt, float *clock_bias, float *freq_offset,
- float *time_of_fix);
- short rpt_0x55 (TSIPPKT *rpt, unsigned char *pos_code, unsigned char *vel_code,
- unsigned char *time_code, unsigned char *aux_code);
- short rpt_0x56 (TSIPPKT *rpt, float vel_ENU[3], float *freq_offset,
- float *time_of_fix);
- short rpt_0x57 (TSIPPKT *rpt, unsigned char *source_code,
- unsigned char *diag_code, short *week_num, float *time_of_fix);
- short rpt_0x58 (TSIPPKT *rpt, unsigned char *op_code, unsigned char *data_type,
- unsigned char *sv_prn, unsigned char *data_length,
- unsigned char *data_packet);
- short rpt_0x59 (TSIPPKT *rpt, unsigned char *code_type,
- unsigned char status_code[32]);
- short rpt_0x5A (TSIPPKT *rpt, unsigned char *sv_prn, float *sample_length,
- float *signal_level, float *code_phase, float *Doppler,
- double *time_of_fix);
- short rpt_0x5B (TSIPPKT *rpt, unsigned char *sv_prn, unsigned char *sv_health,
- unsigned char *sv_iode, unsigned char *fit_interval_flag,
- float *time_of_collection, float *time_of_eph, float *sv_accy);
- short rpt_0x5C (TSIPPKT *rpt, unsigned char *sv_prn, unsigned char *slot,
- unsigned char *chan, unsigned char *acq_flag, unsigned char *eph_flag,
- float *signal_level, float *time_of_last_msmt, float *elev,
- float *azim, unsigned char *old_msmt_flag,
- unsigned char *integer_msec_flag, unsigned char *bad_data_flag,
- unsigned char *data_collect_flag);
- short rpt_0x6D (TSIPPKT *rpt, unsigned char *manual_mode, unsigned char *nsvs,
- unsigned char *ndim, unsigned char sv_prn[], float *pdop,
- float *hdop, float *vdop, float *tdop);
- short rpt_0x82 (TSIPPKT *rpt, unsigned char *diff_mode);
- short rpt_0x83 (TSIPPKT *rpt, double ECEF_pos[3], double *clock_bias,
- float *time_of_fix);
- short rpt_0x84 (TSIPPKT *rpt, double *lat, double *lon, double *alt,
- double *clock_bias, float *time_of_fix);
- short rpt_Paly0xBB(TSIPPKT *rpt, TSIP_RCVR_CFG *TsipxBB);
- short rpt_0xBC (TSIPPKT *rpt, unsigned char *port_num,
- unsigned char *in_baud, unsigned char *out_baud,
- unsigned char *data_bits, unsigned char *parity,
- unsigned char *stop_bits, unsigned char *flow_control,
- unsigned char *protocols_in, unsigned char *protocols_out,
- unsigned char *reserved);
- /* prototypes for superpacket parsers */
- short rpt_0x8F0B (TSIPPKT *rpt, unsigned short *event, double *tow,
- unsigned char *date, unsigned char *month, short *year,
- unsigned char *dim_mode, short *utc_offset, double *bias, double *drift,
- float *bias_unc, float *dr_unc, double *lat, double *lon, double *alt,
- char sv_id[8]);
- short rpt_0x8F14 (TSIPPKT *rpt, short *datum_idx, double datum_coeffs[5]);
- short rpt_0x8F15 (TSIPPKT *rpt, short *datum_idx, double datum_coeffs[5]);
- short rpt_0x8F20 (TSIPPKT *rpt, unsigned char *info, double *lat,
- double *lon, double *alt, double vel_enu[], double *time_of_fix,
- short *week_num, unsigned char *nsvs, unsigned char sv_prn[],
- short sv_IODC[], short *datum_index);
- short rpt_0x8F41 (TSIPPKT *rpt, unsigned char *bSearchRange,
- unsigned char *bBoardOptions, unsigned long *iiSerialNumber,
- unsigned char *bBuildYear, unsigned char *bBuildMonth,
- unsigned char *bBuildDay, unsigned char *bBuildHour,
- float *fOscOffset, unsigned short *iTestCodeId);
- short rpt_0x8F42 (TSIPPKT *rpt, unsigned char *bProdOptionsPre,
- unsigned char *bProdNumberExt, unsigned short *iCaseSerialNumberPre,
- unsigned long *iiCaseSerialNumber, unsigned long *iiProdNumber,
- unsigned short *iPremiumOptions, unsigned short *iMachineID,
- unsigned short *iKey);
- short rpt_0x8F45 (TSIPPKT *rpt, unsigned char *bSegMask);
- short rpt_0x8F4A_16 (TSIPPKT *rpt, unsigned char *pps_enabled,
- unsigned char *pps_timebase, unsigned char *pos_polarity,
- double *pps_offset, float *bias_unc_threshold);
- short rpt_0x8F4B (TSIPPKT *rpt, unsigned long *decorr_max);
- short rpt_0x8F4D (TSIPPKT *rpt, unsigned long *event_mask);
- short rpt_0x8FA5 (TSIPPKT *rpt, unsigned char *spktmask);
- short rpt_0x8FAD (TSIPPKT *rpt, unsigned short *COUNT, double *FracSec,
- unsigned char *Hour, unsigned char *Minute, unsigned char *Second,
- unsigned char *Day, unsigned char *Month, unsigned short *Year,
- unsigned char *Status, unsigned char *Flags);
- /**/
- /* prototypes for command-encode primitives with suffix convention: */
- /* c = clear, s = set, q = query, e = enable, d = disable */
- void cmd_0x1F (TSIPPKT *cmd);
- void cmd_0x26 (TSIPPKT *cmd);
- void cmd_0x2F (TSIPPKT *cmd);
- void cmd_0x35s (TSIPPKT *cmd, unsigned char pos_code, unsigned char vel_code,
- unsigned char time_code, unsigned char opts_code);
- void cmd_0x3C (TSIPPKT *cmd, unsigned char sv_prn);
- void cmd_0x3Ds (TSIPPKT *cmd, unsigned char baud_out, unsigned char baud_inp,
- unsigned char char_code, unsigned char stopbitcode,
- unsigned char output_mode, unsigned char input_mode);
- void cmd_0xBBq (TSIPPKT *cmd, unsigned char subcode) ;
- /* prototypes 8E commands */
- void cmd_0x8E0Bq (TSIPPKT *cmd);
- void cmd_0x8E41q (TSIPPKT *cmd);
- void cmd_0x8E42q (TSIPPKT *cmd);
- void cmd_0x8E4Aq (TSIPPKT *cmd);
- void cmd_0x8E4As (TSIPPKT *cmd, unsigned char PPSOnOff, unsigned char TimeBase,
- unsigned char Polarity, double PPSOffset, float Uncertainty);
- void cmd_0x8E4Bq (TSIPPKT *cmd);
- void cmd_0x8E4Ds (TSIPPKT *cmd, unsigned long AutoOutputMask);
- void cmd_0x8EADq (TSIPPKT *cmd);
- /* header/source border XXXXXXXXXXXXXXXXXXXXXXXXXX */
- /* Trimble parse functions */
- static int parse0x8FAD P((TSIPPKT *, struct peer *));
- static int parse0x8F0B P((TSIPPKT *, struct peer *));
- #ifdef TRIMBLE_OUTPUT_FUNC
- static int parseany P((TSIPPKT *, struct peer *));
- static void TranslateTSIPReportToText P((TSIPPKT *, char *));
- #endif /* TRIMBLE_OUTPUT_FUNC */
- static int parse0x5C P((TSIPPKT *, struct peer *));
- static int parse0x4F P((TSIPPKT *, struct peer *));
- static void tsip_input_proc P((TSIPPKT *, int));
- /* Trimble helper functions */
- static void bPutFloat P((float *, unsigned char *));
- static void bPutDouble P((double *, unsigned char *));
- static void bPutULong P((unsigned long *, unsigned char *));
- static int print_msg_table_header P((int rptcode, char *HdrStr, int force));
- static char * show_time P((float time_of_week));
- /* RIPE NCC functions */
- static void ripencc_control P((int, struct refclockstat *, struct
- refclockstat *, struct peer *));
- static int ripencc_ppsapi P((struct peer *, int, int));
- static int ripencc_get_pps_ts P((struct ripencc_unit *, l_fp *));
- static int ripencc_start P((int, struct peer *));
- static void ripencc_shutdown P((int, struct peer *));
- static void ripencc_poll P((int, struct peer *));
- static void ripencc_send P((struct peer *, TSIPPKT spt));
- static void ripencc_receive P((struct recvbuf *));
- /* fill in reflock structure for our clock */
- struct refclock refclock_ripencc = {
- ripencc_start, /* start up driver */
- ripencc_shutdown, /* shut down driver */
- ripencc_poll, /* transmit poll message */
- ripencc_control, /* control function */
- noentry, /* initialize driver */
- noentry, /* debug info */
- NOFLAGS /* clock flags */
- };
- /*
- * Tables to compute the ddd of year form icky dd/mm timecode. Viva la
- * leap.
- */
- static int day1tab[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
- static int day2tab[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
- /*
- * ripencc_start - open the GPS devices and initialize data for processing
- */
- static int
- ripencc_start(int unit, struct peer *peer)
- {
- register struct ripencc_unit *up;
- struct refclockproc *pp;
- char device[40];
- int fd;
- struct termios tio;
- TSIPPKT spt;
- /*
- * Open serial port
- */
- (void)snprintf(device, sizeof(device), DEVICE, unit);
- if (!(fd = refclock_open(device, SPEED232, LDISC_RAW)))
- return (0);
- /* from refclock_palisade.c */
- if (tcgetattr(fd, &tio) < 0) {
- msyslog(LOG_ERR, "Palisade(%d) tcgetattr(fd, &tio): %m",unit);
- return (0);
- }
- /*
- * set flags
- */
- tio.c_cflag |= (PARENB|PARODD);
- tio.c_iflag &= ~ICRNL;
- if (tcsetattr(fd, TCSANOW, &tio) == -1) {
- msyslog(LOG_ERR, "Palisade(%d) tcsetattr(fd, &tio): %m",unit);
- return (0);
- }
- /*
- * Allocate and initialize unit structure
- */
- if (!(up = (struct ripencc_unit *)
- emalloc(sizeof(struct ripencc_unit)))) {
- (void) close(fd);
- return (0);
- }
- memset((char *)up, 0, sizeof(struct ripencc_unit));
- pp = peer->procptr;
- pp->io.clock_recv = ripencc_receive;
- pp->io.srcclock = (caddr_t)peer;
- pp->io.datalen = 0;
- pp->io.fd = fd;
- if (!io_addclock(&pp->io)) {
- (void) close(fd);
- free(up);
- return (0);
- }
- pp->unitptr = (caddr_t)up;
- /*
- * Initialize miscellaneous variables
- */
- peer->precision = PRECISION;
- pp->clockdesc = DESCRIPTION;
- memcpy((char *)&pp->refid, REFID, REFID_LEN);
- up->pollcnt = 2;
- up->unit = unit;
- up->leapdelta = 0;
- up->utcflags = 0;
- /*
- * Initialize the Clock
- */
- /* query software versions */
- cmd_0x1F(&spt);
- ripencc_send(peer, spt);
- /* query receiver health */
- cmd_0x26(&spt);
- ripencc_send(peer, spt);
- /* query serial numbers */
- cmd_0x8E42q(&spt);
- ripencc_send(peer, spt);
-
- /* query manuf params */
- cmd_0x8E41q(&spt);
- ripencc_send(peer, spt);
- /* i/o opts */ /* trimble manual page A30 */
- cmd_0x35s(&spt,
- 0x1C, /* position */
- 0x00, /* velocity */
- 0x05, /* timing */
- 0x0a); /* auxilary */
- ripencc_send(peer, spt);
-
- /* turn off port A */
- cmd_0x3Ds (&spt,
- 0x0B, /* baud_out */
- 0x0B, /* baud_inp */
- 0x07, /* char_code */
- 0x07, /* stopbitcode */
- 0x01, /* output_mode */
- 0x00); /* input_mode */
- ripencc_send(peer, spt);
- /* set i/o options */
- cmd_0x8E4As (&spt,
- 0x01, /* PPS on */
- 0x01, /* Timebase UTC */
- 0x00, /* polarity positive */
- 0., /* 100 ft. cable XXX make flag */
- 1e-6 * GPS_C); /* turn of biasuncert. > (1us) */
- ripencc_send(peer,spt);
- /* all outomatic packet output off */
- cmd_0x8E4Ds(&spt,
- 0x00000000); /* AutoOutputMask */
- ripencc_send(peer, spt);
- cmd_0xBBq (&spt,
- 0x00); /* query primary configuration */
- ripencc_send(peer,spt);
- /* query PPS parameters */
- cmd_0x8E4Aq (&spt); /* query PPS params */
- ripencc_send(peer,spt);
- /* query survey limit */
- cmd_0x8E4Bq (&spt); /* query survey limit */
- ripencc_send(peer,spt);
- #ifdef DEBUG_NCC
- if (debug)
- printf("ripencc_start: success\n");
- #endif /* DEBUG_NCC */
- /*
- * Start the PPSAPI interface if it is there. Default to use
- * the assert edge and do not enable the kernel hardpps.
- */
- if (time_pps_create(fd, &up->handle) < 0) {
- up->handle = 0;
- msyslog(LOG_ERR, "refclock_ripencc: time_pps_create failed: %m");
- return (1);
- }
- return(ripencc_ppsapi(peer, 0, 0));
- }
- /*
- * ripencc_control - fudge control
- */
- static void
- ripencc_control(
- int unit, /* unit (not used) */
- struct refclockstat *in, /* input parameters (not used) */
- struct refclockstat *out, /* output parameters (not used) */
- struct peer *peer /* peer structure pointer */
- )
- {
- struct refclockproc *pp;
- #ifdef DEBUG_NCC
- msyslog(LOG_INFO,"%s()",__FUNCTION__);
- #endif /* DEBUG_NCC */
- pp = peer->procptr;
- ripencc_ppsapi(peer, pp->sloppyclockflag & CLK_FLAG2,
- pp->sloppyclockflag & CLK_FLAG3);
- }
- /*
- * Initialize PPSAPI
- */
- int
- ripencc_ppsapi(
- struct peer *peer, /* peer structure pointer */
- int enb_clear, /* clear enable */
- int enb_hardpps /* hardpps enable */
- )
- {
- struct refclockproc *pp;
- struct ripencc_unit *up;
- int capability;
- pp = peer->procptr;
- up = (struct ripencc_unit *)pp->unitptr;
- if (time_pps_getcap(up->handle, &capability) < 0) {
- msyslog(LOG_ERR,
- "refclock_ripencc: time_pps_getcap failed: %m");
- return (0);
- }
- memset(&up->pps_params, 0, sizeof(pps_params_t));
- if (enb_clear)
- up->pps_params.mode = capability & PPS_CAPTURECLEAR;
- else
- up->pps_params.mode = capability & PPS_CAPTUREASSERT;
- if (!up->pps_params.mode) {
- msyslog(LOG_ERR,
- "refclock_ripencc: invalid capture edge %d",
- !enb_clear);
- return (0);
- }
- up->pps_params.mode |= PPS_TSFMT_TSPEC;
- if (time_pps_setparams(up->handle, &up->pps_params) < 0) {
- msyslog(LOG_ERR,
- "refclock_ripencc: time_pps_setparams failed: %m");
- return (0);
- }
- if (enb_hardpps) {
- if (time_pps_kcbind(up->handle, PPS_KC_HARDPPS,
- up->pps_params.mode & ~PPS_TSFMT_TSPEC,
- PPS_TSFMT_TSPEC) < 0) {
- msyslog(LOG_ERR,
- "refclock_ripencc: time_pps_kcbind failed: %m");
- return (0);
- }
- pps_enable = 1;
- }
- peer->precision = PPS_PRECISION;
- #if DEBUG_NCC
- if (debug) {
- time_pps_getparams(up->handle, &up->pps_params);
- printf(
- "refclock_ripencc: capability 0x%x version %d mode 0x%x kern %d\n",
- capability, up->pps_params.api_version,
- up->pps_params.mode, enb_hardpps);
- }
- #endif /* DEBUG_NCC */
- return (1);
- }
- /*
- * This function is called every 64 seconds from ripencc_receive
- * It will fetch the pps time
- *
- * Return 0 on failure and 1 on success.
- */
- static int
- ripencc_get_pps_ts(
- struct ripencc_unit *up,
- l_fp *tsptr
- )
- {
- pps_info_t pps_info;
- struct timespec timeout, ts;
- double dtemp;
- l_fp tstmp;
- #ifdef DEBUG_PPS
- msyslog(LOG_INFO,"ripencc_get_pps_ts\n");
- #endif /* DEBUG_PPS */
- /*
- * Convert the timespec nanoseconds field to ntp l_fp units.
- */
- if (up->handle == 0)
- return (0);
- timeout.tv_sec = 0;
- timeout.tv_nsec = 0;
- memcpy(&pps_info, &up->pps_info, sizeof(pps_info_t));
- if (time_pps_fetch(up->handle, PPS_TSFMT_TSPEC, &up->pps_info,
- &timeout) < 0)
- return (0);
- if (up->pps_params.mode & PPS_CAPTUREASSERT) {
- if (pps_info.assert_sequence ==
- up->pps_info.assert_sequence)
- return (0);
- ts = up->pps_info.assert_timestamp;
- } else if (up->pps_params.mode & PPS_CAPTURECLEAR) {
- if (pps_info.clear_sequence ==
- up->pps_info.clear_sequence)
- return (0);
- ts = up->pps_info.clear_timestamp;
- } else {
- return (0);
- }
- if ((up->ts.tv_sec == ts.tv_sec) && (up->ts.tv_nsec == ts.tv_nsec))
- return (0);
- up->ts = ts;
- tstmp.l_ui = ts.tv_sec + JAN_1970;
- dtemp = ts.tv_nsec * FRAC / 1e9;
- tstmp.l_uf = (u_int32)dtemp;
- #ifdef DEBUG_PPS
- msyslog(LOG_INFO,"ts.tv_sec: %d\n",(int)ts.tv_sec);
- msyslog(LOG_INFO,"ts.tv_nsec: %ld\n",ts.tv_nsec);
- #endif /* DEBUG_PPS */
- *tsptr = tstmp;
- return (1);
- }
- /*
- * ripencc_shutdown - shut down a GPS clock
- */
- static void
- ripencc_shutdown(int unit, struct peer *peer)
- {
- register struct ripencc_unit *up;
- struct refclockproc *pp;
- pp = peer->procptr;
- up = (struct ripencc_unit *)pp->unitptr;
- if (up->handle != 0)
- time_pps_destroy(up->handle);
- io_closeclock(&pp->io);
- free(up);
- }
- /*
- * ripencc_poll - called by the transmit procedure
- */
- static void
- ripencc_poll(int unit, struct peer *peer)
- {
- register struct ripencc_unit *up;
- struct refclockproc *pp;
- TSIPPKT spt;
- #ifdef DEBUG_NCC
- if (debug)
- fprintf(stderr, "ripencc_poll(%d)\n", unit);
- #endif /* DEBUG_NCC */
- pp = peer->procptr;
- up = (struct ripencc_unit *)pp->unitptr;
- if (up->pollcnt == 0)
- refclock_report(peer, CEVNT_TIMEOUT);
- else
- up->pollcnt--;
- pp->polls++;
- up->polled = 1;
- /* poll for UTC superpacket */
- cmd_0x8EADq (&spt);
- ripencc_send(peer,spt);
- }
- /*
- * ripencc_send - send message to clock
- * use the structures being created by the trimble functions!
- * makes the code more readable/clean
- */
- static void
- ripencc_send(struct peer *peer, TSIPPKT spt)
- {
- unsigned char *ip, *op;
- unsigned char obuf[512];
- #ifdef DEBUG_RAW
- {
- register struct ripencc_unit *up;
- register struct refclockproc *pp;
- pp = peer->procptr;
- up = (struct ripencc_unit *)pp->unitptr;
- if (debug)
- printf("ripencc_send(%d, %02X)\n", up->unit, cmd);
- }
- #endif /* DEBUG_RAW */
- ip = spt.buf;
- op = obuf;
- *op++ = 0x10;
- *op++ = spt.code;
- while (spt.len--) {
- if (op-obuf > sizeof(obuf)-5) {
- msyslog(LOG_ERR, "ripencc_send obuf overflow!");
- refclock_report(peer, CEVNT_FAULT);
- return;
- }
-
- if (*ip == 0x10) /* byte stuffing */
- *op++ = 0x10;
- *op++ = *ip++;
- }
-
- *op++ = 0x10;
- *op++ = 0x03;
- #ifdef DEBUG_RAW
- if (debug) { /* print raw packet */
- unsigned char *cp;
- int i;
- printf("ripencc_send: len %d\n", op-obuf);
- for (i=1, cp=obuf; cp<op; i++, cp++) {
- printf(" %02X", *cp);
- if (i%10 == 0)
- printf("\n");
- }
- printf("\n");
- }
- #endif /* DEBUG_RAW */
- if (write(peer->procptr->io.fd, obuf, op-obuf) == -1) {
- refclock_report(peer, CEVNT_FAULT);
- }
- }
- /*
- * ripencc_receive()
- *
- * called when a packet is received on the serial port
- * takes care of further processing
- *
- */
- static void
- ripencc_receive(struct recvbuf *rbufp)
- {
- register struct ripencc_unit *up;
- register struct refclockproc *pp;
- struct peer *peer;
- static TSIPPKT rpt; /* structure for current incoming TSIP report */
- TSIPPKT spt; /* send packet */
- int ns_since_pps;
- int i;
- char *cp;
- /* Use these variables to hold data until we decide its worth keeping */
- char rd_lastcode[BMAX];
- l_fp rd_tmp;
- u_short rd_lencode;
- /* msyslog(LOG_INFO, "%s",__FUNCTION__); */
- /*
- * Initialize pointers and read the timecode and timestamp
- */
- peer = (struct peer *)rbufp->recv_srcclock;
- pp = peer->procptr;
- up = (struct ripencc_unit *)pp->unitptr;
- rd_lencode = refclock_gtlin(rbufp, rd_lastcode, BMAX, &rd_tmp);
- #ifdef DEBUG_RAW
- if (debug)
- fprintf(stderr, "ripencc_receive(%d)\n", up->unit);
- #endif /* DEBUG_RAW */
- #ifdef DEBUG_RAW
- if (debug) { /* print raw packet */
- int i;
- unsigned char *cp;
- printf("ripencc_receive: len %d\n", rbufp->recv_length);
- for (i=1, cp=(char*)&rbufp->recv_space; i <= rbufp->recv_length; i++, cp++) {
- printf(" %02X", *cp);
- if (i%10 == 0)
- printf("\n");
- }
- printf("\n");
- }
- #endif /* DEBUG_RAW */
- cp = (char*) &rbufp->recv_space;
- i=rbufp->recv_length;
- while (i--) { /* loop over received chars */
- tsip_input_proc(&rpt, (unsigned char) *cp++);
- if (rpt.status != TSIP_PARSED_FULL)
- continue;
- switch (rpt.code) {
- case 0x8F: /* superpacket */
- switch (rpt.buf[0]) {
- case 0xAD: /* UTC Time */
- /*
- * When polling on port B the timecode
- * is the time of the previous PPS.
- * If we completed receiving the packet
- * less than 150ms after the turn of the second,
- * it may have the code of the previous second.
- * We do not trust that and simply poll again
- * without even parsing it.
- *
- * More elegant would be to re-schedule the poll,
- * but I do not know (yet) how to do that cleanly.
- *
- */
- /* BLA ns_since_pps = ncc_tstmp(rbufp, &trtmp); */
- /* if (up->polled && ns_since_pps > -1 && ns_since_pps < 150) { */
- ns_since_pps=200;
- if (up->polled && ns_since_pps < 150) {
- msyslog(LOG_INFO, "%s(): up->polled",__FUNCTION__);
- ripencc_poll(up->unit, peer);
- break;
- }
- /*
- * Parse primary utc time packet
- * and fill refclock structure
- * from results.
- */
- if (parse0x8FAD(&rpt, peer) < 0) {
- msyslog(LOG_INFO, "%s(): parse0x8FAD < 0",__FUNCTION__);
- refclock_report(peer, CEVNT_BADREPLY);
- break;
- }
- /*
- * If the PPSAPI is working, rather use its
- * timestamps.
- * assume that the PPS occurs on the second
- * so blow any msec
- */
- if (ripencc_get_pps_ts(up, &rd_tmp) == 1) {
- pp->lastrec = up->tstamp = rd_tmp;
- pp->nsec = 0;
- }
- else
- msyslog(LOG_INFO, "%s(): ripencc_get_pps_ts returns failure\n",__FUNCTION__);
- if (!up->polled) {
- msyslog(LOG_INFO, "%s(): unrequested packet\n",__FUNCTION__);
- /* unrequested packet */
- break;
- }
- /* we have been polled ! */
- up->polled = 0;
- up->pollcnt = 2;
- /* poll for next packet */
- cmd_0x8E0Bq(&spt);
- ripencc_send(peer,spt);
-
- if (ns_since_pps < 0) { /* no PPS */
- msyslog(LOG_INFO, "%s(): ns_since_pps < 0",__FUNCTION__);
- refclock_report(peer, CEVNT_BADTIME);
- break;
- }
- /*
- * Process the new sample in the median filter and determine the
- * reference clock offset and dispersion.
- */
- if (!refclock_process(pp)) {
- msyslog(LOG_INFO, "%s(): !refclock_process",__FUNCTION__);
- refclock_report(peer, CEVNT_BADTIME);
- break;
- }
- refclock_receive(peer);
- break;
-
- case 0x0B: /* comprehensive time packet */
- parse0x8F0B(&rpt, peer);
- break;
- default: /* other superpackets */
- #ifdef DEBUG_NCC
- msyslog(LOG_INFO, "%s(): calling parseany",__FUNCTION__);
- #endif /* DEBUG_NCC */
- #ifdef TRIMBLE_OUTPUT_FUNC
- parseany(&rpt, peer);
- #endif /* TRIMBLE_OUTPUT_FUNC */
- break;
- }
- break;
- case 0x4F: /* UTC parameters, for leap info */
- parse0x4F(&rpt, peer);
- break;
- case 0x5C: /* sat tracking data */
- parse0x5C(&rpt, peer);
- break;
- default: /* other packets */
- #ifdef TRIMBLE_OUTPUT_FUNC
- parseany(&rpt, peer);
- #endif /* TRIMBLE_OUTPUT_FUNC */
- break;
- }
- rpt.status = TSIP_PARSED_EMPTY;
- }
- }
- /*
- * All trimble functions that are directly referenced from driver code
- * (so not from parseany)
- */
- void cmd_0x1F (TSIPPKT *cmd)
- /* request software versions */
- {
- cmd->len = 0;
- cmd->code = 0x1F;
- }
- void cmd_0x26 (TSIPPKT *cmd)
- /* request receiver health */
- {
- cmd->len = 0;
- cmd->code = 0x26;
- }
- void cmd_0x2F (TSIPPKT *cmd)
- /* request UTC params */
- {
- cmd->len = 0;
- cmd->code = 0x2F;
- }
- void cmd_0x35s (TSIPPKT *cmd, unsigned char pos_code, unsigned char vel_code,
- unsigned char time_code, unsigned char opts_code)
- /* set serial I/O options */
- {
- cmd->buf[0] = pos_code;
- cmd->buf[1] = vel_code;
- cmd->buf[2] = time_code;
- cmd->buf[3] = opts_code;
- cmd->len = 4;
- cmd->code = 0x35;
- }
- void cmd_0x3C (TSIPPKT *cmd, unsigned char sv_prn)
- /* request tracking status */
- {
- cmd->buf[0] = sv_prn;
- cmd->len = 1;
- cmd->code = 0x3C;
- }
- void cmd_0x3Ds (TSIPPKT *cmd,
- unsigned char baud_out, unsigned char baud_inp,
- unsigned char char_code, unsigned char stopbitcode,
- unsigned char output_mode, unsigned char input_mode)
- /* set Channel A configuration for dual-port operation */
- {
- cmd->buf[0] = baud_out; /* XMT baud rate */
- cmd->buf[1] = baud_inp; /* RCV baud rate */
- cmd->buf[2] = char_code; /* parity and #bits per byte */
- cmd->buf[3] = stopbitcode; /* number of stop bits code */
- cmd->buf[4] = output_mode; /* Ch. A transmission mode */
- cmd->buf[5] = input_mode; /* Ch. A reception mode */
- cmd->len = 6;
- cmd->code = 0x3D;
- }
- /* query primary configuration */
- void cmd_0xBBq (TSIPPKT *cmd,
- unsigned char subcode)
- {
- cmd->len = 1;
- cmd->code = 0xBB;
- cmd->buf[0] = subcode;
- }
- /**** Superpackets ****/
- void cmd_0x8E0Bq (TSIPPKT *cmd)
- /* 8E-0B to query 8F-0B controls */
- {
- cmd->len = 1;
- cmd->code = 0x8E;
- cmd->buf[0] = 0x0B;
- }
- void cmd_0x8E41q (TSIPPKT *cmd)
- /* 8F-41 to query board serial number */
- {
- cmd->len = 1;
- cmd->code = 0x8E;
- cmd->buf[0] = 0x41;
- }
- void cmd_0x8E42q (TSIPPKT *cmd)
- /* 8F-42 to query product serial number */
- {
- cmd->len = 1;
- cmd->code = 0x8E;
- cmd->buf[0] = 0x42;
- }
- void cmd_0x8E4Aq (TSIPPKT *cmd)
- /* 8F-4A to query PPS parameters */
- {
- cmd->len = 1;
- cmd->code = 0x8E;
- cmd->buf[0] = 0x4A;
- }
- /* set i/o options */
- void cmd_0x8E4As (TSIPPKT *cmd,
- unsigned char PPSOnOff,
- unsigned char TimeBase,
- unsigned char Polarity,
- double PPSOffset,
- float Uncertainty)
- {
- cmd->len = 16;
- cmd->code = 0x8E;
- cmd->buf[0] = 0x4A;
- cmd->buf[1] = PPSOnOff;
- cmd->buf[2] = TimeBase;
- cmd->buf[3] = Polarity;
- bPutDouble (&PPSOffset, &cmd->buf[4]);
- bPutFloat (&Uncertainty, &cmd->buf[12]);
- }
- void cmd_0x8E4Bq (TSIPPKT *cmd)
- /* 8F-4B query survey limit */
- {
- cmd->len = 1;
- cmd->code = 0x8E;
- cmd->buf[0] = 0x4B;
- }
- /* poll for UTC superpacket */
- void cmd_0x8EADq (TSIPPKT *cmd)
- /* 8E-AD to query 8F-AD controls */
- {
- cmd->len = 1;
- cmd->code = 0x8E;
- cmd->buf[0] = 0xAD;
- }
- /* all outomatic packet output off */
- void cmd_0x8E4Ds (TSIPPKT *cmd,
- unsigned long AutoOutputMask)
- {
- cmd->len = 5;
- cmd->code = 0x8E;
- cmd->buf[0] = 0x4D;
- bPutULong (&AutoOutputMask, &cmd->buf[1]);
- }
- /* for DOS machines, reverse order of bytes as they come through the
- * serial port. */
- #ifdef BYTESWAP
- static short bGetShort (unsigned char *bp)
- {
- short outval;
- unsigned char *optr;
- optr = (unsigned char*)&outval + 1;
- *optr-- = *bp++;
- *optr = *bp;
- return outval;
- }
- #ifdef TRIMBLE_OUTPUT_FUNC
- static unsigned short bGetUShort (unsigned char *bp)
- {
- unsigned short outval;
- unsigned char *optr;
- optr = (unsigned char*)&outval + 1;
- *optr-- = *bp++;
- *optr = *bp;
- return outval;
- }
- static long bGetLong (unsigned char *bp)
- {
- long outval;
- unsigned char *optr;
- optr = (unsigned char*)&outval + 3;
- *optr-- = *bp++;
- *optr-- = *bp++;
- *optr-- = *bp++;
- *optr = *bp;
- return outval;
- }
- static unsigned long bGetULong (unsigned char *bp)
- {
- unsigned long outval;
- unsigned char *optr;
- optr = (unsigned char*)&outval + 3;
- *optr-- = *bp++;
- *optr-- = *bp++;
- *optr-- = *bp++;
- *optr = *bp;
- return outval;
- }
- #endif /* TRIMBLE_OUTPUT_FUNC */
- static float bGetSingle (unsigned char *bp)
- {
- float outval;
- unsigned char *optr;
- optr = (unsigned char*)&outval + 3;
- *optr-- = *bp++;
- *optr-- = *bp++;
- *optr-- = *bp++;
- *optr = *bp;
- return outval;
- }
- static double bGetDouble (unsigned char *bp)
- {
- double outval;
- unsigned char *optr;
- optr = (unsigned char*)&outval + 7;
- *optr-- = *bp++;
- *optr-- = *bp++;
- *optr-- = *bp++;
- *optr-- = *bp++;
- *optr-- = *bp++;
- *optr-- = *bp++;
- *optr-- = *bp++;
- *optr = *bp;
- return outval;
- }
- #else /* not BYTESWAP */
- #define bGetShort(bp) (*(short*)(bp))
- #define bGetLong(bp) (*(long*)(bp))
- #define bGetULong(bp) (*(unsigned long*)(bp))
- #define bGetSingle(bp) (*(float*)(bp))
- #define bGetDouble(bp) (*(double*)(bp))
- #endif /* BYTESWAP */
- /*
- * Byte-reversal is necessary for little-endian (Intel-based) machines.
- * TSIP streams are Big-endian (Motorola-based).
- */
- #ifdef BYTESWAP
- void
- bPutFloat (float *in, unsigned char *out)
- {
- unsigned char *inptr;
- inptr = (unsigned char*)in + 3;
- *out++ = *inptr--;
- *out++ = *inptr--;
- *out++ = *inptr--;
- *out = *inptr;
- }
- static void
- bPutULong (unsigned long *in, unsigned char *out)
- {
- unsigned char *inptr;
- inptr = (unsigned char*)in + 3;
- *out++ = *inptr--;
- *out++ = *inptr--;
- *out++ = *inptr--;
- *out = *inptr;
- }
- static void
- bPutDouble (double *in, unsigned char *out)
- {
- unsigned char *inptr;
- inptr = (unsigned char*)in + 7;
- *out++ = *inptr--;
- *out++ = *inptr--;
- *out++ = *inptr--;
- *out++ = *inptr--;
- *out++ = *inptr--;
- *out++ = *inptr--;
- *out++ = *inptr--;
- *out = *inptr;
- }
- #else /* not BYTESWAP */
- void bPutShort (short a, unsigned char *cmdbuf) {*(short*) cmdbuf = a;}
- void bPutULong (long a, unsigned char *cmdbuf) {*(long*) cmdbuf = a;}
- void bPutFloat (float a, unsigned char *cmdbuf) {*(float*) cmdbuf = a;}
- void bPutDouble (double a, unsigned char *cmdbuf){*(double*) cmdbuf = a;}
- #endif /* BYTESWAP */
- /*
- * Parse primary utc time packet
- * and fill refclock structure
- * from results.
- *
- * 0 = success
- * -1 = errors
- */
- static int
- parse0x8FAD(rpt, peer)
- TSIPPKT *rpt;
- struct peer *peer;
- {
- register struct refclockproc *pp;
- register struct ripencc_unit *up;
- unsigned day, month, year; /* data derived from received timecode */
- unsigned hour, minute, second;
- unsigned char trackstat, utcflags;
- static char logbuf[1024]; /* logging string buffer */
- int i;
- unsigned char *buf;
-
- buf = rpt->buf;
- pp = peer->procptr;
- if (rpt->len != 22)
- return (-1);
-
- if (bGetShort(&buf[1]) != 0) {
- #ifdef DEBUG_NCC
- if (debug)
- printf("parse0x8FAD: event count != 0\n");
- #endif /* DEBUG_NCC */
- return(-1);
- }
- if (bGetDouble(&buf[3]) != 0.0) {
- #ifdef DEBUG_NCC
- if (debug)
- printf("parse0x8FAD: fracsecs != 0\n");
- #endif /* DEBUG_NCC */
- return(-1);
- }
- hour = (unsigned int) buf[11];
- minute = (unsigned int) buf[12];
- second = (unsigned int) buf[13];
- day = (unsigned int) buf[14];
- month = (unsigned int) buf[15];
- year = bGetShort(&buf[16]);
- trackstat = buf[18];
- utcflags = buf[19];
- sprintf(logbuf, "U1 %d.%d.%d %02d:%02d:%02d %d %02x",
- day, month, year, hour, minute, second, trackstat, utcflags);
- #ifdef DEBUG_NCC
- if (debug)
- puts(logbuf);
- #endif /* DEBUG_NCC */
- record_clock_stats(&peer->srcadr, logbuf);
- if (!utcflags & UTCF_UTC_AVAIL)
- return(-1);
- /* poll for UTC parameters once and then if UTC flag changed */
- up = (struct ripencc_unit *) pp->unitptr;
- if (utcflags != up->utcflags) {
- TSIPPKT spt; /* local structure for send packet */
- cmd_0x2F (&spt); /* request UTC params */
- ripencc_send(peer,spt);
- up->utcflags = utcflags;
- }
-
- /*
- * If we hit the leap second, we choose to skip this sample
- * rather than rely on other code to be perfectly correct.
- * No offense, just defense ;-).
- */
- if (second == 60)
- return(-1);
- /* now check and convert the time we received */
- pp->year = year;
- if (month < 1 || month > 12 || day < 1 || day > 31)
- return(-1);
- if (pp->year % 4) {
- if (day > day1tab[month - 1])
- return(-1);
- for (i = 0; i < month - 1; i++)
- day += day1tab[i];
- } else {
- if (day > day2tab[month - 1])
- return(-1);
- for (i = 0; i < month - 1; i++)
- day += day2tab[i];
- }
- pp->day = day;
- pp->hour = hour;
- pp->minute = minute;
- pp-> second = second;
- pp->nsec = 0;
- if ((utcflags&UTCF_LEAP_PNDG) && up->leapdelta != 0)
- pp-> leap = (up->leapdelta > 0 ? LEAP_ADDSECOND : LEAP_DELSECOND);
- else
- pp-> leap = LEAP_NOWARNING;
- return (0);
- }
- /*
- * Parse comprehensive time packet
- *
- * 0 = success
- * -1 = errors
- */
- int parse0x8F0B(rpt, peer)
- TSIPPKT *rpt;
- struct peer *peer;
- {
- register struct refclockproc *pp;
- unsigned day, month, year; /* data derived from received timecode */
- unsigned hour, minute, second;
- unsigned utcoff;
- unsigned char mode;
- double bias, rate;
- float biasunc, rateunc;
- double lat, lon, alt;
- short lat_deg, lon_deg;
- float lat_min, lon_min;
- unsigned char north_south, east_west;
- char sv[9];
- static char logbuf[1024]; /* logging string buffer */
- unsigned char b;
- int i;
- unsigned char *buf;
- double tow;
-
- buf = rpt->buf;
- pp = peer->procptr;
- if (rpt->len != 74)
- return (-1);
-
- if (bGetShort(&buf[1]) != 0)
- return(-1);;
- tow = bGetDouble(&buf[3]);
- if (tow == -1.0) {
- return(-1);
- }
- else if ((tow >= 604800.0) || (tow < 0.0)) {
- return(-1);
- }
- else
- {
- if (tow < 604799.9) tow = tow + .00000001;
- second = (unsigned int) fmod(tow, 60.);
- minute = (unsigned int) fmod(tow/60., 60.);
- hour = (unsigned int )fmod(tow / 3600., 24.);
- }
- day = (unsigned int) buf[11];
- month = (unsigned int) buf[12];
- year = bGetShort(&buf[13]);
- mode = buf[15];
- utcoff = bGetShort(&buf[16]);
- bias = bGetDouble(&buf[18]) / GPS_C * 1e9; /* ns */
- rate = bGetDouble(&buf[26]) / GPS_C * 1e9; /* ppb */
- biasunc = bGetSingle(&buf[34]) / GPS_C * 1e9; /* ns */
- rateunc = bGetSingle(&buf[38]) / GPS_C * 1e9; /* ppb */
- lat = bGetDouble(&buf[42]) * R2D;
- lon = bGetDouble(&buf[50]) * R2D;
- alt = bGetDouble(&buf[58]);
- if (lat < 0.0) {
- north_south = 'S';
- lat = -lat;
- }
- else {
- north_south = 'N';
- }
- lat_deg = (short)lat;
- lat_min = (lat - lat_deg) * 60.0;
- if (lon < 0.0) {
- east_west = 'W';
- lon = -lon;
- }
- else {
- east_west = 'E';
- }
- lon_deg = (short)lon;
- lon_min = (lon - lon_deg) * 60.0;
- for (i=0; i<8; i++) {
- sv[i] = buf[i + 66];
- if (sv[i]) {
- TSIPPKT spt; /* local structure for sendpacket */
- b = (unsigned char) (sv[i]<0 ? -sv[i] : sv[i]);
- /* request tracking status */
- cmd_0x3C (&spt, b);
- ripencc_send(peer,spt);
- }
- }
- 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",
- day, month, year, hour, minute, second, mode, bias, biasunc, rate, rateunc, utcoff,
- lat_deg, lat_min, north_south, lon_deg, lon_min, east_west, alt,
- sv[0], sv[1], sv[2], sv[3], sv[4], sv[5], sv[6], sv[7]);
- #ifdef DEBUG_NCC
- if (debug)
- puts(logbuf);
- #endif /* DEBUG_NCC */
- record_clock_stats(&peer->srcadr, logbuf);
- return (0);
- }
- #ifdef TRIMBLE_OUTPUT_FUNC
- /*
- * Parse any packet using Trimble machinery
- */
- int parseany(rpt, peer)
- TSIPPKT *rpt;
- struct peer *peer;
- {
- static char logbuf[1024]; /* logging string buffer */
- TranslateTSIPReportToText (rpt, logbuf); /* anything else */
- #ifdef DEBUG_NCC
- if (debug)
- puts(&logbuf[1]);
- #endif /* DEBUG_NCC */
- record_clock_stats(&peer->srcadr, &logbuf[1]);
- return(0);
- }
- #endif /* TRIMBLE_OUTPUT_FUNC */
- /*
- * Parse UTC Parameter Packet
- *
- * See the IDE for documentation!
- *
- * 0 = success
- * -1 = errors
- */
- int parse0x4F(rpt, peer)
- TSIPPKT *rpt;
- struct peer *peer;
- {
- register struct ripencc_unit *up;
- double a0;
- float a1, tot;
- int dt_ls, wn_t, wn_lsf, dn, dt_lsf;
- static char logbuf[1024]; /* logging string buffer */
- unsigned char *buf;
-
- buf = rpt->buf;
-
- if (rpt->len != 26)
- return (-1);
- a0 = bGetDouble (buf);
- a1 = bGetSingle (&buf[8]);
- dt_ls = bGetShort (&buf[12]);
- tot = bGetSingle (&buf[14]);
- wn_t = bGetShort (&buf[18]);
- wn_lsf = bGetShort (&buf[20]);
- dn = bGetShort (&buf[22]);
- dt_lsf = bGetShort (&buf[24]);
- sprintf(logbuf, "L1 %d %d %d %g %g %g %d %d %d",
- dt_lsf - dt_ls, dt_ls, dt_lsf, a0, a1, tot, wn_t, wn_lsf, dn);
- #ifdef DEBUG_NCC
- if (debug)
- puts(logbuf);
- #endif /* DEBUG_NCC */
- record_clock_stats(&peer->srcadr, logbuf);
- up = (struct ripencc_unit *) peer->procptr->unitptr;
- up->leapdelta = dt_lsf - dt_ls;
- return (0);
- }
- /*
- * Parse Tracking Status packet
- *
- * 0 = success
- * -1 = errors
- */
- int parse0x5C(rpt, peer)
- TSIPPKT *rpt;
- struct peer *peer;
- {
- unsigned char prn, channel, aqflag, ephstat;
- float snr, azinuth, elevation;
- static char logbuf[1024]; /* logging string buffer */
- unsigned char *buf;
-
- buf = rpt->buf;
-
- if (rpt->len != 24)
- return(-1);
- prn = buf[0];
- channel = (unsigned char)(buf[1] >> 3);
- if (channel == 0x10)
- channel = 2;
- else
- channel++;
- aqflag = buf[2];
- ephstat = buf[3];
- snr = bGetSingle(&buf[4]);
- elevation = bGetSingle(&buf[12]) * R2D;
- azinuth = bGetSingle(&buf[16]) * R2D;
- sprintf(logbuf, "S1 %02d %d %d %02x %4.1f %5.1f %4.1f",
- prn, channel, aqflag, ephstat, snr, azinuth, elevation);
- #ifdef DEBUG_NCC
- if (debug)
- puts(logbuf);
- #endif /* DEBUG_NCC */
- record_clock_stats(&peer->srcadr, logbuf);
- return (0);
- }
- /******* Code below is from Trimble Tsipchat *************/
- /*
- * *************************************************************************
- *
- * Trimble Navigation, Ltd.
- * OEM Products Development Group
- * P.O. Box 3642
- * 645 North Mary Avenue
- * Sunnyvale, California 94088-3642
- *
- * Corporate Headquarter:
- * Telephone: (408) 481-8000
- * Fax: (408) 481-6005
- *
- * Technical Support Center:
- * Telephone: (800) 767-4822 (U.S. and Canada)
- * (408) 481-6940 (outside U.S. and Canada)
- * Fax: (408) 481-6020
- * BBS: (408) 481-7800
- * e-mail: trimble_support@trimble.com
- * ftp://ftp.trimble.com/pub/sct/embedded/bin
- *
- * *************************************************************************
- *
- * ------- BYTE-SWAPPING -------
- * TSIP is big-endian (Motorola) protocol. To use on little-endian (Intel)
- * systems, the bytes of all multi-byte types (shorts, floats, doubles, etc.)
- * must be reversed. This is controlled by the MACRO BYTESWAP; if defined, it
- * assumes little-endian protocol.
- * --------------------------------
- *
- * T_PARSER.C and T_PARSER.H contains primitive functions that interpret
- * reports received from the receiver. A second source file pair,
- * T_FORMAT.C and T_FORMAT.H, contin the matching TSIP command formatters.
- *
- * The module is in very portable, basic C language. It can be used as is, or
- * with minimal changes if a TSIP communications application is needed separate
- * from TSIPCHAT. The construction of most argument lists avoid the use of
- * structures, but the developer is encouraged to reconstruct them using such
- * definitions to meet project requirements. Declarations of T_PARSER.C
- * functions are included in T_PARSER.H to provide prototyping definitions.
- *
- * There are two types of functions: a serial input processing routine,
- * tsip_input_proc()
- * which assembles incoming bytes into a TSIPPKT structure, and the
- * report parsers, rpt_0x??().
- *
- * 1) The function tsip_input_proc() accumulates bytes from the receiver,
- * strips control bytes (DLE), and checks if the report end sequence (DLE ETX)
- * has been received. rpt.status is defined as TSIP_PARSED_FULL (== 1)
- * if a complete packet is available.
- *
- * 2) The functions rpt_0x??() are report string interpreters patterned after
- * the document called "Trimble Standard Interface Protocol". It should be
- * noted that if the report buffer is sent into the receiver with the wrong
- * length (byte count), the rpt_0x??() returns the Boolean equivalence for
- * TRUE.
- *
- * *************************************************************************
- *
- */
- /**/
- static void tsip_input_proc (
- TSIPPKT *rpt,
- int inbyte)
- /* reads bytes until serial buffer is empty or a complete report
- * has been received; end of report is signified by DLE ETX.
- */
- {
- unsigned char newbyte;
- if (inbyte < 0 || inbyte > 0xFF) return;
- newbyte = (unsigned char)(inbyte);
- switch (rpt->status)
- {
- case TSIP_PARSED_DLE_1:
- switch (newbyte)
- {
- case 0:
- case ETX:
- /* illegal TSIP IDs */
- rpt->len = 0;
- rpt->status = TSIP_PARSED_EMPTY;
- break;
- case DLE:
- /* try normal message start again */
- rpt->len = 0;
- rpt->status = TSIP_PARSED_DLE_1;
- break;
- default:
- /* legal TSIP ID; start message */
- rpt->code = newbyte;
- rpt->len = 0;
- rpt->status = TSIP_PARSED_DATA;
- break;
- }
- break;
- case TSIP_PARSED_DATA:
- switch (newbyte) {
- case DLE:
- /* expect DLE or ETX next */
- rpt->status = TSIP_PARSED_DLE_2;
- break;
- default:
- /* normal data byte */
- rpt->buf[rpt->len] = newbyte;
- rpt->len++;
- /* no change in rpt->status */
- break;
- }
- break;
- case TSIP_PARSED_DLE_2:
- switch (newbyte) {
- case DLE:
- /* normal data byte */
- rpt->buf[rpt->len] = newbyte;
- rpt->len++;
- rpt->status = TSIP_PARSED_DATA;
- break;
- case ETX:
- /* end of message; return TRUE here. */
- rpt->status = TSIP_PARSED_FULL;
- break;
- default:
- /* error: treat as TSIP_PARSED_DLE_1; start new report packet */
- rpt->code = newbyte;
- rpt->len = 0;
- rpt->status = TSIP_PARSED_DATA;
- }
- break;
- case TSIP_PARSED_FULL:
- case TSIP_PARSED_EMPTY:
- default:
- switch (newbyte) {
- case DLE:
- /* normal message start */
- rpt->len = 0;
- rpt->status = TSIP_PARSED_DLE_1;
- break;
- default:
- /* error: ignore newbyte */
- rpt->len = 0;
- rpt->status = TSIP_PARSED_EMPTY;
- }
- break;
- }
- if (rpt->len > MAX_RPTBUF) {
- /* error: start new report packet */
- rpt->status = TSIP_PARSED_EMPTY;
- rpt->len = 0;
- }
- }
- #ifdef TRIMBLE_OUTPUT_FUNC
- /**/
- short rpt_0x3D (TSIPPKT *rpt,
- unsigned char *tx_baud_index,
- unsigned char *rx_baud_index,
- unsigned char *char_format_index,
- unsigned char *stop_bits,
- unsigned char *tx_mode_index,
- unsigned char *rx_mode_index)
- /* Channel A configuration for dual port operation */
- {
- unsigned char *buf;
- buf = rpt->buf;
- if (rpt->len != 6) return TRUE;
- *tx_baud_index = buf[0];
- *rx_baud_index = buf[1];
- *char_format_index = buf[2];
- *stop_bits = (unsigned char)((buf[3] == 0x07) ? 1 : 2);
- *tx_mode_index = buf[4];
- *rx_mode_index = buf[5];
- return FALSE;
- }
- /**/
- short rpt_0x40 (TSIPPKT *rpt,
- unsigned char *sv_prn,
- short *week_num,
- float *t_zc,
- float *eccentricity,
- float *t_oa,
- float *i_0,
- float *OMEGA_dot,
- float *sqrt_A,
- float *OMEGA_0,
- float *omega,
- float *M_0)
- /* almanac data for specified satellite */
- {
- unsigned char *buf;
- buf = rpt->buf;
- if (rpt->len != 39) return TRUE;
- *sv_prn = buf[0];
- *t_zc = bGetSingle (&buf[1]);
- *week_num = bGetShort (&buf[5]);
- *eccentricity = bGetSingle (&buf[7]);
- *t_oa = bGetSingle (&buf[11]);
- *i_0 = bGetSingle (&buf[15]);
- *OMEGA_dot = bGetSingle (&buf[19]);
- *sqrt_A = bGetSingle (&buf[23]);
- *OMEGA_0 = bGetSingle (&buf[27]);
- *omega = bGetSingle (&buf[31]);
- *M_0 = bGetSingle (&buf[35]);
- return FALSE;
- }
- short rpt_0x41 (TSIPPKT *rpt,
- float *time_of_week,
- float *UTC_offset,
- short *week_num)
- /* GPS time */
- {
- unsigned char *buf;
- buf = rpt->buf;
-
- if (rpt->len != 10) return TRUE;
- *time_of_week = bGetSingle (buf);
- *week_num = bGetShort (&buf[4]);
- *UTC_offset = bGetSingle (&buf[6]);
- return FALSE;
- }
- short rpt_0x42 (TSIPPKT *rpt,
- float pos_ECEF[3],
- float *time_of_fix)
- /* position in ECEF, single precision */
- {
- unsigned char *buf;
- buf = rpt->buf;
-
- if (rpt->len != 16) return TRUE;
- pos_ECEF[0] = bGetSingle (buf);
- pos_ECEF[1]= bGetSingle (&buf[4]);
- pos_ECEF[2]= bGetSingle (&buf[8]);
- *time_of_fix = bGetSingle (&buf[12]);
- return FALSE;
- }
- short rpt_0x43 (TSIPPKT *rpt,
- float ECEF_vel[3],
- float *freq_offset,
- float *time_of_fix)
- /* velocity in ECEF, single precision */
- {
- unsigned char *buf;
- buf = rpt->bu…