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