gnss-js 1.16.0 → 1.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  decodeGpsLnavFrame
3
- } from "./chunk-4LVD4DYL.js";
3
+ } from "./chunk-IQ5OIMQD.js";
4
4
  import {
5
5
  getUtcDate
6
6
  } from "./chunk-HVXYFUCB.js";
@@ -50,11 +50,27 @@ function* oem4Frames(data, view, stats) {
50
50
  }
51
51
 
52
52
  // src/novatel/nav.ts
53
+ var ID_IONUTC = 8;
53
54
  var ID_RAWEPHEM = 41;
54
55
  var ID_GLOEPHEMERIS = 723;
56
+ var ID_GALEPHEMERIS = 1122;
57
+ var ID_QZSSEPHEMERIS = 1336;
58
+ var ID_GPSEPHEM = 7;
59
+ var ID_BDSEPHEMERIS = 1696;
55
60
  var GPS_EPOCH_MS = Date.UTC(1980, 0, 6);
61
+ var BDT_EPOCH_MS = Date.UTC(2006, 0, 1);
56
62
  var SEC_PER_WEEK = 7 * 86400;
57
63
  var SEC_PER_DAY = 86400;
64
+ var MS_PER_WEEK = SEC_PER_WEEK * 1e3;
65
+ var gpsMs = (week, sec) => GPS_EPOCH_MS + week * MS_PER_WEEK + sec * 1e3;
66
+ var sowOf = (dateMs) => dateMs / 1e3 % SEC_PER_WEEK;
67
+ function nearWeekMs(refMs, sow) {
68
+ const refWeek = Math.floor((refMs - GPS_EPOCH_MS) / MS_PER_WEEK);
69
+ let ms = gpsMs(refWeek, sow);
70
+ if (ms < refMs - MS_PER_WEEK / 2) ms += MS_PER_WEEK;
71
+ else if (ms > refMs + MS_PER_WEEK / 2) ms -= MS_PER_WEEK;
72
+ return ms;
73
+ }
58
74
  function decodeRawEphem(data, view, p) {
59
75
  const prn = view.getUint32(p, true);
60
76
  if (prn < 1 || prn > 32) return null;
@@ -100,23 +116,188 @@ function decodeGloEphemeris(view, p) {
100
116
  freqNum
101
117
  };
102
118
  }
