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