Annotation of embedaddon/ntp/ntpd/refclock_ripencc.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * $Id: refclock_ripencc.c,v 1.13 2002/06/18 14:20:55 marks Exp marks $
        !             3:  *
        !             4:  * Copyright (c) 2002  RIPE NCC
        !             5:  *
        !             6:  * All Rights Reserved
        !             7:  *
        !             8:  * Permission to use, copy, modify, and distribute this software and its
        !             9:  * documentation for any purpose and without fee is hereby granted,
        !            10:  * provided that the above copyright notice appear in all copies and that
        !            11:  * both that copyright notice and this permission notice appear in
        !            12:  * supporting documentation, and that the name of the author not be
        !            13:  * used in advertising or publicity pertaining to distribution of the
        !            14:  * software without specific, written prior permission.
        !            15:  *
        !            16:  * THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
        !            17:  * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
        !            18:  * AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
        !            19:  * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
        !            20:  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
        !            21:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            22:  *
        !            23:  *
        !            24:  *
        !            25:  * This driver was developed for use with the RIPE NCC TTM project.
        !            26:  *
        !            27:  *
        !            28:  * The initial driver was developed by Daniel Karrenberg <dfk@ripe.net        !            29:  * using the code made available by Trimble. This was for xntpd-3.x.x
        !            30:  *
        !            31:  * Rewrite of the driver for ntpd-4.x.x by Mark Santcroos <marks@ripe.net>
        !            32:  *
        !            33:  */
        !            34: 
        !            35: #ifdef HAVE_CONFIG_H
        !            36: #include <config.h>
        !            37: #endif /* HAVE_CONFIG_H */
        !            38: 
        !            39: #if defined(REFCLOCK) && defined(CLOCK_RIPENCC)
        !            40: 
        !            41: #include "ntp_stdlib.h"
        !            42: #include "ntpd.h"
        !            43: #include "ntp_refclock.h"
        !            44: #include "ntp_unixtime.h"
        !            45: #include "ntp_io.h"
        !            46: 
        !            47: #ifdef HAVE_PPSAPI
        !            48: # include "ppsapi_timepps.h"
        !            49: #endif
        !            50: 
        !            51: /*
        !            52:  * Definitions
        !            53:  */
        !            54: 
        !            55: /* we are on little endian */
        !            56: #define BYTESWAP
        !            57: 
        !            58: /* 
        !            59:  * DEBUG statements: uncomment if necessary
        !            60:  */
        !            61: /* #define DEBUG_NCC */ /* general debug statements */
        !            62: /* #define DEBUG_PPS */ /* debug pps */
        !            63: /* #define DEBUG_RAW */ /* print raw packets */
        !            64: 
        !            65: #define TRIMBLE_OUTPUT_FUNC
        !            66: #define TSIP_VERNUM "7.12a"
        !            67: 
        !            68: #ifndef FALSE
        !            69: #define FALSE  (0)
        !            70: #define TRUE   (!FALSE)
        !            71: #endif /* FALSE */
        !            72: 
        !            73: #define GPS_PI         (3.1415926535898)
        !            74: #define GPS_C          (299792458.)
        !            75: #define        D2R             (GPS_PI/180.0)
        !            76: #define        R2D             (180.0/GPS_PI)
        !            77: #define WEEK   (604800.)
        !            78: #define MAXCHAN  (8)
        !            79: 
        !            80: /* control characters for TSIP packets */
        !            81: #define DLE    (0x10)
        !            82: #define ETX    (0x03)
        !            83: 
        !            84: #define MAX_RPTBUF (256)
        !            85: 
        !            86: /* values of TSIPPKT.status */
        !            87: #define TSIP_PARSED_EMPTY      0
        !            88: #define TSIP_PARSED_FULL       1
        !            89: #define TSIP_PARSED_DLE_1      2
        !            90: #define TSIP_PARSED_DATA       3
        !            91: #define TSIP_PARSED_DLE_2      4
        !            92: 
        !            93: #define UTCF_UTC_AVAIL  (unsigned char) (1)     /* UTC available */
        !            94: #define UTCF_LEAP_SCHD  (unsigned char) (1<<4)  /* Leap scheduled */
        !            95: #define UTCF_LEAP_PNDG  (unsigned char) (1<<5)  /* Leap pending, will occur at end of day */
        !            96: 
        !            97: #define DEVICE  "/dev/gps%d"   /* name of radio device */
        !            98: #define PRECISION       (-9)    /* precision assumed (about 2 ms) */
        !            99: #define PPS_PRECISION   (-20)  /* precision assumed (about 1 us) */
        !           100: #define REFID           "GPS\0" /* reference id */
        !           101: #define REFID_LEN      4
        !           102: #define DESCRIPTION     "RIPE NCC GPS (Palisade)"      /* Description */
        !           103: #define SPEED232        B9600   /* 9600 baud */
        !           104: 
        !           105: #define NSAMPLES        3       /* stages of median filter */
        !           106: 
        !           107: /* Structures */
        !           108: 
        !           109: /* TSIP packets have the following structure, whether report or command. */
        !           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>