gnss-js 1.36.0 → 1.37.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/index.cjs CHANGED
@@ -142,6 +142,7 @@ __export(src_exports, {
142
142
  decodeBinexEph: () => decodeBinexEph,
143
143
  decodeEphemeris: () => decodeEphemeris,
144
144
  decodeMsmFull: () => decodeMsmFull,
145
+ decodeSbfNavigation: () => decodeSbfNavigation,
145
146
  deg2dms: () => deg2dms,
146
147
  deg2rad: () => deg2rad,
147
148
  detrendIonoArcs: () => detrendIonoArcs,
@@ -260,6 +261,7 @@ __export(src_exports, {
260
261
  parseSbfCnav: () => parseSbfCnav,
261
262
  parseSbfGalNav: () => parseSbfGalNav,
262
263
  parseSbfGloNav: () => parseSbfGloNav,
264
+ parseSbfGpsNav: () => parseSbfGpsNav,
263
265
  parseSbfHas: () => parseSbfHas,
264
266
  parseSbfIonoUtc: () => parseSbfIonoUtc,
265
267
  parseSbfMeas: () => parseSbfMeas,
@@ -2699,6 +2701,38 @@ function setBitU(buff, pos, len, data) {
2699
2701
  }
2700
2702
  }
2701
2703
  }
2704
+ var GpsLnavAssembler = class _GpsLnavAssembler {
2705
+ buffers = /* @__PURE__ */ new Map();
2706
+ last = /* @__PURE__ */ new Map();
2707
+ /** Subframe ID (1–5) from the HOW word of a parity-stripped subframe. */
2708
+ static subframeId(subframe) {
2709
+ return getBitU(subframe, 43, 3);
2710
+ }
2711
+ /**
2712
+ * Push one parity-stripped 30-byte LNAV subframe for `prn`, resolving
2713
+ * the 10-bit week against `refWeek`. See {@link LnavPush} for outcomes.
2714
+ */
2715
+ push(prn, subframe, refWeek) {
2716
+ const id = _GpsLnavAssembler.subframeId(subframe);
2717
+ if (id < 1 || id > 3) return { kind: "skipped" };
2718
+ let sf = this.buffers.get(prn);
2719
+ if (!sf) {
2720
+ sf = { buf: new Uint8Array(90), have: 0 };
2721
+ this.buffers.set(prn, sf);
2722
+ }
2723
+ sf.buf.set(subframe, (id - 1) * 30);
2724
+ sf.have |= 1 << id - 1;
2725
+ if (id !== 3 || sf.have !== 7) return { kind: "incomplete" };
2726
+ const eph = decodeGpsLnavFrame(sf.buf, { prn, refWeek });
2727
+ if (!eph) return { kind: "decodeFailed" };
2728
+ const prev = this.last.get(prn);
2729
+ if (prev && prev.iode === eph.iode && prev.tocDate.getTime() === eph.tocDate.getTime()) {
2730
+ return { kind: "duplicate" };
2731
+ }
2732
+ this.last.set(prn, eph);
2733
+ return { kind: "eph", eph };
2734
+ }
2735
+ };
2702
2736
  function decodeGpsLnavFrame(subframes, opts = {}) {
2703
2737
  if (subframes.length < 90) return null;
2704
2738
  const b = subframes;
@@ -5918,38 +5952,19 @@ function parseUbxNav(data, opts = {}) {
5918
5952
  }
5919
5953
  }
5920
5954
  if (refWeek === void 0) return { ephemerides, badParity };
5921
- const subframes = /* @__PURE__ */ new Map();
5922
- const last = /* @__PURE__ */ new Map();
5955
+ const assembler = new GpsLnavAssembler();
5923
5956
  for (const f of ubxFrames(data)) {
5924
5957
  if (f.msgClass !== 2 || f.msgId !== 19) continue;
5925
5958
  const lnav = readLnavSubframe(view, f);
5926
5959
  if (!lnav) continue;
5927
- const { prn, gnssId, svId, buff, id } = lnav;
5960
+ const { prn, buff, id } = lnav;
5928
5961
  if (id < 1 || id > 5) {
5929
5962
  badParity++;
5930
5963
  continue;
5931
5964
  }
5932
- if (id > 3) continue;
5933
- const key = gnssId * 256 + svId;
5934
- let sf = subframes.get(key);
5935
- if (!sf) {
5936
- sf = { buf: new Uint8Array(90), have: 0 };
5937
- subframes.set(key, sf);
5938
- }
5939
- sf.buf.set(buff, (id - 1) * 30);
5940
- sf.have |= 1 << id - 1;
5941
- if (id !== 3 || sf.have !== 7) continue;
5942
- const eph = decodeGpsLnavFrame(sf.buf, { prn, refWeek });
5943
- if (!eph) {
5944
- badParity++;
5945
- continue;
5946
- }
5947
- const prev = last.get(prn);
5948
- if (prev && prev.iode === eph.iode && prev.tocDate.getTime() === eph.tocDate.getTime()) {
5949
- continue;
5950
- }
5951
- last.set(prn, eph);
5952
- ephemerides.push(eph);
5965
+ const r = assembler.push(prn, buff, refWeek);
5966
+ if (r.kind === "eph") ephemerides.push(r.eph);
5967
+ else if (r.kind === "decodeFailed") badParity++;
5953
5968
  }
5954
5969
  return { ephemerides, badParity };
5955
5970
  }
@@ -7360,38 +7375,78 @@ function parseSbfIonoUtc(data) {
7360
7375
  return { ionoCorrections, leapSeconds };
7361
7376
  }
7362
7377
 
7378
+ // src/sbf/rawnav-gps.ts
7379
+ var WNC_DNU = 65535;
7380
+ function extractSbfLnavSubframe(view, b) {
7381
+ const sf = new Uint8Array(30);
7382
+ for (let k = 0; k < 10; k++) {
7383
+ const w = view.getUint32(b + 20 + 4 * k, true);
7384
+ setBitU(sf, 24 * k, 24, w >>> 6 & 16777215);
7385
+ }
7386
+ return sf;
7387
+ }
7388
+ function feedGpsLnavBlock(view, b, assembler) {
7389
+ const prn = svidToPrn(view.getUint8(b + 14));
7390
+ if (!prn || prn[0] !== "G" && prn[0] !== "J") return {};
7391
+ if (view.getUint8(b + 15) !== 1) return {};
7392
+ const wnc = view.getUint16(b + 12, true);
7393
+ if (wnc === WNC_DNU) return {};
7394
+ const r = assembler.push(prn, extractSbfLnavSubframe(view, b), wnc);
7395
+ if (r.kind === "eph") return { eph: r.eph };
7396
+ if (r.kind === "decodeFailed") return { badParity: true };
7397
+ return {};
7398
+ }
7399
+ function parseSbfGpsNav(data) {
7400
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
7401
+ const ephemerides = [];
7402
+ const assembler = new GpsLnavAssembler();
7403
+ let badParity = 0;
7404
+ let messages = 0;
7405
+ scanSbfFrames(data, view, (id, b, len) => {
7406
+ if (id !== 4017 && id !== 4066 || len < 60) return;
7407
+ messages++;
7408
+ const r = feedGpsLnavBlock(view, b, assembler);
7409
+ if (r.eph) ephemerides.push(r.eph);
7410
+ else if (r.badParity) badParity++;
7411
+ });
7412
+ return { ephemerides, badParity, messages };
7413
+ }
7414
+
7363
7415
  // src/sbf/rawnav.ts
7364
- var SIGNAL_OF_BLOCK = {
7416
+ var CNAV_SIGNAL_OF_BLOCK = {
7365
7417
  4018: "L2C",
7366
7418
  4019: "L5"
7367
7419
  };
7420
+ function newCnavAssemblers() {
7421
+ return { L2C: new CnavAssembler(), L5: new CnavAssembler() };
7422
+ }
7423
+ function feedCnavBlock(view, b, id, asm) {
7424
+ const signal = CNAV_SIGNAL_OF_BLOCK[id];
7425
+ if (!signal) return {};
7426
+ const msg = new Uint8Array(40);
7427
+ for (let k = 0; k < 10; k++) {
7428
+ const w = view.getUint32(b + 20 + 4 * k, true);
7429
+ msg[4 * k] = w >>> 24;
7430
+ msg[4 * k + 1] = w >>> 16 & 255;
7431
+ msg[4 * k + 2] = w >>> 8 & 255;
7432
+ msg[4 * k + 3] = w & 255;
7433
+ }
7434
+ if (!cnavCrcOk(msg)) return { badCrc: true };
7435
+ const eph = asm[signal].push(msg);
7436
+ return eph ? { eph: { ...eph, signal } } : {};
7437
+ }
7368
7438
  function parseSbfCnav(data) {
7369
7439
  const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
7370
7440
  const ephemerides = [];
7371
- const assemblers = {
7372
- L2C: new CnavAssembler(),
7373
- L5: new CnavAssembler()
7374
- };
7441
+ const asm = newCnavAssemblers();
7375
7442
  let badCrc = 0;
7376
7443
  let messages = 0;
7377
7444
  scanSbfFrames(data, view, (id, b, len) => {
7378
- const signal = SIGNAL_OF_BLOCK[id];
7379
- if (!signal || len < 60) return;
7445
+ if (!CNAV_SIGNAL_OF_BLOCK[id] || len < 60) return;
7380
7446
  messages++;
7381
- const msg = new Uint8Array(40);
7382
- for (let k = 0; k < 10; k++) {
7383
- const w = view.getUint32(b + 20 + 4 * k, true);
7384
- msg[4 * k] = w >>> 24;
7385
- msg[4 * k + 1] = w >>> 16 & 255;
7386
- msg[4 * k + 2] = w >>> 8 & 255;
7387
- msg[4 * k + 3] = w & 255;
7388
- }
7389
- if (!cnavCrcOk(msg)) {
7390
- badCrc++;
7391
- return;
7392
- }
7393
- const eph = assemblers[signal].push(msg);
7394
- if (eph) ephemerides.push({ ...eph, signal });
7447
+ const r = feedCnavBlock(view, b, id, asm);
7448
+ if (r.eph) ephemerides.push(r.eph);
7449
+ else if (r.badCrc) badCrc++;
7395
7450
  });
7396
7451
  return { ephemerides, badCrc, messages };
7397
7452
  }
@@ -7399,50 +7454,51 @@ function parseSbfCnav(data) {
7399
7454
  // src/sbf/rawnav-gal.ts
7400
7455
  var INAV_SOURCES = [17, 21, 22];
7401
7456
  var FNAV_SOURCES = [20, 22];
7457
+ function newGalAssemblers() {
7458
+ return { inav: new GalInavAssembler(), fnav: new GalFnavAssembler() };
7459
+ }
7460
+ function feedGalBlock(data, view, b, id, asm) {
7461
+ const prnStr = svidToPrn(data[b + 14]);
7462
+ if (!prnStr || prnStr[0] !== "E") return {};
7463
+ const prn = parseInt(prnStr.slice(1), 10);
7464
+ const source = data[b + 17] & 31;
7465
+ const page = new Uint8Array(32);
7466
+ for (let k = 0; k < 8; k++) {
7467
+ const w = view.getUint32(b + 20 + 4 * k, true);
7468
+ page[4 * k] = w >>> 24;
7469
+ page[4 * k + 1] = w >>> 16 & 255;
7470
+ page[4 * k + 2] = w >>> 8 & 255;
7471
+ page[4 * k + 3] = w & 255;
7472
+ }
7473
+ let eph;
7474
+ let src;
7475
+ if (id === 4023) {
7476
+ src = "inav";
7477
+ if (!INAV_SOURCES.includes(source)) return {};
7478
+ if (getBitU22(page, 0) !== 0 || getBitU22(page, 114) !== 1) return {};
7479
+ if (!galInavPageCrcOk(page)) return { badCrc: true };
7480
+ eph = asm.inav.push(prn, page);
7481
+ } else {
7482
+ src = "fnav";
7483
+ if (!FNAV_SOURCES.includes(source)) return {};
7484
+ if (isFnavDummy(page)) return {};
7485
+ if (!galFnavPageCrcOk(page)) return { badCrc: true };
7486
+ eph = asm.fnav.push(prn, page);
7487
+ }
7488
+ return eph ? { eph: { ...eph, source: src } } : {};
7489
+ }
7402
7490
  function parseSbfGalNav(data) {
7403
7491
  const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
7404
7492
  const ephemerides = [];
7405
- const inav = new GalInavAssembler();
7406
- const fnav = new GalFnavAssembler();
7493
+ const asm = newGalAssemblers();
7407
7494
  let badCrc = 0;
7408
7495
  let messages = 0;
7409
7496
  scanSbfFrames(data, view, (id, b, len) => {
7410
7497
  if (id !== 4022 && id !== 4023 || len < 52) return;
7411
7498
  messages++;
7412
- const prnStr = svidToPrn(data[b + 14]);
7413
- if (!prnStr || prnStr[0] !== "E") return;
7414
- const prn = parseInt(prnStr.slice(1), 10);
7415
- const source = data[b + 17] & 31;
7416
- const page = new Uint8Array(32);
7417
- for (let k = 0; k < 8; k++) {
7418
- const w = view.getUint32(b + 20 + 4 * k, true);
7419
- page[4 * k] = w >>> 24;
7420
- page[4 * k + 1] = w >>> 16 & 255;
7421
- page[4 * k + 2] = w >>> 8 & 255;
7422
- page[4 * k + 3] = w & 255;
7423
- }
7424
- let eph;
7425
- let src;
7426
- if (id === 4023) {
7427
- src = "inav";
7428
- if (!INAV_SOURCES.includes(source)) return;
7429
- if (getBitU22(page, 0) !== 0 || getBitU22(page, 114) !== 1) return;
7430
- if (!galInavPageCrcOk(page)) {
7431
- badCrc++;
7432
- return;
7433
- }
7434
- eph = inav.push(prn, page);
7435
- } else {
7436
- src = "fnav";
7437
- if (!FNAV_SOURCES.includes(source)) return;
7438
- if (isFnavDummy(page)) return;
7439
- if (!galFnavPageCrcOk(page)) {
7440
- badCrc++;
7441
- return;
7442
- }
7443
- eph = fnav.push(prn, page);
7444
- }
7445
- if (eph) ephemerides.push({ ...eph, source: src });
7499
+ const r = feedGalBlock(data, view, b, id, asm);
7500
+ if (r.eph) ephemerides.push(r.eph);
7501
+ else if (r.badCrc) badCrc++;
7446
7502
  });
7447
7503
  return { ephemerides, badCrc, messages };
7448
7504
  }
@@ -7457,7 +7513,26 @@ function isFnavDummy(page) {
7457
7513
  var GPS_EPOCH_MS10 = Date.UTC(1980, 0, 6);
7458
7514
  var MS_PER_WEEK5 = 7 * 86400 * 1e3;
7459
7515
  var TOW_DNU = 4294967295;
7460
- var WNC_DNU = 65535;
7516
+ var WNC_DNU2 = 65535;
7517
+ function feedBdsBlock(view, b, assembler) {
7518
+ const prn = svidToPrn(view.getUint8(b + 14));
7519
+ if (!prn || prn[0] !== "C") return {};
7520
+ const sf = new Uint8Array(38);
7521
+ for (let k = 0; k < 10; k++) {
7522
+ const w = view.getUint32(b + 20 + 4 * k, true);
7523
+ sf[4 * k] = w >>> 24;
7524
+ if (k < 9) {
7525
+ sf[4 * k + 1] = w >>> 16 & 255;
7526
+ sf[4 * k + 2] = w >>> 8 & 255;
7527
+ sf[4 * k + 3] = w & 255;
7528
+ } else {
7529
+ sf[37] = w >>> 16 & 240;
7530
+ }
7531
+ }
7532
+ if (!bdsSubframeParityOk(sf)) return { badCrc: true };
7533
+ const eph = assembler.push(prn, sf);
7534
+ return eph ? { eph } : {};
7535
+ }
7461
7536
  function parseSbfBdsNav(data) {
7462
7537
  const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
7463
7538
  const ephemerides = [];
@@ -7467,29 +7542,41 @@ function parseSbfBdsNav(data) {
7467
7542
  scanSbfFrames(data, view, (id, b, len) => {
7468
7543
  if (id !== 4047 || len < 60) return;
7469
7544
  messages++;
7470
- const prn = svidToPrn(view.getUint8(b + 14));
7471
- if (!prn || prn[0] !== "C") return;
7472
- const sf = new Uint8Array(38);
7473
- for (let k = 0; k < 10; k++) {
7474
- const w = view.getUint32(b + 20 + 4 * k, true);
7475
- sf[4 * k] = w >>> 24;
7476
- if (k < 9) {
7477
- sf[4 * k + 1] = w >>> 16 & 255;
7478
- sf[4 * k + 2] = w >>> 8 & 255;
7479
- sf[4 * k + 3] = w & 255;
7480
- } else {
7481
- sf[37] = w >>> 16 & 240;
7482
- }
7483
- }
7484
- if (!bdsSubframeParityOk(sf)) {
7485
- badCrc++;
7486
- return;
7487
- }
7488
- const eph = assembler.push(prn, sf);
7489
- if (eph) ephemerides.push(eph);
7545
+ const r = feedBdsBlock(view, b, assembler);
7546
+ if (r.eph) ephemerides.push(r.eph);
7547
+ else if (r.badCrc) badCrc++;
7490
7548
  });
7491
7549
  return { ephemerides, badCrc, messages };
7492
7550
  }
7551
+ function feedGloBlock(view, b, assembler) {
7552
+ const prn = svidToPrn(view.getUint8(b + 14));
7553
+ if (!prn || prn[0] !== "R") return {};
7554
+ const towMs = view.getUint32(b + 8, true);
7555
+ const wnc = view.getUint16(b + 12, true);
7556
+ if (towMs === TOW_DNU || wnc === WNC_DNU2) return {};
7557
+ const str = new Uint8Array(11);
7558
+ for (let k = 0; k < 3; k++) {
7559
+ const w = view.getUint32(b + 20 + 4 * k, true);
7560
+ str[4 * k] = w >>> 24;
7561
+ if (k < 2) {
7562
+ str[4 * k + 1] = w >>> 16 & 255;
7563
+ str[4 * k + 2] = w >>> 8 & 255;
7564
+ str[4 * k + 3] = w & 255;
7565
+ } else {
7566
+ str[9] = w >>> 16 & 255;
7567
+ str[10] = w >>> 8 & 248;
7568
+ }
7569
+ }
7570
+ if (!testGloString(str)) return { badCrc: true };
7571
+ const eph = assembler.push(
7572
+ prn,
7573
+ str,
7574
+ new Date(GPS_EPOCH_MS10 + wnc * MS_PER_WEEK5 + towMs),
7575
+ view.getUint8(b + 18) - 8
7576
+ // FreqNr, offset by 8
7577
+ );
7578
+ return eph ? { eph } : {};
7579
+ }
7493
7580
  function parseSbfGloNav(data) {
7494
7581
  const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
7495
7582
  const ephemerides = [];
@@ -7499,38 +7586,161 @@ function parseSbfGloNav(data) {
7499
7586
  scanSbfFrames(data, view, (id, b, len) => {
7500
7587
  if (id !== 4026 || len < 32) return;
7501
7588
  messages++;
7502
- const prn = svidToPrn(view.getUint8(b + 14));
7503
- if (!prn || prn[0] !== "R") return;
7504
- const towMs = view.getUint32(b + 8, true);
7505
- const wnc = view.getUint16(b + 12, true);
7506
- if (towMs === TOW_DNU || wnc === WNC_DNU) return;
7507
- const str = new Uint8Array(11);
7508
- for (let k = 0; k < 3; k++) {
7509
- const w = view.getUint32(b + 20 + 4 * k, true);
7510
- str[4 * k] = w >>> 24;
7511
- if (k < 2) {
7512
- str[4 * k + 1] = w >>> 16 & 255;
7513
- str[4 * k + 2] = w >>> 8 & 255;
7514
- str[4 * k + 3] = w & 255;
7515
- } else {
7516
- str[9] = w >>> 16 & 255;
7517
- str[10] = w >>> 8 & 248;
7518
- }
7589
+ const r = feedGloBlock(view, b, assembler);
7590
+ if (r.eph) ephemerides.push(r.eph);
7591
+ else if (r.badCrc) badCrc++;
7592
+ });
7593
+ return { ephemerides, badCrc, messages };
7594
+ }
7595
+
7596
+ // src/sbf/navigation.ts
7597
+ var F4_DNU3 = -2e10;
7598
+ function ephKey(e) {
7599
+ const source = "source" in e ? e.source : "";
7600
+ return `${e.prn}|${e.tocDate.getTime()}|${source}`;
7601
+ }
7602
+ function decodeSbfNavigation(data) {
7603
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
7604
+ const ephemerides = [];
7605
+ const seen = /* @__PURE__ */ new Set();
7606
+ const cnav = [];
7607
+ const ionoCorrections = {};
7608
+ let leapSeconds = null;
7609
+ const counts = {
7610
+ decodedNav: 0,
7611
+ gpsLnavRaw: 0,
7612
+ cnavRaw: 0,
7613
+ galRaw: 0,
7614
+ gloRaw: 0,
7615
+ bdsRaw: 0,
7616
+ badFrames: 0
7617
+ };
7618
+ const cnavAsm = newCnavAssemblers();
7619
+ const galAsm = newGalAssemblers();
7620
+ const gloAsm = new GloStringAssembler();
7621
+ const bdsAsm = new BdsAssembler();
7622
+ const lnavAsm = new GpsLnavAssembler();
7623
+ const addEph = (e) => {
7624
+ if (!e) return;
7625
+ const key = ephKey(e);
7626
+ if (seen.has(key)) return;
7627
+ seen.add(key);
7628
+ ephemerides.push(e);
7629
+ };
7630
+ const f4s = (b, n) => {
7631
+ const out = [];
7632
+ for (let k = 0; k < n; k++) {
7633
+ const v = view.getFloat32(b + 4 * k, true);
7634
+ if (v === F4_DNU3) return null;
7635
+ out.push(v);
7519
7636
  }
7520
- if (!testGloString(str)) {
7521
- badCrc++;
7522
- return;
7637
+ return out;
7638
+ };
7639
+ scanSbfFrames(data, view, (id, b, len) => {
7640
+ switch (id) {
7641
+ /* ---- decoded ephemeris blocks ---- */
7642
+ case 5891:
7643
+ if (len >= 140) {
7644
+ counts.decodedNav++;
7645
+ addEph(decodeGpsQzsNav(view, b, "G"));
7646
+ }
7647
+ return;
7648
+ case 4095:
7649
+ if (len >= 140) {
7650
+ counts.decodedNav++;
7651
+ addEph(decodeGpsQzsNav(view, b, "J"));
7652
+ }
7653
+ return;
7654
+ case 4002:
7655
+ if (len >= 149) {
7656
+ counts.decodedNav++;
7657
+ addEph(decodeGalNav(view, b));
7658
+ }
7659
+ return;
7660
+ case 4081:
7661
+ if (len >= 140) {
7662
+ counts.decodedNav++;
7663
+ addEph(decodeBdsNav(view, b));
7664
+ }
7665
+ return;
7666
+ case 4004:
7667
+ if (len >= 96) {
7668
+ counts.decodedNav++;
7669
+ addEph(decodeGloNav(view, b));
7670
+ }
7671
+ return;
7672
+ /* ---- raw navigation-frame blocks ---- */
7673
+ case 4017:
7674
+ // GPSRawCA
7675
+ case 4066: {
7676
+ if (len < 60) return;
7677
+ counts.gpsLnavRaw++;
7678
+ const r = feedGpsLnavBlock(view, b, lnavAsm);
7679
+ if (r.eph) addEph(r.eph);
7680
+ else if (r.badParity) counts.badFrames++;
7681
+ return;
7682
+ }
7683
+ case 4018:
7684
+ // GPSRawL2C
7685
+ case 4019: {
7686
+ if (len < 60) return;
7687
+ counts.cnavRaw++;
7688
+ const r = feedCnavBlock(view, b, id, cnavAsm);
7689
+ if (r.eph) cnav.push(r.eph);
7690
+ else if (r.badCrc) counts.badFrames++;
7691
+ return;
7692
+ }
7693
+ case 4022:
7694
+ // GALRawFNAV
7695
+ case 4023: {
7696
+ if (len < 52) return;
7697
+ counts.galRaw++;
7698
+ const r = feedGalBlock(data, view, b, id, galAsm);
7699
+ if (r.eph) addEph(r.eph);
7700
+ else if (r.badCrc) counts.badFrames++;
7701
+ return;
7702
+ }
7703
+ case 4026: {
7704
+ if (len < 32) return;
7705
+ counts.gloRaw++;
7706
+ const r = feedGloBlock(view, b, gloAsm);
7707
+ if (r.eph) addEph(r.eph);
7708
+ else if (r.badCrc) counts.badFrames++;
7709
+ return;
7710
+ }
7711
+ case 4047: {
7712
+ if (len < 60) return;
7713
+ counts.bdsRaw++;
7714
+ const r = feedBdsBlock(view, b, bdsAsm);
7715
+ if (r.eph) addEph(r.eph);
7716
+ else if (r.badCrc) counts.badFrames++;
7717
+ return;
7718
+ }
7719
+ /* ---- iono / UTC ---- */
7720
+ case 5893:
7721
+ // GPSIon
7722
+ case 4120: {
7723
+ if (len < 48) return;
7724
+ const alpha = f4s(b + 16, 4);
7725
+ const beta = f4s(b + 32, 4);
7726
+ if (!alpha || !beta) return;
7727
+ const sys = id === 5893 ? "GPS" : "BDS";
7728
+ ionoCorrections[`${sys}A`] = alpha;
7729
+ ionoCorrections[`${sys}B`] = beta;
7730
+ return;
7731
+ }
7732
+ case 4030: {
7733
+ if (len < 28) return;
7734
+ const ai = f4s(b + 16, 3);
7735
+ if (ai) ionoCorrections["GAL"] = ai;
7736
+ return;
7737
+ }
7738
+ case 5894:
7739
+ if (len >= 37) leapSeconds = view.getInt8(b + 33);
7740
+ return;
7523
7741
  }
7524
- const eph = assembler.push(
7525
- prn,
7526
- str,
7527
- new Date(GPS_EPOCH_MS10 + wnc * MS_PER_WEEK5 + towMs),
7528
- view.getUint8(b + 18) - 8
7529
- // FreqNr, offset by 8
7530
- );
7531
- if (eph) ephemerides.push(eph);
7532
7742
  });
7533
- return { ephemerides, badCrc, messages };
7743
+ return { ephemerides, cnav, ionoCorrections, leapSeconds, counts };
7534
7744
  }
7535
7745
 
7536
7746
  // src/navbits/rs255.ts
@@ -16398,6 +16608,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
16398
16608
  decodeBinexEph,
16399
16609
  decodeEphemeris,
16400
16610
  decodeMsmFull,
16611
+ decodeSbfNavigation,
16401
16612
  deg2dms,
16402
16613
  deg2rad,
16403
16614
  detrendIonoArcs,
@@ -16516,6 +16727,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
16516
16727
  parseSbfCnav,
16517
16728
  parseSbfGalNav,
16518
16729
  parseSbfGloNav,
16730
+ parseSbfGpsNav,
16519
16731
  parseSbfHas,
16520
16732
  parseSbfIonoUtc,
16521
16733
  parseSbfMeas,
package/dist/index.d.cts CHANGED
@@ -11,7 +11,7 @@ export { C as ClkFile, I as IonexGrid, S as Sp3File, a as Sp3Sample, c as clkBia
11
11
  export { B as BitReader, E as EphemerisInfo, R as Rtcm3DebugHandler, a as Rtcm3Decoder, b as Rtcm3Frame, d as decodeEphemeris, r as readString, c as reportDecodeError, s as setRtcm3DebugHandler } from './ephemeris-Ohl6NAfw.cjs';
12
12
  export { MessageTypeStats, MsmEpoch, MsmSatObs, MsmSignal, RTCM3_MESSAGE_NAMES, SatCn0, SignalCn0, StationMeta, StreamStats, createStationMeta, createStreamStats, decodeMsmFull, msmEpochToDate, resetGloFreqCache, rtcm3Constellation, setGloFreqNumber, updateStationMeta, updateStreamStats } from './rtcm3.cjs';
13
13
  export { UbxCnavResult, UbxFrame, UbxIonoUtcResult, UbxMeasurement, UbxNavOptions, UbxNavResult, UbxParseResult, UbxRawNavOptions, UbxRawNavResult, UbxRawxEpoch, parseUbxCnav, parseUbxIonoUtc, parseUbxNav, parseUbxRawNav, parseUbxRawx, ubxFrames } from './ubx.cjs';
14
- export { HasMessage, SbfBdsNavResult, SbfCnavEphemeris, SbfCnavResult, SbfGalEphemeris, SbfGalNavResult, SbfGloNavResult, SbfHasMessage, SbfHasResult, SbfIonoUtcResult, SbfMeasEpoch, SbfMeasurement, SbfParseResult, parseSbfBdsNav, parseSbfCnav, parseSbfGalNav, parseSbfGloNav, parseSbfHas, parseSbfIonoUtc, parseSbfMeas, sbfCrc16, scanSbfFrames } from './sbf.cjs';
14
+ export { HasMessage, SbfBdsNavResult, SbfCnavEphemeris, SbfCnavResult, SbfGalEphemeris, SbfGalNavResult, SbfGloNavResult, SbfGpsNavResult, SbfHasMessage, SbfHasResult, SbfIonoUtcResult, SbfMeasEpoch, SbfMeasurement, SbfNavCounts, SbfNavigation, SbfParseResult, decodeSbfNavigation, parseSbfBdsNav, parseSbfCnav, parseSbfGalNav, parseSbfGloNav, parseSbfGpsNav, parseSbfHas, parseSbfIonoUtc, parseSbfMeas, sbfCrc16, scanSbfFrames } from './sbf.cjs';
15
15
  export { NovatelEpoch, NovatelMeasurement, NovatelNavResult, NovatelParseResult, OEM4_HLEN, Oem4Frame, crc32, oem4Frames, parseNovatelNav, parseNovatelRange } from './novatel.cjs';
16
16
  export { TrimbleEpoch, TrimbleFrame, TrimbleMeasurement, TrimbleNavResult, TrimbleParseResult, parseTrimble, parseTrimbleNav, trimbleFrames } from './trimble.cjs';
17
17
  export { BinexEpoch, BinexMeasurement, BinexParseResult, BinexRecord, binexCrc16, binexCrc32, binexCsum8, binexRecords, decodeBinexEph, getBnxi, parseBinex } from './binex.cjs';
package/dist/index.d.ts CHANGED
@@ -11,7 +11,7 @@ export { C as ClkFile, I as IonexGrid, S as Sp3File, a as Sp3Sample, c as clkBia
11
11
  export { B as BitReader, E as EphemerisInfo, R as Rtcm3DebugHandler, a as Rtcm3Decoder, b as Rtcm3Frame, d as decodeEphemeris, r as readString, c as reportDecodeError, s as setRtcm3DebugHandler } from './ephemeris-Ohl6NAfw.js';
12
12
  export { MessageTypeStats, MsmEpoch, MsmSatObs, MsmSignal, RTCM3_MESSAGE_NAMES, SatCn0, SignalCn0, StationMeta, StreamStats, createStationMeta, createStreamStats, decodeMsmFull, msmEpochToDate, resetGloFreqCache, rtcm3Constellation, setGloFreqNumber, updateStationMeta, updateStreamStats } from './rtcm3.js';
13
13
  export { UbxCnavResult, UbxFrame, UbxIonoUtcResult, UbxMeasurement, UbxNavOptions, UbxNavResult, UbxParseResult, UbxRawNavOptions, UbxRawNavResult, UbxRawxEpoch, parseUbxCnav, parseUbxIonoUtc, parseUbxNav, parseUbxRawNav, parseUbxRawx, ubxFrames } from './ubx.js';
14
- export { HasMessage, SbfBdsNavResult, SbfCnavEphemeris, SbfCnavResult, SbfGalEphemeris, SbfGalNavResult, SbfGloNavResult, SbfHasMessage, SbfHasResult, SbfIonoUtcResult, SbfMeasEpoch, SbfMeasurement, SbfParseResult, parseSbfBdsNav, parseSbfCnav, parseSbfGalNav, parseSbfGloNav, parseSbfHas, parseSbfIonoUtc, parseSbfMeas, sbfCrc16, scanSbfFrames } from './sbf.js';
14
+ export { HasMessage, SbfBdsNavResult, SbfCnavEphemeris, SbfCnavResult, SbfGalEphemeris, SbfGalNavResult, SbfGloNavResult, SbfGpsNavResult, SbfHasMessage, SbfHasResult, SbfIonoUtcResult, SbfMeasEpoch, SbfMeasurement, SbfNavCounts, SbfNavigation, SbfParseResult, decodeSbfNavigation, parseSbfBdsNav, parseSbfCnav, parseSbfGalNav, parseSbfGloNav, parseSbfGpsNav, parseSbfHas, parseSbfIonoUtc, parseSbfMeas, sbfCrc16, scanSbfFrames } from './sbf.js';
15
15
  export { NovatelEpoch, NovatelMeasurement, NovatelNavResult, NovatelParseResult, OEM4_HLEN, Oem4Frame, crc32, oem4Frames, parseNovatelNav, parseNovatelRange } from './novatel.js';
16
16
  export { TrimbleEpoch, TrimbleFrame, TrimbleMeasurement, TrimbleNavResult, TrimbleParseResult, parseTrimble, parseTrimbleNav, trimbleFrames } from './trimble.js';
17
17
  export { BinexEpoch, BinexMeasurement, BinexParseResult, BinexRecord, binexCrc16, binexCrc32, binexCsum8, binexRecords, decodeBinexEph, getBnxi, parseBinex } from './binex.js';
package/dist/index.js CHANGED
@@ -50,28 +50,30 @@ import {
50
50
  parseUbxRawNav,
51
51
  parseUbxRawx,
52
52
  ubxFrames
53
- } from "./chunk-FEOMYZEU.js";
53
+ } from "./chunk-ZQDLYLQA.js";
54
54
  import {
55
55
  crc16,
56
+ decodeSbfNavigation,
56
57
  parseSbfAlmanac,
57
58
  parseSbfBdsNav,
58
59
  parseSbfCnav,
59
60
  parseSbfGalNav,
60
61
  parseSbfGloNav,
62
+ parseSbfGpsNav,
61
63
  parseSbfHas,
62
64
  parseSbfIonoUtc,
63
65
  parseSbfMeas,
64
66
  parseSbfNav,
65
67
  scanSbfFrames
66
- } from "./chunk-AFEDNWXI.js";
67
- import "./chunk-5AUK42AL.js";
68
+ } from "./chunk-24TKGUTY.js";
69
+ import "./chunk-FA2UTLEQ.js";
68
70
  import {
69
71
  OEM4_HLEN,
70
72
  crc32,
71
73
  oem4Frames,
72
74
  parseNovatelNav,
73
75
  parseNovatelRange
74
- } from "./chunk-F4CM6Q4F.js";
76
+ } from "./chunk-5X4AG4MK.js";
75
77
  import {
76
78
  parseTrimble,
77
79
  parseTrimbleNav,
@@ -85,7 +87,7 @@ import {
85
87
  decodeBinexEph,
86
88
  getBnxi,
87
89
  parseBinex
88
- } from "./chunk-OK4GGNOO.js";
90
+ } from "./chunk-D25WNE43.js";
89
91
  import {
90
92
  connectToMountpoint,
91
93
  fetchSourcetable,
@@ -228,9 +230,9 @@ import {
228
230
  writeRinexNav,
229
231
  writeRinexNav4,
230
232
  writeRinexObsBlob
231
- } from "./chunk-5RNDQQ6J.js";
232
- import "./chunk-726LQBGM.js";
233
- import "./chunk-IQ5OIMQD.js";
233
+ } from "./chunk-6SWJTN6H.js";
234
+ import "./chunk-YUW33VXK.js";
235
+ import "./chunk-V2D5KUKH.js";
234
236
  import {
235
237
  SYSTEM_ORDER,
236
238
  crxDecompress,
@@ -470,6 +472,7 @@ export {
470
472
  decodeBinexEph,
471
473
  decodeEphemeris,
472
474
  decodeMsmFull,
475
+ decodeSbfNavigation,
473
476
  deg2dms,
474
477
  deg2rad,
475
478
  detrendIonoArcs,
@@ -588,6 +591,7 @@ export {
588
591
  parseSbfCnav,
589
592
  parseSbfGalNav,
590
593
  parseSbfGloNav,
594
+ parseSbfGpsNav,
591
595
  parseSbfHas,
592
596
  parseSbfIonoUtc,
593
597
  parseSbfMeas,
package/dist/novatel.js CHANGED
@@ -4,9 +4,9 @@ import {
4
4
  oem4Frames,
5
5
  parseNovatelNav,
6
6
  parseNovatelRange
7
- } from "./chunk-F4CM6Q4F.js";
8
- import "./chunk-726LQBGM.js";
9
- import "./chunk-IQ5OIMQD.js";
7
+ } from "./chunk-5X4AG4MK.js";
8
+ import "./chunk-YUW33VXK.js";
9
+ import "./chunk-V2D5KUKH.js";
10
10
  import "./chunk-HVXYFUCB.js";
11
11
  import "./chunk-LEEU5OIO.js";
12
12
  export {