Annotation of embedaddon/ntp/ntpd/refclock_ripencc.c, revision 1.1.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>