PageRenderTime 71ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/contrib/ntp/ntpd/refclock_ripencc.c

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