MRTKLIB 0.7.14
Modernized GNSS Positioning Library
Loading...
Searching...
No Matches
mrtk_rtcm.c
Go to the documentation of this file.
1/*------------------------------------------------------------------------------
2 * mrtk_rtcm.c : RTCM common functions
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#include "mrtklib/mrtk_rtcm.h"
17
18#include <stdlib.h>
19#include <string.h>
20
21#include "mrtklib/mrtk_bits.h"
22#include "mrtklib/mrtk_trace.h"
23
24/*--- forward declarations for legacy functions resolved at link time -------*/
25
26/* constants -----------------------------------------------------------------*/
27
28#define RTCM2PREAMB 0x66 /* rtcm ver.2 frame preamble */
29#define RTCM3PREAMB 0xD3 /* rtcm ver.3 frame preamble */
30
31/* initialize rtcm control -----------------------------------------------------
32 * initialize rtcm control struct and reallocate memory for observation and
33 * ephemeris buffer in rtcm control struct
34 * args : rtcm_t *raw IO rtcm control struct
35 * return : status (1:ok,0:memory allocation error)
36 *-----------------------------------------------------------------------------*/
38 gtime_t time0 = {0};
39 obsd_t data0 = {{0}};
40 eph_t eph0 = {0, -1, -1};
41 geph_t geph0 = {0, -1};
42 ssr_t ssr0 = {{{0}}};
43 int i, j;
44
45 trace(NULL, 3, "init_rtcm:\n");
46
47 rtcm->staid = rtcm->stah = rtcm->seqno = rtcm->outtype = 0;
48 rtcm->time = rtcm->time_s = time0;
49 rtcm->sta.name[0] = rtcm->sta.marker[0] = '\0';
50 rtcm->sta.antdes[0] = rtcm->sta.antsno[0] = '\0';
51 rtcm->sta.rectype[0] = rtcm->sta.recver[0] = rtcm->sta.recsno[0] = '\0';
52 rtcm->sta.antsetup = rtcm->sta.itrf = rtcm->sta.deltype = 0;
53 for (i = 0; i < 3; i++) {
54 rtcm->sta.pos[i] = rtcm->sta.del[i] = 0.0;
55 }
56 rtcm->sta.hgt = 0.0;
57 rtcm->dgps = NULL;
58 for (i = 0; i < MAXSAT; i++) {
59 rtcm->ssr[i] = ssr0;
60 }
61 rtcm->msg[0] = rtcm->msgtype[0] = rtcm->opt[0] = '\0';
62 for (i = 0; i < 6; i++) {
63 rtcm->msmtype[i][0] = '\0';
64 }
65 rtcm->obsflag = rtcm->ephsat = 0;
66 for (i = 0; i < MAXSAT; i++) {
67 for (j = 0; j < NFREQ + NEXOBS; j++) {
68 rtcm->cp[i][j] = 0.0;
69 rtcm->lock[i][j] = rtcm->loss[i][j] = 0;
70 rtcm->lltime[i][j] = time0;
71 }
72 }
73 rtcm->nbyte = rtcm->nbit = rtcm->len = 0;
74 rtcm->word = 0;
75 for (i = 0; i < 100; i++) {
76 rtcm->nmsg2[i] = 0;
77 }
78 for (i = 0; i < 400; i++) {
79 rtcm->nmsg3[i] = 0;
80 }
81
82 rtcm->obs.data = NULL;
83 rtcm->nav.eph = NULL;
84 rtcm->nav.geph = NULL;
85 rtcm->nav.pppiono = NULL;
86
87 /* lclblk is deliberately left untouched: the struct must be zero-initialized
88 * before the first init_rtcm() call (all callers use calloc/memset), and an
89 * existing allocation is preserved across re-init to match the legacy
90 * embedded-array semantics (init_rtcm never cleared lclblk) */
91
92 /* reallocate memory for observation and ephemeris buffer */
93 if (!(rtcm->obs.data = (obsd_t*)malloc(sizeof(obsd_t) * MAXOBS)) ||
94 !(rtcm->nav.eph = (eph_t*)malloc(sizeof(eph_t) * MAXSAT * 2)) ||
95 !(rtcm->nav.geph = (geph_t*)malloc(sizeof(geph_t) * MAXPRNGLO))) {
97 return 0;
98 }
99 rtcm->obs.n = 0;
100 rtcm->nav.n = MAXSAT * 2;
101 rtcm->nav.ng = MAXPRNGLO;
102 for (i = 0; i < MAXOBS; i++) {
103 rtcm->obs.data[i] = data0;
104 }
105 for (i = 0; i < MAXSAT * 2; i++) {
106 rtcm->nav.eph[i] = eph0;
107 }
108 for (i = 0; i < MAXPRNGLO; i++) {
109 rtcm->nav.geph[i] = geph0;
110 }
111 return 1;
112}
113/* free rtcm control ----------------------------------------------------------
114 * free observation and ephemeris buffer in rtcm control struct
115 * args : rtcm_t *raw IO rtcm control struct
116 * return : none
117 *-----------------------------------------------------------------------------*/
119 trace(NULL, 3, "free_rtcm:\n");
120
121 /* free memory for observation and ephemeris buffer */
122 free(rtcm->obs.data);
123 rtcm->obs.data = NULL;
124 rtcm->obs.n = 0;
125 free(rtcm->nav.eph);
126 rtcm->nav.eph = NULL;
127 rtcm->nav.n = 0;
128 free(rtcm->nav.geph);
129 rtcm->nav.geph = NULL;
130 rtcm->nav.ng = 0;
131 free(rtcm->lclblk);
132 rtcm->lclblk = NULL;
133}
134/* get local correction block --------------------------------------------------
135 * return the local correction block, lazily allocating it on first use
136 * args : rtcm_t *rtcm IO rtcm control struct
137 * return : local correction block (NULL: memory allocation error)
138 *-----------------------------------------------------------------------------*/
140 if (!rtcm->lclblk) {
141 rtcm->lclblk = (lclblock_t*)calloc(1, sizeof(lclblock_t));
142 }
143 return rtcm->lclblk;
144}
145/* input RTCM 2 message from stream --------------------------------------------
146 * fetch next RTCM 2 message and input a message from byte stream
147 * args : rtcm_t *rtcm IO rtcm control struct
148 * uint8_t data I stream data (1 byte)
149 * return : status (-1: error message, 0: no message, 1: input observation data,
150 * 2: input ephemeris, 5: input station pos/ant parameters,
151 * 6: input time parameter, 7: input dgps corrections,
152 * 9: input special message)
153 * notes : before firstly calling the function, time in rtcm control struct has
154 * to be set to the approximate time within 1/2 hour in order to resolve
155 * ambiguity of time in rtcm messages.
156 * supported msgs RTCM ver.2: 1,3,9,14,16,17,18,19,22
157 * refer [1] for RTCM ver.2
158 *-----------------------------------------------------------------------------*/
159int input_rtcm2(rtcm_t* rtcm, uint8_t data) {
160 uint8_t preamb;
161 int i;
162
163 trace(NULL, 5, "input_rtcm2: data=%02x\n", data);
164
165 if ((data & 0xC0) != 0x40) {
166 return 0; /* ignore if upper 2bit != 01 */
167 }
168
169 for (i = 0; i < 6; i++, data >>= 1) { /* decode 6-of-8 form */
170 rtcm->word = (rtcm->word << 1) + (data & 1);
171
172 /* synchronize frame */
173 if (rtcm->nbyte == 0) {
174 preamb = (uint8_t)(rtcm->word >> 22);
175 if (rtcm->word & 0x40000000) {
176 preamb ^= 0xFF; /* decode preamble */
177 }
178 if (preamb != RTCM2PREAMB) {
179 continue;
180 }
181
182 /* check parity */
183 if (!decode_word(rtcm->word, rtcm->buff)) {
184 continue;
185 }
186 rtcm->nbyte = 3;
187 rtcm->nbit = 0;
188 continue;
189 }
190 if (++rtcm->nbit < 30) {
191 continue;
192 } else {
193 rtcm->nbit = 0;
194 }
195
196 /* check parity */
197 if (!decode_word(rtcm->word, rtcm->buff + rtcm->nbyte)) {
198 trace(NULL, 2, "rtcm2 partity error: i=%d word=%08x\n", i, rtcm->word);
199 rtcm->nbyte = 0;
200 rtcm->word &= 0x3;
201 continue;
202 }
203 rtcm->nbyte += 3;
204 if (rtcm->nbyte == 6) {
205 rtcm->len = (rtcm->buff[5] >> 3) * 3 + 6;
206 }
207 if (rtcm->nbyte < rtcm->len) {
208 continue;
209 }
210 rtcm->nbyte = 0;
211 rtcm->word &= 0x3;
212
213 /* decode rtcm2 message */
214 return decode_rtcm2(rtcm);
215 }
216 return 0;
217}
218/* input RTCM 3 message from stream --------------------------------------------
219 * fetch next RTCM 3 message and input a message from byte stream
220 * args : rtcm_t *rtcm IO rtcm control struct
221 * uint8_t data I stream data (1 byte)
222 * return : status (-1: error message, 0: no message, 1: input observation data,
223 * 2: input ephemeris, 5: input station pos/ant parameters,
224 * 10: input ssr messages)
225 * notes : before firstly calling the function, time in rtcm control struct has
226 * to be set to the approximate time within 1/2 week in order to resolve
227 * ambiguity of time in rtcm messages.
228 *
229 * to specify input options, set rtcm->opt to the following option
230 * strings separated by spaces.
231 *
232 * -EPHALL : input all ephemerides (default: only new)
233 * -STA=nnn : input only message with STAID=nnn (default: all)
234 * -GLss : select signal ss for GPS MSM (ss=1C,1P,...)
235 * -RLss : select signal ss for GLO MSM (ss=1C,1P,...)
236 * -ELss : select signal ss for GAL MSM (ss=1C,1B,...)
237 * -JLss : select signal ss for QZS MSM (ss=1C,2C,...)
238 * -CLss : select signal ss for BDS MSM (ss=2I,7I,...)
239 * -ILss : select signal ss for IRN MSM (ss=5A,9A,...)
240 * -GALINAV : select I/NAV for Galileo ephemeris (default: all)
241 * -GALFNAV : select F/NAV for Galileo ephemeris (default: all)
242 *
243 * supported RTCM 3 messages (ref [7][10][15][16][17][18])
244 *
245 * TYPE : GPS GLONASS Galileo QZSS BDS SBAS NavIC
246 * ----------------------------------------------------------------------
247 * OBS COMP L1 : 1001~ 1009~ - - - - -
248 * FULL L1 : 1002 1010 - - - - -
249 * COMP L1L2: 1003~ 1011~ - - - - -
250 * FULL L1L2: 1004 1012 - - - - -
251 *
252 * NAV : 1019 1020 1045** 1044 1042 - 1041
253 * - - 1046** - 63* - -
254 *
255 * MSM 1 : 1071~ 1081~ 1091~ 1111~ 1121~ 1101~ 1131~
256 * 2 : 1072~ 1082~ 1092~ 1112~ 1122~ 1102~ 1132~
257 * 3 : 1073~ 1083~ 1093~ 1113~ 1123~ 1103~ 1133~
258 * 4 : 1074 1084 1094 1114 1124 1104 1134
259 * 5 : 1075 1085 1095 1115 1125 1105 1135
260 * 6 : 1076 1086 1096 1116 1126 1106 1136
261 * 7 : 1077 1087 1097 1117 1127 1107 1137
262 *
263 * SSR ORBIT : 1057 1063 1240* 1246* 1258* - -
264 * CLOCK : 1058 1064 1241* 1247* 1259* - -
265 * CODE BIAS: 1059 1065 1242* 1248* 1260* - -
266 * OBT/CLK : 1060 1066 1243* 1249* 1261* - -
267 * URA : 1061 1067 1244* 1250* 1262* - -
268 * HR-CLOCK : 1062 1068 1245* 1251* 1263* - -
269 * PHAS BIAS: 11* - 12* 13* 14* - -
270 *
271 * ANT/RCV INFO : 1007 1008 1033
272 * STA POSITION : 1005 1006
273 *
274 * PROPRIETARY : 4076 (IGS)
275 * ----------------------------------------------------------------------
276 * (* draft, ** 1045:F/NAV,1046:I/NAV, ~ only encode)
277 *
278 * for MSM observation data with multiple signals for a frequency,
279 * a signal is selected according to internal priority. to select
280 * a specified signal, use the input options.
281 *
282 * RTCM 3 message format:
283 * +----------+--------+-----------+--------------------+----------+
284 * | preamble | 000000 | length | data message | parity |
285 * +----------+--------+-----------+--------------------+----------+
286 * |<-- 8 --->|<- 6 -->|<-- 10 --->|<--- length x 8 --->|<-- 24 -->|
287 *
288 *-----------------------------------------------------------------------------*/
289int input_rtcm3(rtcm_t* rtcm, uint8_t data) {
290 trace(NULL, 5, "input_rtcm3: data=%02x\n", data);
291
292 /* synchronize frame */
293 if (rtcm->nbyte == 0) {
294 if (data != RTCM3PREAMB) {
295 return 0;
296 }
297 rtcm->buff[rtcm->nbyte++] = data;
298 return 0;
299 }
300 rtcm->buff[rtcm->nbyte++] = data;
301
302 if (rtcm->nbyte == 3) {
303 rtcm->len = getbitu(rtcm->buff, 14, 10) + 3; /* length without parity */
304 }
305 if (rtcm->nbyte < 3 || rtcm->nbyte < rtcm->len + 3) {
306 return 0;
307 }
308 rtcm->nbyte = 0;
309
310 /* check parity */
311 if (rtk_crc24q(rtcm->buff, rtcm->len) != getbitu(rtcm->buff, rtcm->len * 8, 24)) {
312 trace(NULL, 2, "rtcm3 parity error: len=%d\n", rtcm->len);
313 return 0;
314 }
315 /* decode rtcm3 message */
316 return decode_rtcm3(rtcm);
317}
318/* input RTCM 2 message from file ----------------------------------------------
319 * fetch next RTCM 2 message and input a messsage from file
320 * args : rtcm_t *rtcm IO rtcm control struct
321 * FILE *fp I file pointer
322 * return : status (-2: end of file, -1...10: same as above)
323 * notes : same as above
324 *-----------------------------------------------------------------------------*/
325int input_rtcm2f(rtcm_t* rtcm, FILE* fp) {
326 int i, data = 0, ret;
327
328 trace(NULL, 4, "input_rtcm2f: data=%02x\n", data);
329
330 for (i = 0; i < 4096; i++) {
331 if ((data = fgetc(fp)) == EOF) {
332 return -2;
333 }
334 if ((ret = input_rtcm2(rtcm, (uint8_t)data))) {
335 return ret;
336 }
337 }
338 return 0; /* return at every 4k bytes */
339}
340/* input RTCM 3 message from file ----------------------------------------------
341 * fetch next RTCM 3 message and input a messsage from file
342 * args : rtcm_t *rtcm IO rtcm control struct
343 * FILE *fp I file pointer
344 * return : status (-2: end of file, -1...10: same as above)
345 * notes : same as above
346 *-----------------------------------------------------------------------------*/
347int input_rtcm3f(rtcm_t* rtcm, FILE* fp) {
348 int i, data = 0, ret;
349
350 trace(NULL, 4, "input_rtcm3f: data=%02x\n", data);
351
352 for (i = 0; i < 4096; i++) {
353 if ((data = fgetc(fp)) == EOF) {
354 return -2;
355 }
356 if ((ret = input_rtcm3(rtcm, (uint8_t)data))) {
357 return ret;
358 }
359 }
360 return 0; /* return at every 4k bytes */
361}
362/* generate RTCM 2 message -----------------------------------------------------
363 * generate RTCM 2 message
364 * args : rtcm_t *rtcm IO rtcm control struct
365 * int type I message type
366 * int sync I sync flag (1:another message follows)
367 * return : status (1:ok,0:error)
368 *-----------------------------------------------------------------------------*/
369int gen_rtcm2(rtcm_t* rtcm, int type, int sync) {
370 trace(NULL, 4, "gen_rtcm2: type=%d sync=%d\n", type, sync);
371
372 rtcm->nbit = rtcm->len = rtcm->nbyte = 0;
373
374 /* not yet implemented */
375
376 return 0;
377}
378/* generate RTCM 3 message -----------------------------------------------------
379 * generate RTCM 3 message
380 * args : rtcm_t *rtcm IO rtcm control struct
381 * int type I message type
382 * int subtype I message subtype
383 * int sync I sync flag (1:another message follows)
384 * return : status (1:ok,0:error)
385 * notes : For rtcm 3 msm, the {nsat} x {nsig} in rtcm->obs should not exceed
386 * 64. If {nsat} x {nsig} of the input obs data exceeds 64, separate
387 * them to multiple ones and call gen_rtcm3() multiple times as user
388 * responsibility.
389 * ({nsat} = number of valid satellites, {nsig} = number of signals in
390 * the obs data)
391 *-----------------------------------------------------------------------------*/
392int gen_rtcm3(rtcm_t* rtcm, int type, int subtype, int sync) {
393 uint32_t crc;
394 int i = 0;
395
396 trace(NULL, 4, "gen_rtcm3: type=%d subtype=%d sync=%d\n", type, subtype, sync);
397
398 rtcm->nbit = rtcm->len = rtcm->nbyte = 0;
399
400 /* set preamble and reserved */
401 setbitu(rtcm->buff, i, 8, RTCM3PREAMB);
402 i += 8;
403 setbitu(rtcm->buff, i, 6, 0);
404 i += 6;
405 setbitu(rtcm->buff, i, 10, 0);
406 i += 10;
407
408 /* encode rtcm 3 message body */
409 if (!encode_rtcm3(rtcm, type, subtype, sync)) {
410 return 0;
411 }
412
413 /* padding to align 8 bit boundary */
414 for (i = rtcm->nbit; i % 8; i++) {
415 setbitu(rtcm->buff, i, 1, 0);
416 }
417 /* message length (header+data) (bytes) */
418 if ((rtcm->len = i / 8) >= 3 + 1024) {
419 trace(NULL, 2, "generate rtcm 3 message length error len=%d\n", rtcm->len - 3);
420 rtcm->nbit = rtcm->len = 0;
421 return 0;
422 }
423 /* message length without header and parity */
424 setbitu(rtcm->buff, 14, 10, rtcm->len - 3);
425
426 /* crc-24q */
427 crc = rtk_crc24q(rtcm->buff, rtcm->len);
428 setbitu(rtcm->buff, i, 24, crc);
429
430 /* length total (bytes) */
431 rtcm->nbyte = rtcm->len + 3;
432
433 return 1;
434}
uint32_t rtk_crc24q(const uint8_t *buff, int len)
Compute CRC-24Q parity for SBAS and RTCM3.
Definition mrtk_bits.c:181
void setbitu(uint8_t *buff, int pos, int len, uint32_t data)
Set unsigned bits in byte data.
Definition mrtk_bits.c:122
uint32_t getbitu(const uint8_t *buff, int pos, int len)
Extract unsigned bits from byte data.
Definition mrtk_bits.c:99
int decode_word(uint32_t word, uint8_t *data)
Check parity and decode GPS navigation data word.
Definition mrtk_bits.c:224
MRTKLIB Bits Module — Binary bit operations and CRC functions.
#define MAXSAT
Definition mrtk_coords.c:45
#define MAXOBS
#define MAXPRNGLO
static rtcm_t * rtcm
int decode_rtcm2(rtcm_t *rtcm)
Decode RTCM ver.2 message (called from rtcm.c).
Definition mrtk_rtcm2.c:452
int decode_rtcm3(rtcm_t *rtcm)
Decode RTCM ver.3 message (called from rtcm.c).
int encode_rtcm3(rtcm_t *rtcm, int type, int subtype, int sync)
Encode RTCM ver.3 message (called from rtcm.c).
int gen_rtcm2(rtcm_t *rtcm, int type, int sync)
Generate RTCM 2 message.
Definition mrtk_rtcm.c:369
lclblock_t * rtcm_lclblk(rtcm_t *rtcm)
Get the local correction block, lazily allocating it on first use.
Definition mrtk_rtcm.c:139
void free_rtcm(rtcm_t *rtcm)
Free RTCM control struct.
Definition mrtk_rtcm.c:118
#define RTCM2PREAMB
Definition mrtk_rtcm.c:28
int input_rtcm3f(rtcm_t *rtcm, FILE *fp)
Input RTCM 3 message from file.
Definition mrtk_rtcm.c:347
int init_rtcm(rtcm_t *rtcm)
Initialize RTCM control struct.
Definition mrtk_rtcm.c:37
int gen_rtcm3(rtcm_t *rtcm, int type, int subtype, int sync)
Generate RTCM 3 message.
Definition mrtk_rtcm.c:392
int input_rtcm2f(rtcm_t *rtcm, FILE *fp)
Input RTCM 2 message from file.
Definition mrtk_rtcm.c:325
int input_rtcm2(rtcm_t *rtcm, uint8_t data)
Input RTCM 2 message from stream (byte-by-byte).
Definition mrtk_rtcm.c:159
#define RTCM3PREAMB
Definition mrtk_rtcm.c:29
int input_rtcm3(rtcm_t *rtcm, uint8_t data)
Input RTCM 3 message from stream (byte-by-byte).
Definition mrtk_rtcm.c:289
MRTKLIB RTCM Module — RTCM message types and functions.
void trace(mrtk_ctx_t *ctx, int level, const char *format,...)
Output trace message.
Definition mrtk_trace.c:78
MRTKLIB Trace Module — debug trace and logging functions.
GPS/GAL/QZS/BDS/IRN broadcast ephemeris type.
Definition mrtk_eph.h:77
GLONASS broadcast ephemeris type.
Definition mrtk_eph.h:111
GNSS time representation.
Definition mrtk_time.h:49
Observation data record.
Definition mrtk_obs.h:44
RTCM control struct type.
Definition mrtk_rtcm.h:50
#define malloc(x)
Definition toml.c:52
#define calloc(x, y)
Definition toml.c:54
#define free(x)
Definition toml.c:53