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