File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / ntpd / refclock_ripencc.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:08:38 2012 UTC (12 years, 2 months ago) by misho
Branches: ntp, MAIN
CVS tags: v4_2_6p5p0, v4_2_6p5, HEAD
ntp 4.2.6p5

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>