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