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.
package/dist/index.d.cts CHANGED
@@ -9,8 +9,8 @@ export { E as EpochSummary, P as ParseOptions, R as RinexHeader, a as RinexResul
9
9
  export { E as Ephemeris, G as GlonassEphemeris, K as KeplerEphemeris, N as NavHeader, a as NavResult, p as parseNavFile } from './nav-BAI1a9vK.cjs';
10
10
  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';
11
11
  export { MessageTypeStats, MsmEpoch, MsmSatObs, MsmSignal, RTCM3_MESSAGE_NAMES, SatCn0, SignalCn0, StationMeta, StreamStats, createStationMeta, createStreamStats, decodeMsmFull, msmEpochToDate, resetGloFreqCache, rtcm3Constellation, setGloFreqNumber, updateStationMeta, updateStreamStats } from './rtcm3.cjs';
12
- export { UbxFrame, UbxMeasurement, UbxNavOptions, UbxNavResult, UbxParseResult, UbxRawxEpoch, parseUbxNav, parseUbxRawx, ubxFrames } from './ubx.cjs';
13
- export { SbfAlmanac, SbfAlmanacResult, SbfGlonassAlmanac, SbfKeplerAlmanac, SbfMeasEpoch, SbfMeasurement, SbfNavResult, SbfParseResult, parseSbfAlmanac, parseSbfMeas, parseSbfNav, sbfCrc16, scanSbfFrames } from './sbf.cjs';
12
+ export { UbxCnavResult, UbxFrame, UbxIonoUtcResult, UbxMeasurement, UbxNavOptions, UbxNavResult, UbxParseResult, UbxRawxEpoch, parseUbxCnav, parseUbxIonoUtc, parseUbxNav, parseUbxRawx, ubxFrames } from './ubx.cjs';
13
+ export { SbfAlmanac, SbfAlmanacResult, SbfCnavEphemeris, SbfCnavResult, SbfGlonassAlmanac, SbfIonoUtcResult, SbfKeplerAlmanac, SbfMeasEpoch, SbfMeasurement, SbfNavResult, SbfParseResult, parseSbfAlmanac, parseSbfCnav, parseSbfIonoUtc, parseSbfMeas, parseSbfNav, sbfCrc16, scanSbfFrames } from './sbf.cjs';
14
14
  export { NovatelEpoch, NovatelMeasurement, NovatelNavResult, NovatelParseResult, OEM4_HLEN, Oem4Frame, crc32, oem4Frames, parseNovatelNav, parseNovatelRange } from './novatel.cjs';
15
15
  export { AllPositionsData, DopValues, EpochSkyData, SatAzEl, SatPoint, SatPosition, VisibilityPass, VisibilityResult, computeAllPositions, computeDop, computeLiveSkyPositions, computeSatPosition, computeVisibility, computeVisibilityFromPositions, dopplerHz, ecefToAzEl, ephInfoToEphemeris, glonassPosition, keplerPosition, maskRadForAzimuth, navTimesFromEph, rangeRate, selectEphemeris } from './orbit.cjs';
16
16
  export { Helmert14, REFERENCE_FRAMES, ReferenceFrame, applyHelmert, dateToEpoch, transformFrame } from './frames.cjs';
@@ -20,3 +20,4 @@ export { CompleteSatSignal, CompleteSignalStats, CompletenessAccumulator, Comple
20
20
  export { AntennaEntry, AntexFile, FrequencyData, frequencyLabel, parseAntex } from './antex.cjs';
21
21
  export { NmeaFix, NmeaStats, NmeaTrack, computeStats, nmeaCoordToDecimal, parseNmeaFile, verifyChecksum } from './nmea.cjs';
22
22
  export { BAND_PRESETS, BandPreset, CONSTELLATIONS, ConstellationRow, DELTA_GLO_L1, DELTA_GLO_L2, FREQ_BDS_B1A, FREQ_BDS_B1C, FREQ_BDS_B1I, FREQ_BDS_B2I, FREQ_BDS_B3A, FREQ_BDS_B3I, FREQ_GAL_E1, FREQ_GAL_E5, FREQ_GAL_E5a, FREQ_GAL_E5b, FREQ_GAL_E6, FREQ_GLO_L1, FREQ_GLO_L1OC, FREQ_GLO_L2, FREQ_GLO_L2OC, FREQ_GLO_L3OC, FREQ_GPS_L1, FREQ_GPS_L2, FREQ_GPS_L5, FREQ_NAVIC_L5, FREQ_QZS_L1, FREQ_QZS_L2, FREQ_QZS_L5, FREQ_QZS_L6, Modulation, SignalDef, computePsdDb, phiAltBOC, phiBOCc, phiBOCs, phiBPSK } from './signals.cjs';
23
+ export { C as CnavEphemeris } from './cnav-CRns0ECn.cjs';
package/dist/index.d.ts CHANGED
@@ -9,8 +9,8 @@ export { E as EpochSummary, P as ParseOptions, R as RinexHeader, a as RinexResul
9
9
  export { E as Ephemeris, G as GlonassEphemeris, K as KeplerEphemeris, N as NavHeader, a as NavResult, p as parseNavFile } from './nav-BAI1a9vK.js';
10
10
  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';
11
11
  export { MessageTypeStats, MsmEpoch, MsmSatObs, MsmSignal, RTCM3_MESSAGE_NAMES, SatCn0, SignalCn0, StationMeta, StreamStats, createStationMeta, createStreamStats, decodeMsmFull, msmEpochToDate, resetGloFreqCache, rtcm3Constellation, setGloFreqNumber, updateStationMeta, updateStreamStats } from './rtcm3.js';
12
- export { UbxFrame, UbxMeasurement, UbxNavOptions, UbxNavResult, UbxParseResult, UbxRawxEpoch, parseUbxNav, parseUbxRawx, ubxFrames } from './ubx.js';
13
- export { SbfAlmanac, SbfAlmanacResult, SbfGlonassAlmanac, SbfKeplerAlmanac, SbfMeasEpoch, SbfMeasurement, SbfNavResult, SbfParseResult, parseSbfAlmanac, parseSbfMeas, parseSbfNav, sbfCrc16, scanSbfFrames } from './sbf.js';
12
+ export { UbxCnavResult, UbxFrame, UbxIonoUtcResult, UbxMeasurement, UbxNavOptions, UbxNavResult, UbxParseResult, UbxRawxEpoch, parseUbxCnav, parseUbxIonoUtc, parseUbxNav, parseUbxRawx, ubxFrames } from './ubx.js';
13
+ export { SbfAlmanac, SbfAlmanacResult, SbfCnavEphemeris, SbfCnavResult, SbfGlonassAlmanac, SbfIonoUtcResult, SbfKeplerAlmanac, SbfMeasEpoch, SbfMeasurement, SbfNavResult, SbfParseResult, parseSbfAlmanac, parseSbfCnav, parseSbfIonoUtc, parseSbfMeas, parseSbfNav, sbfCrc16, scanSbfFrames } from './sbf.js';
14
14
  export { NovatelEpoch, NovatelMeasurement, NovatelNavResult, NovatelParseResult, OEM4_HLEN, Oem4Frame, crc32, oem4Frames, parseNovatelNav, parseNovatelRange } from './novatel.js';
15
15
  export { AllPositionsData, DopValues, EpochSkyData, SatAzEl, SatPoint, SatPosition, VisibilityPass, VisibilityResult, computeAllPositions, computeDop, computeLiveSkyPositions, computeSatPosition, computeVisibility, computeVisibilityFromPositions, dopplerHz, ecefToAzEl, ephInfoToEphemeris, glonassPosition, keplerPosition, maskRadForAzimuth, navTimesFromEph, rangeRate, selectEphemeris } from './orbit.js';
16
16
  export { Helmert14, REFERENCE_FRAMES, ReferenceFrame, applyHelmert, dateToEpoch, transformFrame } from './frames.js';
@@ -20,3 +20,4 @@ export { CompleteSatSignal, CompleteSignalStats, CompletenessAccumulator, Comple
20
20
  export { AntennaEntry, AntexFile, FrequencyData, frequencyLabel, parseAntex } from './antex.js';
21
21
  export { NmeaFix, NmeaStats, NmeaTrack, computeStats, nmeaCoordToDecimal, parseNmeaFile, verifyChecksum } from './nmea.js';
22
22
  export { BAND_PRESETS, BandPreset, CONSTELLATIONS, ConstellationRow, DELTA_GLO_L1, DELTA_GLO_L2, FREQ_BDS_B1A, FREQ_BDS_B1C, FREQ_BDS_B1I, FREQ_BDS_B2I, FREQ_BDS_B3A, FREQ_BDS_B3I, FREQ_GAL_E1, FREQ_GAL_E5, FREQ_GAL_E5a, FREQ_GAL_E5b, FREQ_GAL_E6, FREQ_GLO_L1, FREQ_GLO_L1OC, FREQ_GLO_L2, FREQ_GLO_L2OC, FREQ_GLO_L3OC, FREQ_GPS_L1, FREQ_GPS_L2, FREQ_GPS_L5, FREQ_NAVIC_L5, FREQ_QZS_L1, FREQ_QZS_L2, FREQ_QZS_L5, FREQ_QZS_L6, Modulation, SignalDef, computePsdDb, phiAltBOC, phiBOCc, phiBOCs, phiBPSK } from './signals.js';
23
+ export { C as CnavEphemeris } from './cnav-CRns0ECn.js';
package/dist/index.js CHANGED
@@ -34,25 +34,30 @@ import {
34
34
  phiBPSK
35
35
  } from "./chunk-2K3FCJBX.js";
36
36
  import {
37
+ parseUbxCnav,
38
+ parseUbxIonoUtc,
37
39
  parseUbxNav,
38
40
  parseUbxRawx,
39
41
  ubxFrames
40
- } from "./chunk-6CX6EXRK.js";
42
+ } from "./chunk-FEGLXNWA.js";
41
43
  import {
42
44
  crc16,
43
45
  parseSbfAlmanac,
46
+ parseSbfCnav,
47
+ parseSbfIonoUtc,
44
48
  parseSbfMeas,
45
49
  parseSbfNav,
46
50
  scanSbfFrames
47
- } from "./chunk-YPOVPXNK.js";
51
+ } from "./chunk-CG7SF45F.js";
52
+ import "./chunk-Y5IWUPJQ.js";
48
53
  import {
49
54
  OEM4_HLEN,
50
55
  crc32,
51
56
  oem4Frames,
52
57
  parseNovatelNav,
53
58
  parseNovatelRange
54
- } from "./chunk-R33A2VA7.js";
55
- import "./chunk-4LVD4DYL.js";
59
+ } from "./chunk-2IM5VXNI.js";
60
+ import "./chunk-IQ5OIMQD.js";
56
61
  import {
57
62
  connectToMountpoint,
58
63
  fetchSourcetable,
@@ -487,11 +492,15 @@ export {
487
492
  parseNovatelRange,
488
493
  parseRinexStream,
489
494
  parseSbfAlmanac,
495
+ parseSbfCnav,
496
+ parseSbfIonoUtc,
490
497
  parseSbfMeas,
491
498
  parseSbfNav,
492
499
  parseSinexBiasDcb,
493
500
  parseSourcetable,
494
501
  parseSp3,
502
+ parseUbxCnav,
503
+ parseUbxIonoUtc,
495
504
  parseUbxNav,
496
505
  parseUbxRawx,
497
506
  phiAltBOC,
package/dist/novatel.cjs CHANGED
@@ -290,11 +290,27 @@ function getUtcDate(date) {
290
290
  }
291
291
 
292
292
  // src/novatel/nav.ts
293
+ var ID_IONUTC = 8;
293
294
  var ID_RAWEPHEM = 41;
294
295
  var ID_GLOEPHEMERIS = 723;
296
+ var ID_GALEPHEMERIS = 1122;
297
+ var ID_QZSSEPHEMERIS = 1336;
298
+ var ID_GPSEPHEM = 7;
299
+ var ID_BDSEPHEMERIS = 1696;
295
300
  var GPS_EPOCH_MS2 = Date.UTC(1980, 0, 6);
301
+ var BDT_EPOCH_MS = Date.UTC(2006, 0, 1);
296
302
  var SEC_PER_WEEK2 = 7 * 86400;
297
303
  var SEC_PER_DAY = 86400;
304
+ var MS_PER_WEEK = SEC_PER_WEEK2 * 1e3;
305
+ var gpsMs = (week, sec) => GPS_EPOCH_MS2 + week * MS_PER_WEEK + sec * 1e3;
306
+ var sowOf = (dateMs) => dateMs / 1e3 % SEC_PER_WEEK2;
307
+ function nearWeekMs(refMs, sow) {
308
+ const refWeek = Math.floor((refMs - GPS_EPOCH_MS2) / MS_PER_WEEK);
309
+ let ms = gpsMs(refWeek, sow);
310
+ if (ms < refMs - MS_PER_WEEK / 2) ms += MS_PER_WEEK;
311
+ else if (ms > refMs + MS_PER_WEEK / 2) ms -= MS_PER_WEEK;
312
+ return ms;
313
+ }
298
314
  function decodeRawEphem(data, view, p) {
299
315
  const prn = view.getUint32(p, true);
300
316
  if (prn < 1 || prn > 32) return null;
@@ -340,23 +356,188 @@ function decodeGloEphemeris(view, p) {
340
356
  freqNum
341
357
  };
342
358
  }
359
+ function decodeGalEphemeris(view, p, headerMs) {
360
+ const prn = view.getUint32(p, true);
361
+ if (prn < 1 || prn > 36) return null;
362
+ const fnav = (view.getUint32(p + 4, true) & 1) !== 0;
363
+ const svhE1b = view.getUint8(p + 12) & 3;
364
+ const svhE5a = view.getUint8(p + 13) & 3;
365
+ const svhE5b = view.getUint8(p + 14) & 3;
366
+ const dvsE1b = view.getUint8(p + 15) & 1;
367
+ const dvsE5a = view.getUint8(p + 16) & 1;
368
+ const dvsE5b = view.getUint8(p + 17) & 1;
369
+ const iodNav = view.getUint32(p + 20, true);
370
+ const toes = view.getUint32(p + 24, true);
371
+ const c = fnav ? p + 148 : p + 176;
372
+ const tocs = view.getUint32(c, true);
373
+ const toeMs = nearWeekMs(headerMs, toes);
374
+ const tocDate = new Date(nearWeekMs(headerMs, tocs));
375
+ return {
376
+ fnav,
377
+ eph: {
378
+ system: "E",
379
+ prn: `E${String(prn).padStart(2, "0")}`,
380
+ toc: sowOf(tocDate.getTime()),
381
+ tocDate,
382
+ af0: view.getFloat64(c + 4, true),
383
+ af1: view.getFloat64(c + 12, true),
384
+ af2: view.getFloat64(c + 20, true),
385
+ iode: iodNav,
386
+ crs: view.getFloat64(p + 92, true),
387
+ deltaN: view.getFloat64(p + 36, true),
388
+ m0: view.getFloat64(p + 44, true),
389
+ cuc: view.getFloat64(p + 68, true),
390
+ e: view.getFloat64(p + 52, true),
391
+ cus: view.getFloat64(p + 76, true),
392
+ sqrtA: view.getFloat64(p + 28, true),
393
+ toe: toes,
394
+ cic: view.getFloat64(p + 100, true),
395
+ omega0: view.getFloat64(p + 132, true),
396
+ cis: view.getFloat64(p + 108, true),
397
+ i0: view.getFloat64(p + 116, true),
398
+ crc: view.getFloat64(p + 84, true),
399
+ omega: view.getFloat64(p + 60, true),
400
+ omegaDot: view.getFloat64(p + 140, true),
401
+ idot: view.getFloat64(p + 124, true),
402
+ week: Math.floor((toeMs - GPS_EPOCH_MS2) / MS_PER_WEEK),
403
+ // RINEX Galileo SVH bit layout (E1B DVS/HS in bits 0-2, E5a in
404
+ // 3-5, E5b in 6-8) — same packing as RTKLIB.
405
+ svHealth: svhE5b << 7 | dvsE5b << 6 | svhE5a << 4 | dvsE5a << 3 | svhE1b << 1 | dvsE1b,
406
+ tgd: view.getFloat64(p + 204, true)
407
+ // BGD E5a/E1 (RINEX slot)
408
+ }
409
+ };
410
+ }
411
+ function decodeBdsEphemeris(view, p) {
412
+ const prn = view.getUint32(p, true);
413
+ if (prn < 1 || prn > 63) return null;
414
+ const week = view.getUint32(p + 4, true);
415
+ const health = view.getUint32(p + 16, true) & 1;
416
+ const tgd1 = view.getFloat64(p + 20, true);
417
+ const tocs = view.getUint32(p + 40, true);
418
+ const toes = view.getUint32(p + 72, true);
419
+ const tocDate = new Date(BDT_EPOCH_MS + week * MS_PER_WEEK + tocs * 1e3);
420
+ return {
421
+ system: "C",
422
+ prn: `C${String(prn).padStart(2, "0")}`,
423
+ toc: sowOf(tocDate.getTime()),
424
+ tocDate,
425
+ af0: view.getFloat64(p + 44, true),
426
+ af1: view.getFloat64(p + 52, true),
427
+ af2: view.getFloat64(p + 60, true),
428
+ iode: view.getUint32(p + 68, true),
429
+ // AODE
430
+ crs: view.getFloat64(p + 172, true),
431
+ deltaN: view.getFloat64(p + 100, true),
432
+ m0: view.getFloat64(p + 108, true),
433
+ cuc: view.getFloat64(p + 148, true),
434
+ e: view.getFloat64(p + 84, true),
435
+ cus: view.getFloat64(p + 156, true),
436
+ sqrtA: view.getFloat64(p + 76, true),
437
+ toe: toes,
438
+ cic: view.getFloat64(p + 180, true),
439
+ omega0: view.getFloat64(p + 116, true),
440
+ cis: view.getFloat64(p + 188, true),
441
+ i0: view.getFloat64(p + 132, true),
442
+ crc: view.getFloat64(p + 164, true),
443
+ omega: view.getFloat64(p + 92, true),
444
+ omegaDot: view.getFloat64(p + 124, true),
445
+ idot: view.getFloat64(p + 140, true),
446
+ week,
447
+ // RINEX BDS week field is the BDT week
448
+ svHealth: health,
449
+ tgd: tgd1
450
+ // TGD1 (B1) — RINEX slot
451
+ };
452
+ }
453
+ function decodeGpsQzssEphemeris(view, p, sys) {
454
+ const prn = view.getUint32(p, true);
455
+ if (sys === "G" && (prn < 1 || prn > 32)) return null;
456
+ if (sys === "J" && (prn < 193 || prn > 202)) return null;
457
+ const health = view.getUint32(p + 12, true) & 63;
458
+ const iode1 = view.getUint32(p + 16, true);
459
+ const week = view.getUint32(p + 24, true);
460
+ const toes = view.getFloat64(p + 32, true);
461
+ const toeMs = gpsMs(week, toes);
462
+ const tocs = view.getFloat64(p + 164, true);
463
+ const tocDate = new Date(nearWeekMs(toeMs, tocs));
464
+ return {
465
+ system: sys,
466
+ prn: `${sys}${String(sys === "J" ? prn - 192 : prn).padStart(2, "0")}`,
467
+ toc: sowOf(tocDate.getTime()),
468
+ tocDate,
469
+ af0: view.getFloat64(p + 180, true),
470
+ af1: view.getFloat64(p + 188, true),
471
+ af2: view.getFloat64(p + 196, true),
472
+ iode: iode1,
473
+ crs: view.getFloat64(p + 104, true),
474
+ deltaN: view.getFloat64(p + 48, true),
475
+ m0: view.getFloat64(p + 56, true),
476
+ cuc: view.getFloat64(p + 80, true),
477
+ e: view.getFloat64(p + 64, true),
478
+ cus: view.getFloat64(p + 88, true),
479
+ sqrtA: Math.sqrt(view.getFloat64(p + 40, true)),
480
+ toe: toes,
481
+ cic: view.getFloat64(p + 112, true),
482
+ omega0: view.getFloat64(p + 144, true),
483
+ cis: view.getFloat64(p + 120, true),
484
+ i0: view.getFloat64(p + 128, true),
485
+ crc: view.getFloat64(p + 96, true),
486
+ omega: view.getFloat64(p + 72, true),
487
+ omegaDot: view.getFloat64(p + 152, true),
488
+ idot: view.getFloat64(p + 136, true),
489
+ week,
490
+ svHealth: health,
491
+ tgd: view.getFloat64(p + 172, true)
492
+ };
493
+ }
343
494
  function parseNovatelNav(data) {
344
495
  const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
345
496
  const stats = { badCrc: 0 };
346
497
  const ephemerides = [];
347
- const lastGps = /* @__PURE__ */ new Map();
498
+ const ionoCorrections = {};
499
+ let leapSeconds = null;
500
+ const lastKep = /* @__PURE__ */ new Map();
348
501
  const lastGlo = /* @__PURE__ */ new Map();
502
+ const pushKepler = (key, eph) => {
503
+ const prev = lastKep.get(key);
504
+ if (prev && prev.iode === eph.iode && prev.toe === eph.toe && prev.tocDate.getTime() === eph.tocDate.getTime()) {
505
+ return;
506
+ }
507
+ lastKep.set(key, eph);
508
+ ephemerides.push(eph);
509
+ };
349
510
  for (const frame of oem4Frames(data, view, stats)) {
350
511
  if (!frame.binary) continue;
351
512
  if (frame.id === ID_RAWEPHEM && frame.msgLen >= 102) {
352
513
  const eph = decodeRawEphem(data, view, frame.payload);
353
- if (!eph) continue;
354
- const prev = lastGps.get(eph.prn);
355
- if (prev && prev.iode === eph.iode && prev.tocDate.getTime() === eph.tocDate.getTime()) {
356
- continue;
514
+ if (eph) pushKepler(eph.prn, eph);
515
+ } else if (frame.id === ID_GALEPHEMERIS && frame.msgLen >= 220) {
516
+ if (frame.week === 0) continue;
517
+ const headerMs = gpsMs(frame.week, frame.towMs / 1e3);
518
+ const dec = decodeGalEphemeris(view, frame.payload, headerMs);
519
+ if (dec)
520
+ pushKepler(`${dec.eph.prn}:${dec.fnav ? "fnav" : "inav"}`, dec.eph);
521
+ } else if (frame.id === ID_BDSEPHEMERIS && frame.msgLen >= 196) {
522
+ const eph = decodeBdsEphemeris(view, frame.payload);
523
+ if (eph) pushKepler(eph.prn, eph);
524
+ } else if (frame.id === ID_GPSEPHEM && frame.msgLen >= 204) {
525
+ const eph = decodeGpsQzssEphemeris(view, frame.payload, "G");
526
+ if (eph) pushKepler(eph.prn, eph);
527
+ } else if (frame.id === ID_QZSSEPHEMERIS && frame.msgLen >= 204) {
528
+ const eph = decodeGpsQzssEphemeris(view, frame.payload, "J");
529
+ if (eph) pushKepler(eph.prn, eph);
530
+ } else if (frame.id === ID_IONUTC && frame.msgLen >= 108) {
531
+ const p = frame.payload;
532
+ const alpha = [];
533
+ const beta = [];
534
+ for (let i = 0; i < 4; i++) {
535
+ alpha.push(view.getFloat64(p + i * 8, true));
536
+ beta.push(view.getFloat64(p + 32 + i * 8, true));
357
537
  }
358
- lastGps.set(eph.prn, eph);
359
- ephemerides.push(eph);
538
+ ionoCorrections["GPSA"] = alpha;
539
+ ionoCorrections["GPSB"] = beta;
540
+ leapSeconds = view.getInt32(p + 96, true);
360
541
  } else if (frame.id === ID_GLOEPHEMERIS && frame.msgLen >= 144) {
361
542
  const eph = decodeGloEphemeris(view, frame.payload);
362
543
  if (!eph) continue;
@@ -368,12 +549,12 @@ function parseNovatelNav(data) {
368
549
  ephemerides.push(eph);
369
550
  }
370
551
  }
371
- return { ephemerides, badCrc: stats.badCrc };
552
+ return { ephemerides, ionoCorrections, leapSeconds, badCrc: stats.badCrc };
372
553
  }
373
554
 
374
555
  // src/novatel/index.ts
375
556
  var GPS_EPOCH_MS3 = Date.UTC(1980, 0, 6);
376
- var MS_PER_WEEK = 7 * 864e5;
557
+ var MS_PER_WEEK2 = 7 * 864e5;
377
558
  var HDR = 28;
378
559
  var ID_RANGE = 43;
379
560
  var ID_RANGECMP = 140;
@@ -542,7 +723,7 @@ function parseNovatelRange(data) {
542
723
  if (!codes.includes(code)) codes.push(code);
543
724
  }
544
725
  epochs.push({
545
- timeMs: GPS_EPOCH_MS3 + week * MS_PER_WEEK + towMs,
726
+ timeMs: GPS_EPOCH_MS3 + week * MS_PER_WEEK2 + towMs,
546
727
  meas
547
728
  });
548
729
  }
@@ -594,7 +775,7 @@ function parseNovatelRange(data) {
594
775
  if (!codes.includes(code)) codes.push(code);
595
776
  }
596
777
  epochs.push({
597
- timeMs: GPS_EPOCH_MS3 + week * MS_PER_WEEK + towMs,
778
+ timeMs: GPS_EPOCH_MS3 + week * MS_PER_WEEK2 + towMs,
598
779
  meas
599
780
  });
600
781
  }
@@ -37,31 +37,54 @@ declare function oem4Frames(data: Uint8Array, view: DataView, stats: {
37
37
 
38
38
  /**
39
39
  * NovAtel navigation-message decoding: RAWEPHEM (message 41, raw GPS
40
- * LNAV subframes 1–3) and GLOEPHEMERIS (message 723, decoded GLONASS
41
- * L1 C/A ephemeris).
40
+ * LNAV subframes 1–3), GLOEPHEMERIS (message 723, decoded GLONASS
41
+ * L1 C/A ephemeris), GALEPHEMERIS (1122), BDSEPHEMERIS (1696),
42
+ * QZSSEPHEMERIS (1336) and IONUTC (8, GPS Klobuchar + UTC parameters).
42
43
  *
43
44
  * Ported from RTKLIB demo5 (rtklibexplorer fork, src/rcv/novatel.c:
44
- * decode_rawephemb / decode_gloephemerisb, Copyright (c) 2007-2020
45
+ * decode_rawephemb / decode_gloephemerisb / decode_galephemerisb /
46
+ * decode_bdsephemerisb / decode_ionutcb, Copyright (c) 2007-2020
45
47
  * T. Takasu, BSD-2-Clause) and cross-checked against the OEM7
46
- * Commands and Logs Reference Manual. Output records mirror what
47
- * `parseNavFile` produces for the equivalent RINEX 3 navigation file:
48
- * GPS `tocDate` is a GPS-scale Date, GLONASS `tocDate` is the UTC
49
- * epoch, GLONASS state vectors are in km (PZ-90), the RINEX clock bias
50
- * is −τ_n, and `messageFrameTime` is the frame time as seconds of the
51
- * UTC week.
48
+ * Commands and Logs Reference Manual. QZSSEPHEMERIS has no RTKLIB
49
+ * decoder (RTKLIB only handles the raw-subframe QZSSRAWEPHEM 1331);
50
+ * its layout is taken from the OEM7 manual §3.150 and is therefore
51
+ * synthetic-tested only, like SBF's QZSNav.
52
+ *
53
+ * Output records mirror what `parseNavFile` produces for the
54
+ * equivalent RINEX 3 navigation file: Keplerian `tocDate` is a
55
+ * GPS-scale Date except BeiDou, whose epochs and week stay on the BDT
56
+ * scale like a RINEX file; angles arrive from the receiver already in
57
+ * radians (NovAtel decodes the semicircle SIS fields itself), so no
58
+ * GPS_PI scaling is applied here; the Galileo clock set follows the
59
+ * received data source (F/NAV when the rcv_fnav flag is set, I/NAV
60
+ * otherwise — RTKLIB's convention, which convbin tags with the RINEX
61
+ * I/NAV / F/NAV data-source flags) and `tgd` is BGD E5a/E1, the first
62
+ * RINEX BGD slot; GLONASS `tocDate` is the UTC epoch, state vectors
63
+ * are in km (PZ-90), the RINEX clock bias is −τ_n, and
64
+ * `messageFrameTime` is the frame time as seconds of the UTC week.
52
65
  */
53
66
 
54
67
  interface NovatelNavResult {
55
68
  /** Broadcast ephemerides in stream order, duplicates suppressed. */
56
69
  ephemerides: Ephemeris[];
70
+ /**
71
+ * Klobuchar coefficients from IONUTC in the RINEX-header shape
72
+ * (`GPSA` = alpha0..3, `GPSB` = beta0..3), last message wins.
73
+ * Empty when no IONUTC message was seen.
74
+ */
75
+ ionoCorrections: Record<string, number[]>;
76
+ /** GPS−UTC leap seconds (Δt_LS) from IONUTC, null when unseen. */
77
+ leapSeconds: number | null;
57
78
  /** Frames whose CRC failed (corruption indicator). */
58
79
  badCrc: number;
59
80
  }
60
81
  /**
61
- * Decode every navigation message (RAWEPHEM, GLOEPHEMERIS) in a
62
- * NovAtel binary byte stream. Repeated broadcasts of an unchanged
63
- * ephemeris are suppressed the same way RTKLIB does: GPS by issue of
64
- * data, GLONASS by reference time and health.
82
+ * Decode every navigation message (RAWEPHEM, GLOEPHEMERIS,
83
+ * GALEPHEMERIS, BDSEPHEMERIS, QZSSEPHEMERIS, IONUTC) in a NovAtel
84
+ * binary byte stream. Repeated broadcasts of an unchanged ephemeris
85
+ * are suppressed the same way RTKLIB does: GPS/QZSS by issue of data,
86
+ * Galileo by IODNav + toe + toc per data source, BeiDou by toe + toc,
87
+ * GLONASS by reference time and health.
65
88
  */
66
89
  declare function parseNovatelNav(data: Uint8Array): NovatelNavResult;
67
90
 
package/dist/novatel.d.ts CHANGED
@@ -37,31 +37,54 @@ declare function oem4Frames(data: Uint8Array, view: DataView, stats: {
37
37
 
38
38
  /**
39
39
  * NovAtel navigation-message decoding: RAWEPHEM (message 41, raw GPS
40
- * LNAV subframes 1–3) and GLOEPHEMERIS (message 723, decoded GLONASS
41
- * L1 C/A ephemeris).
40
+ * LNAV subframes 1–3), GLOEPHEMERIS (message 723, decoded GLONASS
41
+ * L1 C/A ephemeris), GALEPHEMERIS (1122), BDSEPHEMERIS (1696),
42
+ * QZSSEPHEMERIS (1336) and IONUTC (8, GPS Klobuchar + UTC parameters).
42
43
  *
43
44
  * Ported from RTKLIB demo5 (rtklibexplorer fork, src/rcv/novatel.c:
44
- * decode_rawephemb / decode_gloephemerisb, Copyright (c) 2007-2020
45
+ * decode_rawephemb / decode_gloephemerisb / decode_galephemerisb /
46
+ * decode_bdsephemerisb / decode_ionutcb, Copyright (c) 2007-2020
45
47
  * T. Takasu, BSD-2-Clause) and cross-checked against the OEM7
46
- * Commands and Logs Reference Manual. Output records mirror what
47
- * `parseNavFile` produces for the equivalent RINEX 3 navigation file:
48
- * GPS `tocDate` is a GPS-scale Date, GLONASS `tocDate` is the UTC
49
- * epoch, GLONASS state vectors are in km (PZ-90), the RINEX clock bias
50
- * is −τ_n, and `messageFrameTime` is the frame time as seconds of the
51
- * UTC week.
48
+ * Commands and Logs Reference Manual. QZSSEPHEMERIS has no RTKLIB
49
+ * decoder (RTKLIB only handles the raw-subframe QZSSRAWEPHEM 1331);
50
+ * its layout is taken from the OEM7 manual §3.150 and is therefore
51
+ * synthetic-tested only, like SBF's QZSNav.
52
+ *
53
+ * Output records mirror what `parseNavFile` produces for the
54
+ * equivalent RINEX 3 navigation file: Keplerian `tocDate` is a
55
+ * GPS-scale Date except BeiDou, whose epochs and week stay on the BDT
56
+ * scale like a RINEX file; angles arrive from the receiver already in
57
+ * radians (NovAtel decodes the semicircle SIS fields itself), so no
58
+ * GPS_PI scaling is applied here; the Galileo clock set follows the
59
+ * received data source (F/NAV when the rcv_fnav flag is set, I/NAV
60
+ * otherwise — RTKLIB's convention, which convbin tags with the RINEX
61
+ * I/NAV / F/NAV data-source flags) and `tgd` is BGD E5a/E1, the first
62
+ * RINEX BGD slot; GLONASS `tocDate` is the UTC epoch, state vectors
63
+ * are in km (PZ-90), the RINEX clock bias is −τ_n, and
64
+ * `messageFrameTime` is the frame time as seconds of the UTC week.
52
65
  */
53
66
 
54
67
  interface NovatelNavResult {
55
68
  /** Broadcast ephemerides in stream order, duplicates suppressed. */
56
69
  ephemerides: Ephemeris[];
70
+ /**
71
+ * Klobuchar coefficients from IONUTC in the RINEX-header shape
72
+ * (`GPSA` = alpha0..3, `GPSB` = beta0..3), last message wins.
73
+ * Empty when no IONUTC message was seen.
74
+ */
75
+ ionoCorrections: Record<string, number[]>;
76
+ /** GPS−UTC leap seconds (Δt_LS) from IONUTC, null when unseen. */
77
+ leapSeconds: number | null;
57
78
  /** Frames whose CRC failed (corruption indicator). */
58
79
  badCrc: number;
59
80
  }
60
81
  /**
61
- * Decode every navigation message (RAWEPHEM, GLOEPHEMERIS) in a
62
- * NovAtel binary byte stream. Repeated broadcasts of an unchanged
63
- * ephemeris are suppressed the same way RTKLIB does: GPS by issue of
64
- * data, GLONASS by reference time and health.
82
+ * Decode every navigation message (RAWEPHEM, GLOEPHEMERIS,
83
+ * GALEPHEMERIS, BDSEPHEMERIS, QZSSEPHEMERIS, IONUTC) in a NovAtel
84
+ * binary byte stream. Repeated broadcasts of an unchanged ephemeris
85
+ * are suppressed the same way RTKLIB does: GPS/QZSS by issue of data,
86
+ * Galileo by IODNav + toe + toc per data source, BeiDou by toe + toc,
87
+ * GLONASS by reference time and health.
65
88
  */
66
89
  declare function parseNovatelNav(data: Uint8Array): NovatelNavResult;
67
90
 
package/dist/novatel.js CHANGED
@@ -4,8 +4,8 @@ import {
4
4
  oem4Frames,
5
5
  parseNovatelNav,
6
6
  parseNovatelRange
7
- } from "./chunk-R33A2VA7.js";
8
- import "./chunk-4LVD4DYL.js";
7
+ } from "./chunk-2IM5VXNI.js";
8
+ import "./chunk-IQ5OIMQD.js";
9
9
  import "./chunk-HVXYFUCB.js";
10
10
  import "./chunk-LEEU5OIO.js";
11
11
  export {