119
+ function decodeGalEphemeris(view, p, headerMs) {
120
+ const prn = view.getUint32(p, true);
121
+ if (prn < 1 || prn > 36) return null;
122
+ const fnav = (view.getUint32(p + 4, true) & 1) !== 0;
123
+ const svhE1b = view.getUint8(p + 12) & 3;
124
+ const svhE5a = view.getUint8(p + 13) & 3;
125
+ const svhE5b = view.getUint8(p + 14) & 3;
126
+ const dvsE1b = view.getUint8(p + 15) & 1;
127
+ const dvsE5a = view.getUint8(p + 16) & 1;
128
+ const dvsE5b = view.getUint8(p + 17) & 1;
129
+ const iodNav = view.getUint32(p + 20, true);
130
+ const toes = view.getUint32(p + 24, true);
131
+ const c = fnav ? p + 148 : p + 176;
132
+ const tocs = view.getUint32(c, true);
133
+ const toeMs = nearWeekMs(headerMs, toes);
134
+ const tocDate = new Date(nearWeekMs(headerMs, tocs));
135
+ return {
136
+ fnav,
137
+ eph: {
138
+ system: "E",
139
+ prn: `E${String(prn).padStart(2, "0")}`,
140
+ toc: sowOf(tocDate.getTime()),
141
+ tocDate,
142
+ af0: view.getFloat64(c + 4, true),
143
+ af1: view.getFloat64(c + 12, true),
144
+ af2: view.getFloat64(c + 20, true),
145
+ iode: iodNav,
146
+ crs: view.getFloat64(p + 92, true),
147
+ deltaN: view.getFloat64(p + 36, true),
148
+ m0: view.getFloat64(p + 44, true),
149
+ cuc: view.getFloat64(p + 68, true),
150
+ e: view.getFloat64(p + 52, true),
151
+ cus: view.getFloat64(p + 76, true),
152
+ sqrtA: view.getFloat64(p + 28, true),
153
+ toe: toes,
154
+ cic: view.getFloat64(p + 100, true),
155
+ omega0: view.getFloat64(p + 132, true),
156
+ cis: view.getFloat64(p + 108, true),
157
+ i0: view.getFloat64(p + 116, true),
158
+ crc: view.getFloat64(p + 84, true),
159
+ omega: view.getFloat64(p + 60, true),
160
+ omegaDot: view.getFloat64(p + 140, true),
161
+ idot: view.getFloat64(p + 124, true),
162
+ week: Math.floor((toeMs - GPS_EPOCH_MS) / MS_PER_WEEK),
163
+ // RINEX Galileo SVH bit layout (E1B DVS/HS in bits 0-2, E5a in
164
+ // 3-5, E5b in 6-8) — same packing as RTKLIB.
165
+ svHealth: svhE5b << 7 | dvsE5b << 6 | svhE5a << 4 | dvsE5a << 3 | svhE1b << 1 | dvsE1b,
166
+ tgd: view.getFloat64(p + 204, true)
167
+ // BGD E5a/E1 (RINEX slot)
168
+ }
169
+ };
170
+ }
171
+ function decodeBdsEphemeris(view, p) {
172
+ const prn = view.getUint32(p, true);
173
+ if (prn < 1 || prn > 63) return null;
174
+ const week = view.getUint32(p + 4, true);
175
+ const health = view.getUint32(p + 16, true) & 1;
176
+ const tgd1 = view.getFloat64(p + 20, true);
177
+ const tocs = view.getUint32(p + 40, true);
178
+ const toes = view.getUint32(p + 72, true);
179
+ const tocDate = new Date(BDT_EPOCH_MS + week * MS_PER_WEEK + tocs * 1e3);
180
+ return {
181
+ system: "C",
182
+ prn: `C${String(prn).padStart(2, "0")}`,
183
+ toc: sowOf(tocDate.getTime()),
184
+ tocDate,
185
+ af0: view.getFloat64(p + 44, true),
186
+ af1: view.getFloat64(p + 52, true),
187
+ af2: view.getFloat64(p + 60, true),
188
+ iode: view.getUint32(p + 68, true),
189
+ // AODE
190
+ crs: view.getFloat64(p + 172, true),
191
+ deltaN: view.getFloat64(p + 100, true),
192
+ m0: view.getFloat64(p + 108, true),
193
+ cuc: view.getFloat64(p + 148, true),
194
+ e: view.getFloat64(p + 84, true),
195
+ cus: view.getFloat64(p + 156, true),
196
+ sqrtA: view.getFloat64(p + 76, true),
197
+ toe: toes,
198
+ cic: view.getFloat64(p + 180, true),
199
+ omega0: view.getFloat64(p + 116, true),
200
+ cis: view.getFloat64(p + 188, true),
201
+ i0: view.getFloat64(p + 132, true),
202
+ crc: view.getFloat64(p + 164, true),
203
+ omega: view.getFloat64(p + 92, true),
204
+ omegaDot: view.getFloat64(p + 124, true),
205
+ idot: view.getFloat64(p + 140, true),
206
+ week,
207
+ // RINEX BDS week field is the BDT week
208
+ svHealth: health,
209
+ tgd: tgd1
210
+ // TGD1 (B1) — RINEX slot
211
+ };
212
+ }
213
+ function decodeGpsQzssEphemeris(view, p, sys) {
214
+ const prn = view.getUint32(p, true);
215
+ if (sys === "G" && (prn < 1 || prn > 32)) return null;
216
+ if (sys === "J" && (prn < 193 || prn > 202)) return null;
217
+ const health = view.getUint32(p + 12, true) & 63;
218
+ const iode1 = view.getUint32(p + 16, true);
219
+ const week = view.getUint32(p + 24, true);
220
+ const toes = view.getFloat64(p + 32, true);
221
+ const toeMs = gpsMs(week, toes);
222
+ const tocs = view.getFloat64(p + 164, true);
223
+ const tocDate = new Date(nearWeekMs(toeMs, tocs));
224
+ return {
225
+ system: sys,
226
+ prn: `${sys}${String(sys === "J" ? prn - 192 : prn).padStart(2, "0")}`,
227
+ toc: sowOf(tocDate.getTime()),
228
+ tocDate,
229
+ af0: view.getFloat64(p + 180, true),
230
+ af1: view.getFloat64(p + 188, true),
231
+ af2: view.getFloat64(p + 196, true),
232
+ iode: iode1,
233
+ crs: view.getFloat64(p + 104, true),
234
+ deltaN: view.getFloat64(p + 48, true),
235
+ m0: view.getFloat64(p + 56, true),
236
+ cuc: view.getFloat64(p + 80, true),
237
+ e: view.getFloat64(p + 64, true),
238
+ cus: view.getFloat64(p + 88, true),
239
+ sqrtA: Math.sqrt(view.getFloat64(p + 40, true)),
240
+ toe: toes,
241
+ cic: view.getFloat64(p + 112, true),
242
+ omega0: view.getFloat64(p + 144, true),
243
+ cis: view.getFloat64(p + 120, true),
244
+ i0: view.getFloat64(p + 128, true),
245
+ crc: view.getFloat64(p + 96, true),
246
+ omega: view.getFloat64(p + 72, true),
247
+ omegaDot: view.getFloat64(p + 152, true),
248
+ idot: view.getFloat64(p + 136, true),
249
+ week,
250
+ svHealth: health,
251
+ tgd: view.getFloat64(p + 172, true)
252
+ };
253
+ }
103
254
  function parseNovatelNav(data) {
104
255
  const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
105
256
  const stats = { badCrc: 0 };
106
257
  const ephemerides = [];
107
- const lastGps = /* @__PURE__ */ new Map();
258
+ const ionoCorrections = {};
259
+ let leapSeconds = null;
260
+ const lastKep = /* @__PURE__ */ new Map();
108
261
  const lastGlo = /* @__PURE__ */ new Map();
262
+ const pushKepler = (key, eph) => {
263
+ const prev = lastKep.get(key);
264
+ if (prev && prev.iode === eph.iode && prev.toe === eph.toe && prev.tocDate.getTime() === eph.tocDate.getTime()) {
265
+ return;
266
+ }
267
+ lastKep.set(key, eph);
268
+ ephemerides.push(eph);
269
+ };
109
270
  for (const frame of oem4Frames(data, view, stats)) {
110
271
  if (!frame.binary) continue;
111
272
  if (frame.id === ID_RAWEPHEM && frame.msgLen >= 102) {
112
273
  const eph = decodeRawEphem(data, view, frame.payload);
113
- if (!eph) continue;
114
- const prev = lastGps.get(eph.prn);
115
- if (prev && prev.iode === eph.iode && prev.tocDate.getTime() === eph.tocDate.getTime()) {
116
- continue;
274
+ if (eph) pushKepler(eph.prn, eph);
275
+ } else if (frame.id === ID_GALEPHEMERIS && frame.msgLen >= 220) {
276
+ if (frame.week === 0) continue;
277
+ const headerMs = gpsMs(frame.week, frame.towMs / 1e3);
278
+ const dec = decodeGalEphemeris(view, frame.payload, headerMs);
279
+ if (dec)
280
+ pushKepler(`${dec.eph.prn}:${dec.fnav ? "fnav" : "inav"}`, dec.eph);
281
+ } else if (frame.id === ID_BDSEPHEMERIS && frame.msgLen >= 196) {
282
+ const eph = decodeBdsEphemeris(view, frame.payload);
283
+ if (eph) pushKepler(eph.prn, eph);
284
+ } else if (frame.id === ID_GPSEPHEM && frame.msgLen >= 204) {
285
+ const eph = decodeGpsQzssEphemeris(view, frame.payload, "G");
286
+ if (eph) pushKepler(eph.prn, eph);
287
+ } else if (frame.id === ID_QZSSEPHEMERIS && frame.msgLen >= 204) {
288
+ const eph = decodeGpsQzssEphemeris(view, frame.payload, "J");
289
+ if (eph) pushKepler(eph.prn, eph);
290
+ } else if (frame.id === ID_IONUTC && frame.msgLen >= 108) {
291
+ const p = frame.payload;
292
+ const alpha = [];
293
+ const beta = [];
294
+ for (let i = 0; i < 4; i++) {
295
+ alpha.push(view.getFloat64(p + i * 8, true));
296
+ beta.push(view.getFloat64(p + 32 + i * 8, true));
117
297
  }
118
- lastGps.set(eph.prn, eph);
119
- ephemerides.push(eph);
298
+ ionoCorrections["GPSA"] = alpha;
299
+ ionoCorrections["GPSB"] = beta;
300
+ leapSeconds = view.getInt32(p + 96, true);
120
301
  } else if (frame.id === ID_GLOEPHEMERIS && frame.msgLen >= 144) {
121
302
  const eph = decodeGloEphemeris(view, frame.payload);
122
303
  if (!eph) continue;
@@ -128,12 +309,12 @@ function parseNovatelNav(data) {
128
309
  ephemerides.push(eph);
129
310
  }
130
311
  }
131
- return { ephemerides, badCrc: stats.badCrc };
312
+ return { ephemerides, ionoCorrections, leapSeconds, badCrc: stats.badCrc };
132
313
  }
133
314
 
134
315
  // src/novatel/index.ts
135
316
  var GPS_EPOCH_MS2 = Date.UTC(1980, 0, 6);
136
- var MS_PER_WEEK = 7 * 864e5;
317
+ var MS_PER_WEEK2 = 7 * 864e5;
137
318
  var HDR = 28;
138
319
  var ID_RANGE = 43;
139
320
  var ID_RANGECMP = 140;
@@ -302,7 +483,7 @@ function parseNovatelRange(data) {
302
483
  if (!codes.includes(code)) codes.push(code);
303
484
  }
304
485
  epochs.push({
305
- timeMs: GPS_EPOCH_MS2 + week * MS_PER_WEEK + towMs,
486
+ timeMs: GPS_EPOCH_MS2 + week * MS_PER_WEEK2 + towMs,
306
487
  meas
307
488
  });
308
489
  }
@@ -354,7 +535,7 @@ function parseNovatelRange(data) {
354
535
  if (!codes.includes(code)) codes.push(code);
355
536
  }
356
537
  epochs.push({
357
- timeMs: GPS_EPOCH_MS2 + week * MS_PER_WEEK + towMs,
538
+ timeMs: GPS_EPOCH_MS2 + week * MS_PER_WEEK2 + towMs,
358
539
  meas
359
540
  });
360
541
  }
