gnss-js 1.52.0 → 1.54.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
@@ -256,6 +256,7 @@ __export(src_exports, {
256
256
  parseNavFile: () => parseNavFile,
257
257
  parseNmeaFile: () => parseNmeaFile,
258
258
  parseNovatelNav: () => parseNovatelNav,
259
+ parseNovatelPvt: () => parseNovatelPvt,
259
260
  parseNovatelRange: () => parseNovatelRange,
260
261
  parseRinexStream: () => parseRinexStream,
261
262
  parseSbfAlmanac: () => parseSbfAlmanac,
@@ -269,6 +270,7 @@ __export(src_exports, {
269
270
  parseSbfIonoUtc: () => parseSbfIonoUtc,
270
271
  parseSbfMeas: () => parseSbfMeas,
271
272
  parseSbfNav: () => parseSbfNav,
273
+ parseSbfPvt: () => parseSbfPvt,
272
274
  parseSbfReceiverSetup: () => parseSbfReceiverSetup,
273
275
  parseSinexBiasDcb: () => parseSinexBiasDcb,
274
276
  parseSourcetable: () => parseSourcetable,
@@ -278,6 +280,7 @@ __export(src_exports, {
278
280
  parseUbxCnav: () => parseUbxCnav,
279
281
  parseUbxIonoUtc: () => parseUbxIonoUtc,
280
282
  parseUbxNav: () => parseUbxNav,
283
+ parseUbxPvt: () => parseUbxPvt,
281
284
  parseUbxRawNav: () => parseUbxRawNav,
282
285
  parseUbxRawx: () => parseUbxRawx,
283
286
  phiAltBOC: () => phiAltBOC,
@@ -6960,8 +6963,59 @@ function parseUbxRawNav(data, opts = {}) {
6960
6963
  return { ephemerides, counts, badParity };
6961
6964
  }
6962
6965
 
6963
- // src/ubx/index.ts
6966
+ // src/ubx/pvt.ts
6964
6967
  var GPS_EPOCH_MS9 = Date.UTC(1980, 0, 6);
6968
+ function parseUbxPvt(data) {
6969
+ const records = [];
6970
+ let messages = 0;
6971
+ for (const f of ubxFrames(data)) {
6972
+ if (f.msgClass !== 1 || f.msgId !== 7 || f.payload.length < 92)
6973
+ continue;
6974
+ messages++;
6975
+ const v = new DataView(
6976
+ f.payload.buffer,
6977
+ f.payload.byteOffset,
6978
+ f.payload.byteLength
6979
+ );
6980
+ const iTow = v.getUint32(0, true);
6981
+ const year = v.getUint16(4, true);
6982
+ const month = v.getUint8(6);
6983
+ const day = v.getUint8(7);
6984
+ const hour = v.getUint8(8);
6985
+ const min = v.getUint8(9);
6986
+ const sec = v.getUint8(10);
6987
+ const fixType = v.getUint8(20);
6988
+ const flags = v.getUint8(21);
6989
+ const numSV = v.getUint8(23);
6990
+ const lon = v.getInt32(24, true) * 1e-7;
6991
+ const lat = v.getInt32(28, true) * 1e-7;
6992
+ const height = v.getInt32(32, true) / 1e3;
6993
+ const hAcc = v.getUint32(40, true) / 1e3;
6994
+ const vAcc = v.getUint32(44, true) / 1e3;
6995
+ const carrSoln = flags >> 6 & 3;
6996
+ const diffSoln = flags >> 1 & 1;
6997
+ const mode = carrSoln === 2 ? "rtk-fixed" : carrSoln === 1 ? "rtk-float" : diffSoln ? "differential" : fixType >= 2 ? "standalone" : "no-pvt";
6998
+ const hasFix = fixType >= 2;
6999
+ const timeMs = year > 1980 ? Date.UTC(year, month - 1, day, hour, min, sec) : GPS_EPOCH_MS9 + iTow;
7000
+ const week = Math.floor((timeMs - GPS_EPOCH_MS9) / 1e3 / 604800);
7001
+ records.push({
7002
+ timeMs,
7003
+ week,
7004
+ tow: iTow / 1e3,
7005
+ mode,
7006
+ latDeg: hasFix ? lat : null,
7007
+ lonDeg: hasFix ? lon : null,
7008
+ heightM: hasFix ? height : null,
7009
+ nrSV: numSV,
7010
+ hAccuracyM: hasFix ? hAcc : null,
7011
+ vAccuracyM: hasFix ? vAcc : null
7012
+ });
7013
+ }
7014
+ return { records, messages };
7015
+ }
7016
+
7017
+ // src/ubx/index.ts
7018
+ var GPS_EPOCH_MS10 = Date.UTC(1980, 0, 6);
6965
7019
  var MS_PER_WEEK4 = 7 * 864e5;
6966
7020
  var SIGNALS = {
6967
7021
  0: { 0: ["G", "1C"], 3: ["G", "2X"], 4: ["G", "2X"] },
@@ -7044,7 +7098,7 @@ function parseUbxRawx(data) {
7044
7098
  if (!codes.includes(sig[1])) codes.push(sig[1]);
7045
7099
  }
7046
7100
  epochs.push({
7047
- timeMs: GPS_EPOCH_MS9 + week * MS_PER_WEEK4 + Math.round(rcvTow * 1e3),
7101
+ timeMs: GPS_EPOCH_MS10 + week * MS_PER_WEEK4 + Math.round(rcvTow * 1e3),
7048
7102
  leapS: leapValid ? leapS : null,
7049
7103
  meas
7050
7104
  });
@@ -7115,7 +7169,7 @@ function svidToPrn(svid) {
7115
7169
 
7116
7170
  // src/sbf/nav.ts
7117
7171
  var PI2 = Math.PI;
7118
- var GPS_EPOCH_MS10 = Date.UTC(1980, 0, 6);
7172
+ var GPS_EPOCH_MS11 = Date.UTC(1980, 0, 6);
7119
7173
  var BDT_EPOCH_MS2 = Date.UTC(2006, 0, 1);
7120
7174
  var SEC_PER_WEEK8 = 7 * 86400;
7121
7175
  var MS_PER_WEEK5 = SEC_PER_WEEK8 * 1e3;
@@ -7127,7 +7181,7 @@ function adjustWeek(refWeek, wn, mod) {
7127
7181
  if (offset < -(mod / 2 - 1)) offset += mod;
7128
7182
  return refWeek - offset;
7129
7183
  }
7130
- var gpsMs = (week, sec) => GPS_EPOCH_MS10 + week * MS_PER_WEEK5 + sec * 1e3;
7184
+ var gpsMs = (week, sec) => GPS_EPOCH_MS11 + week * MS_PER_WEEK5 + sec * 1e3;
7131
7185
  var sowOf2 = (dateMs) => dateMs / 1e3 % SEC_PER_WEEK8;
7132
7186
  function decodeGpsQzsNav(view, b, sys) {
7133
7187
  const svid = view.getUint8(b + 14);
@@ -7277,7 +7331,7 @@ function decodeGloNav(view, b) {
7277
7331
  const tocDate = new Date(toeGpsMs - leapMs);
7278
7332
  const tofGpsMs = gpsMs(wnc, 0) + view.getUint32(b + 8, true);
7279
7333
  const tofLeapMs = getGpsLeap(new Date(tofGpsMs)) * 1e3;
7280
- const messageFrameTime = (tofGpsMs - tofLeapMs - GPS_EPOCH_MS10) / 1e3 % SEC_PER_WEEK8;
7334
+ const messageFrameTime = (tofGpsMs - tofLeapMs - GPS_EPOCH_MS11) / 1e3 % SEC_PER_WEEK8;
7281
7335
  return {
7282
7336
  system: "R",
7283
7337
  prn,
@@ -7509,6 +7563,58 @@ function parseSbfReceiverSetup(data) {
7509
7563
  return out;
7510
7564
  }
7511
7565
 
7566
+ // src/sbf/pvt.ts
7567
+ var GPS_EPOCH_MS12 = Date.UTC(1980, 0, 6);
7568
+ var RAD2DEG = 180 / Math.PI;
7569
+ var DNU_F8 = -2e10;
7570
+ var MODE_LABELS = {
7571
+ 0: "no-pvt",
7572
+ 1: "standalone",
7573
+ 2: "differential",
7574
+ 3: "fixed-location",
7575
+ 4: "rtk-fixed",
7576
+ 5: "rtk-float",
7577
+ 6: "sbas-aided",
7578
+ 7: "moving-base-rtk-fixed",
7579
+ 8: "moving-base-rtk-float",
7580
+ 10: "ppp"
7581
+ };
7582
+ function parseSbfPvt(data) {
7583
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
7584
+ const records = [];
7585
+ let messages = 0;
7586
+ scanSbfFrames(data, view, (id, b, len) => {
7587
+ if (id !== 4007 || len < 96) return;
7588
+ messages++;
7589
+ const tow = view.getUint32(b + 8, true);
7590
+ const wnc = view.getUint16(b + 12, true);
7591
+ if (tow === 4294967295 || wnc === 65535) return;
7592
+ const modeByte = view.getUint8(b + 14);
7593
+ const modeType = modeByte & 15;
7594
+ const lat = view.getFloat64(b + 16, true);
7595
+ const lon = view.getFloat64(b + 24, true);
7596
+ const hgt = view.getFloat64(b + 32, true);
7597
+ const nrSV = view.getUint8(b + 74);
7598
+ const hAcc = view.getUint16(b + 90, true);
7599
+ const vAcc = view.getUint16(b + 92, true);
7600
+ const hasFix = lat > DNU_F8 && lon > DNU_F8 && hgt > DNU_F8;
7601
+ records.push({
7602
+ timeMs: GPS_EPOCH_MS12 + wnc * 6048e5 + tow,
7603
+ week: wnc,
7604
+ tow: tow / 1e3,
7605
+ modeType,
7606
+ mode: MODE_LABELS[modeType] ?? `mode-${modeType}`,
7607
+ latDeg: hasFix ? lat * RAD2DEG : null,
7608
+ lonDeg: hasFix ? lon * RAD2DEG : null,
7609
+ heightM: hasFix ? hgt : null,
7610
+ nrSV: nrSV === 255 ? null : nrSV,
7611
+ hAccuracyM: hAcc === 65535 ? null : hAcc / 100,
7612
+ vAccuracyM: vAcc === 65535 ? null : vAcc / 100
7613
+ });
7614
+ });
7615
+ return { records, messages };
7616
+ }
7617
+
7512
7618
  // src/sbf/rawnav-gps.ts
7513
7619
  var WNC_DNU = 65535;
7514
7620
  function extractSbfLnavSubframe(view, b) {
@@ -7644,7 +7750,7 @@ function isFnavDummy(page) {
7644
7750
  }
7645
7751
 
7646
7752
  // src/sbf/rawnav-bds.ts
7647
- var GPS_EPOCH_MS11 = Date.UTC(1980, 0, 6);
7753
+ var GPS_EPOCH_MS13 = Date.UTC(1980, 0, 6);
7648
7754
  var MS_PER_WEEK6 = 7 * 86400 * 1e3;
7649
7755
  var TOW_DNU = 4294967295;
7650
7756
  var WNC_DNU2 = 65535;
@@ -7705,7 +7811,7 @@ function feedGloBlock(view, b, assembler) {
7705
7811
  const eph = assembler.push(
7706
7812
  prn,
7707
7813
  str2,
7708
- new Date(GPS_EPOCH_MS11 + wnc * MS_PER_WEEK6 + towMs),
7814
+ new Date(GPS_EPOCH_MS13 + wnc * MS_PER_WEEK6 + towMs),
7709
7815
  view.getUint8(b + 18) - 8
7710
7816
  // FreqNr, offset by 8
7711
7817
  );
@@ -8455,7 +8561,7 @@ function parseSbfHas(data) {
8455
8561
 
8456
8562
  // src/sbf/index.ts
8457
8563
  var CLIGHT = 299792458;
8458
- var GPS_EPOCH_MS12 = Date.UTC(1980, 0, 6);
8564
+ var GPS_EPOCH_MS14 = Date.UTC(1980, 0, 6);
8459
8565
  var MS_PER_WEEK7 = 7 * 864e5;
8460
8566
  var M3_SYS = ["G", "R", "E", "C", "S", "J", "I"];
8461
8567
  var M3_PR_BASE = [19e6, 19e6, 22e6, 2e7, 34e6, 34e6, 34e6];
@@ -9109,7 +9215,7 @@ function parseSbfMeas(data) {
9109
9215
  const tow = view.getUint32(i + 8, true);
9110
9216
  const wnc = view.getUint16(i + 12, true);
9111
9217
  if (tow !== 4294967295 && wnc !== 65535) {
9112
- ensureEpoch(GPS_EPOCH_MS12 + wnc * MS_PER_WEEK7 + tow);
9218
+ ensureEpoch(GPS_EPOCH_MS14 + wnc * MS_PER_WEEK7 + tow);
9113
9219
  if (id === 4109) decodeMeas3Ranges(i, tow);
9114
9220
  else if (id === 4110) decodeMeas3CN0(i, len);
9115
9221
  else if (id === 4111) decodeMeas3Doppler(i, len);
@@ -9176,15 +9282,15 @@ var ID_GPSEPHEM = 7;
9176
9282
  var ID_BDSEPHEMERIS = 1696;
9177
9283
  var ID_RAWWAASFRAME = 287;
9178
9284
  var ID_RAWSBASFRAME = 973;
9179
- var GPS_EPOCH_MS13 = Date.UTC(1980, 0, 6);
9285
+ var GPS_EPOCH_MS15 = Date.UTC(1980, 0, 6);
9180
9286
  var BDT_EPOCH_MS3 = Date.UTC(2006, 0, 1);
9181
9287
  var SEC_PER_WEEK9 = 7 * 86400;
9182
9288
  var SEC_PER_DAY2 = 86400;
9183
9289
  var MS_PER_WEEK8 = SEC_PER_WEEK9 * 1e3;
9184
- var gpsMs2 = (week, sec) => GPS_EPOCH_MS13 + week * MS_PER_WEEK8 + sec * 1e3;
9290
+ var gpsMs2 = (week, sec) => GPS_EPOCH_MS15 + week * MS_PER_WEEK8 + sec * 1e3;
9185
9291
  var sowOf3 = (dateMs) => dateMs / 1e3 % SEC_PER_WEEK9;
9186
9292
  function nearWeekMs(refMs, sow) {
9187
- const refWeek = Math.floor((refMs - GPS_EPOCH_MS13) / MS_PER_WEEK8);
9293
+ const refWeek = Math.floor((refMs - GPS_EPOCH_MS15) / MS_PER_WEEK8);
9188
9294
  let ms = gpsMs2(refWeek, sow);
9189
9295
  if (ms < refMs - MS_PER_WEEK8 / 2) ms += MS_PER_WEEK8;
9190
9296
  else if (ms > refMs + MS_PER_WEEK8 / 2) ms -= MS_PER_WEEK8;
@@ -9211,9 +9317,9 @@ function decodeGloEphemeris(view, p) {
9211
9317
  tof += Math.floor(tow / SEC_PER_DAY2) * SEC_PER_DAY2;
9212
9318
  if (tof < tow - 43200) tof += SEC_PER_DAY2;
9213
9319
  else if (tof > tow + 43200) tof -= SEC_PER_DAY2;
9214
- const toeGpsMs = GPS_EPOCH_MS13 + (week * SEC_PER_WEEK9 + tow) * 1e3;
9215
- const tofGpsMs = GPS_EPOCH_MS13 + (week * SEC_PER_WEEK9 + tof) * 1e3;
9216
- const tofUtcSec = (getUtcDate(new Date(tofGpsMs)).getTime() - GPS_EPOCH_MS13) / 1e3;
9320
+ const toeGpsMs = GPS_EPOCH_MS15 + (week * SEC_PER_WEEK9 + tow) * 1e3;
9321
+ const tofGpsMs = GPS_EPOCH_MS15 + (week * SEC_PER_WEEK9 + tof) * 1e3;
9322
+ const tofUtcSec = (getUtcDate(new Date(tofGpsMs)).getTime() - GPS_EPOCH_MS15) / 1e3;
9217
9323
  return {
9218
9324
  system: "R",
9219
9325
  prn: `R${String(slot).padStart(2, "0")}`,
@@ -9278,7 +9384,7 @@ function decodeGalEphemeris(view, p, headerMs) {
9278
9384
  omega: view.getFloat64(p + 60, true),
9279
9385
  omegaDot: view.getFloat64(p + 140, true),
9280
9386
  idot: view.getFloat64(p + 124, true),
9281
- week: Math.floor((toeMs - GPS_EPOCH_MS13) / MS_PER_WEEK8),
9387
+ week: Math.floor((toeMs - GPS_EPOCH_MS15) / MS_PER_WEEK8),
9282
9388
  // RINEX Galileo SVH bit layout (E1B DVS/HS in bits 0-2, E5a in
9283
9389
  // 3-5, E5b in 6-8) — same packing as RTKLIB.
9284
9390
  svHealth: svhE5b << 7 | dvsE5b << 6 | svhE5a << 4 | dvsE5a << 3 | svhE1b << 1 | dvsE1b,
@@ -9464,8 +9570,57 @@ function parseNovatelNav(data, opts = {}) {
9464
9570
  };
9465
9571
  }
9466
9572
 
9573
+ // src/novatel/pvt.ts
9574
+ var GPS_EPOCH_MS16 = Date.UTC(1980, 0, 6);
9575
+ var BESTPOS = 42;
9576
+ function posTypeToMode(t) {
9577
+ if (t === 0) return "no-pvt";
9578
+ if (t === 16) return "standalone";
9579
+ if (t === 17) return "differential";
9580
+ if (t === 18 || t === 20) return "sbas-aided";
9581
+ if (t === 32 || t === 33 || t === 34) return "rtk-float";
9582
+ if (t === 48 || t === 50) return "rtk-fixed";
9583
+ if (t >= 68 && t <= 78) return "ppp";
9584
+ return `mode-${t}`;
9585
+ }
9586
+ function parseNovatelPvt(data) {
9587
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
9588
+ const records = [];
9589
+ let messages = 0;
9590
+ const stats = { badCrc: 0 };
9591
+ for (const f of oem4Frames(data, view, stats)) {
9592
+ if (f.id !== BESTPOS || !f.binary || f.msgLen < 72) continue;
9593
+ messages++;
9594
+ const p = f.payload;
9595
+ const posType = view.getUint32(p + 4, true);
9596
+ const lat = view.getFloat64(p + 8, true);
9597
+ const lon = view.getFloat64(p + 16, true);
9598
+ const hgtMsl = view.getFloat64(p + 24, true);
9599
+ const undulation = view.getFloat32(p + 32, true);
9600
+ const latSig = view.getFloat32(p + 40, true);
9601
+ const lonSig = view.getFloat32(p + 44, true);
9602
+ const hgtSig = view.getFloat32(p + 48, true);
9603
+ const nrSV = view.getUint8(p + 65);
9604
+ const hasFix = posType !== 0 && Number.isFinite(lat) && Number.isFinite(lon);
9605
+ records.push({
9606
+ timeMs: GPS_EPOCH_MS16 + f.week * 6048e5 + f.towMs,
9607
+ week: f.week,
9608
+ tow: f.towMs / 1e3,
9609
+ mode: posTypeToMode(posType),
9610
+ latDeg: hasFix ? lat : null,
9611
+ lonDeg: hasFix ? lon : null,
9612
+ // BESTPOS height is above MSL; ellipsoidal = MSL + geoid undulation.
9613
+ heightM: hasFix ? hgtMsl + undulation : null,
9614
+ nrSV,
9615
+ hAccuracyM: hasFix ? Math.hypot(latSig, lonSig) : null,
9616
+ vAccuracyM: hasFix ? hgtSig : null
9617
+ });
9618
+ }
9619
+ return { records, messages };
9620
+ }
9621
+
9467
9622
  // src/novatel/index.ts
9468
- var GPS_EPOCH_MS14 = Date.UTC(1980, 0, 6);
9623
+ var GPS_EPOCH_MS17 = Date.UTC(1980, 0, 6);
9469
9624
  var MS_PER_WEEK9 = 7 * 864e5;
9470
9625
  var HDR = 28;
9471
9626
  var ID_RANGE = 43;
@@ -9635,7 +9790,7 @@ function parseNovatelRange(data) {
9635
9790
  if (!codes.includes(code)) codes.push(code);
9636
9791
  }
9637
9792
  epochs.push({
9638
- timeMs: GPS_EPOCH_MS14 + week * MS_PER_WEEK9 + towMs,
9793
+ timeMs: GPS_EPOCH_MS17 + week * MS_PER_WEEK9 + towMs,
9639
9794
  meas
9640
9795
  });
9641
9796
  }
@@ -9687,7 +9842,7 @@ function parseNovatelRange(data) {
9687
9842
  if (!codes.includes(code)) codes.push(code);
9688
9843
  }
9689
9844
  epochs.push({
9690
- timeMs: GPS_EPOCH_MS14 + week * MS_PER_WEEK9 + towMs,
9845
+ timeMs: GPS_EPOCH_MS17 + week * MS_PER_WEEK9 + towMs,
9691
9846
  meas
9692
9847
  });
9693
9848
  }
@@ -9738,14 +9893,14 @@ function* trimbleFrames(data, stats) {
9738
9893
  }
9739
9894
 
9740
9895
  // src/trimble/nav.ts
9741
- var GPS_EPOCH_MS15 = Date.UTC(1980, 0, 6);
9896
+ var GPS_EPOCH_MS18 = Date.UTC(1980, 0, 6);
9742
9897
  var BDT_EPOCH_MS4 = Date.UTC(2006, 0, 1);
9743
9898
  var SEC_PER_WEEK10 = 7 * 86400;
9744
9899
  var MS_PER_WEEK10 = SEC_PER_WEEK10 * 1e3;
9745
9900
  var GPS_PI2 = 3.1415926535898;
9746
9901
  var BDS_WEEK_OFFSET = 1356;
9747
9902
  var BDS_LEAP_SEC = 14;
9748
- var gpsMs3 = (week, sec) => GPS_EPOCH_MS15 + week * MS_PER_WEEK10 + sec * 1e3;
9903
+ var gpsMs3 = (week, sec) => GPS_EPOCH_MS18 + week * MS_PER_WEEK10 + sec * 1e3;
9749
9904
  var sowOf4 = (dateMs) => dateMs / 1e3 % SEC_PER_WEEK10;
9750
9905
  var SUB_GPS_EPHEMERIS = 1;
9751
9906
  var SUB_ION_UTC = 3;
@@ -9898,7 +10053,7 @@ function decodeGloEphemeris2(view, base) {
9898
10053
  // RINEX stores −τn as the clock bias; the record carries τn (ICD sign).
9899
10054
  tauN: -view.getFloat64(base + 113, false),
9900
10055
  gammaN: view.getFloat64(base + 121, false),
9901
- messageFrameTime: (tocMs - GPS_EPOCH_MS15) / 1e3 % SEC_PER_WEEK10,
10056
+ messageFrameTime: (tocMs - GPS_EPOCH_MS18) / 1e3 % SEC_PER_WEEK10,
9902
10057
  // State vector: metres / m·s⁻¹ / m·s⁻² → km / km·s⁻¹ / km·s⁻².
9903
10058
  x: view.getFloat64(base + 33, false) / 1e3,
9904
10059
  xDot: view.getFloat64(base + 41, false) / 1e3,
@@ -9969,7 +10124,7 @@ function parseTrimbleNav(data) {
9969
10124
  }
9970
10125
 
9971
10126
  // src/trimble/index.ts
9972
- var GPS_EPOCH_MS16 = Date.UTC(1980, 0, 6);
10127
+ var GPS_EPOCH_MS19 = Date.UTC(1980, 0, 6);
9973
10128
  var MS_PER_WEEK11 = 7 * 864e5;
9974
10129
  var REC_TYPE_27 = 6;
9975
10130
  var SYS = {
@@ -10167,7 +10322,7 @@ function decodeEpoch(epoch, epochs, obsCodes) {
10167
10322
  o += c.length;
10168
10323
  }
10169
10324
  const dv = new DataView(M.buffer, M.byteOffset, M.byteLength);
10170
- const timeMs = GPS_EPOCH_MS16 + epoch.week * MS_PER_WEEK11 + epoch.towMs;
10325
+ const timeMs = GPS_EPOCH_MS19 + epoch.week * MS_PER_WEEK11 + epoch.towMs;
10171
10326
  const meas = [];
10172
10327
  let q = 0;
10173
10328
  for (let sv = 0; sv < epoch.nsv && q + 8 <= M.length; sv++) {
@@ -10348,13 +10503,13 @@ function* binexRecords(data, view, stats) {
10348
10503
  }
10349
10504
 
10350
10505
  // src/binex/nav.ts
10351
- var GPS_EPOCH_MS17 = Date.UTC(1980, 0, 6);
10506
+ var GPS_EPOCH_MS20 = Date.UTC(1980, 0, 6);
10352
10507
  var GLO_DAY0_MS = Date.UTC(1980, 0, 1);
10353
10508
  var BDT_EPOCH_MS5 = Date.UTC(2006, 0, 1);
10354
10509
  var SEC_PER_WEEK11 = 7 * 86400;
10355
10510
  var MS_PER_WEEK12 = SEC_PER_WEEK11 * 1e3;
10356
10511
  var SC2RAD = GPS_PI;
10357
- var gpsMs4 = (week, sec) => GPS_EPOCH_MS17 + week * MS_PER_WEEK12 + sec * 1e3;
10512
+ var gpsMs4 = (week, sec) => GPS_EPOCH_MS20 + week * MS_PER_WEEK12 + sec * 1e3;
10358
10513
  var sowOf5 = (dateMs) => (dateMs / 1e3 % SEC_PER_WEEK11 + SEC_PER_WEEK11) % SEC_PER_WEEK11;
10359
10514
  var two6 = (n) => String(n).padStart(2, "0");
10360
10515
  var Reader = class {
@@ -10642,7 +10797,7 @@ function decodeBinexEph(view, body, len, le) {
10642
10797
  }
10643
10798
 
10644
10799
  // src/binex/index.ts
10645
- var GPS_EPOCH_MS18 = Date.UTC(1980, 0, 6);
10800
+ var GPS_EPOCH_MS21 = Date.UTC(1980, 0, 6);
10646
10801
  var CLIGHT2 = 299792458;
10647
10802
  var OBS_CODES = {
10648
10803
  0: [
@@ -10900,7 +11055,7 @@ function decodeObsRecord(data, view, body, len, obsCodes) {
10900
11055
  p += 4;
10901
11056
  const msec = view.getUint16(p);
10902
11057
  p += 2;
10903
- const timeMs = GPS_EPOCH_MS18 + min * 6e4 + msec;
11058
+ const timeMs = GPS_EPOCH_MS21 + min * 6e4 + msec;
10904
11059
  const flag = data[p++];
10905
11060
  const nsat = (flag & 63) + 1;
10906
11061
  if (flag & 128) p += 3;
@@ -10986,7 +11141,7 @@ function parseBinex(data) {
10986
11141
  var GM_GPS = 3986005e8;
10987
11142
  var GM_GAL = 3986004418e5;
10988
11143
  var GM_BDS = 3986004418e5;
10989
- var GPS_EPOCH_MS19 = Date.UTC(1980, 0, 6);
11144
+ var GPS_EPOCH_MS22 = Date.UTC(1980, 0, 6);
10990
11145
  var BDT_EPOCH_MS6 = Date.UTC(2006, 0, 1);
10991
11146
  var WEEK_MS = 6048e5;
10992
11147
  var BDT_MINUS_GPST_MS = 14e3;
@@ -10995,7 +11150,7 @@ function almanacEpochMs(alm) {
10995
11150
  if (alm.system === "C") {
10996
11151
  return BDT_EPOCH_MS6 + alm.weekAlm * WEEK_MS + alm.toaSec * 1e3 + BDT_MINUS_GPST_MS;
10997
11152
  }
10998
- return GPS_EPOCH_MS19 + alm.weekAlm * WEEK_MS + alm.toaSec * 1e3;
11153
+ return GPS_EPOCH_MS22 + alm.weekAlm * WEEK_MS + alm.toaSec * 1e3;
10999
11154
  }
11000
11155
  function almanacSatPosition(alm, timeMs) {
11001
11156
  const GM = alm.system === "E" ? GM_GAL : alm.system === "C" ? GM_BDS : GM_GPS;
@@ -11504,10 +11659,10 @@ function selectBest(ephs, timeMs) {
11504
11659
  }
11505
11660
  return best;
11506
11661
  }
11507
- var GPS_EPOCH_MS20 = START_GPS_TIME.getTime();
11662
+ var GPS_EPOCH_MS23 = START_GPS_TIME.getTime();
11508
11663
  var MS_PER_WEEK13 = 7 * 864e5;
11509
11664
  var BDS_EPOCH_MS = START_BDS_TIME.getTime();
11510
- var GAL_EPOCH_MS = GPS_EPOCH_MS20 + 1024 * MS_PER_WEEK13;
11665
+ var GAL_EPOCH_MS = GPS_EPOCH_MS23 + 1024 * MS_PER_WEEK13;
11511
11666
  function ephInfoToEphemeris(info) {
11512
11667
  const sys = info.prn.charAt(0);
11513
11668
  if (sys === "R") {
@@ -11558,8 +11713,8 @@ function ephInfoToEphemeris(info) {
11558
11713
  } else if (sys === "E") {
11559
11714
  epochMs = GAL_EPOCH_MS;
11560
11715
  } else {
11561
- epochMs = GPS_EPOCH_MS20;
11562
- const weeksNow = (info.lastReceived - GPS_EPOCH_MS20) / MS_PER_WEEK13;
11716
+ epochMs = GPS_EPOCH_MS23;
11717
+ const weeksNow = (info.lastReceived - GPS_EPOCH_MS23) / MS_PER_WEEK13;
11563
11718
  week += 1024 * Math.round((weeksNow - week) / 1024);
11564
11719
  }
11565
11720
  const tocDate = new Date(epochMs + week * MS_PER_WEEK13 + tocSec * 1e3);
@@ -17766,6 +17921,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
17766
17921
  parseNavFile,
17767
17922
  parseNmeaFile,
17768
17923
  parseNovatelNav,
17924
+ parseNovatelPvt,
17769
17925
  parseNovatelRange,
17770
17926
  parseRinexStream,
17771
17927
  parseSbfAlmanac,
@@ -17779,6 +17935,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
17779
17935
  parseSbfIonoUtc,
17780
17936
  parseSbfMeas,
17781
17937
  parseSbfNav,
17938
+ parseSbfPvt,
17782
17939
  parseSbfReceiverSetup,
17783
17940
  parseSinexBiasDcb,
17784
17941
  parseSourcetable,
@@ -17788,6 +17945,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
17788
17945
  parseUbxCnav,
17789
17946
  parseUbxIonoUtc,
17790
17947
  parseUbxNav,
17948
+ parseUbxPvt,
17791
17949
  parseUbxRawNav,
17792
17950
  parseUbxRawx,
17793
17951
  phiAltBOC,
package/dist/index.d.cts CHANGED
@@ -1,3 +1,4 @@
1
+ export { R as ReceiverPvt } from './receiver-pvt-CVFvi4kT.cjs';
1
2
  export { D as DAYS_MJD2000_MJD, a as DAYS_MJD_JULIAN, H as HourCode, M as MILLISECONDS_GPS_TAI, b as MILLISECONDS_IN_DAY, c as MILLISECONDS_IN_HOUR, d as MILLISECONDS_IN_MINUTE, e as MILLISECONDS_IN_SECOND, f as MILLISECONDS_IN_WEEK, g as MILLISECONDS_TT_TAI, R as RINEX_CODES, S as SECONDS_IN_DAY, h as SECONDS_IN_HOUR, i as SECONDS_IN_MINUTE, j as SECONDS_IN_WEEK, k as START_BDS_TIME, l as START_GAL_TIME, m as START_GLO_LEAP, n as START_GPS_TIME, o as START_JULIAN_TAI, p as START_MJD_UNIX_SECONDS, q as START_NTP_TIME, r as START_TAI_TIME, s as START_UNIX_TIME, T as TimeDifference } from './time-DnI1VpE8.cjs';
2
3
  export { WGS84_ECCENTRICITY_SQUARED, WGS84_FLATTENING, WGS84_SEMI_MAJOR_AXIS, WGS84_SEMI_MINOR_AXIS } from './constants.cjs';
3
4
  export { A as ARC_GAP_FACTOR, B as BAND_LABELS, a as BDS_SATELLITES, b as BdsSatellite, C as C_LIGHT, D as DEFAULT_ELEV_MASK_DEG, c as DUAL_FREQ_PAIRS, F as FREQ, G as GLO_CHANNEL_FALLBACK, d as GLO_F1_BASE, e as GLO_F1_STEP, f as GLO_F2_BASE, g as GLO_F2_STEP, h as GLO_F3, O as OMEGA_E, i as OnSlipDetected, S as SYSTEM_NAMES, j as SYS_SHORT, k as buildGloChannelMap, l as buildObsIndices, m as formatUTCTime, n as getFreq, o as gloFreq } from './gnss-BtXrG3zH.cjs';
@@ -10,9 +11,9 @@ export { C as CnavEphemeris, E as Ephemeris, G as GlonassEphemeris, K as KeplerE
10
11
  export { C as ClkFile, I as IonexGrid, S as Sp3File, a as Sp3Sample, c as clkBias, p as parseClk, b as parseIonex, d as parseSp3, s as sp3Position } from './clk-DGVBGRzA.cjs';
11
12
  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
13
  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
- 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, SbfGeoNavResult, SbfGloNavResult, SbfGpsNavResult, SbfHasMessage, SbfHasResult, SbfIonoUtcResult, SbfMeasEpoch, SbfMeasurement, SbfNavCounts, SbfNavigation, SbfParseResult, SbfReceiverSetup, decodeSbfNavigation, feedGeoBlock, parseSbfBdsNav, parseSbfCnav, parseSbfGalNav, parseSbfGeoNav, parseSbfGloNav, parseSbfGpsNav, parseSbfHas, parseSbfIonoUtc, parseSbfMeas, parseSbfReceiverSetup, sbfCrc16, scanSbfFrames } from './sbf.cjs';
15
- export { NovatelEpoch, NovatelMeasurement, NovatelNavResult, NovatelParseResult, OEM4_HLEN, Oem4Frame, crc32, oem4Frames, parseNovatelNav, parseNovatelRange } from './novatel.cjs';
14
+ export { UbxCnavResult, UbxFrame, UbxIonoUtcResult, UbxMeasurement, UbxNavOptions, UbxNavResult, UbxParseResult, UbxPvtResult, UbxRawNavOptions, UbxRawNavResult, UbxRawxEpoch, parseUbxCnav, parseUbxIonoUtc, parseUbxNav, parseUbxPvt, parseUbxRawNav, parseUbxRawx, ubxFrames } from './ubx.cjs';
15
+ export { HasMessage, SbfBdsNavResult, SbfCnavEphemeris, SbfCnavResult, SbfGalEphemeris, SbfGalNavResult, SbfGeoNavResult, SbfGloNavResult, SbfGpsNavResult, SbfHasMessage, SbfHasResult, SbfIonoUtcResult, SbfMeasEpoch, SbfMeasurement, SbfNavCounts, SbfNavigation, SbfParseResult, SbfPvt, SbfPvtResult, SbfReceiverSetup, decodeSbfNavigation, feedGeoBlock, parseSbfBdsNav, parseSbfCnav, parseSbfGalNav, parseSbfGeoNav, parseSbfGloNav, parseSbfGpsNav, parseSbfHas, parseSbfIonoUtc, parseSbfMeas, parseSbfPvt, parseSbfReceiverSetup, sbfCrc16, scanSbfFrames } from './sbf.cjs';
16
+ export { NovatelEpoch, NovatelMeasurement, NovatelNavResult, NovatelParseResult, NovatelPvtResult, OEM4_HLEN, Oem4Frame, crc32, oem4Frames, parseNovatelNav, parseNovatelPvt, parseNovatelRange } from './novatel.cjs';
16
17
  export { TrimbleEpoch, TrimbleFrame, TrimbleMeasurement, TrimbleNavResult, TrimbleParseResult, parseTrimble, parseTrimbleNav, trimbleFrames } from './trimble.cjs';
17
18
  export { BinexEpoch, BinexMeasurement, BinexParseResult, BinexRecord, binexCrc16, binexCrc32, binexCsum8, binexRecords, decodeBinexEph, getBnxi, parseBinex } from './binex.cjs';
18
19
  export { AllPositionsData, AlmanacPosition, DopValues, EpochSkyData, SatAzEl, SatPoint, SatPosition, VisibilityPass, VisibilityResult, almanacEpochMs, almanacSatPosition, computeAllPositions, computeDop, computeLiveSkyPositions, computeSatPosition, computeVisibility, computeVisibilityFromPositions, dopplerHz, ecefToAzEl, ephInfoToEphemeris, glonassAlmanacEpochMs, glonassAlmanacPosition, glonassPosition, keplerPosition, maskRadForAzimuth, navTimesFromEph, rangeRate, selectEphemeris } from './orbit.cjs';
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export { R as ReceiverPvt } from './receiver-pvt-CVFvi4kT.js';
1
2
  export { D as DAYS_MJD2000_MJD, a as DAYS_MJD_JULIAN, H as HourCode, M as MILLISECONDS_GPS_TAI, b as MILLISECONDS_IN_DAY, c as MILLISECONDS_IN_HOUR, d as MILLISECONDS_IN_MINUTE, e as MILLISECONDS_IN_SECOND, f as MILLISECONDS_IN_WEEK, g as MILLISECONDS_TT_TAI, R as RINEX_CODES, S as SECONDS_IN_DAY, h as SECONDS_IN_HOUR, i as SECONDS_IN_MINUTE, j as SECONDS_IN_WEEK, k as START_BDS_TIME, l as START_GAL_TIME, m as START_GLO_LEAP, n as START_GPS_TIME, o as START_JULIAN_TAI, p as START_MJD_UNIX_SECONDS, q as START_NTP_TIME, r as START_TAI_TIME, s as START_UNIX_TIME, T as TimeDifference } from './time-DnI1VpE8.js';
2
3
  export { WGS84_ECCENTRICITY_SQUARED, WGS84_FLATTENING, WGS84_SEMI_MAJOR_AXIS, WGS84_SEMI_MINOR_AXIS } from './constants.js';
3
4
  export { A as ARC_GAP_FACTOR, B as BAND_LABELS, a as BDS_SATELLITES, b as BdsSatellite, C as C_LIGHT, D as DEFAULT_ELEV_MASK_DEG, c as DUAL_FREQ_PAIRS, F as FREQ, G as GLO_CHANNEL_FALLBACK, d as GLO_F1_BASE, e as GLO_F1_STEP, f as GLO_F2_BASE, g as GLO_F2_STEP, h as GLO_F3, O as OMEGA_E, i as OnSlipDetected, S as SYSTEM_NAMES, j as SYS_SHORT, k as buildGloChannelMap, l as buildObsIndices, m as formatUTCTime, n as getFreq, o as gloFreq } from './gnss-DhnEr0Dy.js';
@@ -10,9 +11,9 @@ export { C as CnavEphemeris, E as Ephemeris, G as GlonassEphemeris, K as KeplerE
10
11
  export { C as ClkFile, I as IonexGrid, S as Sp3File, a as Sp3Sample, c as clkBias, p as parseClk, b as parseIonex, d as parseSp3, s as sp3Position } from './clk-DGVBGRzA.js';
11
12
  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
13
  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
- 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, SbfGeoNavResult, SbfGloNavResult, SbfGpsNavResult, SbfHasMessage, SbfHasResult, SbfIonoUtcResult, SbfMeasEpoch, SbfMeasurement, SbfNavCounts, SbfNavigation, SbfParseResult, SbfReceiverSetup, decodeSbfNavigation, feedGeoBlock, parseSbfBdsNav, parseSbfCnav, parseSbfGalNav, parseSbfGeoNav, parseSbfGloNav, parseSbfGpsNav, parseSbfHas, parseSbfIonoUtc, parseSbfMeas, parseSbfReceiverSetup, sbfCrc16, scanSbfFrames } from './sbf.js';
15
- export { NovatelEpoch, NovatelMeasurement, NovatelNavResult, NovatelParseResult, OEM4_HLEN, Oem4Frame, crc32, oem4Frames, parseNovatelNav, parseNovatelRange } from './novatel.js';
14
+ export { UbxCnavResult, UbxFrame, UbxIonoUtcResult, UbxMeasurement, UbxNavOptions, UbxNavResult, UbxParseResult, UbxPvtResult, UbxRawNavOptions, UbxRawNavResult, UbxRawxEpoch, parseUbxCnav, parseUbxIonoUtc, parseUbxNav, parseUbxPvt, parseUbxRawNav, parseUbxRawx, ubxFrames } from './ubx.js';
15
+ export { HasMessage, SbfBdsNavResult, SbfCnavEphemeris, SbfCnavResult, SbfGalEphemeris, SbfGalNavResult, SbfGeoNavResult, SbfGloNavResult, SbfGpsNavResult, SbfHasMessage, SbfHasResult, SbfIonoUtcResult, SbfMeasEpoch, SbfMeasurement, SbfNavCounts, SbfNavigation, SbfParseResult, SbfPvt, SbfPvtResult, SbfReceiverSetup, decodeSbfNavigation, feedGeoBlock, parseSbfBdsNav, parseSbfCnav, parseSbfGalNav, parseSbfGeoNav, parseSbfGloNav, parseSbfGpsNav, parseSbfHas, parseSbfIonoUtc, parseSbfMeas, parseSbfPvt, parseSbfReceiverSetup, sbfCrc16, scanSbfFrames } from './sbf.js';
16
+ export { NovatelEpoch, NovatelMeasurement, NovatelNavResult, NovatelParseResult, NovatelPvtResult, OEM4_HLEN, Oem4Frame, crc32, oem4Frames, parseNovatelNav, parseNovatelPvt, parseNovatelRange } from './novatel.js';
16
17
  export { TrimbleEpoch, TrimbleFrame, TrimbleMeasurement, TrimbleNavResult, TrimbleParseResult, parseTrimble, parseTrimbleNav, trimbleFrames } from './trimble.js';
17
18
  export { BinexEpoch, BinexMeasurement, BinexParseResult, BinexRecord, binexCrc16, binexCrc32, binexCsum8, binexRecords, decodeBinexEph, getBnxi, parseBinex } from './binex.js';
18
19
  export { AllPositionsData, AlmanacPosition, DopValues, EpochSkyData, SatAzEl, SatPoint, SatPosition, VisibilityPass, VisibilityResult, almanacEpochMs, almanacSatPosition, computeAllPositions, computeDop, computeLiveSkyPositions, computeSatPosition, computeVisibility, computeVisibilityFromPositions, dopplerHz, ecefToAzEl, ephInfoToEphemeris, glonassAlmanacEpochMs, glonassAlmanacPosition, glonassPosition, keplerPosition, maskRadForAzimuth, navTimesFromEph, rangeRate, selectEphemeris } from './orbit.js';
package/dist/index.js CHANGED
@@ -47,10 +47,11 @@ import {
47
47
  parseUbxCnav,
48
48
  parseUbxIonoUtc,
49
49
  parseUbxNav,
50
+ parseUbxPvt,
50
51
  parseUbxRawNav,
51
52
  parseUbxRawx,
52
53
  ubxFrames
53
- } from "./chunk-DEVUKH6A.js";
54
+ } from "./chunk-MRC6LIPM.js";
54
55
  import {
55
56
  crc16,
56
57
  decodeSbfNavigation,
@@ -66,17 +67,19 @@ import {
66
67
  parseSbfIonoUtc,
67
68
  parseSbfMeas,
68
69
  parseSbfNav,
70
+ parseSbfPvt,
69
71
  parseSbfReceiverSetup,
70
72
  scanSbfFrames
71
- } from "./chunk-DE5IUULR.js";
73
+ } from "./chunk-ZPNMIUNZ.js";
72
74
  import "./chunk-FA2UTLEQ.js";
73
75
  import {
74
76
  OEM4_HLEN,
75
77
  crc32,
76
78
  oem4Frames,
77
79
  parseNovatelNav,
80
+ parseNovatelPvt,
78
81
  parseNovatelRange
79
- } from "./chunk-ZS5RLFWI.js";
82
+ } from "./chunk-KUTNIP3O.js";
80
83
  import {
81
84
  parseTrimble,
82
85
  parseTrimbleNav,
@@ -593,6 +596,7 @@ export {
593
596
  parseNavFile,
594
597
  parseNmeaFile,
595
598
  parseNovatelNav,
599
+ parseNovatelPvt,
596
600
  parseNovatelRange,
597
601
  parseRinexStream,
598
602
  parseSbfAlmanac,
@@ -606,6 +610,7 @@ export {
606
610
  parseSbfIonoUtc,
607
611
  parseSbfMeas,
608
612
  parseSbfNav,
613
+ parseSbfPvt,
609
614
  parseSbfReceiverSetup,
610
615
  parseSinexBiasDcb,
611
616
  parseSourcetable,
@@ -615,6 +620,7 @@ export {
615
620
  parseUbxCnav,
616
621
  parseUbxIonoUtc,
617
622
  parseUbxNav,
623
+ parseUbxPvt,
618
624
  parseUbxRawNav,
619
625
  parseUbxRawx,
620
626
  phiAltBOC,
package/dist/novatel.cjs CHANGED
@@ -24,6 +24,7 @@ __export(novatel_exports, {
24
24
  crc32: () => crc32,
25
25
  oem4Frames: () => oem4Frames,
26
26
  parseNovatelNav: () => parseNovatelNav,
27
+ parseNovatelPvt: () => parseNovatelPvt,
27
28
  parseNovatelRange: () => parseNovatelRange
28
29
  });
29
30
  module.exports = __toCommonJS(novatel_exports);
@@ -823,8 +824,57 @@ function parseNovatelNav(data, opts = {}) {
823
824
  };
824
825
  }
825
826
 
826
- // src/novatel/index.ts
827
+ // src/novatel/pvt.ts
827
828
  var GPS_EPOCH_MS5 = Date.UTC(1980, 0, 6);
829
+ var BESTPOS = 42;
830
+ function posTypeToMode(t) {
831
+ if (t === 0) return "no-pvt";
832
+ if (t === 16) return "standalone";
833
+ if (t === 17) return "differential";
834
+ if (t === 18 || t === 20) return "sbas-aided";
835
+ if (t === 32 || t === 33 || t === 34) return "rtk-float";
836
+ if (t === 48 || t === 50) return "rtk-fixed";
837
+ if (t >= 68 && t <= 78) return "ppp";
838
+ return `mode-${t}`;
839
+ }
840
+ function parseNovatelPvt(data) {
841
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
842
+ const records = [];
843
+ let messages = 0;
844
+ const stats = { badCrc: 0 };
845
+ for (const f of oem4Frames(data, view, stats)) {
846
+ if (f.id !== BESTPOS || !f.binary || f.msgLen < 72) continue;
847
+ messages++;
848
+ const p = f.payload;
849
+ const posType = view.getUint32(p + 4, true);
850
+ const lat = view.getFloat64(p + 8, true);
851
+ const lon = view.getFloat64(p + 16, true);
852
+ const hgtMsl = view.getFloat64(p + 24, true);
853
+ const undulation = view.getFloat32(p + 32, true);
854
+ const latSig = view.getFloat32(p + 40, true);
855
+ const lonSig = view.getFloat32(p + 44, true);
856
+ const hgtSig = view.getFloat32(p + 48, true);
857
+ const nrSV = view.getUint8(p + 65);
858
+ const hasFix = posType !== 0 && Number.isFinite(lat) && Number.isFinite(lon);
859
+ records.push({
860
+ timeMs: GPS_EPOCH_MS5 + f.week * 6048e5 + f.towMs,
861
+ week: f.week,
862
+ tow: f.towMs / 1e3,
863
+ mode: posTypeToMode(posType),
864
+ latDeg: hasFix ? lat : null,
865
+ lonDeg: hasFix ? lon : null,
866
+ // BESTPOS height is above MSL; ellipsoidal = MSL + geoid undulation.
867
+ heightM: hasFix ? hgtMsl + undulation : null,
868
+ nrSV,
869
+ hAccuracyM: hasFix ? Math.hypot(latSig, lonSig) : null,
870
+ vAccuracyM: hasFix ? hgtSig : null
871
+ });
872
+ }
873
+ return { records, messages };
874
+ }
875
+
876
+ // src/novatel/index.ts
877
+ var GPS_EPOCH_MS6 = Date.UTC(1980, 0, 6);
828
878
  var MS_PER_WEEK3 = 7 * 864e5;
829
879
  var HDR = 28;
830
880
  var ID_RANGE = 43;
@@ -994,7 +1044,7 @@ function parseNovatelRange(data) {
994
1044
  if (!codes.includes(code)) codes.push(code);
995
1045
  }
996
1046
  epochs.push({
997
- timeMs: GPS_EPOCH_MS5 + week * MS_PER_WEEK3 + towMs,
1047
+ timeMs: GPS_EPOCH_MS6 + week * MS_PER_WEEK3 + towMs,
998
1048
  meas
999
1049
  });
1000
1050
  }
@@ -1046,7 +1096,7 @@ function parseNovatelRange(data) {
1046
1096
  if (!codes.includes(code)) codes.push(code);
1047
1097
  }
1048
1098
  epochs.push({
1049
- timeMs: GPS_EPOCH_MS5 + week * MS_PER_WEEK3 + towMs,
1099
+ timeMs: GPS_EPOCH_MS6 + week * MS_PER_WEEK3 + towMs,
1050
1100
  meas
1051
1101
  });
1052
1102
  }
@@ -1061,5 +1111,6 @@ function parseNovatelRange(data) {
1061
1111
  crc32,
1062
1112
  oem4Frames,
1063
1113
  parseNovatelNav,
1114
+ parseNovatelPvt,
1064
1115
  parseNovatelRange
1065
1116
  });