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