@@ -1,3 +1,7 @@
1
+ import {
2
+ CnavAssembler,
3
+ cnavCrcOk
4
+ } from "./chunk-Y5IWUPJQ.js";
1
5
  import {
2
6
  getGpsLeap
3
7
  } from "./chunk-HVXYFUCB.js";
@@ -371,6 +375,75 @@ function parseSbfAlmanac(data) {
371
375
  return { almanacs, badCrc };
372
376
  }
373
377
 
378
+ // src/sbf/iono.ts
379
+ var F4_DNU2 = -2e10;
380
+ function parseSbfIonoUtc(data) {
381
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
382
+ const ionoCorrections = {};
383
+ let leapSeconds = null;
384
+ const f4s = (b, n) => {
385
+ const out = [];
386
+ for (let k = 0; k < n; k++) {
387
+ const v = view.getFloat32(b + 4 * k, true);
388
+ if (v === F4_DNU2) return null;
389
+ out.push(v);
390
+ }
391
+ return out;
392
+ };
393
+ scanSbfFrames(data, view, (id, b, len) => {
394
+ if ((id === 5893 || id === 4120) && len >= 48) {
395
+ const alpha = f4s(b + 16, 4);
396
+ const beta = f4s(b + 32, 4);
397
+ if (!alpha || !beta) return;
398
+ const sys = id === 5893 ? "GPS" : "BDS";
399
+ ionoCorrections[`${sys}A`] = alpha;
400
+ ionoCorrections[`${sys}B`] = beta;
401
+ } else if (id === 4030 && len >= 28) {
402
+ const ai = f4s(b + 16, 3);
403
+ if (ai) ionoCorrections["GAL"] = ai;
404
+ } else if (id === 5894 && len >= 37) {
405
+ leapSeconds = view.getInt8(b + 33);
406
+ }
407
+ });
408
+ return { ionoCorrections, leapSeconds };
409
+ }
410
+
411
+ // src/sbf/rawnav.ts
412
+ var SIGNAL_OF_BLOCK = {
413
+ 4018: "L2C",
414
+ 4019: "L5"
415
+ };
416
+ function parseSbfCnav(data) {
417
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
418
+ const ephemerides = [];
419
+ const assemblers = {
420
+ L2C: new CnavAssembler(),
421
+ L5: new CnavAssembler()
422
+ };
423
+ let badCrc = 0;
424
+ let messages = 0;
425
+ scanSbfFrames(data, view, (id, b, len) => {
426
+ const signal = SIGNAL_OF_BLOCK[id];
427
+ if (!signal || len < 60) return;
428
+ messages++;
429
+ const msg = new Uint8Array(40);
430
+ for (let k = 0; k < 10; k++) {
431
+ const w = view.getUint32(b + 20 + 4 * k, true);
432
+ msg[4 * k] = w >>> 24;
433
+ msg[4 * k + 1] = w >>> 16 & 255;
434
+ msg[4 * k + 2] = w >>> 8 & 255;
435
+ msg[4 * k + 3] = w & 255;
436
+ }
437
+ if (!cnavCrcOk(msg)) {
438
+ badCrc++;
439
+ return;
440
+ }
441
+ const eph = assemblers[signal].push(msg);
442
+ if (eph) ephemerides.push({ ...eph, signal });
443
+ });
444
+ return { ephemerides, badCrc, messages };
445
+ }
446
+
374
447
  // src/sbf/index.ts
