MRTKLIB 0.7.14
Modernized GNSS Positioning Library
Loading...
Searching...
No Matches
mrtk_rcv_rt17.c
Go to the documentation of this file.
1/*------------------------------------------------------------------------------
2 * mrtk_rcv_rt17.c : Trimble RT17 receiver raw data decoder
3 *
4 * Copyright (C) 2026 H.SHIONO (MRTKLIB Project)
5 * Copyright (C) 2023-2025 Cabinet Office, Japan
6 * Copyright (C) 2024-2025 Lighthouse Technology & Consulting Co. Ltd.
7 * Copyright (C) 2023-2025 Japan Aerospace Exploration Agency
8 * Copyright (C) 2023-2025 TOSHIBA ELECTRONIC TECHNOLOGIES CORPORATION
9 * Copyright (C) 2015- Mitsubishi Electric Corp.
10 * Copyright (C) 2014 Geospatial Information Authority of Japan
11 * Copyright (C) 2014 T.SUZUKI
12 * Copyright (C) 2007-2023 T.TAKASU
13 *
14 * SPDX-License-Identifier: BSD-2-Clause
15 *----------------------------------------------------------------------------*/
16/*
17| Trimble real-time binary data stream and file handler functions.
18|
19| Written in July 2014 by Daniel A. Cook, for inclusion into the RTKLIB library.
20| Copyright (C) 2014, 2016 by Daniel A. Cook. All Rights Reserved.
21|
22| Here we implement four public functions, one for reading Trimble real-time
23| binary data streams and another for reading log files containng data in the
24| same format, a third to initialize RT17 related memory storage and a fourth
25| to free up RT17 related memory storage. This real-time streaming data format,
26| sometimes called RT-17, was designed by Trimble for use by Trimble receivers.
27| Trimble receivers with the "Real-Time Survey Data" or "Binary Outputs" options
28| can output this data. The RT-17 moniker refers to the GPS observables data
29| record (record type 0) itself. There is also a GNSS observables data record
30| (record type 6), which is referred to as RT-27. We also wish to handle RT-27
31| data records, but lack sufficient documentation to do so.
32|
33| Notes:
34|
35| To specify receiver dependent options, set raw->opt to the following case
36| sensitive option strings separated by spaces.
37|
38| Receiver dependent options:
39|
40| -EPHALL : Input all ephemerides
41| -WEEK=n : Explicitly set starting GPS week number
42|
43| Neither the Trimble RT-17 observables packets nor the ION / UTC data packets
44| contain the GPS week number. By default the current computer "now" time is
45| used to determine the GPS week number. This works well in real time, but
46| can be problematic when later converting and/or post processing recorded
47| data. When recording data, also enable either GSOF Position & Time (1) or
48| GSOF Current Time (16) messages on the same serial port along with the
49| RT-17 Real-Time Survey Data output. For best results enable the GSOF
50| message(s) and get them streaming prior to enabling the RT-17 messages.
51|
52| If desired the -WEEK=n option can be specified when converting or post
53| processing recorded data to explicitly set the starting GPS week number.
54| This option overrides anything and everything, including the current
55| computer "now" time and any GSOF or other messages read from the raw
56| data stream or recorded file. Note that the GPS week number explicitly
57| specified with the -WEEK=n option GPS is automatically incremented when
58| and if a subsequent GPS week number rollover occurs in the raw data.
59|
60| In addition to enabling RT-17 Real-Time Survey Data output, it is very
61| helpful to also enable GSOF Position & Time (1) or GSOF Current Time (16)
62| messages on the same serial port. This allows the GPS week number to be
63| determined without using the current computer "now" time or the -WEEK=n
64| option. Although not as important for real-time streaming data use where
65| the current computer "now" time can be used to determine the current GPS
66| week number, it becomes more important when recording files for later
67| conversion and/or post processing. For best results enable the GSOF
68| message(s) and get them streaming prior to enabling the RT-17 messages.
69|
70| Support is provided for the following Trimble RT-17 packet Types:
71|
72| Raw Observation Satellite ION/UTC
73| Format Data Ephemerides Parameters GSOF
74| ------- --------------- ---------------- ---------------- ------------
75| Trimble 0x57 (RAWDATA) 0x55 (RETSVDATA) 0x55 (RETSVDATA) 1, 16,
76| RT-17 Recordtype 0 & 7 Subtype 1 Subtype 3 26, 41
77|
78| When the -WEEK=n option is NOT used, the GPS week number is set from any
79| RAWDATA record type 7 or GENOUT (GSOF) 1, 16, 26, 41 records encountered
80| in the raw data stream. These messages are only used to obtain the GPS
81| WEEK number and are not used for any other purpose.
82|
83| Support is not provided for the GPS L2C or L5 signals. Those would likely
84| require Trimble RT-27 protocol support. Support for that and much more
85| could easily be added by anyone with the required RAWDATA record type
86| 6 documentation.
87|
88| For Trimble GPS receivers which are capable of RT-17 binary output, the
89| receiver and/or receiver configuration software generally provide several
90| RT-17 binary output options:
91|
92| 1. Compact format aka Concise format
93| (RECOMMENDED)
94|
95| This option causes the raw satellite data to be streamed in a more compact
96| format. The compact format does not include L2 DOPPLER observables.
97|
98| 2. Expanded format
99|
100| This is usually the default format if compact format is not enabled. The
101| only advantage of this format over compact format is that L2 DOPPLER
102| observables are output when used in combination with the Real Time
103| Enhancements option. Otherwise this format just consumes more bandwidth
104| and/or file space than compact format while offering no other advantages.
105|
106| 3. Real Time Enhancements, aka Real-time Enhanced format, aka R-T FLAGS
107|
108| This option adds extra data to the raw satellite data output by the
109| receiver. When used in combination with expanded format, L2 DOPPLER
110| observables are output. L2 DOPPLER can be used by RTKLIB.
111|
112| 3. Measurements
113| (REQUIRED)
114|
115| If your configuration has a measurements option, enable it. Measurements
116| are the raw satellite data. If you don't see this option then it is
117| implied and enabled by default.
118|
119| 4. Ephermeris AKA Stream Ephemeris
120| (HIGHLY RECOMMENDED)
121|
122| This option causes satellite ephemerides and UTC / ION data to be streamed
123| along with the raw satellite data. Streamed ephemerides and UTC / ION data
124| consume very little extra bandwidth in the stream and/or space in a file.
125| In most situations with most applications you will need them as well.
126|
127| 5. Positions AKA Stream Positions
128| (NOT RECOMMENDED)
129|
130| Streamed positions are of no use to RTKLIB. They will be ignored. RTKLIB
131| computes positions from the raw satellite data. It has no use for the
132| receiver's position solutions. Streamed positions also consume
133| considerable bandwidth in the stream and/or space in a file.
134|
135| 6. Positions Only
136| (HIGHLY NOT RECOMMENDED)
137|
138| Enabling the positions only option causes only positions and nothing else
139| to be output, including no raw satellite data and no ephemerides and no
140| ION / UTC data.
141|
142| Design notes:
143|
144| This source code handles GPS L1/L2 only. RT-17 is GPS. RT27 is GNSS.
145| If you have RT27 (RAWDATA 57h record type 6) documentation, please
146| forward it to the author.
147|
148| An RT-17 real-time survey data message is a series of RAWDATA (57h,
149| Real-time survey data report) and RETSVDATA (55h, Satellite information
150| report) packets.
151|
152| Each assembled RAWDATA message in an RT-17 packet stream may contain
153| any of the following: Compact Format raw satellite measurements, Expanded
154| Format raw satellite measurements, a receiver computed position or an
155| event mark. Receiver computed positions and event marks are of no
156| interest to RTKLIB, therefore we ignore them.
157|
158| Each RETSVDATA message in an RT-17 packet stream may contain any one
159| of the following: SV flags indicating tracking, a GPS Ephemeris, a GPS
160| Almanac, ION / UTC Data or an Extended GPS Almanac. Of these only
161| the GPS Ephemeris and the ION / UTC Data are of interest to RTKLIB.
162| In practice only GPS Ephemeris and ION / UTC Data are transmitted.
163| Some receivers can be set to transmit them at regular intervals
164| rather than only when they change.
165|
166| Certain simplifying assumptions are made concerning the way in which
167| RAWDATA and GENOUT packets are transmitted in the stream or stored
168| into the file.
169|
170| Therefore it is assumed that:
171|
172| 1. RAWDATA and GENOUT packets are never interleaved or interspersed
173| with packets of other types.
174|
175| 2. The sequence of page frames in a RAWDATA message are transmitted in the
176| stream or stored into a file as packets in order from first to last.
177| RAWDATA page numbers are one based. That is, 1 of n, 2 of n, 3 of n,
178| ..., to 15 of 15 for a total of 15 possible pages. We check for this
179| ordering. RAWDATA messages can therefore reach almost 4K in total
180| length. We check for potential buffer overflows in the input_rt17()
181| function.
182|
183| 3. The Record Interpretation Flags (RIF) field is repeated within the
184| page frame of every page making up a single RAWDATA message. It is
185| assumed that this is redundant and that the actual value of the record
186| interpretation flags does not change from one page to the next within
187| a single RAWDATA message. We check for this too.
188|
189| 4. The sequence of pages in a GENOUT message are transmitted in the
190| stream or stored into a file as packets in order from first to last.
191| GENOUT page numbers are zero based. That is, 0 of n, 1 of n, 2 of n,
192| ..., to 255 of 255 for a total of 256 possible pages. We check for
193| this ordering. GENOUT messages can therefore reach almost 64K in
194| total length. Such a large GENOUT message could exceed our maximum
195| buffer size. We check for potential buffer overflows in the
196| input_rt17() function.
197|
198| This code was tested using RT-17 data output from the following receivers:
199|
200| 1. Trimble 4000SSI, firmware version 7.32
201| 2. Trimble 5700, firmware version 2.32
202| 3. Spectra Precision Epoch 25 Base, firmware version 2.32
203|
204| By convention functions within this source file appear in alphabetical
205| order. Public functions appear as a set first (there are only two of
206| them), followed by private functions as a set. Because of this, forward
207| definitions are required for the private functions. Please keep that
208| in mind when making changes to this source file.
209|
210| References:
211|
212| 1. Trimble Serial Reference Specification, Version 4.82, Revision A,
213| December 2013. Though not being in any way specific to the BD9xx
214| family of receivers, a handy downloadable copy of this document
215| is contained in the "Trimble OEM BD9xx GNSS Receiver Family ICD"
216| document located at <http://www.trimble.com/OEM_ReceiverHelp/
217| v4.85/en/BinaryInterfaceControlDoc.pdf>
218|
219| 2. Trimble General Serial Output Format (GSOF)
220| <http://www.trimble.com/OEM_ReceiverHelp/v4.85/en/GSOFmessages_GSOF.html>
221|
222| 3. ICD-GPS-200C, Interface Control Document, Revision C, 10 October 1993
223| <http://www.gps.gov/technical/icwg/ICD-GPS-200C.pdf>
224|
225| 4. IS-GPS-200H, Interface Specification, 24 September 2013
226| <http://www.gps.gov/technical/icwg/IS-GPS-200H.pdf>
227|
228| 5. RTKLIB Version 2.4.2 Manual, April 29 2013
229| <http://www.rtklib.com/prog/manual_2.4.2.pdf>
230*/
231
232/* Included files: */
233#include <ctype.h>
234#include <math.h>
235#include <stdio.h>
236#include <stdlib.h>
237#include <string.h>
238
239#include "mrtklib/mrtk_bits.h"
240#include "mrtklib/mrtk_eph.h"
241#include "mrtklib/mrtk_mat.h"
242#include "mrtklib/mrtk_nav.h"
243#include "mrtklib/mrtk_obs.h"
244#include "mrtklib/mrtk_rcvraw.h"
245#include "mrtklib/mrtk_rtcm.h"
246#include "mrtklib/mrtk_sys.h"
247#include "mrtklib/mrtk_time.h"
248#include "mrtklib/mrtk_trace.h"
249
250/* Local constants (duplicated from rtklib.h to avoid dependency) */
251#define PI 3.1415926535897932 /* pi */
252#define D2R (PI / 180.0) /* deg to rad */
253#define R2D (180.0 / PI) /* rad to deg */
254#define CLIGHT 299792458.0 /* speed of light (m/s) */
255#define SC2RAD 3.1415926535898 /* semi-circle to radian (IS-GPS) */
256
257#define SYS_NONE 0x00
258#define SYS_GPS 0x01
259#define SYS_SBS 0x02
260#define SYS_GLO 0x04
261#define SYS_GAL 0x08
262#define SYS_QZS 0x10
263#define SYS_CMP 0x20
264#define SYS_IRN 0x40
265
266#define TSYS_GPS 0
267#define TSYS_UTC 1
268#define TSYS_GLO 2
269#define TSYS_GAL 3
270#define TSYS_QZS 4
271#define TSYS_CMP 5
272#define TSYS_IRN 6
273
274#define FREQ1 1.57542E9 /* L1/E1/B1C frequency (Hz) */
275#define FREQ2 1.22760E9 /* L2 frequency (Hz) */
276#define FREQ5 1.17645E9 /* L5/E5a/B2a frequency (Hz) */
277#define FREQ6 1.27875E9 /* E6/L6 frequency (Hz) */
278#define FREQ7 1.20714E9 /* E5b/B2I frequency (Hz) */
279#define FREQ8 1.191795E9 /* E5ab/B2ab frequency (Hz) */
280#define FREQ9 2.492028E9 /* S frequency (Hz) */
281#define FREQ1_GLO 1.60200E9 /* GLONASS G1 base frequency (Hz) */
282#define DFRQ1_GLO 0.56250E6 /* GLONASS G1 bias frequency (Hz/n) */
283#define FREQ2_GLO 1.24600E9 /* GLONASS G2 base frequency (Hz) */
284#define DFRQ2_GLO 0.43750E6 /* GLONASS G2 bias frequency (Hz/n) */
285#define FREQ3_GLO 1.202025E9 /* GLONASS G3 frequency (Hz) */
286#define FREQ1a_GLO 1.600995E9 /* GLONASS G1a frequency (Hz) */
287#define FREQ2a_GLO 1.248060E9 /* GLONASS G2a frequency (Hz) */
288#define FREQ1_CMP 1.561098E9 /* BDS B1I frequency (Hz) */
289
290#define MINPRNGPS 1
291#define MAXPRNGPS 32
292#define MINPRNSBS 120
293#define MAXPRNSBS 158
294
295/* Power-of-2 constants */
296#define P2_5 0.03125
297#define P2_6 0.015625
298#define P2_11 4.882812500000000E-04
299#define P2_15 3.051757812500000E-05
300#define P2_17 7.629394531250000E-06
301#define P2_19 1.907348632812500E-06
302#define P2_20 9.536743164062500E-07
303#define P2_21 4.768371582031250E-07
304#define P2_23 1.192092895507810E-07
305#define P2_24 5.960464477539063E-08
306#define P2_27 7.450580596923828E-09
307#define P2_29 1.862645149230957E-09
308#define P2_30 9.313225746154785E-10
309#define P2_31 4.656612873077393E-10
310#define P2_32 2.328306436538696E-10
311#define P2_33 1.164153218269348E-10
312#define P2_34 5.820766091346740E-11
313#define P2_35 2.910383045673370E-11
314#define P2_38 3.637978807091710E-12
315#define P2_40 9.094947017729280E-13
316#define P2_43 1.136868377216160E-13
317#define P2_46 1.421085471520200E-14
318#define P2_50 8.881784197001252E-16
319#define P2_55 2.775557561562891E-17
320#define P2_59 1.734723475976810E-18
321
322/* Forward declarations for functions in rtklib (resolved at link time) */
323
324/* General purpose flag bits masks: */
325#define M_BIT0 (1 << 0)
326#define M_BIT1 (1 << 1)
327#define M_BIT2 (1 << 2)
328#define M_BIT3 (1 << 3)
329#define M_BIT4 (1 << 4)
330#define M_BIT5 (1 << 5)
331#define M_BIT6 (1 << 6)
332#define M_BIT7 (1 << 7)
333#define M_BIT8 (1 << 8)
334#define M_BIT9 (1 << 9)
335#define M_BIT10 (1 << 10)
336#define M_BIT11 (1 << 11)
337#define M_BIT12 (1 << 12)
338#define M_BIT13 (1 << 13)
339#define M_BIT14 (1 << 14)
340#define M_BIT15 (1 << 15)
341
342/* Constant definitions: */
343#define STX 2 /* Start of packet character */
344#define ETX 3 /* End of packet character */
345#define GENOUT 0x40 /* General Serial Output Format (GSOF) */
346#define RETSVDATA 0x55 /* Satellite information reports */
347#define RAWDATA 0x57 /* Position or real-time survey data report */
348#define MBUFF_LENGTH 8192 /* Message buffer length */
349#define PBUFF_LENGTH (4 + 255 + 2) /* Packet buffer length */
350
351/* Record Interpretation Flags bit masks: */
352#define M_CONCISE M_BIT0 /* Concise format */
353#define M_ENHANCED M_BIT1 /* Enhanced record with real-time flags and IODE information */
354
355/* rt17.flag bit definitions: */
356#define M_WEEK_OPTION M_BIT0 /* GPS week number set by WEEK=n option */
357#define M_WEEK_EPH M_BIT1 /* GPS week number set by ephemeris week */
358#define M_WEEK_TIME M_BIT2 /* GPS week set by computer time */
359#define M_WEEK_SCAN M_BIT3 /* WEEK=n option already looked for, no need to do it again */
360
361/* Data conversion macros: */
362#define I1(p) (*((int8_t*)(p))) /* One byte signed integer */
363#define U1(p) (*((uint8_t*)(p))) /* One byte uint32_teger */
364#define I2(p) ReadI2(p) /* Two byte signed integer */
365#define U2(p) ReadU2(p) /* Two byte uint32_teger */
366#define I4(p) ReadI4(p) /* Four byte signed integer */
367#define U4(p) ReadU4(p) /* Four byte uint32_teger */
368#define R4(p) ReadR4(p) /* IEEE S_FLOAT floating point number */
369#define R8(p) ReadR8(p) /* IEEE T_FLOAT floating point number */
370
371/* Internal structure definitions. */
372typedef union {
373 uint16_t u2;
374 uint8_t c[2];
376
377/* GENOUT 0x40 message types: */
378static const char* GSOFTable[] = {
379 /* 00 */ NULL,
380 /* 01 */ "Position Time",
381 /* 02 */ "Latitude Longitude Height",
382 /* 03 */ "ECEF Position",
383 /* 04 */ "Local Datum LLH Position",
384 /* 05 */ "Local Zone ENU Position",
385 /* 06 */ "ECEF Delta",
386 /* 07 */ "Tangent Plane Delta",
387 /* 08 */ "Velocity Data",
388 /* 09 */ "DOP Information",
389 /* 10 */ "Clock Information",
390 /* 11 */ "Position VCV Information",
391 /* 12 */ "Position Sigma Information",
392 /* 13 */ "SV Brief Information",
393 /* 14 */ "SV Detailed Information",
394 /* 15 */ "Receiver Serial Number",
395 /* 16 */ "Current Time UTC",
396 /* 17 */ NULL,
397 /* 18 */ NULL,
398 /* 19 */ NULL,
399 /* 20 */ NULL,
400 /* 21 */ NULL,
401 /* 22 */ NULL,
402 /* 23 */ NULL,
403 /* 24 */ NULL,
404 /* 25 */ NULL,
405 /* 26 */ "Position Time UTC",
406 /* 27 */ "Attitude Information",
407 /* 28 */ NULL,
408 /* 29 */ NULL,
409 /* 30 */ NULL,
410 /* 31 */ NULL,
411 /* 32 */ NULL,
412 /* 33 */ "All SV Brief Information",
413 /* 34 */ "All SV Detailed Information",
414 /* 35 */ "Received Base Information",
415 /* 36 */ NULL,
416 /* 37 */ "Battery and Memory Information",
417 /* 38 */ NULL,
418 /* 39 */ NULL,
419 /* 40 */ "L-Band Status Information",
420 /* 41 */ "Base Position and Quality Indicator"};
421
422/* RAWDATA 0x57 message types: */
423static const char* RawdataTable[] = {
424 /* 00 */ "Real-time GPS Survey Data, type 17",
425 /* 01 */ "Position Record, type 11",
426 /* 02 */ "Event Mark",
427 /* 03 */ NULL,
428 /* 04 */ NULL,
429 /* 05 */ NULL,
430 /* 06 */ "Real-time GNSS Survey Data, type 27",
431 /* 07 */ "Enhanced Position Record, type 29"};
432
433/* RETSVDATA 0x55 message types: */
434static const char* RetsvdataTable[] = {
435 /* 00 */ "SV Flags",
436 /* 01 */ "GPS Ephemeris",
437 /* 02 */ "GPS Almanac",
438 /* 03 */ "ION / UTC Data",
439 /* 04 */ "Disable Satellite, depreciated",
440 /* 05 */ "Enable Satellite, depreciated",
441 /* 06 */ NULL,
442 /* 07 */ "Extended GPS Almanac",
443 /* 08 */ "GLONASS Almanac",
444 /* 09 */ "GLONASS Ephemeris",
445 /* 10 */ NULL,
446 /* 11 */ "Galileo Ephemeris",
447 /* 12 */ "Galileo Almanac",
448 /* 13 */ NULL,
449 /* 14 */ "QZSS Ephemeris",
450 /* 15 */ NULL,
451 /* 16 */ "QZSS Almanac",
452 /* 17 */ NULL,
453 /* 18 */ NULL,
454 /* 19 */ NULL,
455 /* 20 */ "SV Flags",
456 /* 21 */ "BeiDou Ephemeris",
457 /* 22 */ "BeiDou Almanac"};
458
459/*
460| Typedefs.
461*/
462
463typedef struct { /* RT17 information struct type */
464 uint8_t* MessageBuffer; /* Message buffer */
465 uint8_t* PacketBuffer; /* Packet buffer */
466 double Tow; /* Receive time of week */
467 uint32_t Flags; /* Miscellaneous internal flag bits */
468 uint32_t MessageBytes; /* Number of bytes in message buffer */
469 uint32_t MessageLength; /* Message length (bytes) */
470 uint32_t PacketBytes; /* How many packet bytes have been read so far */
471 uint32_t PacketLength; /* Total size of packet to be read */
472 uint32_t Page; /* Last page number */
473 uint32_t Reply; /* Current reply number */
474 int Week; /* GPS week number */
475} rt17_t;
476
477/*
478| Internal private function forward declarations (in alphabetical order):
479*/
480static int CheckPacketChecksum(uint8_t* PacketBuffer);
481static void ClearMessageBuffer(rt17_t* rt17);
482static void ClearPacketBuffer(rt17_t* rt17);
483static int DecodeBeidouEphemeris(raw_t* Raw);
484static int DecodeGalileoEphemeris(raw_t* Raw);
485static int DecodeGLONASSEphemeris(raw_t* Raw);
486static int DecodeGPSEphemeris(raw_t* Raw);
487static int DecodeGSOF(raw_t* Raw);
488static int DecodeGSOF1(raw_t* Raw, uint8_t* p);
489static int DecodeGSOF3(raw_t* Raw, uint8_t* p);
490static int DecodeGSOF15(raw_t* Raw, uint8_t* p);
491static int DecodeGSOF16(raw_t* Raw, uint8_t* p);
492static int DecodeGSOF26(raw_t* Raw, uint8_t* p);
493static int DecodeGSOF41(raw_t* Raw, uint8_t* p);
494static int DecodeIONAndUTCData(raw_t* Raw);
495static int DecodeQZSSEphemeris(raw_t* Raw);
496static int DecodeRawdata(raw_t* Raw);
497static int DecodeRetsvdata(raw_t* Raw);
498static int DecodeType17(raw_t* Raw, uint32_t rif);
499static int DecodeType29(raw_t* Raw);
500static int GetWeek(raw_t* Raw, double tow);
501static int16_t ReadI2(uint8_t* p);
502static int32_t ReadI4(uint8_t* p);
503static float ReadR4(uint8_t* p);
504static double ReadR8(uint8_t* p);
505static uint16_t ReadU2(uint8_t* p);
506static uint32_t ReadU4(uint8_t* p);
507static void SetWeek(raw_t* Raw, int Week, double tow);
508static int SyncPacket(rt17_t* rt17, uint8_t Data);
509static void UnwrapRawdata(rt17_t* rt17, uint32_t* rif);
510static void UnwrapGenout(rt17_t* rt17);
511
512/* Public functions (in alphabetical order): */
513
514/* free_rt17 - Free up RT17 dependent private storage */
515void free_rt17(raw_t* Raw) {
516 rt17_t* rt17 = NULL;
517
518 if (Raw->format != STRFMT_RT17) {
519 return;
520 }
521
522 if ((rt17 = (rt17_t*)Raw->rcv_data)) {
523 if (rt17->MessageBuffer) {
524 memset(rt17->MessageBuffer, 0, MBUFF_LENGTH);
525 free(rt17->MessageBuffer);
526 rt17->MessageBuffer = NULL;
527 }
528
529 if (rt17->PacketBuffer) {
530 memset(rt17->PacketBuffer, 0, PBUFF_LENGTH);
531 free(rt17->PacketBuffer);
532 rt17->PacketBuffer = NULL;
533 }
534
535 memset(rt17, 0, sizeof(rt17_t));
536 free(rt17);
537 Raw->rcv_data = NULL;
538 }
539}
540
541/* init_rt17 = Initialize RT17 dependent private storage */
542int init_rt17(raw_t* Raw) {
543 rt17_t* rt17 = NULL;
544 uint8_t *MessageBuffer = NULL, *PacketBuffer = NULL;
545
546 if (Raw->format != STRFMT_RT17) {
547 return 0;
548 }
549
550 if (!(rt17 = (rt17_t*)calloc(1, sizeof(rt17_t)))) {
551 tracet(NULL, 0, "RT17: unable to allocate RT17 dependent private data structure.\n");
552 return 0;
553 }
554 Raw->rcv_data = (void*)rt17;
555
556 if (!(MessageBuffer = (uint8_t*)calloc(MBUFF_LENGTH, sizeof(uint8_t)))) {
557 tracet(NULL, 0, "RT17: unable to allocate RT17 message buffer.\n");
558 free_rt17(Raw);
559 return 0;
560 }
561 rt17->MessageBuffer = MessageBuffer;
562
563 if (!(PacketBuffer = (uint8_t*)calloc(PBUFF_LENGTH, sizeof(uint8_t)))) {
564 tracet(NULL, 0, "RT17: unable to allocate RT17 packet buffer.\n");
565 free_rt17(Raw);
566 return 0;
567 }
568 rt17->PacketBuffer = PacketBuffer;
569
570 return 1;
571}
572
573/*
574| input_rt17 - Read an RT-17 mesasge from a raw data stream
575|
576| Returns:
577|
578| -1: error message
579| 0: no message (tells caller to please read more data from the stream)
580| 1: input observation data
581| 2: input ephemeris
582| 9: input ion/utc parameter
583|
584| Each message begins with a 4-byte header, followed by the bytes of data in the packet,
585| and the packet ends with a 2-byte trailer. Byte 3 is set to 0 (00h) when the packet
586| contains no data.
587*/
588int input_rt17(raw_t* Raw, uint8_t Data) {
589 rt17_t* rt17 = (rt17_t*)Raw->rcv_data;
590 uint8_t* MessageBuffer = rt17->MessageBuffer;
591 uint8_t* PacketBuffer = rt17->PacketBuffer;
592 uint32_t Page, Pages, Reply;
593 int Ret = 0;
594
595 /* If no current packet */
596 if (rt17->PacketBytes == 0) {
597 /* Find something that looks like a packet. */
598 if (SyncPacket(rt17, Data)) {
599 /* Found one. */
600 rt17->PacketLength = 4 + PacketBuffer[3] + 2; /* 4 (header) + length + 2 (trailer) */
601 rt17->PacketBytes = 4; /* We now have four bytes in the packet buffer */
602 }
603
604 /* Continue reading the rest of the packet from the stream */
605 return 0;
606 }
607
608 /* Store the next byte of the packet */
609 PacketBuffer[rt17->PacketBytes++] = Data;
610
611 /*
612 | Keep storing bytes into the current packet
613 | until we have what we think are all of them.
614 */
615 if (rt17->PacketBytes < rt17->PacketLength) {
616 return 0;
617 }
618
619 /*
620 | At this point we think have an entire packet.
621 | The prospective packet must end with an ETX.
622 */
623 if (rt17->PacketBuffer[rt17->PacketLength - 1] != ETX) {
624 tracet(NULL, 2, "RT17: Prospective packet did not end with an ETX character. Some data lost.\n");
625 ClearPacketBuffer(rt17);
626 return 0;
627 }
628
629 /*
630 | We do indeed have an entire packet.
631 | Check the packet checksum.
632 */
633 if (!CheckPacketChecksum(PacketBuffer)) {
634 tracet(NULL, 2, "RT17: Packet checksum failure. Packet discarded.\n");
635 ClearPacketBuffer(rt17);
636 return 0;
637 }
638
639 if (Raw->outtype) {
640 sprintf(Raw->msgtype, "RT17 0x%02X (%4d)", PacketBuffer[2], rt17->PacketLength);
641 }
642
643 /* If this is a SVDATA packet, then process it immediately */
644 if (PacketBuffer[2] == RETSVDATA) {
645 Ret = DecodeRetsvdata(Raw);
646 ClearPacketBuffer(rt17);
647 return Ret;
648 }
649
650 /* Accumulate a sequence of RAWDATA packets (pages) */
651 if (PacketBuffer[2] == RAWDATA) {
652 Page = PacketBuffer[5] >> 4;
653 Pages = PacketBuffer[5] & 15;
654 Reply = PacketBuffer[6];
655
656 /*
657 | If this is the first RAWDATA packet in a sequence of RAWDATA packets,
658 | then make sure it's page one and not a packet somewhere in the middle.
659 | If not page one, then skip it and continue reading from the stream
660 | until we find one that starts at page one. Otherwise make sure it is
661 | a part of the same requence of packets as the last one, that it's
662 | page number is in sequence.
663 */
664 if (rt17->MessageBytes == 0) {
665 if (Page != 1) {
666 tracet(NULL, 2, "RT17: First RAWDATA packet is not page #1. Packet discarded.\n");
667 ClearPacketBuffer(rt17);
668 return 0;
669 }
670
671 rt17->Reply = PacketBuffer[6];
672 } else if ((Reply != rt17->Reply) || (Page != (rt17->Page + 1))) {
673 tracet(
674 NULL, 2,
675 "RT17: RAWDATA packet sequence number mismatch or page out of order. %u RAWDATA packets discarded.\n",
676 Page);
677 ClearMessageBuffer(rt17);
678 ClearPacketBuffer(rt17);
679 return 0;
680 }
681
682 /* Check for message buffer overflow */
683 if ((rt17->MessageBytes + rt17->PacketBytes) > MBUFF_LENGTH) {
684 tracet(NULL, 2, "RT17: Buffer would overflow. %u RAWDATA packets discarded.\n", Page);
685 ClearMessageBuffer(rt17);
686 ClearPacketBuffer(rt17);
687 return 0;
688 }
689
690 memcpy(MessageBuffer + rt17->MessageBytes, PacketBuffer, rt17->PacketBytes);
691 rt17->MessageBytes += rt17->PacketBytes;
692 rt17->MessageLength += rt17->PacketLength;
693 ClearPacketBuffer(rt17);
694
695 if (Page == Pages) {
696 Ret = DecodeRawdata(Raw);
697 ClearMessageBuffer(rt17);
698 return Ret;
699 }
700
701 rt17->Page = Page;
702
703 return 0;
704 }
705
706 /* Accumulate a sequence of GENOUT (GSOF) packets (pages) */
707 if (PacketBuffer[2] == GENOUT) {
708 Reply = PacketBuffer[4];
709 Page = PacketBuffer[5];
710 Pages = PacketBuffer[6];
711
712 /*
713 | If this is the first GENOUT packet in a sequence of GENOUT packets,
714 | then make sure it's page zero and not a packet somewhere in the middle.
715 | If not page zero, then skip it and continue reading from the stream
716 | until we find one that starts at page zero. Otherwise make sure it is
717 | a part of the same requence of packets as the last one, that it's
718 | page number is in sequence.
719 */
720 if (rt17->MessageBytes == 0) {
721 if (Page != 0) {
722 tracet(NULL, 3, "RT17: First GENOUT packet is not page #0. Packet discarded.\n");
723 ClearPacketBuffer(rt17);
724 return 0;
725 }
726
727 rt17->Reply = PacketBuffer[4];
728 } else if ((Reply != rt17->Reply) || (Page != (rt17->Page + 1))) {
729 tracet(NULL, 2,
730 "RT17: GENOUT packet sequence number mismatch or page out of order. %u GENOUT packets discarded.\n",
731 Page);
732 ClearMessageBuffer(rt17);
733 ClearPacketBuffer(rt17);
734 return 0;
735 }
736
737 /* Check for message buffer overflow. */
738 if ((rt17->MessageBytes + rt17->PacketBytes) > MBUFF_LENGTH) {
739 tracet(NULL, 2, "RT17: Buffer would overflow. %u GENOUT packets discarded.\n", Page);
740 ClearMessageBuffer(rt17);
741 ClearPacketBuffer(rt17);
742 return 0;
743 }
744
745 memcpy(MessageBuffer + rt17->MessageBytes, PacketBuffer, rt17->PacketBytes);
746 rt17->MessageBytes += rt17->PacketBytes;
747 rt17->MessageLength += rt17->PacketLength;
748 ClearPacketBuffer(rt17);
749
750 if (Page == Pages) {
751 Ret = DecodeGSOF(Raw);
752 ClearMessageBuffer(rt17);
753 return Ret;
754 }
755
756 rt17->Page = Page;
757
758 return 0;
759 }
760
761 /*
762 | If we fall through to here, then the packet is not one that we support
763 | (and hence we can't really even get here). Dump the packet on the floor
764 | and continue reading from the stream.
765 */
766 tracet(NULL, 2, "RT17: Packet is not GENOUT, RAWDATA or RETSVDATA. Packet discarded.\n");
767 ClearPacketBuffer(rt17);
768 return 0;
769}
770
771/*
772| input_rt17f - Read an RT-17 mesasge from a file
773|
774| Returns:
775|
776| -2: End of file (EOF)
777| -1: error message
778| 0: no message
779| 1: input observation data
780| 2: input ephemeris
781| 9: input ion/utc parameter
782*/
783int input_rt17f(raw_t* Raw, FILE* fp) {
784 int i, Data, Ret;
785
786 for (i = 0; i < 4096; i++) {
787 if ((Data = fgetc(fp)) == EOF) {
788 return -2;
789 }
790 if ((Ret = input_rt17(Raw, (uint8_t)Data))) {
791 return Ret;
792 }
793 }
794
795 return 0; /* return at every 4k bytes */
796}
797
798/*
799| Private functions (in alphabetical order):
800*/
801
802/*
803| CheckPacketChecksum - Check the packet checksum
804|
805| The checksum is computed as the modulo 256 (unsigned 8-bit integer) sum
806| of the packet contents starting with the status byte, including the
807| packet type byte, length byte, data bytes and ending with the last byte
808| of the data bytes. It does not include the STX leader, the ETX trailer
809| nor the checksum byte.
810*/
811static int CheckPacketChecksum(uint8_t* PacketBuffer) {
812 uint8_t Checksum = 0;
813 uint8_t* p = &PacketBuffer[1]; /* Starting with status */
814 uint32_t Length = PacketBuffer[3] + 3; /* status, type, length, data */
815
816 /* Compute the packet checksum */
817 while (Length > 0) {
818 Checksum += *p++;
819 Length--;
820 }
821
822 /*
823 | Make sure our computed checksum matches the one at the end of the packet.
824 | (Note that the above loop by design very conveniently left *p pointing
825 | to the checksum byte at the end of the packet.)
826 */
827 return (Checksum == *p);
828}
829
830/* ClearMessageBuffer - Clear the raw data stream buffer */
831static void ClearMessageBuffer(rt17_t* rt17) {
832 uint8_t* MessageBuffer = rt17->MessageBuffer;
833 int i;
834
835 for (i = 0; i < 4; i++) {
836 MessageBuffer[i] = 0;
837 }
838
839 rt17->MessageLength = rt17->MessageBytes = 0;
840 rt17->Reply = 0;
841}
842
843/* ClearPacketBuffer - Clear the packet buffer */
844static void ClearPacketBuffer(rt17_t* rt17) {
845 uint8_t* PacketBuffer = rt17->PacketBuffer;
846 int i;
847
848 for (i = 0; i < 4; i++) {
849 PacketBuffer[i] = 0;
850 }
851
852 rt17->PacketLength = rt17->PacketBytes = 0;
853}
854
855/*
856| DecodeBeidouEphemeris - Decode a Beidou Ephemeris record
857|
858| Returns:
859|
860| -1: error message
861| 2: input ephemeris
862|
863| See reference #1 above for documentation of the RETSVDATA Beidou Ephemeris.
864*/
865static int DecodeBeidouEphemeris(raw_t* Raw) {
866 tracet(NULL, 3, "DecodeBeidouEphemeris(); not yet implemented.\n");
867 return 0;
868
869#if 0
870 rt17_t *rt17 = (rt17_t*) Raw->rcv_data;
871 uint8_t *p = rt17->PacketBuffer;
872 int prn, sat, toc, tow;
873 uint32_t Flags, toe;
874 double sqrtA;
875 eph_t eph={0};
876 tracet(NULL,3, "RT17: DecodeBeidouEphemeris(); Length=%d\n", rt17->PacketLength);
877 if (rt17->PacketLength < 182)
878 {
879 tracet(NULL,2, "RT17: RETSVDATA packet length %d < 182 bytes. GPS ephemeris packet discarded.\n", rt17->PacketLength);
880 return -1;
881 }
882 prn = U1(p+5);
883 if (!(sat=satno(SYS_CMP, prn)))
884 {
885 tracet(NULL,2, "RT17: Beidou ephemeris satellite number error, PRN=%d.\n", prn);
886 return -1;
887 }
888
889 eph.week = U2(p+6); /* 006-007: Ephemeris Week number (weeks) */
890 eph.iodc = U2(p+8); /* 008-009: IODC */
891 /* Reserved byte */ /* 010-010: RESERVED */
892 eph.iode = U1(p+11); /* 011-011: IODE */
893 tow = I4(p+12); /* 012-015: TOW */
894 toc = I4(p+16); /* 016-019: TOC (seconds) */
895 toe = U4(p+20); /* 020-023: TOE (seconds) */
896 eph.tgd[0]= R8(p+24); /* 024-031: TGD (seconds) */
897 eph.f2 = R8(p+32); /* 032-029: AF2 (seconds/seconds^2) */
898 eph.f1 = R8(p+40); /* 040-047: AF1 (seconds/seconds) */
899 eph.f0 = R8(p+48); /* 048-055: AF0 (seconds) */
900 eph.crs = R8(p+56); /* 056-063: CRS (meters) */
901 eph.deln = R8(p+64); /* 064-071: DELTA N (semi-circles/second) */
902 eph.M0 = R8(p+72); /* 072-079: M SUB 0 (semi-circles) */
903 eph.cuc = R8(p+80); /* 080-087: CUC (semi-circles) */
904 eph.e = R8(p+88); /* 088-095: ECCENTRICITY (dimensionless) */
905 eph.cus = R8(p+96); /* 096-103: CUS (semi-circles) */
906 sqrtA = R8(p+104); /* 104-111: SQRT A (meters ^ 0.5) */
907 eph.cic = R8(p+112); /* 112-119: CIC (semi-circles) */
908 eph.OMG0 = R8(p+120); /* 120-127: OMEGA SUB 0 (semi-circles) */
909 eph.cis = R8(p+128); /* 128-135: CIS (semi-circlces) */
910 eph.i0 = R8(p+136); /* 136-143: I SUB 0 (semi-circles) */
911 eph.crc = R8(p+144); /* 144-151: CRC (meters) */
912 eph.omg = R8(p+152); /* 152-159: OMEGA (semi-circles?) */
913 eph.OMGd = R8(p+160); /* 160-167: OMEGA DOT (semi-circles/second) */
914 eph.idot = R8(p+168); /* 168-175: I DOT (semi-circles/second) */
915 Flags = U4(p+176); /* 176-179: FLAGS */
916
917 /*
918 | Multiply these by PI to make semi-circle units into radian units for RTKLIB.
919 */
920 eph.deln *= SC2RAD;
921 eph.i0 *= SC2RAD;
922 eph.idot *= SC2RAD;
923 eph.M0 *= SC2RAD;
924 eph.omg *= SC2RAD;
925 eph.OMG0 *= SC2RAD;
926 eph.OMGd *= SC2RAD;
927 /*
928 | As specifically directed to do so by Reference #1, multiply these by PI.
929 | to make semi-circle units into radian units, which is what RTKLIB needs.
930 */
931 eph.cic *= SC2RAD;
932 eph.cis *= SC2RAD;
933 eph.cuc *= SC2RAD;
934 eph.cus *= SC2RAD;
935
936 /*
937 | Select the correct curve fit interval as per ICD-GPS-200 sections
938 | 20.3.3.4.3.1 and 20.3.4.4 using IODC, fit flag and Table 20-XII.
939 */
940 if (Flags & M_BIT10) /* Subframe 2, word 10, bit 17 (fit flag) */
941 {
942 if ((eph.iodc >= 240) && (eph.iodc <= 247))
943 eph.fit = 8;
944 else if (((eph.iodc >= 248) && (eph.iodc <= 255)) || (eph.iodc == 496))
945 eph.fit = 14;
946 else if ((eph.iodc >= 497) && (eph.iodc <= 503))
947 eph.fit = 26;
948 else if ((eph.iodc >= 504) && (eph.iodc <= 510))
949 eph.fit = 50;
950 else if ((eph.iodc == 511) || ((eph.iodc >= 752) && (eph.iodc <= 756)))
951 eph.fit = 74;
952 else if ((eph.iodc >= 757) && (eph.iodc <= 763))
953 eph.fit = 98;
954 else if (((eph.iodc >= 764) && (eph.iodc <= 767)) || ((eph.iodc >= 1008) && (eph.iodc <= 1010)))
955 eph.fit = 122;
956 else if ((eph.iodc >= 1011) && (eph.iodc <= 1020))
957 eph.fit = 146;
958 else
959 eph.fit = 6;
960 }
961 else
962 eph.fit = 4;
963
964 eph.flag = (Flags & M_BIT0); /* Subframe 1, word 4, bit 1, Data flag for L2 P-code */
965 eph.code = (Flags >> 1) & 3; /* Subframe 1, word 3, bits 11-12, Codes on L2 channel */
966 eph.svh = (Flags >> 4) & 127; /* Subframe 1, word 3, bits 17-22, SV health from ephemeris */
967 eph.sva = (Flags >> 11) & 15; /* Subframe 1, word 3, bits 13-16, User Range Accuracy index */
968 eph.A = sqrtA * sqrtA;
969 eph.toes = toe;
970 eph.toc = bdt2gpst(bdt2time(eph.week, toc));
971 eph.toe = bdt2gpst(bdt2time(eph.week, toe));
972 eph.ttr = bdt2gpst(bdt2time(eph.week, tow));
973 tracet(NULL,3, "RT17: DecodeBeidouEphemeris(); SAT=%d, IODC=%d, IODE=%d, WEEK=%d.\n", sat, eph.iodc, eph.iode, eph.week);
974 if (!strstr(Raw->opt,"-EPHALL"))
975 {
976 if (eph.iode == Raw->nav.eph[sat-1].iode)
977 return 0; /* unchanged */
978 }
979 eph.sat = sat;
980 Raw->nav.eph[sat-1] = eph;
981 Raw->ephsat = sat;
982 return 2;
983#endif
984}
985
986/*
987| DecodeGalileoEphemeris - Decode a Galileo Ephemeris record
988|
989| Returns:
990|
991| -1: error message
992| 2: input ephemeris
993|
994| See reference #1 above for documentation of the RETSVDATA Galileo Ephemeris.
995*/
997 tracet(NULL, 3, "DecodeGalileoEphemeris(); not yet implemented.\n");
998 return 0;
999
1000#if 0
1001 rt17_t *rt17 = (rt17_t*) Raw->rcv_data;
1002 uint8_t *p = rt17->PacketBuffer;
1003 int prn, sat, toc, tow;
1004 uint32_t toe;
1005 double sqrtA;
1006 eph_t eph={0};
1007 uint8_t SISA, MODEL1, MODEL2;
1008 uint16_t IODnav, HSDVS;
1009 double BDG1, BDG2;
1010 tracet(NULL,3, "RT17: DecodeGalileoEphemeris(); Length=%d\n", rt17->PacketLength);
1011 if (rt17->PacketLength < 190)
1012 {
1013 tracet(NULL,2, "RT17: RETSVDATA packet length %d < 190 bytes. Galileo ephemeris packet discarded.\n", rt17->PacketLength);
1014 return -1;
1015 }
1016 prn = U1(p+5);
1017 if (!(sat=satno(SYS_GAL, prn)))
1018 {
1019 tracet(NULL,2, "RT17: Galileo ephemeris satellite number error, PRN=%d.\n", prn);
1020 return -1;
1021 }
1022
1023 eph.code = U1(p+6); /* 006-006: Data source 0:E1B 1:E5B 2:E5A */
1024 eph.week = U2(p+7); /* 007-008: Ephemeris Week number (weeks) */
1025 tow = I4(p+9); /* 008-012: TOW */
1026 IODnav = U2(p+13); /* 013-014: Ephemeris and clock correction issue of data */
1027 toe = U4(p+15); /* 015-018: TOE (seconds) */
1028 eph.crs = R8(p+19); /* 019-026: CRS (meters) */
1029 eph.deln = R8(p+27); /* 027-034: DELTA N (semi-circles/second) */
1030 eph.M0 = R8(p+35); /* 035-042: M SUB 0 (semi-circles) */
1031 eph.cuc = R8(p+43); /* 043-050: CUC (semi-circles) */
1032 eph.e = R8(p+51); /* 051-058: ECCENTRICITY (dimensionless) */
1033 eph.cus = R8(p+59); /* 059-066: CUS (semi-circles) */
1034 sqrtA = R8(p+67); /* 067-074: SQRT A (meters ^ 0.5) */
1035 eph.cic = R8(p+75); /* 075-082: CIC (semi-circles) */
1036 eph.OMG0 = R8(p+83); /* 083-090: OMEGA SUB 0 (semi-circles) */
1037 eph.cis = R8(p+91); /* 091-098: CIS (semi-circlces) */
1038 eph.i0 = R8(p+99); /* 099-106: I SUB 0 (semi-circles) */
1039 eph.crc = R8(p+107); /* 107-114: CRC (meters) */
1040 eph.omg = R8(p+115); /* 115-122: OMEGA (semi-circles?) */
1041 eph.OMGd = R8(p+123); /* 123-130: OMEGA DOT (semi-circles/second) */
1042 eph.idot = R8(p+131); /* 131-138: I DOT (semi-circles/second) */
1043 SISA = U1(p+149); /* 149-149: ? */
1044 HSDVS = U2(p+150); /* 150-151: Signal Health Flag */
1045 toc = I4(p+142); /* 142-145: TOC (seconds) */
1046 eph.f0 = R8(p+146); /* 146-153: AF0 (seconds) */
1047 eph.f1 = R8(p+154); /* 154-161: AF1 (seconds/seconds) */
1048 eph.f2 = R8(p+162); /* 162-169: AF2 (seconds/seconds^2) */
1049 BDG1 = R8(p+170); /* 170-177: Seconds */
1050 MODEL1 = U1(p+178); /* 178-178: Clock model for TOC/AF0?2/BGD1 */
1051 BDG2 = R8(p+179); /* 179-186: Seconds */
1052 MODEL2 = U1(p+187); /* 187-187: Clock model for BGD2 */
1053 /*
1054 | Multiply these by PI to make semi-circle units into radian units for RTKLIB.
1055 */
1056 eph.deln *= SC2RAD;
1057 eph.i0 *= SC2RAD;
1058 eph.idot *= SC2RAD;
1059 eph.M0 *= SC2RAD;
1060 eph.omg *= SC2RAD;
1061 eph.OMG0 *= SC2RAD;
1062 eph.OMGd *= SC2RAD;
1063 /*
1064 | As specifically directed to do so by Reference #1, multiply these by PI.
1065 | to make semi-circle units into radian units, which is what RTKLIB needs.
1066 */
1067 eph.cic *= SC2RAD;
1068 eph.cis *= SC2RAD;
1069 eph.cuc *= SC2RAD;
1070 eph.cus *= SC2RAD;
1071
1072 eph.A = sqrtA * sqrtA;
1073 eph.toes = toe;
1074 eph.toc = gst2time(eph.week, toc);
1075 eph.toe = gst2time(eph.week, toe);
1076 eph.ttr = gst2time(eph.week, tow);
1077 tracet(NULL,3, "RT17: DecodeGalileoEphemeris(); SAT=%d, IODC=%d, IODE=%d, WEEK=%d.\n", sat, eph.iodc, eph.iode, eph.week);
1078 if (!strstr(Raw->opt,"-EPHALL"))
1079 {
1080 if (eph.iode == Raw->nav.eph[sat-1].iode)
1081 return 0; /* unchanged */
1082 }
1083 eph.sat = sat;
1084 Raw->nav.eph[sat-1] = eph;
1085 Raw->ephsat = sat;
1086 return 2;
1087#endif
1088}
1089
1090/*
1091| DecodeGLONASSEphemeris - Decode a GLONASS Ephemeris record
1092|
1093| Returns:
1094|
1095| -1: error message
1096| 2: input ephemeris
1097|
1098| See reference #1 above for documentation of the RETSVDATA GLONASS Ephemeris.
1099*/
1101 tracet(NULL, 3, "DecodeGLONASSEphemeris(); not yet implemented.\n");
1102 return 0;
1103}
1104
1105/*
1106| DecodeGPSEphemeris - Decode a GPS Ephemeris record
1107|
1108| Returns:
1109|
1110| -1: error message
1111| 2: input ephemeris
1112|
1113| See ICD-GPS-200C.PDF for documentation of the GPS satellite ephemeris.
1114| See reference #1 above for documentation of the RETSVDATA GPS Ephemeris.
1115*/
1116static int DecodeGPSEphemeris(raw_t* Raw) {
1117 rt17_t* rt17 = (rt17_t*)Raw->rcv_data;
1118 uint8_t* p = rt17->PacketBuffer;
1119 int prn, sat, toc, tow;
1120 uint32_t Flags, toe;
1121 double sqrtA;
1122 eph_t eph = {0};
1123
1124 tracet(NULL, 3, "RT17: DecodeGPSEphemeris(); Length=%d\n", rt17->PacketLength);
1125
1126 if (rt17->PacketLength < 182) {
1127 tracet(NULL, 2, "RT17: RETSVDATA packet length %d < 182 bytes. GPS ephemeris packet discarded.\n",
1128 rt17->PacketLength);
1129 return -1;
1130 }
1131
1132 prn = U1(p + 5);
1133
1134 if (!(sat = satno(SYS_GPS, prn))) {
1135 tracet(NULL, 2, "RT17: GPS ephemeris satellite number error, PRN=%d.\n", prn);
1136 return -1;
1137 }
1138
1139 eph.week = U2(p + 6); /* 006-007: Ephemeris Week number (weeks) */
1140 eph.iodc = U2(p + 8); /* 008-009: IODC */
1141 /* Reserved byte */ /* 010-010: RESERVED */
1142 eph.iode = U1(p + 11); /* 011-011: IODE */
1143 tow = I4(p + 12); /* 012-015: TOW */
1144 toc = I4(p + 16); /* 016-019: TOC (seconds) */
1145 toe = U4(p + 20); /* 020-023: TOE (seconds) */
1146 eph.tgd[0] = R8(p + 24); /* 024-031: TGD (seconds) */
1147 eph.f2 = R8(p + 32); /* 032-029: AF2 (seconds/seconds^2) */
1148 eph.f1 = R8(p + 40); /* 040-047: AF1 (seconds/seconds) */
1149 eph.f0 = R8(p + 48); /* 048-055: AF0 (seconds) */
1150 eph.crs = R8(p + 56); /* 056-063: CRS (meters) */
1151 eph.deln = R8(p + 64); /* 064-071: DELTA N (semi-circles/second) */
1152 eph.M0 = R8(p + 72); /* 072-079: M SUB 0 (semi-circles) */
1153 eph.cuc = R8(p + 80); /* 080-087: CUC (semi-circles) */
1154 eph.e = R8(p + 88); /* 088-095: ECCENTRICITY (dimensionless) */
1155 eph.cus = R8(p + 96); /* 096-103: CUS (semi-circles) */
1156 sqrtA = R8(p + 104); /* 104-111: SQRT A (meters ^ 0.5) */
1157 eph.cic = R8(p + 112); /* 112-119: CIC (semi-circles) */
1158 eph.OMG0 = R8(p + 120); /* 120-127: OMEGA SUB 0 (semi-circles) */
1159 eph.cis = R8(p + 128); /* 128-135: CIS (semi-circlces) */
1160 eph.i0 = R8(p + 136); /* 136-143: I SUB 0 (semi-circles) */
1161 eph.crc = R8(p + 144); /* 144-151: CRC (meters) */
1162 eph.omg = R8(p + 152); /* 152-159: OMEGA (semi-circles?) */
1163 eph.OMGd = R8(p + 160); /* 160-167: OMEGA DOT (semi-circles/second) */
1164 eph.idot = R8(p + 168); /* 168-175: I DOT (semi-circles/second) */
1165 Flags = U4(p + 176); /* 176-179: FLAGS */
1166
1167 /*
1168 | Multiply these by PI to make ICD specified semi-circle units into radian
1169 | units for RTKLIB.
1170 */
1171 eph.deln *= SC2RAD;
1172 eph.i0 *= SC2RAD;
1173 eph.idot *= SC2RAD;
1174 eph.M0 *= SC2RAD;
1175 eph.omg *= SC2RAD;
1176 eph.OMG0 *= SC2RAD;
1177 eph.OMGd *= SC2RAD;
1178
1179 /*
1180 | As specifically directed to do so by Reference #1, multiply these by PI.
1181 | to make semi-circle units into radian units, which is what ICD-GPS-200C
1182 | calls for and also what RTKLIB needs.
1183 */
1184 eph.cic *= SC2RAD;
1185 eph.cis *= SC2RAD;
1186 eph.cuc *= SC2RAD;
1187 eph.cus *= SC2RAD;
1188
1189 /*
1190 | Select the correct curve fit interval as per ICD-GPS-200 sections
1191 | 20.3.3.4.3.1 and 20.3.4.4 using IODC, fit flag and Table 20-XII.
1192 */
1193 if (Flags & M_BIT10) /* Subframe 2, word 10, bit 17 (fit flag) */
1194 {
1195 if ((eph.iodc >= 240) && (eph.iodc <= 247)) {
1196 eph.fit = 8;
1197 } else if (((eph.iodc >= 248) && (eph.iodc <= 255)) || (eph.iodc == 496)) {
1198 eph.fit = 14;
1199 } else if ((eph.iodc >= 497) && (eph.iodc <= 503)) {
1200 eph.fit = 26;
1201 } else if ((eph.iodc >= 504) && (eph.iodc <= 510)) {
1202 eph.fit = 50;
1203 } else if ((eph.iodc == 511) || ((eph.iodc >= 752) && (eph.iodc <= 756))) {
1204 eph.fit = 74;
1205 } else if ((eph.iodc >= 757) && (eph.iodc <= 763)) {
1206 eph.fit = 98;
1207 } else if (((eph.iodc >= 764) && (eph.iodc <= 767)) || ((eph.iodc >= 1008) && (eph.iodc <= 1010))) {
1208 eph.fit = 122;
1209 } else if ((eph.iodc >= 1011) && (eph.iodc <= 1020)) {
1210 eph.fit = 146;
1211 } else {
1212 eph.fit = 6;
1213 }
1214 } else {
1215 eph.fit = 4;
1216 }
1217
1218 eph.flag = (Flags & M_BIT0); /* Subframe 1, word 4, bit 1, Data flag for L2 P-code */
1219 eph.code = (Flags >> 1) & 3; /* Subframe 1, word 3, bits 11-12, Codes on L2 channel */
1220 eph.svh = (Flags >> 4) & 127; /* Subframe 1, word 3, bits 17-22, SV health from ephemeris */
1221 eph.sva = (Flags >> 11) & 15; /* Subframe 1, word 3, bits 13-16, User Range Accuracy index */
1222
1223 eph.A = sqrtA * sqrtA;
1224
1225 eph.toes = toe;
1226 eph.toc = gpst2time(eph.week, toc);
1227 eph.toe = gpst2time(eph.week, toe);
1228 eph.ttr = gpst2time(eph.week, tow);
1229
1230 tracet(NULL, 3, "RT17: DecodeGPSEphemeris(); SAT=%d, IODC=%d, IODE=%d, WEEK=%d.\n", sat, eph.iodc, eph.iode,
1231 eph.week);
1232
1233 if (rt17->Week && (rt17->Week != eph.week)) {
1234 tracet(NULL, 2, "RT17: Currently set or assumed GPS week does not match received ephemeris week.\n");
1235 tracet(NULL, 2, "RT17: Set or assumed GPS week: %d Received ephemeris week: %d\n", rt17->Week, eph.week);
1236 }
1237
1238 if (!(rt17->Flags & M_WEEK_OPTION)) {
1239 if (!rt17->Week || (rt17->Flags & M_WEEK_TIME) || (eph.week > rt17->Week)) {
1240 if (!rt17->Week) {
1241 tracet(NULL, 2, "RT17: Initial GPS WEEK number unknown; WEEK number %d assumed for now.\n", eph.week);
1242 } else {
1243 tracet(NULL, 2, "RT17: Changing assumed week number from %d to %d.\n", rt17->Week, eph.week);
1244 }
1245 rt17->Flags &= ~M_WEEK_TIME;
1246 rt17->Flags |= M_WEEK_EPH;
1247 rt17->Week = eph.week;
1248 }
1249 }
1250
1251 if (!strstr(Raw->opt, "-EPHALL")) {
1252 if (eph.iode == Raw->nav.eph[sat - 1].iode) {
1253 return 0; /* unchanged */
1254 }
1255 }
1256
1257 eph.sat = sat;
1258 Raw->nav.eph[sat - 1] = eph;
1259 Raw->ephsat = sat;
1260
1261 return 2;
1262}
1263
1264/* DecodeGSOF - Decode a General Serial Output Format (GSOF) message */
1265static int DecodeGSOF(raw_t* Raw) {
1266 rt17_t* rt17 = (rt17_t*)Raw->rcv_data;
1267 int InputLength, Ret = 0;
1268 uint8_t RecordLength, RecordType, *p;
1269 char* RecordType_s = NULL;
1270
1271 /*
1272 | Reassemble origional message by removing packet headers,
1273 | trailers and page framing.
1274 */
1275 UnwrapGenout(rt17);
1276
1277 p = rt17->MessageBuffer;
1278 InputLength = rt17->MessageLength;
1279
1280 while (InputLength) {
1281 RecordType = p[0];
1282 RecordLength = p[1];
1283
1284 if (RecordType < (sizeof(GSOFTable) / sizeof(char*))) {
1285 RecordType_s = (char*)GSOFTable[RecordType];
1286 }
1287
1288 if (!RecordType_s) {
1289 RecordType_s = "Unknown";
1290 }
1291
1292 tracet(NULL, 3, "RT17: Trimble packet type=0x40 (GENOUT), GSOF record type=%d (%s), Length=%d.\n", RecordType,
1293 RecordType_s, RecordLength);
1294
1295 /* Process (or possibly ignore) the message */
1296 switch (RecordType) {
1297 case 1:
1298 Ret = DecodeGSOF1(Raw, p);
1299 break;
1300 case 3:
1301 Ret = DecodeGSOF3(Raw, p);
1302 break;
1303 case 15:
1304 Ret = DecodeGSOF15(Raw, p);
1305 break;
1306 case 16:
1307 Ret = DecodeGSOF16(Raw, p);
1308 break;
1309 case 26:
1310 Ret = DecodeGSOF26(Raw, p);
1311 break;
1312 case 41:
1313 Ret = DecodeGSOF41(Raw, p);
1314 break;
1315 default:
1316 tracet(NULL, 3, "RT17: GSOF message not processed.\n");
1317 }
1318
1319 RecordLength += 2;
1320 p += RecordLength;
1321 InputLength -= RecordLength;
1322 }
1323
1324 return Ret;
1325}
1326
1327/* DecodeGSOF1 - Decode a Position Time GSOF message */
1328static int DecodeGSOF1(raw_t* Raw, uint8_t* p) {
1329 if (p[1] < 6) {
1330 tracet(NULL, 2, "RT17: GSOF Position Time message record length %d < 6 bytes. Record discarded.\n", p[1]);
1331 } else {
1332 SetWeek(Raw, I2(p + 6), ((double)I4(p + 2)) * 0.001);
1333 }
1334
1335 return 0;
1336}
1337
1338/* DecodeGSOF3 - Decode an ECEF Position GSOF message */
1339static int DecodeGSOF3(raw_t* Raw, uint8_t* p) {
1340 sta_t* sta = &Raw->sta;
1341
1342 if (p[1] < 24) {
1343 tracet(NULL, 2, "RT17: GSOF ECEF Position record length %d < 24 bytes. Record discarded.\n", p[1]);
1344 } else {
1345 sta->pos[0] = R8(p + 2);
1346 sta->pos[1] = R8(p + 10);
1347 sta->pos[2] = R8(p + 18);
1348 sta->del[0] = 0.0;
1349 sta->del[1] = 0.0;
1350 sta->del[2] = 0.0;
1351 sta->hgt = 0.0;
1352 sta->deltype = 0; /* e/n/u */
1353 }
1354
1355 return 5;
1356}
1357
1358/* DecodeGSOF15 - Decode a Receiver Serial Number GSOF message */
1359static int DecodeGSOF15(raw_t* Raw, uint8_t* p) {
1360 if (p[1] < 15) {
1361 tracet(NULL, 2, "RT17: GSOF Receiver Serial Number record length %d < 15 bytes. Record discarded.\n", p[1]);
1362 } else {
1363 sprintf(Raw->sta.recsno, "%u", U4(p + 2));
1364 }
1365
1366 return 0;
1367}
1368
1369/* DecodeGSOF16 - Decode a Current Time GSOF message */
1370static int DecodeGSOF16(raw_t* Raw, uint8_t* p) {
1371 if (p[1] < 9) {
1372 tracet(NULL, 2, "RT17: GSOF Current Time message record length %d < 9 bytes. Record discarded.\n", p[1]);
1373 } else if (U1(p + 10) & M_BIT0) { /* If week and milliseconds of week are valid */
1374 SetWeek(Raw, I2(p + 6), ((double)I4(p + 2)) * 0.001);
1375 }
1376
1377 return 0;
1378}
1379
1380/* DecodeGSOF26 - Decode a Position Time UTC GSOF message */
1381static int DecodeGSOF26(raw_t* Raw, uint8_t* p) {
1382 if (p[1] < 6) {
1383 tracet(NULL, 2, "RT17: GSOF Position Time UTC message record length %d < 6 bytes. Record discarded.\n", p[1]);
1384 } else {
1385 SetWeek(Raw, I2(p + 6), ((double)I4(p + 2)) * 0.001);
1386 }
1387
1388 return 0;
1389}
1390
1391/* DecodeGSOF41 - Decode a Base Position and Quality Indicator GSOF message */
1392static int DecodeGSOF41(raw_t* raw, uint8_t* p) {
1393 if (p[1] < 6) {
1394 tracet(NULL, 2,
1395 "RT17: GSOF Base Position and Quality Indicator message record length %d < 6 bytes. Record discarded.\n",
1396 p[1]);
1397 } else {
1398 SetWeek(raw, I2(p + 6), ((double)I4(p + 2)) * 0.001);
1399 }
1400
1401 return 0;
1402}
1403
1404/*
1405| DecodeIONAndUTCData - Decode an ION / UTC data record
1406|
1407| Returns:
1408|
1409| -1: error message
1410| 9: input ion/utc parameter|
1411|
1412| See ICD-GPS-200C.PDF for documetation of GPS ION / UTC data.
1413| See reference #1 above for documentation of RETSVDATA and ION / UTC data.
1414*/
1415static int DecodeIONAndUTCData(raw_t* Raw) {
1416 rt17_t* rt17 = (rt17_t*)Raw->rcv_data;
1417 int week;
1418 uint8_t* p = rt17->PacketBuffer;
1419 nav_t* nav = &Raw->nav;
1420 double* ion_gps = nav->ion_gps;
1421 double* utc_gps = nav->utc_gps;
1422
1423 tracet(NULL, 3, "RT17: DecodeIONAndUTCData, Length=%d.\n", rt17->PacketLength);
1424
1425 if (rt17->PacketLength < 129) {
1426 tracet(NULL, 2, "RT17: RETSVDATA packet length %d < 129 bytes. GPS ION / UTC data packet discarded.\n",
1427 rt17->PacketLength);
1428 return -1;
1429 }
1430
1431 /* ION / UTC data does not have the current GPS week number. Punt! */
1432 week = GetWeek(Raw, 0.0);
1433
1434 ion_gps[0] = R8(p + 6); /* 006-013: ALPHA 0 (seconds) */
1435 ion_gps[1] = R8(p + 14); /* 014-021: ALPHA 1 (seconds/semi-circle) */
1436 ion_gps[2] = R8(p + 22); /* 022-029: ALPHA 2 (seconds/semi-circle)^2 */
1437 ion_gps[3] = R8(p + 30); /* 030-037: ALPHA 3 (seconds/semi-circle)^3 */
1438 ion_gps[4] = R8(p + 38); /* 038-045: BETA 0 (seconds) */
1439 ion_gps[5] = R8(p + 46); /* 046-053: BETA 1 (seconds/semi-circle) */
1440 ion_gps[6] = R8(p + 54); /* 054-061: BETA 2 (seconds/semi-circle)^2 */
1441 ion_gps[7] = R8(p + 62); /* 062-069: BETA 3 (seconds/semi-circle)^3 */
1442 utc_gps[0] = R8(p + 70); /* 070-077: ASUB0 (seconds)*/
1443 utc_gps[1] = R8(p + 78); /* 078-085: ASUB1 (seconds/seconds) */
1444 utc_gps[2] = R8(p + 86); /* 086-093: TSUB0T */
1445 utc_gps[3] = week;
1446 utc_gps[4] = R8(p + 94); /* 094-101: DELTATLS (seconds) */
1447 /* Unused by RTKLIB R8 */ /* 102-109: DELTATLSF */
1448 /* Unused by RTKLIB R8 */ /* 110-117: IONTIME */
1449 /* Unused by RTKLIB U1 */ /* 118-118: WNSUBT */
1450 /* Unused by RTKLIB U1 */ /* 119-119: WNSUBLSF */
1451 /* Unused by RTKLIB U1 */ /* 120-120: DN */
1452 /* Reserved six bytes */ /* 121-126: RESERVED */
1453
1454 return 9;
1455}
1456
1457/*
1458| DecodeQZSSEphemeris - Decode a QZSS Ephemeris record
1459|
1460| Returns:
1461|
1462| -1: error message
1463| 2: input ephemeris
1464|
1465| See reference #1 above for documentation of the RETSVDATA QZSS Ephemeris.
1466*/
1467static int DecodeQZSSEphemeris(raw_t* Raw) {
1468 tracet(NULL, 3, "DecodeQZSSEphemeris(); not yet implemented.\n");
1469 return 0;
1470
1471#if 0
1472 rt17_t *rt17 = (rt17_t*) Raw->rcv_data;
1473 uint8_t *p = rt17->PacketBuffer;
1474 int prn, sat, toc, tow;
1475 uint32_t Flags, toe;
1476 double sqrtA;
1477 eph_t eph={0};
1478 tracet(NULL,3, "RT17: DecodeQZSSEphemeris(); Length=%d\n", rt17->PacketLength);
1479 if (rt17->PacketLength < 184)
1480 {
1481 tracet(NULL,2, "RT17: RETSVDATA packet length %d < 184 bytes. QZSS ephemeris packet discarded.\n", rt17->PacketLength);
1482 return -1;
1483 }
1484 prn = U1(p+5);
1485 if (!(sat=satno(SYS_GPS, prn)))
1486 {
1487 tracet(NULL,2, "RT17: QZSS ephemeris satellite number error, PRN=%d.\n", prn);
1488 return -1;
1489 }
1490
1491 /* Not used by RTKLIB 006-006: Source: 0:L1CA 1:L1C 2:L2C 3:L5 */
1492 eph.week = U2(p+8); /* 008-009: Ephemeris Week number (weeks) */
1493 eph.iodc = U2(p+10); /* 010-011: IODC */
1494 /* Reserved byte 012-012: RESERVED */
1495 eph.iode = U1(p+13); /* 013-013: IODE */
1496 tow = I4(p+14); /* 014-017: TOW */
1497 toc = I4(p+18); /* 018-021: TOC (seconds) */
1498 toe = U4(p+22); /* 022-025: TOE (seconds) */
1499 eph.tgd[0]= R8(p+26); /* 026-033: TGD (seconds) */
1500 eph.f2 = R8(p+34); /* 034-041: AF2 (seconds/seconds^2) */
1501 eph.f1 = R8(p+42); /* 042-049: AF1 (seconds/seconds) */
1502 eph.f0 = R8(p+50); /* 050-057: AF0 (seconds) */
1503 eph.crs = R8(p+58); /* 058-065: CRS (meters) */
1504 eph.deln = R8(p+66); /* 066-073: DELTA N (semi-circles/second) */
1505 eph.M0 = R8(p+74); /* 074-081: M SUB 0 (semi-circles) */
1506 eph.cuc = R8(p+82); /* 082-089: CUC (semi-circles) */
1507 eph.e = R8(p+90); /* 090-097: ECCENTRICITY (dimensionless) */
1508 eph.cus = R8(p+98); /* 098-105: CUS (semi-circles) */
1509 sqrtA = R8(p+106); /* 106-113: SQRT A (meters ^ 0.5) */
1510 eph.cic = R8(p+114); /* 114-121: CIC (semi-circles) */
1511 eph.OMG0 = R8(p+122); /* 122-129: OMEGA SUB 0 (semi-circles) */
1512 eph.cis = R8(p+130); /* 130-137: CIS (semi-circlces) */
1513 eph.i0 = R8(p+138); /* 138-145: I SUB 0 (semi-circles) */
1514 eph.crc = R8(p+146); /* 146-153: CRC (meters) */
1515 eph.omg = R8(p+154); /* 154-161: OMEGA (semi-circles?) */
1516 eph.OMGd = R8(p+162); /* 162-169: OMEGA DOT (semi-circles/second) */
1517 eph.idot = R8(p+170); /* 170-177: I DOT (semi-circles/second) */
1518 Flags = U4(p+178); /* 178-181: FLAGS */
1519
1520 /*
1521 | Multiply these by PI to make ICD specified semi-circle units into radian
1522 | units for RTKLIB.
1523 */
1524 eph.deln *= SC2RAD;
1525 eph.i0 *= SC2RAD;
1526 eph.idot *= SC2RAD;
1527 eph.M0 *= SC2RAD;
1528 eph.omg *= SC2RAD;
1529 eph.OMG0 *= SC2RAD;
1530 eph.OMGd *= SC2RAD;
1531 /*
1532 | As specifically directed to do so by Reference #1, multiply these by PI.
1533 | to make semi-circle units into radian units, which is what ICD-GPS-200C
1534 | calls for and also what RTKLIB needs.
1535 */
1536 eph.cic *= SC2RAD;
1537 eph.cis *= SC2RAD;
1538 eph.cuc *= SC2RAD;
1539 eph.cus *= SC2RAD;
1540
1541 /*
1542 | Select the correct curve fit interval as per ICD-GPS-200 sections
1543 | 20.3.3.4.3.1 and 20.3.4.4 using IODC, fit flag and Table 20-XII.
1544 */
1545 if (Flags & M_BIT10) /* Subframe 2, word 10, bit 17 (fit flag) */
1546 {
1547 if ((eph.iodc >= 240) && (eph.iodc <= 247))
1548 eph.fit = 8;
1549 else if (((eph.iodc >= 248) && (eph.iodc <= 255)) || (eph.iodc == 496))
1550 eph.fit = 14;
1551 else if ((eph.iodc >= 497) && (eph.iodc <= 503))
1552 eph.fit = 26;
1553 else if ((eph.iodc >= 504) && (eph.iodc <= 510))
1554 eph.fit = 50;
1555 else if ((eph.iodc == 511) || ((eph.iodc >= 752) && (eph.iodc <= 756)))
1556 eph.fit = 74;
1557 else if ((eph.iodc >= 757) && (eph.iodc <= 763))
1558 eph.fit = 98;
1559 else if (((eph.iodc >= 764) && (eph.iodc <= 767)) || ((eph.iodc >= 1008) && (eph.iodc <= 1010)))
1560 eph.fit = 122;
1561 else if ((eph.iodc >= 1011) && (eph.iodc <= 1020))
1562 eph.fit = 146;
1563 else
1564 eph.fit = 6;
1565 }
1566 else
1567 eph.fit = 4;
1568
1569 eph.flag = (Flags & M_BIT0); /* Subframe 1, word 4, bit 1, Data flag for L2 P-code */
1570 eph.code = (Flags >> 1) & 3; /* Subframe 1, word 3, bits 11-12, Codes on L2 channel */
1571 eph.svh = (Flags >> 4) & 127; /* Subframe 1, word 3, bits 17-22, SV health from ephemeris */
1572 eph.sva = (Flags >> 11) & 15; /* Subframe 1, word 3, bits 13-16, User Range Accuracy index */
1573 eph.A = sqrtA * sqrtA;
1574 eph.toes = toe;
1575 eph.toc = gpst2time(eph.week, toc);
1576 eph.toe = gpst2time(eph.week, toe);
1577 eph.ttr = gpst2time(eph.week, tow);
1578 tracet(NULL,3, "RT17: DecodeQZSSEphemeris(); SAT=%d, IODC=%d, IODE=%d, WEEK=%d.\n", sat, eph.iodc, eph.iode, eph.week);
1579 if (!strstr(Raw->opt,"-EPHALL"))
1580 {
1581 if (eph.iode == Raw->nav.eph[sat-1].iode)
1582 return 0; /* unchanged */
1583 }
1584 eph.sat = sat;
1585 Raw->nav.eph[sat-1] = eph;
1586 Raw->ephsat = sat;
1587 return 2;
1588#endif
1589}
1590
1591/*
1592| DecodeRawdata - Decode an RAWDATA packet sequence
1593|
1594| Returns:
1595|
1596| -1: error message
1597| 0: no message (tells caller to please read more data from the stream)
1598| 1: input observation data
1599*/
1600static int DecodeRawdata(raw_t* Raw) {
1601 rt17_t* rt17 = (rt17_t*)Raw->rcv_data;
1602 uint8_t* MessageBuffer = rt17->MessageBuffer;
1603 int Ret = 0;
1604 uint32_t rif;
1605 char* RecordType_s = NULL;
1606 uint8_t RecordType = MessageBuffer[4];
1607
1608 if (RecordType < (sizeof(RawdataTable) / sizeof(char*))) {
1609 RecordType_s = (char*)RawdataTable[RecordType];
1610 }
1611
1612 if (!RecordType_s) {
1613 RecordType_s = "Unknown";
1614 }
1615
1616 tracet(NULL, 3, "RT17: Trimble packet type=0x57 (RAWDATA), Recordtype=%d (%s), Length=%d.\n", RecordType,
1617 RecordType_s, rt17->MessageLength);
1618
1619 /*
1620 | Reassemble origional message by removing packet headers,
1621 | trailers and page framing.
1622 */
1623 UnwrapRawdata(rt17, &rif);
1624
1625 /* Process (or possibly ignore) the message */
1626 switch (RecordType) {
1627 case 0:
1628 Ret = DecodeType17(Raw, rif);
1629 break;
1630 case 7:
1631 Ret = DecodeType29(Raw);
1632 break;
1633 default:
1634 tracet(NULL, 3, "RT17: Packet not processed.\n");
1635 }
1636
1637 return Ret;
1638}
1639
1640/*
1641| DecodeRetsvdata - Decode an SVDATA packet
1642|
1643| Returns:
1644|
1645| -1: error message
1646| 0: no message (tells caller to please read more data from the stream)
1647| 2: input ephemeris
1648| 9: input ion/utc parameter
1649*/
1650static int DecodeRetsvdata(raw_t* Raw) {
1651 rt17_t* rt17 = (rt17_t*)Raw->rcv_data;
1652 uint8_t* PacketBuffer = rt17->PacketBuffer;
1653 int Ret = 0;
1654 char* Subtype_s = NULL;
1655 uint8_t Subtype = PacketBuffer[4];
1656
1657 if (Subtype < (sizeof(RetsvdataTable) / sizeof(char*))) {
1658 Subtype_s = (char*)RetsvdataTable[Subtype];
1659 }
1660
1661 if (!Subtype_s) {
1662 Subtype_s = "Unknown";
1663 }
1664
1665 tracet(NULL, 3, "RT17: Trimble packet type=0x55 (RETSVDATA), Subtype=%d (%s), Length=%d.\n", Subtype, Subtype_s,
1666 rt17->PacketLength);
1667
1668 /* Process (or possibly ignore) the message */
1669 switch (Subtype) {
1670 case 1:
1671 Ret = DecodeGPSEphemeris(Raw);
1672 break;
1673 case 3:
1674 Ret = DecodeIONAndUTCData(Raw);
1675 break;
1676 case 9:
1677 Ret = DecodeGLONASSEphemeris(Raw);
1678 break;
1679 case 11:
1680 Ret = DecodeGalileoEphemeris(Raw);
1681 break;
1682 case 14:
1683 Ret = DecodeQZSSEphemeris(Raw);
1684 break;
1685 case 21:
1686 Ret = DecodeBeidouEphemeris(Raw);
1687 break;
1688 default:
1689 tracet(NULL, 3, "RT17: Packet not processed.\n");
1690 }
1691
1692 return Ret;
1693}
1694
1695/*
1696| DecodeType17 - Decode Real-Time survey data (record type 17)
1697|
1698| Returns:
1699|
1700| -1: error message
1701| 0: no message (tells caller to please read more data from the stream)
1702| 1: input observation data
1703|
1704| Handles expanded and concise formats with and without enhanced record data.
1705*/
1706static int DecodeType17(raw_t* Raw, uint32_t rif) {
1707 rt17_t* rt17 = (rt17_t*)Raw->rcv_data;
1708 uint8_t* p = rt17->MessageBuffer;
1709 double ClockOffset, tow;
1710 int Flags1, Flags2, FlagStatus, i, n, nsat, prn, Week;
1711 gtime_t Time;
1712 obsd_t* obs;
1713
1714 tow = R8(p) * 0.001;
1715 p += 8; /* Receive time within the current GPS week. */
1716 ClockOffset = R8(p) * 0.001;
1717 p += 8; /* Clock offset value. 0.0 = not known */
1718
1719#if 0
1720 tow += ClockOffset;
1721#endif
1722
1723 /* The observation data does not have the current GPS week number. Punt! */
1724 Week = GetWeek(Raw, tow);
1725 Time = gpst2time(Week, tow);
1726
1727 nsat = U1(p);
1728 p++; /* Number of SV data blocks in the record */
1729
1730 for (i = n = 0; (i < nsat) && (i < MAXOBS); i++) {
1731 obs = &Raw->obs.data[n];
1732 memset(obs, 0, sizeof(obsd_t));
1733 obs->time = Time;
1734
1735 if (rif & M_CONCISE) {
1736 /* Satellite number (1-32). */
1737 prn = U1(p);
1738 p++;
1739
1740 /* These indicate what data is loaded, is valid, etc */
1741 Flags1 = U1(p);
1742 p++;
1743 Flags2 = U1(p);
1744 p++;
1745
1746 /* These are not needed by RTKLIB */
1747 p++; /* I1 Satellite Elevation Angle (degrees) */
1748 p += 2; /* I2 Satellite Azimuth (degrees) */
1749
1750 if (Flags1 & M_BIT6) /* L1 data valid */
1751 {
1752 /* Measure of L1 signal strength (dB * 4) */
1753 obs->SNR[0] = (uint16_t)(U1(p) * 0.25 / SNR_UNIT + 0.5);
1754 p++;
1755
1756 /* Full L1 C/A code or P-code pseudorange (meters) */
1757 obs->P[0] = R8(p);
1758 p += 8;
1759
1760 /* L1 Continuous Phase (cycles) */
1761 if (Flags1 & M_BIT4) { /* L1 phase valid */
1762 obs->L[0] = -R8(p);
1763 }
1764 p += 8;
1765
1766 /* L1 Doppler (Hz) */
1767 obs->D[0] = R4(p);
1768 p += 4;
1769 }
1770
1771 if (Flags1 & M_BIT0) /* L2 data loaded */
1772 {
1773 /* Measure of L2 signal strength (dB * 4) */
1774 obs->SNR[1] = (uint16_t)(U1(p) * 0.25 / SNR_UNIT + 0.5);
1775 p++;
1776
1777 /* L2 Continuous Phase (cycles) */
1778 if (Flags1 & M_BIT5) {
1779 obs->L[1] = -R8(p);
1780 }
1781 p += 8;
1782
1783 /* L2 P-Code or L2 Encrypted Code */
1784 if (Flags1 & M_BIT5) { /* L2 range valid */
1785 obs->P[1] = obs->P[0] + R4(p);
1786 }
1787 p += 4;
1788 }
1789
1790 /*
1791 | We can't use the IODE flags in this context.
1792 | We already have slip flags and don't need slip counters.
1793 */
1794 if (rif & M_ENHANCED) {
1795 p++; /* U1 IODE, Issue of Data Ephemeris */
1796 p++; /* U1 L1 cycle slip roll-over counter */
1797 p++; /* U1 L2 cycle slip roll-over counter */
1798 }
1799 } else /* Expanded Format */
1800 {
1801 /* Satellite number (1-32) */
1802 prn = U1(p);
1803 p++;
1804
1805 /* These indicate what data is loaded, is valid, etc */
1806 Flags1 = U1(p);
1807 p++;
1808 Flags2 = U1(p);
1809 p++;
1810
1811 /* Indicates whether FLAGS1 bit 6 and FLAGS2 are valid */
1812 FlagStatus = U1(p);
1813 p++;
1814
1815 /* These are not needed by RTKLIB */
1816 p += 2; /* I2 Satellite Elevation Angle (degrees) */
1817 p += 2; /* I2 Satellite Azimuth (degrees) */
1818
1819 /*
1820 | FLAG STATUS bit 0 set = Bit 6 of FLAGS1 and bit 0-7 of FLAGS2 are valid.
1821 | FLAG STATUS bit 0 clear = Bit 6 of FLAGS1 and bit 0-7 of FLAGS2 are UNDEFINED.
1822 |
1823 | According to reference #1 above, this bit should ALWAYS be set
1824 | for RAWDATA. If this bit is not set, then we're lost and cannot
1825 | process this message any further.
1826 */
1827 if (!(FlagStatus & M_BIT0)) { /* Flags invalid */
1828 return 0;
1829 }
1830
1831 if (Flags1 & M_BIT6) /* L1 data valid */
1832 {
1833 /* Measure of satellite signal strength (dB) */
1834 obs->SNR[0] = (uint16_t)(R8(p) / SNR_UNIT + 0.5);
1835 p += 8;
1836
1837 /* Full L1 C/A code or P-code pseudorange (meters) */
1838 obs->P[0] = R8(p);
1839 p += 8;
1840
1841 /* L1 Continuous Phase (cycles) */
1842 if (Flags1 & M_BIT4) { /* L1 phase valid */
1843 obs->L[0] = -R8(p);
1844 }
1845 p += 8;
1846
1847 /* L1 Doppler (Hz) */
1848 obs->D[0] = R8(p);
1849 p += 8;
1850
1851 /* Reserved 8 bytes */
1852 p += 8;
1853 }
1854
1855 if (Flags1 & M_BIT0) /* L2 data loaded */
1856 {
1857 /* Measure of L2 signal strength (dB) */
1858 obs->SNR[1] = (uint16_t)(R8(p) / SNR_UNIT + 0.5);
1859 p += 8;
1860
1861 /* L2 Continuous Phase (cycles) */
1862 if (Flags1 & M_BIT5) { /* L2 phase valid */
1863 obs->L[1] = -R8(p);
1864 }
1865 p += 8;
1866
1867 /* L2 P-Code or L2 Encrypted Code */
1868 if (Flags1 & M_BIT5) { /* L2 pseudorange valid */
1869 obs->P[1] = obs->P[0] + R8(p);
1870 }
1871 p += 8;
1872 }
1873
1874 if (rif & M_ENHANCED) {
1875 /*
1876 | We can't use the IODE flags in this context.
1877 | We already have slip flags and don't need slip counters.
1878 */
1879 p++; /* U1 IODE, Issue of Data Ephemeris */
1880 p++; /* U1 L1 cycle slip roll-over counter */
1881 p++; /* U1 L2 cycle slip roll-over counter */
1882 p++; /* U1 Reserved byte */
1883
1884 /* L2 Doppler (Hz) */
1885 obs->D[1] = R8(p);
1886 p += 8;
1887 }
1888 }
1889
1890 if (obs->P[0] == 0.0) {
1891 obs->code[0] = CODE_NONE;
1892 } else if (Flags2 & M_BIT0) {
1893 obs->code[0] = CODE_L1P;
1894 } else {
1895 obs->code[0] = CODE_L1C;
1896 }
1897
1898 if (obs->P[1] == 0.0) {
1899 obs->code[1] = CODE_NONE;
1900 } else if (Flags2 & M_BIT2) {
1901 obs->code[1] = CODE_L2W;
1902 } else if (Flags2 & M_BIT1) {
1903 obs->code[1] = CODE_L2P;
1904 } else {
1905 obs->code[1] = CODE_L2C;
1906 }
1907
1908 if (Flags1 & M_BIT1) {
1909 obs->LLI[0] |= 1; /* L1 cycle slip */
1910 }
1911
1912 if (Flags1 & M_BIT2) {
1913 obs->LLI[1] |= 1; /* L2 cycle slip */
1914 }
1915 if ((Flags2 & M_BIT2) && (obs->P[1] != 0.0)) {
1916 obs->LLI[1] |= 4; /* Tracking encrypted code */
1917 }
1918
1919 if (!(obs->sat = satno(SYS_GPS, prn))) {
1920 tracet(NULL, 2, "RT17: Satellite number error, PRN=%d.\n", prn);
1921 continue;
1922 }
1923
1924#if 0
1925 /* Apply clock offset to observables */
1926 if (ClockOffset != 0.0)
1927 {
1928 obs->P[0] += ClockOffset * (CLIGHT/FREQ1);
1929 obs->P[1] += ClockOffset * (CLIGHT/FREQ2);
1930 obs->L[0] += ClockOffset * FREQ1;
1931 obs->L[1] += ClockOffset * FREQ2;
1932 }
1933#endif
1934 n++;
1935 }
1936
1937 Raw->time = Time;
1938 Raw->obs.n = n;
1939
1940 if (n > 0) {
1941 tracet(NULL, 2, "RT17: Observations output:\n");
1942 traceobs(NULL, 2, Raw->obs.data, Raw->obs.n);
1943 }
1944
1945 return (n > 0);
1946}
1947
1948/* DecodeType29 - Decode Enhanced position (record type 29) */
1949static int DecodeType29(raw_t* Raw) {
1950 rt17_t* rt17 = (rt17_t*)Raw->rcv_data;
1951 uint8_t* p = rt17->MessageBuffer;
1952
1953 if (*p < 7) {
1954 tracet(NULL, 2, "RT17: Enhanced Position record block #1 length %d < 7 bytes. Record discarded.\n", *p);
1955 } else {
1956 SetWeek(Raw, I2(p + 1), ((double)I4(p + 3)) * 0.001);
1957 }
1958
1959 return 0;
1960}
1961
1962/*
1963| GetWeek - Get GPS week number
1964|
1965| Returns: GPS week number
1966|
1967| The -WEEK=n initial week option overrides everything else.
1968| Week rollover and increment from the initial week and
1969| subsequent weeks is handled.
1970*/
1971static int GetWeek(raw_t* Raw, double Tow) {
1972 rt17_t* rt17 = (rt17_t*)Raw->rcv_data;
1973 int Week = 0;
1974
1975 if (rt17->Flags & M_WEEK_OPTION) {
1976 if ((Tow && rt17->Tow) && (Tow < rt17->Tow)) {
1977 tracet(NULL, 2, "RT17: GPS WEEK rolled over from %d to %d.\n", rt17->Week, rt17->Week + 1);
1978 rt17->Week++;
1979 }
1980
1981 if (Tow != 0.0) {
1982 rt17->Tow = Tow;
1983 }
1984 } else if (!(rt17->Flags & M_WEEK_SCAN)) {
1985 char* opt = strstr(Raw->opt, "-WEEK=");
1986
1987 rt17->Flags |= M_WEEK_SCAN;
1988
1989 if (opt) {
1990 if (!sscanf(opt + 6, "%d", &Week) || (Week <= 0)) {
1991 tracet(NULL, 0, "RT17: Invalid -WEEK=n receiver option value.\n");
1992 } else {
1993 rt17->Week = Week;
1994 rt17->Flags |= M_WEEK_OPTION;
1995 tracet(NULL, 2, "RT17: Initial GPS WEEK explicitly set to %d by user.\n", Week, Week);
1996 }
1997 }
1998 }
1999
2000 Week = rt17->Week;
2001
2002 if (!Week && !(rt17->Flags & (M_WEEK_OPTION | M_WEEK_EPH))) {
2003 if ((Raw->time.time == 0) && (Raw->time.sec == 0.0)) {
2004 Raw->time = timeget();
2005 }
2006
2007 time2gpst(Raw->time, &Week);
2008
2009 if (Tow != 0.0) {
2010 Raw->time = gpst2time(Week, Tow);
2011 }
2012
2013 rt17->Week = Week;
2014 rt17->Flags |= M_WEEK_TIME;
2015 tracet(NULL, 2, "RT17: Initial GPS WEEK number unknown; WEEK number %d assumed for now.\n", Week);
2016 }
2017
2018 return Week;
2019}
2020
2021/* ReadI2 - Fetch & convert a signed two byte integer (short) */
2022static int16_t ReadI2(uint8_t* p) {
2023 union I2 {
2024 int16_t i2;
2025 uint8_t c[2];
2026 } u;
2027 ENDIAN_TEST et;
2028
2029 memcpy(&u.i2, p, sizeof(u.i2));
2030
2031 et.u2 = 0;
2032 et.c[0] = 1;
2033 if (et.u2 == 1) {
2034 uint8_t t;
2035 t = u.c[0];
2036 u.c[0] = u.c[1];
2037 u.c[1] = t;
2038 }
2039 return u.i2;
2040}
2041
2042/* ReadI4 - Fetch & convert a four byte signed integer (int) */
2043static int32_t ReadI4(uint8_t* p) {
2044 union i4 {
2045 int32_t i4;
2046 uint8_t c[4];
2047 } u;
2048 ENDIAN_TEST et;
2049
2050 memcpy(&u.i4, p, sizeof(u.i4));
2051
2052 et.u2 = 0;
2053 et.c[0] = 1;
2054 if (et.u2 == 1) {
2055 uint8_t t;
2056 t = u.c[0];
2057 u.c[0] = u.c[3];
2058 u.c[3] = t;
2059 t = u.c[1];
2060 u.c[1] = u.c[2];
2061 u.c[2] = t;
2062 }
2063 return u.i4;
2064}
2065
2066/* ReadR4 - Fetch & convert an IEEE S_FLOAT (float) */
2067static float ReadR4(uint8_t* p) {
2068 union R4 {
2069 float f;
2070 uint32_t u4;
2071 } u;
2072 u.u4 = U4(p);
2073 return u.f;
2074}
2075
2076/* ReadR8 - Fetch & convert an IEEE T_FLOAT (double) */
2077static double ReadR8(uint8_t* p) {
2078 ENDIAN_TEST et;
2079 union R8 {
2080 double d;
2081 uint8_t c[8];
2082 } u;
2083
2084 memcpy(&u.d, p, sizeof(u.d));
2085
2086 et.u2 = 0;
2087 et.c[0] = 1;
2088 if (et.u2 == 1) {
2089 uint8_t t;
2090 t = u.c[0];
2091 u.c[0] = u.c[7];
2092 u.c[7] = t;
2093 t = u.c[1];
2094 u.c[1] = u.c[6];
2095 u.c[6] = t;
2096 t = u.c[2];
2097 u.c[2] = u.c[5];
2098 u.c[5] = t;
2099 t = u.c[3];
2100 u.c[3] = u.c[4];
2101 u.c[4] = t;
2102 }
2103 return u.d;
2104}
2105
2106/* ReadU2 - Fetch & convert an unsigned twe byte integer (uint16_t) */
2107static uint16_t ReadU2(uint8_t* p) {
2108 ENDIAN_TEST et;
2109 union U2 {
2110 uint16_t u2;
2111 uint8_t c[2];
2112 } u;
2113
2114 memcpy(&u.u2, p, sizeof(u.u2));
2115
2116 et.u2 = 0;
2117 et.c[0] = 1;
2118 if (et.u2 == 1) {
2119 uint8_t t;
2120 t = u.c[0];
2121 u.c[0] = u.c[1];
2122 u.c[1] = t;
2123 }
2124 return u.u2;
2125}
2126
2127/* ReadU4 - Fetch & convert a four byte uint32_teger (uint32_t) */
2128static uint32_t ReadU4(uint8_t* p) {
2129 ENDIAN_TEST et;
2130 union U4 {
2131 uint32_t u4;
2132 uint8_t c[4];
2133 } u;
2134
2135 memcpy(&u.u4, p, sizeof(u.u4));
2136
2137 et.u2 = 0;
2138 et.c[0] = 1;
2139 if (et.u2 == 1) {
2140 uint8_t t;
2141 t = u.c[0];
2142 u.c[0] = u.c[3];
2143 u.c[3] = t;
2144 t = u.c[1];
2145 u.c[1] = u.c[2];
2146 u.c[2] = t;
2147 }
2148 return u.u4;
2149}
2150
2151/*
2152| SetWeek - Set GPS week number
2153|
2154| The -WEEK=n initial week option overrides us.
2155*/
2156static void SetWeek(raw_t* Raw, int Week, double Tow) {
2157 rt17_t* rt17 = (rt17_t*)Raw->rcv_data;
2158
2159 if (!(rt17->Flags & M_WEEK_OPTION)) {
2160 if (rt17->Week) {
2161 if (Week != rt17->Week) {
2162 if (Week == (rt17->Week + 1)) {
2163 tracet(NULL, 2, "RT17: GPS WEEK rolled over from %d to %d.\n", rt17->Week, Week);
2164 } else {
2165 tracet(NULL, 2, "RT17: GPS WEEK changed from %d to %d.\n", rt17->Week, Week);
2166 }
2167 }
2168 } else {
2169 tracet(NULL, 2, "RT17: GPS WEEK initially set to %d.\n", Week);
2170 }
2171
2172 rt17->Week = Week;
2173 }
2174
2175 /* Also update the time if we can */
2176 if (Week && (Tow != 0.0)) {
2177 Raw->time = gpst2time(Week, Tow);
2178 }
2179}
2180
2181/* SyncPacket - Synchronize the raw data stream to the start of a series of RT-17 packets */
2182static int SyncPacket(rt17_t* rt17, uint8_t Data) {
2183 uint8_t Type, *PacketBuffer = rt17->PacketBuffer;
2184
2185 PacketBuffer[0] = PacketBuffer[1];
2186 PacketBuffer[1] = PacketBuffer[2];
2187 PacketBuffer[2] = PacketBuffer[3];
2188 PacketBuffer[3] = Data;
2189
2190 Type = PacketBuffer[2];
2191
2192 /*
2193 | Byte 0 must be an STX character.
2194 | Byte 1 = status byte which we always ignore (for now).
2195 | Byte 2 = packet type which must be GENOUT (0x40) RAWDATA (0x57) or RETSVDATA (0x55) (for now).
2196 | Byte 3 = data length which must be non-zero for any packet we're interested in.
2197 */
2198 return ((PacketBuffer[0] == STX) && (Data != 0) && ((Type == GENOUT) || (Type == RAWDATA) || (Type == RETSVDATA)));
2199}
2200
2201/*
2202| UnwrapGenout - Reassemble GENOUT message by removing packet headers, trailers and page framing
2203|
2204| The GENOUT message is broken up on _arbitrary byte boundries_ into
2205| pages of no more than 246 bytes each, then wrapped with page frames,
2206| packet headers and packet trailers. We reassemble the original message
2207| so that it is uninterrupted by removing the extraneous packet headers,
2208| trailers and page framing.
2209*/
2210static void UnwrapGenout(rt17_t* rt17) {
2211 uint8_t* p_in = rt17->MessageBuffer;
2212 uint8_t* p_out = p_in;
2213 uint32_t InputLength, InputLengthTotal = rt17->MessageLength;
2214 uint32_t OutputLength, OutputLengthTotal = 0;
2215
2216 while (InputLengthTotal > 0) {
2217 InputLength = p_in[3] + 6;
2218 OutputLength = p_in[3] - 3;
2219 memmove(p_out, p_in + 7, OutputLength);
2220 p_in += InputLength;
2221 p_out += OutputLength;
2222 OutputLengthTotal += OutputLength;
2223 InputLengthTotal -= InputLength;
2224 }
2225 rt17->MessageBytes = rt17->MessageLength = OutputLengthTotal;
2226}
2227
2228/*
2229| UnwrapRawdata - Reassemble message by removing packet headers, trailers and page framing
2230|
2231| The RAWDATA message is broken up on _arbitrary byte boundries_ into
2232| pages of no more than 244 bytes each, then wrapped with page frames,
2233| packet headers and packet trailers. We reassemble the original message
2234| so that it is uninterrupted by removing the extraneous packet headers,
2235| trailers and page framing.
2236|
2237| While we're at it we also check to make sure the Record Interpretation
2238| Flags are consistent. They should be the same in every page frame.
2239*/
2240static void UnwrapRawdata(rt17_t* rt17, uint32_t* rif) {
2241 uint8_t* p_in = rt17->MessageBuffer;
2242 uint8_t* p_out = p_in;
2243 uint32_t InputLength, InputLengthTotal = rt17->MessageLength;
2244 uint32_t OutputLength, OutputLengthTotal = 0;
2245
2246 *rif = p_in[7];
2247
2248 while (InputLengthTotal > 0) {
2249 if ((uint32_t)p_in[7] != *rif) {
2250 tracet(NULL, 2, "RT17: Inconsistent Record Interpretation Flags within a single RAWDATA message.\n");
2251 }
2252
2253 InputLength = p_in[3] + 6;
2254 OutputLength = p_in[3] - 4;
2255 memmove(p_out, p_in + 8, OutputLength);
2256 p_in += InputLength;
2257 p_out += OutputLength;
2258 OutputLengthTotal += OutputLength;
2259 InputLengthTotal -= InputLength;
2260 }
2261 rt17->MessageBytes = rt17->MessageLength = OutputLengthTotal;
2262}
MRTKLIB Bits Module — Binary bit operations and CRC functions.
#define CLIGHT
Definition mrtk_coords.c:41
#define SYS_GPS
Definition mrtk_eph.c:65
#define SYS_CMP
Definition mrtk_eph.c:70
#define SYS_GAL
Definition mrtk_eph.c:68
MRTKLIB Broadcast Ephemeris Module — Satellite orbit/clock types and Kepler/GLONASS/SBAS orbit comput...
struct nav_s nav_t
Definition mrtk_eph.h:40
#define SNR_UNIT
#define MAXOBS
#define CODE_L2P
#define CODE_L1C
#define CODE_L2C
#define CODE_NONE
#define CODE_L2W
#define CODE_L1P
MRTKLIB Matrix Module — Matrix/vector operations and estimation.
int satno(int sys, int prn)
Convert satellite system+prn/slot number to satellite number.
Definition mrtk_nav.c:58
MRTKLIB Navigation Module — Navigation data types and satellite/nav utility functions.
#define FREQ2
Definition mrtk_obs.c:68
#define FREQ1
Definition mrtk_obs.c:67
MRTKLIB Observation Module — Observation data types and utility functions.
static float ReadR4(uint8_t *p)
#define R8(p)
static int DecodeGPSEphemeris(raw_t *Raw)
void free_rt17(raw_t *Raw)
#define U1(p)
#define M_CONCISE
int input_rt17f(raw_t *Raw, FILE *fp)
#define M_WEEK_SCAN
#define M_BIT5
static int DecodeGSOF3(raw_t *Raw, uint8_t *p)
int init_rt17(raw_t *Raw)
static int DecodeQZSSEphemeris(raw_t *Raw)
static int DecodeType17(raw_t *Raw, uint32_t rif)
static double ReadR8(uint8_t *p)
static int CheckPacketChecksum(uint8_t *PacketBuffer)
static const char * GSOFTable[]
static int DecodeGSOF(raw_t *Raw)
#define U4(p)
static void UnwrapRawdata(rt17_t *rt17, uint32_t *rif)
#define M_BIT6
static int DecodeGSOF15(raw_t *Raw, uint8_t *p)
static int DecodeRetsvdata(raw_t *Raw)
#define I4(p)
static int DecodeIONAndUTCData(raw_t *Raw)
static void UnwrapGenout(rt17_t *rt17)
static int DecodeGLONASSEphemeris(raw_t *Raw)
static int GetWeek(raw_t *Raw, double tow)
static int DecodeType29(raw_t *Raw)
static void ClearMessageBuffer(rt17_t *rt17)
#define M_BIT10
#define M_BIT1
#define M_BIT2
#define M_WEEK_TIME
static uint32_t ReadU4(uint8_t *p)
int input_rt17(raw_t *Raw, uint8_t Data)
static int DecodeGSOF41(raw_t *Raw, uint8_t *p)
#define PBUFF_LENGTH
static int SyncPacket(rt17_t *rt17, uint8_t Data)
static int32_t ReadI4(uint8_t *p)
#define GENOUT
#define M_BIT0
#define R4(p)
static int DecodeGalileoEphemeris(raw_t *Raw)
static const char * RetsvdataTable[]
static int DecodeGSOF26(raw_t *Raw, uint8_t *p)
static void SetWeek(raw_t *Raw, int Week, double tow)
#define MBUFF_LENGTH
static int DecodeGSOF1(raw_t *Raw, uint8_t *p)
#define STX
static int DecodeRawdata(raw_t *Raw)
#define RETSVDATA
#define M_BIT4
static int DecodeGSOF16(raw_t *Raw, uint8_t *p)
static void ClearPacketBuffer(rt17_t *rt17)
static int DecodeBeidouEphemeris(raw_t *Raw)
#define RAWDATA
static const char * RawdataTable[]
#define U2(p)
static uint16_t ReadU2(uint8_t *p)
#define M_ENHANCED
#define ETX
#define M_WEEK_OPTION
#define I2(p)
#define M_WEEK_EPH
static int16_t ReadI2(uint8_t *p)
#define SC2RAD
Definition mrtk_rcvraw.c:33
MRTKLIB Receiver Raw Data Module — Receiver raw data types and decoder functions for various GNSS rec...
#define STRFMT_RT17
Definition mrtk_rcvraw.h:60
MRTKLIB RTCM Module — RTCM message types and functions.
MRTKLIB System Module — OS/filesystem utility functions.
gtime_t gst2time(int week, double sec)
Convert Galileo system time week/tow to gtime_t.
Definition mrtk_time.c:197
gtime_t bdt2time(int week, double sec)
Convert BeiDou time week/tow to gtime_t.
Definition mrtk_time.c:229
gtime_t gpst2time(int week, double sec)
Convert GPS week/tow to gtime_t.
Definition mrtk_time.c:165
double time2gpst(gtime_t t, int *week)
Convert gtime_t to GPS week/tow.
Definition mrtk_time.c:181
gtime_t bdt2gpst(gtime_t t)
Convert BeiDou time to GPS time.
Definition mrtk_time.c:465
gtime_t timeget(void)
Get current time in UTC.
Definition mrtk_time.c:289
MRTKLIB Time Module — GNSS time types and conversion functions.
void traceobs(mrtk_ctx_t *ctx, int level, const obsd_t *obs, int n)
Output trace observation data.
Definition mrtk_trace.c:122
void tracet(mrtk_ctx_t *ctx, int level, const char *format,...)
Output trace message with elapsed time.
Definition mrtk_trace.c:91
MRTKLIB Trace Module — debug trace and logging functions.
GPS/GAL/QZS/BDS/IRN broadcast ephemeris type.
Definition mrtk_eph.h:77
double OMG0
Definition mrtk_eph.h:90
double omg
Definition mrtk_eph.h:90
int sat
Definition mrtk_eph.h:78
gtime_t ttr
Definition mrtk_eph.h:88
double OMGd
Definition mrtk_eph.h:90
double f1
Definition mrtk_eph.h:94
double f0
Definition mrtk_eph.h:94
int svh
Definition mrtk_eph.h:81
double e
Definition mrtk_eph.h:90
double idot
Definition mrtk_eph.h:90
double M0
Definition mrtk_eph.h:90
double A
Definition mrtk_eph.h:90
double cis
Definition mrtk_eph.h:91
int flag
Definition mrtk_eph.h:86
gtime_t toe
Definition mrtk_eph.h:88
double fit
Definition mrtk_eph.h:93
int week
Definition mrtk_eph.h:82
gtime_t toc
Definition mrtk_eph.h:88
double cic
Definition mrtk_eph.h:91
double tgd[6]
Definition mrtk_eph.h:95
double cus
Definition mrtk_eph.h:91
double cuc
Definition mrtk_eph.h:91
double toes
Definition mrtk_eph.h:92
int code
Definition mrtk_eph.h:83
double crs
Definition mrtk_eph.h:91
double i0
Definition mrtk_eph.h:90
int iode
Definition mrtk_eph.h:79
int sva
Definition mrtk_eph.h:80
double deln
Definition mrtk_eph.h:90
double crc
Definition mrtk_eph.h:91
double f2
Definition mrtk_eph.h:94
int iodc
Definition mrtk_eph.h:79
GNSS time representation.
Definition mrtk_time.h:49
double sec
Definition mrtk_time.h:51
time_t time
Definition mrtk_time.h:50
double utc_gps[8]
Definition mrtk_nav.h:414
eph_t * eph
Definition mrtk_nav.h:400
double ion_gps[8]
Definition mrtk_nav.h:421
obsd_t * data
Definition mrtk_obs.h:61
int n
Definition mrtk_obs.h:60
Observation data record.
Definition mrtk_obs.h:44
float D[5+5]
Definition mrtk_obs.h:52
gtime_t time
Definition mrtk_obs.h:45
uint8_t sat
Definition mrtk_obs.h:46
uint8_t LLI[5+5]
Definition mrtk_obs.h:48
double L[5+5]
Definition mrtk_obs.h:50
double P[5+5]
Definition mrtk_obs.h:51
uint16_t SNR[5+5]
Definition mrtk_obs.h:47
uint8_t code[5+5]
Definition mrtk_obs.h:49
Receiver raw data control type.
Definition mrtk_rcvraw.h:78
nav_t nav
Definition mrtk_rcvraw.h:83
void * rcv_data
int outtype
obs_t obs
Definition mrtk_rcvraw.h:81
int format
char msgtype[256]
Definition mrtk_rcvraw.h:88
char opt[256]
sta_t sta
Definition mrtk_rcvraw.h:84
int ephsat
Definition mrtk_rcvraw.h:85
gtime_t time
Definition mrtk_rcvraw.h:79
uint8_t * PacketBuffer
uint32_t MessageBytes
uint32_t Reply
uint8_t * MessageBuffer
uint32_t PacketLength
uint32_t Flags
double Tow
uint32_t MessageLength
uint32_t Page
uint32_t PacketBytes
double pos[3]
Definition mrtk_nav.h:380
char recsno[MAXANT]
Definition mrtk_nav.h:376
int deltype
Definition mrtk_nav.h:379
double hgt
Definition mrtk_nav.h:382
double del[3]
Definition mrtk_nav.h:381
#define calloc(x, y)
Definition toml.c:54
#define free(x)
Definition toml.c:53
uint8_t c[2]