gnss-js 1.16.0 → 1.17.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.
package/dist/ubx.cjs CHANGED
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/ubx/index.ts
21
21
  var ubx_exports = {};
22
22
  __export(ubx_exports, {
23
+ parseUbxIonoUtc: () => parseUbxIonoUtc,
23
24
  parseUbxNav: () => parseUbxNav,
24
25
  parseUbxRawx: () => parseUbxRawx,
25
26
  ubxFrames: () => ubxFrames
@@ -201,6 +202,30 @@ function decodeGpsLnavFrame(subframes, opts = {}) {
201
202
 
202
203
  // src/ubx/nav.ts
203
204
  var PREAMB_CNAV = 139;
205
+ function readLnavSubframe(view, f) {
206
+ const p = f.payload;
207
+ if (p.length < 8) return null;
208
+ const gnssId = p[0];
209
+ const svId = p[1];
210
+ let prn;
211
+ if (gnssId === 0 && svId >= 1 && svId <= 32) {
212
+ prn = `G${String(svId).padStart(2, "0")}`;
213
+ } else if (gnssId === 5 && svId >= 1 && svId <= 10) {
214
+ if (p.length === 44) return null;
215
+ prn = `J${String(svId).padStart(2, "0")}`;
216
+ } else {
217
+ return null;
218
+ }
219
+ if (p.length < 8 + 40) return null;
220
+ const base = f.payloadStart + 8;
221
+ if (view.getUint32(base, true) >>> 24 === PREAMB_CNAV) return null;
222
+ const buff = new Uint8Array(30);
223
+ for (let k = 0; k < 10; k++) {
224
+ const dwrd = view.getUint32(base + 4 * k, true);
225
+ setBitU(buff, 24 * k, 24, dwrd >>> 6 & 16777215);
226
+ }
227
+ return { prn, gnssId, svId, buff, id: getBitU(buff, 43, 3) };
228
+ }
204
229
  function parseUbxNav(data, opts = {}) {
205
230
  const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
206
231
  const ephemerides = [];
@@ -222,28 +247,9 @@ function parseUbxNav(data, opts = {}) {
222
247
  const last = /* @__PURE__ */ new Map();
223
248
  for (const f of ubxFrames(data)) {
224
249
  if (f.msgClass !== 2 || f.msgId !== 19) continue;
225
- const p = f.payload;
226
- if (p.length < 8) continue;
227
- const gnssId = p[0];
228
- const svId = p[1];
229
- let prn;
230
- if (gnssId === 0 && svId >= 1 && svId <= 32) {
231
- prn = `G${String(svId).padStart(2, "0")}`;
232
- } else if (gnssId === 5 && svId >= 1 && svId <= 10) {
233
- if (p.length === 44) continue;
234
- prn = `J${String(svId).padStart(2, "0")}`;
235
- } else {
236
- continue;
237
- }
238
- if (p.length < 8 + 40) continue;
239
- const base = f.payloadStart + 8;
240
- if (view.getUint32(base, true) >>> 24 === PREAMB_CNAV) continue;
241
- const buff = new Uint8Array(30);
242
- for (let k = 0; k < 10; k++) {
243
- const dwrd = view.getUint32(base + 4 * k, true);
244
- setBitU(buff, 24 * k, 24, dwrd >>> 6 & 16777215);
245
- }
246
- const id = getBitU(buff, 43, 3);
250
+ const lnav = readLnavSubframe(view, f);
251
+ if (!lnav) continue;
252
+ const { prn, gnssId, svId, buff, id } = lnav;
247
253
  if (id < 1 || id > 5) {
248
254
  badParity++;
249
255
  continue;
@@ -273,6 +279,34 @@ function parseUbxNav(data, opts = {}) {
273
279
  return { ephemerides, badParity };
274
280
  }
275
281
 
282
+ // src/ubx/iono.ts
283
+ function parseUbxIonoUtc(data) {
284
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
285
+ const ionoCorrections = {};
286
+ let leapSeconds = null;
287
+ for (const f of ubxFrames(data)) {
288
+ if (f.msgClass !== 2 || f.msgId !== 19) continue;
289
+ const sf = readLnavSubframe(view, f);
290
+ if (!sf || sf.gnssId !== 0 || sf.id !== 4) continue;
291
+ const b = sf.buff;
292
+ if (getBitU(b, 48, 2) !== 1 || getBitU(b, 50, 6) !== 56) continue;
293
+ ionoCorrections["GPSA"] = [
294
+ getBitS(b, 56, 8) * 2 ** -30,
295
+ getBitS(b, 64, 8) * 2 ** -27,
296
+ getBitS(b, 72, 8) * 2 ** -24,
297
+ getBitS(b, 80, 8) * 2 ** -24
298
+ ];
299
+ ionoCorrections["GPSB"] = [
300
+ getBitS(b, 88, 8) * 2 ** 11,
301
+ getBitS(b, 96, 8) * 2 ** 14,
302
+ getBitS(b, 104, 8) * 2 ** 16,
303
+ getBitS(b, 112, 8) * 2 ** 16
304
+ ];
305
+ leapSeconds = getBitS(b, 192, 8);
306
+ }
307
+ return { ionoCorrections, leapSeconds };
308
+ }
309
+
276
310
  // src/ubx/index.ts
277
311
  var GPS_EPOCH_MS2 = Date.UTC(1980, 0, 6);
278
312
  var MS_PER_WEEK = 7 * 864e5;
@@ -367,6 +401,7 @@ function parseUbxRawx(data) {
367
401
  }
368
402
  // Annotate the CommonJS export names for ESM import in node:
369
403
  0 && (module.exports = {
404
+ parseUbxIonoUtc,
370
405
  parseUbxNav,
371
406
  parseUbxRawx,
372
407
  ubxFrames
package/dist/ubx.d.cts CHANGED
@@ -46,7 +46,9 @@ declare function ubxFrames(data: Uint8Array, stats?: {
46
46
  *
47
47
  * Other constellations in RXM-SFRBX (Galileo I/NAV, BDS D1/D2, GLONASS
48
48
  * strings, SBAS) and GPS/QZSS CNAV are out of scope and skipped
49
- * silently, as are LNAV subframes 4/5 (iono/UTC/almanac pages).
49
+ * silently. LNAV subframes 4/5 are skipped here except that
50
+ * `parseUbxIonoUtc` (./iono.ts) decodes the subframe-4 page-18
51
+ * iono/UTC parameters through the shared `readLnavSubframe` helper.
50
52
  */
51
53
 
52
54
  interface UbxNavOptions {
@@ -77,6 +79,44 @@ interface UbxNavResult {
77
79
  */
78
80
  declare function parseUbxNav(data: Uint8Array, opts?: UbxNavOptions): UbxNavResult;
79
81
 
82
+ /**
83
+ * u-blox UBX ionosphere / UTC decoding: the GPS LNAV subframe 4
84
+ * page 18 broadcast (Klobuchar coefficients + GPS-UTC parameters)
85
+ * from RXM-SFRBX.
86
+ *
87
+ * Ported from RTKLIB demo5 (rtklibexplorer fork, src/rcvraw.c:
88
+ * decode_frame_ion / decode_frame_utc, Copyright (c) 2007-2020
89
+ * T. Takasu, BSD-2-Clause); frame extraction is shared with
90
+ * `parseUbxNav` through `readLnavSubframe` (./nav.ts).
91
+ *
92
+ * Scope is GPS satellites (gnssId 0) only: QZSS also broadcasts
93
+ * page-18-format iono parameters, but those are the separate
94
+ * wide-area/Japan-area QZSS coefficient set, not the GPS one a RINEX
95
+ * `GPSA`/`GPSB` header carries. Scale factors follow IS-GPS-200
96
+ * §20.3.3.5.1 (alpha_n in s/semicircle^n, beta_n in s/semicircle^n) —
97
+ * the same semicircle-based units the RINEX nav header prints, so the
98
+ * output matches `parseNavFile` on a converted header. Like
99
+ * `parseUbxNav`, the decoder never consults the system clock (nothing
100
+ * here needs a week reference).
101
+ */
102
+ interface UbxIonoUtcResult {
103
+ /**
104
+ * Iono coefficient sets keyed like `NavHeader.ionoCorrections`:
105
+ * `GPSA` (alpha_0..3) and `GPSB` (beta_0..3). The page repeats
106
+ * (nominally every 12.5 min per satellite); the last broadcast in
107
+ * the stream wins.
108
+ */
109
+ ionoCorrections: Record<string, number[]>;
110
+ /** GPS-UTC ΔtLS from the last page-18 broadcast, if any. */
111
+ leapSeconds: number | null;
112
+ }
113
+ /**
114
+ * Decode every GPS LNAV subframe 4 page 18 (data ID 1, SV ID 56) in a
115
+ * UBX byte stream (RXM-SFRBX) into Klobuchar iono coefficients and the
116
+ * current leap-second count.
117
+ */
118
+ declare function parseUbxIonoUtc(data: Uint8Array): UbxIonoUtcResult;
119
+
80
120
  /**
81
121
  * u-blox UBX raw-measurement decoding (RXM-RAWX) — the path from a
82
122
  * receiver log to RINEX-grade observables.
@@ -133,4 +173,4 @@ interface UbxParseResult {
133
173
  */
134
174
  declare function parseUbxRawx(data: Uint8Array): UbxParseResult;
135
175
 
136
- export { type UbxFrame, type UbxMeasurement, type UbxNavOptions, type UbxNavResult, type UbxParseResult, type UbxRawxEpoch, parseUbxNav, parseUbxRawx, ubxFrames };
176
+ export { type UbxFrame, type UbxIonoUtcResult, type UbxMeasurement, type UbxNavOptions, type UbxNavResult, type UbxParseResult, type UbxRawxEpoch, parseUbxIonoUtc, parseUbxNav, parseUbxRawx, ubxFrames };
package/dist/ubx.d.ts CHANGED
@@ -46,7 +46,9 @@ declare function ubxFrames(data: Uint8Array, stats?: {
46
46
  *
47
47
  * Other constellations in RXM-SFRBX (Galileo I/NAV, BDS D1/D2, GLONASS
48
48
  * strings, SBAS) and GPS/QZSS CNAV are out of scope and skipped
49
- * silently, as are LNAV subframes 4/5 (iono/UTC/almanac pages).
49
+ * silently. LNAV subframes 4/5 are skipped here except that
50
+ * `parseUbxIonoUtc` (./iono.ts) decodes the subframe-4 page-18
51
+ * iono/UTC parameters through the shared `readLnavSubframe` helper.
50
52
  */
51
53
 
52
54
  interface UbxNavOptions {
@@ -77,6 +79,44 @@ interface UbxNavResult {
77
79
  */
78
80
  declare function parseUbxNav(data: Uint8Array, opts?: UbxNavOptions): UbxNavResult;
79
81
 
82
+ /**
83
+ * u-blox UBX ionosphere / UTC decoding: the GPS LNAV subframe 4
84
+ * page 18 broadcast (Klobuchar coefficients + GPS-UTC parameters)
85
+ * from RXM-SFRBX.
86
+ *
87
+ * Ported from RTKLIB demo5 (rtklibexplorer fork, src/rcvraw.c:
88
+ * decode_frame_ion / decode_frame_utc, Copyright (c) 2007-2020
89
+ * T. Takasu, BSD-2-Clause); frame extraction is shared with
90
+ * `parseUbxNav` through `readLnavSubframe` (./nav.ts).
91
+ *
92
+ * Scope is GPS satellites (gnssId 0) only: QZSS also broadcasts
93
+ * page-18-format iono parameters, but those are the separate
94
+ * wide-area/Japan-area QZSS coefficient set, not the GPS one a RINEX
95
+ * `GPSA`/`GPSB` header carries. Scale factors follow IS-GPS-200
96
+ * §20.3.3.5.1 (alpha_n in s/semicircle^n, beta_n in s/semicircle^n) —
97
+ * the same semicircle-based units the RINEX nav header prints, so the
98
+ * output matches `parseNavFile` on a converted header. Like
99
+ * `parseUbxNav`, the decoder never consults the system clock (nothing
100
+ * here needs a week reference).
101
+ */
102
+ interface UbxIonoUtcResult {
103
+ /**
104
+ * Iono coefficient sets keyed like `NavHeader.ionoCorrections`:
105
+ * `GPSA` (alpha_0..3) and `GPSB` (beta_0..3). The page repeats
106
+ * (nominally every 12.5 min per satellite); the last broadcast in
107
+ * the stream wins.
108
+ */
109
+ ionoCorrections: Record<string, number[]>;
110
+ /** GPS-UTC ΔtLS from the last page-18 broadcast, if any. */
111
+ leapSeconds: number | null;
112
+ }
113
+ /**
114
+ * Decode every GPS LNAV subframe 4 page 18 (data ID 1, SV ID 56) in a
115
+ * UBX byte stream (RXM-SFRBX) into Klobuchar iono coefficients and the
116
+ * current leap-second count.
117
+ */
118
+ declare function parseUbxIonoUtc(data: Uint8Array): UbxIonoUtcResult;
119
+
80
120
  /**
81
121
  * u-blox UBX raw-measurement decoding (RXM-RAWX) — the path from a
82
122
  * receiver log to RINEX-grade observables.
@@ -133,4 +173,4 @@ interface UbxParseResult {
133
173
  */
134
174
  declare function parseUbxRawx(data: Uint8Array): UbxParseResult;
135
175
 
136
- export { type UbxFrame, type UbxMeasurement, type UbxNavOptions, type UbxNavResult, type UbxParseResult, type UbxRawxEpoch, parseUbxNav, parseUbxRawx, ubxFrames };
176
+ export { type UbxFrame, type UbxIonoUtcResult, type UbxMeasurement, type UbxNavOptions, type UbxNavResult, type UbxParseResult, type UbxRawxEpoch, parseUbxIonoUtc, parseUbxNav, parseUbxRawx, ubxFrames };
package/dist/ubx.js CHANGED
@@ -1,10 +1,12 @@
1
1
  import {
2
+ parseUbxIonoUtc,
2
3
  parseUbxNav,
3
4
  parseUbxRawx,
4
5
  ubxFrames
5
- } from "./chunk-6CX6EXRK.js";
6
- import "./chunk-4LVD4DYL.js";
6
+ } from "./chunk-IG5CDNDS.js";
7
+ import "./chunk-REYOYF7O.js";
7
8
  export {
9
+ parseUbxIonoUtc,
8
10
  parseUbxNav,
9
11
  parseUbxRawx,
10
12
  ubxFrames
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gnss-js",
3
- "version": "1.16.0",
3
+ "version": "1.17.0",
4
4
  "description": "Comprehensive GNSS library for JavaScript — time scales, coordinates, RINEX parsing, RTCM3 decoding, orbit computation, and signal analysis",
5
5
  "type": "module",
6
6
  "sideEffects": false,