375
448
  var CLIGHT = 299792458;
376
449
  var GPS_EPOCH_MS2 = Date.UTC(1980, 0, 6);
@@ -1044,5 +1117,7 @@ export {
1044
1117
  scanSbfFrames,
1045
1118
  parseSbfNav,
1046
1119
  parseSbfAlmanac,
1120
+ parseSbfIonoUtc,
1121
+ parseSbfCnav,
1047
1122
  parseSbfMeas
1048
1123
  };
@@ -1,8 +1,13 @@
1
+ import {
2
+ CnavAssembler,
3
+ cnavCrcOk
4
+ } from "./chunk-Y5IWUPJQ.js";
1
5
  import {
2
6
  decodeGpsLnavFrame,
7
+ getBitS,
3
8
  getBitU,
4
9
  setBitU
5
- } from "./chunk-4LVD4DYL.js";
10
+ } from "./chunk-IQ5OIMQD.js";
6
11
 
7
12
  // src/ubx/frame.ts
8
13
  function* ubxFrames(data, stats = { badChecksums: 0 }) {
@@ -38,6 +43,30 @@ function* ubxFrames(data, stats = { badChecksums: 0 }) {
38
43
 
39
44
  // src/ubx/nav.ts
40
45
  var PREAMB_CNAV = 139;
46
+ function readLnavSubframe(view, f) {
47
+ const p = f.payload;
48
+ if (p.length < 8) return null;
49
+ const gnssId = p[0];
50
+ const svId = p[1];
51
+ let prn;
52
+ if (gnssId === 0 && svId >= 1 && svId <= 32) {
53
+ prn = `G${String(svId).padStart(2, "0")}`;
54
+ } else if (gnssId === 5 && svId >= 1 && svId <= 10) {
55
+ if (p.length === 44) return null;
56
+ prn = `J${String(svId).padStart(2, "0")}`;
57
+ } else {
58
+ return null;
59
+ }
60
+ if (p.length < 8 + 40) return null;
61
+ const base = f.payloadStart + 8;
62
+ if (view.getUint32(base, true) >>> 24 === PREAMB_CNAV) return null;
63
+ const buff = new Uint8Array(30);
64
+ for (let k = 0; k < 10; k++) {
65
+ const dwrd = view.getUint32(base + 4 * k, true);
66
+ setBitU(buff, 24 * k, 24, dwrd >>> 6 & 16777215);
67
+ }
68
+ return { prn, gnssId, svId, buff, id: getBitU(buff, 43, 3) };
69
+ }
41
70
  function parseUbxNav(data, opts = {}) {
42
71
  const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
43
72
  const ephemerides = [];
@@ -59,28 +88,9 @@ function parseUbxNav(data, opts = {}) {
59
88
  const last = /* @__PURE__ */ new Map();
60
89
  for (const f of ubxFrames(data)) {
61
90
  if (f.msgClass !== 2 || f.msgId !== 19) continue;
62
- const p = f.payload;
63
- if (p.length < 8) continue;
64
- const gnssId = p[0];
65
- const svId = p[1];
66
- let prn;
67
- if (gnssId === 0 && svId >= 1 && svId <= 32) {
68
- prn = `G${String(svId).padStart(2, "0")}`;
69
- } else if (gnssId === 5 && svId >= 1 && svId <= 10) {
70
- if (p.length === 44) continue;
71
- prn = `J${String(svId).padStart(2, "0")}`;
72
- } else {
73
- continue;
74
- }
75
- if (p.length < 8 + 40) continue;
76
- const base = f.payloadStart + 8;
77
- if (view.getUint32(base, true) >>> 24 === PREAMB_CNAV) continue;
78
- const buff = new Uint8Array(30);
79
- for (let k = 0; k < 10; k++) {
80
- const dwrd = view.getUint32(base + 4 * k, true);
81
- setBitU(buff, 24 * k, 24, dwrd >>> 6 & 16777215);
82
- }
83
- const id = getBitU(buff, 43, 3);
91
+ const lnav = readLnavSubframe(view, f);
92
+ if (!lnav) continue;
93
+ const { prn, gnssId, svId, buff, id } = lnav;
84
94
  if (id < 1 || id > 5) {
85
95
  badParity++;
86
96
  continue;
@@ -110,6 +120,68 @@ function parseUbxNav(data, opts = {}) {
110
120
  return { ephemerides, badParity };
111
121
  }
112
122
 
123
+ // src/ubx/iono.ts
124
+ function parseUbxIonoUtc(data) {
125
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
126
+ const ionoCorrections = {};
127
+ let leapSeconds = null;
128
+ for (const f of ubxFrames(data)) {
129
+ if (f.msgClass !== 2 || f.msgId !== 19) continue;
130
+ const sf = readLnavSubframe(view, f);
131
+ if (!sf || sf.gnssId !== 0 || sf.id !== 4) continue;
132
+ const b = sf.buff;
133
+ if (getBitU(b, 48, 2) !== 1 || getBitU(b, 50, 6) !== 56) continue;
134
+ ionoCorrections["GPSA"] = [
135
+ getBitS(b, 56, 8) * 2 ** -30,
136
+ getBitS(b, 64, 8) * 2 ** -27,
137
+ getBitS(b, 72, 8) * 2 ** -24,
138
+ getBitS(b, 80, 8) * 2 ** -24
139
+ ];
140
+ ionoCorrections["GPSB"] = [
141
+ getBitS(b, 88, 8) * 2 ** 11,
142
+ getBitS(b, 96, 8) * 2 ** 14,
143
+ getBitS(b, 104, 8) * 2 ** 16,
144
+ getBitS(b, 112, 8) * 2 ** 16
145
+ ];
146
+ leapSeconds = getBitS(b, 192, 8);
147
+ }
148
+ return { ionoCorrections, leapSeconds };
149
+ }
150
+
151
+ // src/ubx/cnav.ts
152
+ function parseUbxCnav(data) {
153
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
154
+ const assembler = new CnavAssembler();
155
+ const ephemerides = [];
156
+ let badCrc = 0;
157
+ let messages = 0;
158
+ for (const f of ubxFrames(data)) {
159
+ if (f.msgClass !== 2 || f.msgId !== 19) continue;
160
+ const p = f.payload;
161
+ if (p.length < 8 + 40) continue;
162
+ if (p[0] !== 0 || p[2] !== 3 && p[2] !== 4) continue;
163
+ const svId = p[1];
164
+ if (svId < 1 || svId > 32) continue;
165
+ messages++;
166
+ const msg = new Uint8Array(40);
167
+ const base = f.payloadStart + 8;
168
+ for (let k = 0; k < 10; k++) {
169
+ const w = view.getUint32(base + 4 * k, true);
170
+ msg[4 * k] = w >>> 24;
171
+ msg[4 * k + 1] = w >>> 16 & 255;
172
+ msg[4 * k + 2] = w >>> 8 & 255;
173
+ msg[4 * k + 3] = w & 255;
174
+ }
175
+ if (!cnavCrcOk(msg)) {
176
+ badCrc++;
177
+ continue;
178
+ }
179
+ const eph = assembler.push(msg);
180
+ if (eph) ephemerides.push(eph);
181
+ }
182
+ return { ephemerides, badCrc, messages };
183
+ }
184
+
113
185
  // src/ubx/index.ts
114
186
  var GPS_EPOCH_MS = Date.UTC(1980, 0, 6);
115
187
  var MS_PER_WEEK = 7 * 864e5;
@@ -206,5 +278,7 @@ function parseUbxRawx(data) {
206
278
  export {
207
279
  ubxFrames,
208
280
  parseUbxNav,
281
+ parseUbxIonoUtc,
282
+ parseUbxCnav,
209
283
  parseUbxRawx
210
284
  };
@@ -140,7 +140,9 @@ function decodeGpsLnavFrame(subframes, opts = {}) {
140
140
  }
141
141
 
142
142
  export {
143
+ GPS_PI,
143
144
  getBitU,
145
+ getBitS,
144
146
  setBitU,
145
147
  decodeGpsLnavFrame
146
148
  };