gnss-js 1.14.1 → 1.15.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
@@ -76,6 +76,7 @@ __export(src_exports, {
76
76
  MILLISECONDS_IN_WEEK: () => MILLISECONDS_IN_WEEK,
77
77
  MILLISECONDS_TT_TAI: () => MILLISECONDS_TT_TAI,
78
78
  MultipathAccumulator: () => MultipathAccumulator,
79
+ OEM4_HLEN: () => OEM4_HLEN,
79
80
  OMEGA_E: () => OMEGA_E,
80
81
  REFERENCE_FRAMES: () => REFERENCE_FRAMES,
81
82
  RINEX_CODES: () => RINEX_CODES,
@@ -119,6 +120,7 @@ __export(src_exports, {
119
120
  computeVisibility: () => computeVisibility,
120
121
  computeVisibilityFromPositions: () => computeVisibilityFromPositions,
121
122
  connectToMountpoint: () => connectToMountpoint,
123
+ crc32: () => crc32,
122
124
  createGzipLineSink: () => createGzipLineSink,
123
125
  createStationMeta: () => createStationMeta,
124
126
  createStreamStats: () => createStreamStats,
@@ -208,6 +210,7 @@ __export(src_exports, {
208
210
  msmEpochToDate: () => msmEpochToDate,
209
211
  navTimesFromEph: () => navTimesFromEph,
210
212
  nmeaCoordToDecimal: () => nmeaCoordToDecimal,
213
+ oem4Frames: () => oem4Frames,
211
214
  padL: () => padL,
212
215
  padR: () => padR,
213
216
  parseAntex: () => parseAntex,
@@ -215,9 +218,12 @@ __export(src_exports, {
215
218
  parseIonex: () => parseIonex,
216
219
  parseNavFile: () => parseNavFile,
217
220
  parseNmeaFile: () => parseNmeaFile,
221
+ parseNovatelNav: () => parseNovatelNav,
218
222
  parseNovatelRange: () => parseNovatelRange,
219
223
  parseRinexStream: () => parseRinexStream,
224
+ parseSbfAlmanac: () => parseSbfAlmanac,
220
225
  parseSbfMeas: () => parseSbfMeas,
226
+ parseSbfNav: () => parseSbfNav,
221
227
  parseSinexBiasDcb: () => parseSinexBiasDcb,
222
228
  parseSourcetable: () => parseSourcetable,
223
229
  parseSp3: () => parseSp3,
@@ -4610,20 +4616,20 @@ var SIGNALS = {
4610
4616
  // GLONASS L1OF, L2OF
4611
4617
  };
4612
4618
  function prnFor(gnssId, svId) {
4613
- const two2 = (n) => String(n).padStart(2, "0");
4619
+ const two3 = (n) => String(n).padStart(2, "0");
4614
4620
  switch (gnssId) {
4615
4621
  case 0:
4616
- return svId >= 1 && svId <= 32 ? `G${two2(svId)}` : null;
4622
+ return svId >= 1 && svId <= 32 ? `G${two3(svId)}` : null;
4617
4623
  case 1:
4618
- return svId >= 120 && svId <= 158 ? `S${two2(svId - 100)}` : null;
4624
+ return svId >= 120 && svId <= 158 ? `S${two3(svId - 100)}` : null;
4619
4625
  case 2:
4620
- return svId >= 1 && svId <= 36 ? `E${two2(svId)}` : null;
4626
+ return svId >= 1 && svId <= 36 ? `E${two3(svId)}` : null;
4621
4627
  case 3:
4622
- return svId >= 1 && svId <= 63 ? `C${two2(svId)}` : null;
4628
+ return svId >= 1 && svId <= 63 ? `C${two3(svId)}` : null;
4623
4629
  case 5:
4624
- return svId >= 1 && svId <= 10 ? `J${two2(svId)}` : null;
4630
+ return svId >= 1 && svId <= 10 ? `J${two3(svId)}` : null;
4625
4631
  case 6:
4626
- return svId >= 1 && svId <= 32 ? `R${two2(svId)}` : null;
4632
+ return svId >= 1 && svId <= 32 ? `R${two3(svId)}` : null;
4627
4633
  default:
4628
4634
  return null;
4629
4635
  }
@@ -4705,10 +4711,7 @@ function parseUbxRawx(data) {
4705
4711
  return { epochs, messageCounts, obsCodes, badChecksums };
4706
4712
  }
4707
4713
 
4708
- // src/sbf/index.ts
4709
- var CLIGHT = 299792458;
4710
- var GPS_EPOCH_MS2 = Date.UTC(1980, 0, 6);
4711
- var MS_PER_WEEK3 = 7 * 864e5;
4714
+ // src/sbf/frame.ts
4712
4715
  var CRC_TABLE = (() => {
4713
4716
  const t = new Uint16Array(256);
4714
4717
  for (let n = 0; n < 256; n++) {
@@ -4725,6 +4728,362 @@ function crc16(data, start, end) {
4725
4728
  crc = (crc << 8 ^ CRC_TABLE[(crc >> 8 ^ data[i]) & 255]) & 65535;
4726
4729
  return crc;
4727
4730
  }
4731
+ function scanSbfFrames(data, view, onBlock) {
4732
+ let badCrc = 0;
4733
+ let i = 0;
4734
+ while (i + 8 <= data.length) {
4735
+ if (data[i] !== 36 || data[i + 1] !== 64) {
4736
+ i++;
4737
+ continue;
4738
+ }
4739
+ const len = view.getUint16(i + 6, true);
4740
+ if (len < 8 || len % 4 !== 0) {
4741
+ i++;
4742
+ continue;
4743
+ }
4744
+ if (i + len > data.length) break;
4745
+ if (crc16(data, i + 4, i + len) !== view.getUint16(i + 2, true)) {
4746
+ badCrc++;
4747
+ i++;
4748
+ continue;
4749
+ }
4750
+ onBlock(view.getUint16(i + 4, true) & 8191, i, len);
4751
+ i += len;
4752
+ }
4753
+ return badCrc;
4754
+ }
4755
+ var two = (n) => String(n).padStart(2, "0");
4756
+ function svidToPrn(svid) {
4757
+ if (svid >= 1 && svid <= 37) return svid <= 32 ? `G${two(svid)}` : null;
4758
+ if (svid <= 61) return svid - 37 <= 27 ? `R${two(svid - 37)}` : null;
4759
+ if (svid <= 62) return null;
4760
+ if (svid <= 68) return svid - 38 <= 27 ? `R${two(svid - 38)}` : null;
4761
+ if (svid <= 70) return null;
4762
+ if (svid <= 106) return svid - 70 <= 36 ? `E${two(svid - 70)}` : null;
4763
+ if (svid <= 119) return null;
4764
+ if (svid <= 140) return `S${two(svid - 100)}`;
4765
+ if (svid <= 180) return svid - 140 <= 50 ? `C${two(svid - 140)}` : null;
4766
+ if (svid <= 190) return `J${two(svid - 180)}`;
4767
+ if (svid <= 197) return svid - 190 <= 14 ? `I${two(svid - 190)}` : null;
4768
+ if (svid <= 215) return `S${two(svid - 157)}`;
4769
+ if (svid <= 222) return svid - 208 <= 14 ? `I${two(svid - 208)}` : null;
4770
+ if (svid <= 245) return svid - 182 <= 50 ? `C${two(svid - 182)}` : null;
4771
+ return null;
4772
+ }
4773
+
4774
+ // src/sbf/nav.ts
4775
+ var PI2 = Math.PI;
4776
+ var GPS_EPOCH_MS2 = Date.UTC(1980, 0, 6);
4777
+ var BDT_EPOCH_MS = Date.UTC(2006, 0, 1);
4778
+ var SEC_PER_WEEK = 7 * 86400;
4779
+ var MS_PER_WEEK3 = SEC_PER_WEEK * 1e3;
4780
+ var F4_DNU = -2e10;
4781
+ var U4_DNU = 4294967295;
4782
+ function adjustWeek(refWeek, wn, mod) {
4783
+ let offset = refWeek % mod - wn;
4784
+ if (offset > mod / 2) offset -= mod;
4785
+ if (offset < -(mod / 2 - 1)) offset += mod;
4786
+ return refWeek - offset;
4787
+ }
4788
+ var gpsMs = (week, sec) => GPS_EPOCH_MS2 + week * MS_PER_WEEK3 + sec * 1e3;
4789
+ var sowOf = (dateMs) => dateMs / 1e3 % SEC_PER_WEEK;
4790
+ function decodeGpsQzsNav(view, b, sys) {
4791
+ const svid = view.getUint8(b + 14);
4792
+ const prn = sys === "G" ? svid : svid - 180;
4793
+ const max = sys === "G" ? 32 : 10;
4794
+ if (prn < 1 || prn > max) return null;
4795
+ const wnc = view.getUint16(b + 12, true);
4796
+ const tgdRaw = view.getFloat32(b + 28, true);
4797
+ const tocs = view.getUint32(b + 32, true);
4798
+ const toes = view.getUint32(b + 88, true);
4799
+ const wnToc = adjustWeek(wnc, view.getUint16(b + 136, true), 1024);
4800
+ const tocDate = new Date(gpsMs(wnToc, tocs));
4801
+ return {
4802
+ system: sys,
4803
+ prn: `${sys}${String(prn).padStart(2, "0")}`,
4804
+ toc: sowOf(tocDate.getTime()),
4805
+ tocDate,
4806
+ af0: view.getFloat32(b + 44, true),
4807
+ af1: view.getFloat32(b + 40, true),
4808
+ af2: view.getFloat32(b + 36, true),
4809
+ iode: view.getUint8(b + 24),
4810
+ crs: view.getFloat32(b + 48, true),
4811
+ deltaN: view.getFloat32(b + 52, true) * PI2,
4812
+ m0: view.getFloat64(b + 56, true) * PI2,
4813
+ cuc: view.getFloat32(b + 64, true),
4814
+ e: view.getFloat64(b + 68, true),
4815
+ cus: view.getFloat32(b + 76, true),
4816
+ sqrtA: view.getFloat64(b + 80, true),
4817
+ toe: toes,
4818
+ cic: view.getFloat32(b + 92, true),
4819
+ omega0: view.getFloat64(b + 96, true) * PI2,
4820
+ cis: view.getFloat32(b + 104, true),
4821
+ i0: view.getFloat64(b + 108, true) * PI2,
4822
+ crc: view.getFloat32(b + 116, true),
4823
+ omega: view.getFloat64(b + 120, true) * PI2,
4824
+ omegaDot: view.getFloat32(b + 128, true) * PI2,
4825
+ idot: view.getFloat32(b + 132, true) * PI2,
4826
+ // RINEX "GPS week to go with toe": RTKLIB writes WNc for GPS and
4827
+ // the week of toc for QZSS — mirrored here so records compare
4828
+ // 1:1 against convbin output. wnToe is still used for `toe` above.
4829
+ week: sys === "G" ? wnc : wnToc,
4830
+ svHealth: view.getUint8(b + 20),
4831
+ tgd: tgdRaw !== F4_DNU ? tgdRaw : 0
4832
+ };
4833
+ }
4834
+ function decodeGalNav(view, b) {
4835
+ const prn = view.getUint8(b + 14) - 70;
4836
+ if (prn < 1 || prn > 36) return null;
4837
+ const source = view.getUint8(b + 15);
4838
+ if (source !== 2 && source !== 16) return null;
4839
+ const wnc = view.getUint16(b + 12, true);
4840
+ const toes = view.getUint32(b + 100, true);
4841
+ const tocs = view.getUint32(b + 104, true);
4842
+ const wnToc = adjustWeek(wnc, view.getUint16(b + 126, true), 4096);
4843
+ const tocDate = new Date(gpsMs(wnToc, tocs));
4844
+ const health = view.getUint16(b + 130, true);
4845
+ let svh = 0;
4846
+ if (health & 1) svh |= health >> 1 & 7;
4847
+ if (health & 16) svh |= (health >> 5 & 7) << 6;
4848
+ if (health & 256) svh |= (health >> 9 & 7) << 3;
4849
+ const bgdE5a = view.getFloat32(b + 136, true);
4850
+ return {
4851
+ system: "E",
4852
+ prn: `E${String(prn).padStart(2, "0")}`,
4853
+ toc: sowOf(tocDate.getTime()),
4854
+ tocDate,
4855
+ af0: view.getFloat64(b + 116, true),
4856
+ af1: view.getFloat32(b + 112, true),
4857
+ af2: view.getFloat32(b + 108, true),
4858
+ iode: view.getUint16(b + 128, true),
4859
+ // IODnav
4860
+ crs: view.getFloat32(b + 88, true),
4861
+ deltaN: view.getFloat32(b + 72, true) * PI2,
4862
+ m0: view.getFloat64(b + 24, true) * PI2,
4863
+ cuc: view.getFloat32(b + 76, true),
4864
+ e: view.getFloat64(b + 32, true),
4865
+ cus: view.getFloat32(b + 80, true),
4866
+ sqrtA: view.getFloat64(b + 16, true),
4867
+ toe: toes,
4868
+ cic: view.getFloat32(b + 92, true),
4869
+ omega0: view.getFloat64(b + 56, true) * PI2,
4870
+ cis: view.getFloat32(b + 96, true),
4871
+ i0: view.getFloat64(b + 40, true) * PI2,
4872
+ crc: view.getFloat32(b + 84, true),
4873
+ omega: view.getFloat64(b + 48, true) * PI2,
4874
+ omegaDot: view.getFloat32(b + 64, true) * PI2,
4875
+ idot: view.getFloat32(b + 68, true) * PI2,
4876
+ week: wnc,
4877
+ // RINEX GAL week is GPS-aligned and continuous
4878
+ svHealth: svh,
4879
+ tgd: bgdE5a !== F4_DNU ? bgdE5a : 0
4880
+ // BGD E5a/E1 (RINEX slot)
4881
+ };
4882
+ }
4883
+ function decodeBdsNav(view, b) {
4884
+ const prn = svidToPrn(view.getUint8(b + 14));
4885
+ if (!prn || prn[0] !== "C") return null;
4886
+ const bdsWeekRef = view.getUint16(b + 12, true) - 1356;
4887
+ const tgd1 = view.getFloat32(b + 24, true);
4888
+ const tocs = view.getUint32(b + 32, true);
4889
+ const toes = view.getUint32(b + 88, true);
4890
+ const wnToc = adjustWeek(bdsWeekRef, view.getUint16(b + 136, true), 8192);
4891
+ const wnToe = adjustWeek(bdsWeekRef, view.getUint16(b + 138, true), 8192);
4892
+ const tocDate = new Date(BDT_EPOCH_MS + wnToc * MS_PER_WEEK3 + tocs * 1e3);
4893
+ return {
4894
+ system: "C",
4895
+ prn,
4896
+ toc: sowOf(tocDate.getTime()),
4897
+ tocDate,
4898
+ af0: view.getFloat32(b + 44, true),
4899
+ af1: view.getFloat32(b + 40, true),
4900
+ af2: view.getFloat32(b + 36, true),
4901
+ iode: view.getUint8(b + 21),
4902
+ // AODE
4903
+ crs: view.getFloat32(b + 48, true),
4904
+ deltaN: view.getFloat32(b + 52, true) * PI2,
4905
+ m0: view.getFloat64(b + 56, true) * PI2,
4906
+ cuc: view.getFloat32(b + 64, true),
4907
+ e: view.getFloat64(b + 68, true),
4908
+ cus: view.getFloat32(b + 76, true),
4909
+ sqrtA: view.getFloat64(b + 80, true),
4910
+ toe: toes,
4911
+ cic: view.getFloat32(b + 92, true),
4912
+ omega0: view.getFloat64(b + 96, true) * PI2,
4913
+ cis: view.getFloat32(b + 104, true),
4914
+ i0: view.getFloat64(b + 108, true) * PI2,
4915
+ crc: view.getFloat32(b + 116, true),
4916
+ omega: view.getFloat64(b + 120, true) * PI2,
4917
+ omegaDot: view.getFloat32(b + 128, true) * PI2,
4918
+ idot: view.getFloat32(b + 132, true) * PI2,
4919
+ week: wnToe,
4920
+ // RINEX BDS week field is the BDT week
4921
+ svHealth: view.getUint8(b + 19),
4922
+ // SatH1
4923
+ tgd: tgd1 !== F4_DNU ? tgd1 : 0
4924
+ // TGD1 B1/B3 (RINEX slot)
4925
+ };
4926
+ }
4927
+ function decodeGloNav(view, b) {
4928
+ const prn = svidToPrn(view.getUint8(b + 14));
4929
+ if (!prn || prn[0] !== "R") return null;
4930
+ const wnc = view.getUint16(b + 12, true);
4931
+ const toes = view.getUint32(b + 76, true);
4932
+ const wnToe = adjustWeek(wnc, view.getUint16(b + 80, true), 1024);
4933
+ const toeGpsMs = gpsMs(wnToe, toes);
4934
+ const leapMs = getGpsLeap(new Date(toeGpsMs)) * 1e3;
4935
+ const tocDate = new Date(toeGpsMs - leapMs);
4936
+ const tofGpsMs = gpsMs(wnc, 0) + view.getUint32(b + 8, true);
4937
+ const tofLeapMs = getGpsLeap(new Date(tofGpsMs)) * 1e3;
4938
+ const messageFrameTime = (tofGpsMs - tofLeapMs - GPS_EPOCH_MS2) / 1e3 % SEC_PER_WEEK;
4939
+ return {
4940
+ system: "R",
4941
+ prn,
4942
+ tocDate,
4943
+ // RINEX stores −τn as the clock bias; SBF carries τn (ICD sign)
4944
+ tauN: -view.getFloat32(b + 68, true),
4945
+ gammaN: view.getFloat32(b + 64, true),
4946
+ messageFrameTime,
4947
+ x: view.getFloat64(b + 16, true),
4948
+ // SBF unit is km, like RINEX
4949
+ xDot: view.getFloat32(b + 40, true),
4950
+ xAcc: view.getFloat32(b + 52, true),
4951
+ y: view.getFloat64(b + 24, true),
4952
+ yDot: view.getFloat32(b + 44, true),
4953
+ yAcc: view.getFloat32(b + 56, true),
4954
+ z: view.getFloat64(b + 32, true),
4955
+ zDot: view.getFloat32(b + 48, true),
4956
+ zAcc: view.getFloat32(b + 60, true),
4957
+ // MSB of the 3-bit Bn word — the unhealthy flag RINEX carries
4958
+ health: view.getUint8(b + 85) >> 2,
4959
+ freqNum: view.getUint8(b + 15) - 8
4960
+ };
4961
+ }
4962
+ function parseSbfNav(data) {
4963
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
4964
+ const ephemerides = [];
4965
+ const badCrc = scanSbfFrames(data, view, (id, b, len) => {
4966
+ let eph = null;
4967
+ if (id === 5891 && len >= 140) eph = decodeGpsQzsNav(view, b, "G");
4968
+ else if (id === 4095 && len >= 140) eph = decodeGpsQzsNav(view, b, "J");
4969
+ else if (id === 4002 && len >= 149) eph = decodeGalNav(view, b);
4970
+ else if (id === 4081 && len >= 140) eph = decodeBdsNav(view, b);
4971
+ else if (id === 4004 && len >= 96) eph = decodeGloNav(view, b);
4972
+ if (eph) ephemerides.push(eph);
4973
+ });
4974
+ return { ephemerides, badCrc };
4975
+ }
4976
+ var GAL_SQRT_A_NOMINAL = Math.sqrt(296e5);
4977
+ var GAL_I_NOMINAL = 56 / 180 * PI2;
4978
+ var I_REF_03 = 0.3 * PI2;
4979
+ function decodeGpsGalAlm(view, b, sys) {
4980
+ const wnc = view.getUint16(b + 12, true);
4981
+ const toa = view.getUint32(b + 20, true);
4982
+ if (toa === U4_DNU) return null;
4983
+ let prn;
4984
+ let weekAlm;
4985
+ let i0;
4986
+ let sqrtA = view.getFloat32(b + 32, true);
4987
+ let health;
4988
+ if (sys === "G") {
4989
+ prn = view.getUint8(b + 14);
4990
+ if (prn < 1 || prn > 32) return null;
4991
+ weekAlm = adjustWeek(wnc, view.getUint8(b + 56), 256);
4992
+ i0 = I_REF_03 + view.getFloat32(b + 24, true) * PI2;
4993
+ health = view.getUint8(b + 58);
4994
+ } else {
4995
+ prn = view.getUint8(b + 57) - 70;
4996
+ if (prn < 1 || prn > 36) return null;
4997
+ weekAlm = adjustWeek(wnc, view.getUint8(b + 56), 4);
4998
+ i0 = GAL_I_NOMINAL + view.getFloat32(b + 24, true) * PI2;
4999
+ sqrtA += GAL_SQRT_A_NOMINAL;
5000
+ health = view.getUint16(b + 58, true);
5001
+ }
5002
+ return {
5003
+ system: sys,
5004
+ prn: `${sys}${String(prn).padStart(2, "0")}`,
5005
+ weekAlm,
5006
+ toaSec: toa,
5007
+ sqrtA,
5008
+ e: view.getFloat32(b + 16, true),
5009
+ i0OrDeltaI: i0,
5010
+ omega0: view.getFloat32(b + 36, true) * PI2,
5011
+ omega: view.getFloat32(b + 40, true) * PI2,
5012
+ m0: view.getFloat32(b + 44, true) * PI2,
5013
+ omegaDot: view.getFloat32(b + 28, true) * PI2,
5014
+ af0: view.getFloat32(b + 52, true),
5015
+ af1: view.getFloat32(b + 48, true),
5016
+ health
5017
+ };
5018
+ }
5019
+ function decodeBdsAlm(view, b) {
5020
+ const prnStr = svidToPrn(view.getUint8(b + 14));
5021
+ if (!prnStr || prnStr[0] !== "C") return null;
5022
+ const prn = parseInt(prnStr.slice(1), 10);
5023
+ const toa = view.getUint32(b + 16, true);
5024
+ if (toa === U4_DNU) return null;
5025
+ const bdsWeekRef = view.getUint16(b + 12, true) - 1356;
5026
+ const geo = prn <= 5 || prn >= 59;
5027
+ return {
5028
+ system: "C",
5029
+ prn: prnStr,
5030
+ weekAlm: adjustWeek(bdsWeekRef, view.getUint8(b + 15), 256),
5031
+ toaSec: toa,
5032
+ sqrtA: view.getFloat32(b + 20, true),
5033
+ e: view.getFloat32(b + 24, true),
5034
+ i0OrDeltaI: (geo ? 0 : I_REF_03) + view.getFloat32(b + 44, true) * PI2,
5035
+ omega0: view.getFloat32(b + 36, true) * PI2,
5036
+ omega: view.getFloat32(b + 28, true) * PI2,
5037
+ m0: view.getFloat32(b + 32, true) * PI2,
5038
+ omegaDot: view.getFloat32(b + 40, true) * PI2,
5039
+ af0: view.getFloat32(b + 48, true),
5040
+ af1: view.getFloat32(b + 52, true),
5041
+ health: view.getUint16(b + 56, true)
5042
+ };
5043
+ }
5044
+ function decodeGloAlm(view, b) {
5045
+ const prn = svidToPrn(view.getUint8(b + 14));
5046
+ if (!prn || prn[0] !== "R") return null;
5047
+ const wnc = view.getUint16(b + 12, true);
5048
+ const toa = view.getUint32(b + 20, true);
5049
+ if (toa === U4_DNU) return null;
5050
+ return {
5051
+ system: "R",
5052
+ prn,
5053
+ freqNr: view.getUint8(b + 15) - 8,
5054
+ weekAlm: adjustWeek(wnc, view.getUint8(b + 52), 256),
5055
+ toaSec: toa,
5056
+ epsilon: view.getFloat32(b + 16, true),
5057
+ deltaI: view.getFloat32(b + 24, true) * PI2,
5058
+ lambda: view.getFloat32(b + 28, true) * PI2,
5059
+ tLambda: view.getFloat32(b + 32, true),
5060
+ omega: view.getFloat32(b + 36, true) * PI2,
5061
+ deltaT: view.getFloat32(b + 40, true),
5062
+ deltaTDot: view.getFloat32(b + 44, true),
5063
+ tau: view.getFloat32(b + 48, true),
5064
+ health: view.getUint8(b + 53),
5065
+ nDay: view.getUint16(b + 54, true),
5066
+ n4: view.getUint8(b + 57)
5067
+ };
5068
+ }
5069
+ function parseSbfAlmanac(data) {
5070
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
5071
+ const almanacs = [];
5072
+ const badCrc = scanSbfFrames(data, view, (id, b, len) => {
5073
+ let alm = null;
5074
+ if (id === 5892 && len >= 60) alm = decodeGpsGalAlm(view, b, "G");
5075
+ else if (id === 4003 && len >= 61) alm = decodeGpsGalAlm(view, b, "E");
5076
+ else if (id === 4119 && len >= 60) alm = decodeBdsAlm(view, b);
5077
+ else if (id === 4005 && len >= 60) alm = decodeGloAlm(view, b);
5078
+ if (alm) almanacs.push(alm);
5079
+ });
5080
+ return { almanacs, badCrc };
5081
+ }
5082
+
5083
+ // src/sbf/index.ts
5084
+ var CLIGHT = 299792458;
5085
+ var GPS_EPOCH_MS3 = Date.UTC(1980, 0, 6);
5086
+ var MS_PER_WEEK4 = 7 * 864e5;
4728
5087
  var M3_SYS = ["G", "R", "E", "C", "S", "J", "I"];
4729
5088
  var M3_PR_BASE = [19e6, 19e6, 22e6, 2e7, 34e6, 34e6, 34e6];
4730
5089
  var M3_INTERVALS = [
@@ -4823,44 +5182,27 @@ var MEAS2_SIG = [
4823
5182
  ["J", "1E"],
4824
5183
  ["J", "5P"]
4825
5184
  ];
4826
- var two = (n) => String(n).padStart(2, "0");
5185
+ var two2 = (n) => String(n).padStart(2, "0");
4827
5186
  function m3Prn(navsys, svid) {
4828
5187
  switch (navsys) {
4829
5188
  case 0:
4830
- return svid < 32 ? `G${two(svid + 1)}` : null;
5189
+ return svid < 32 ? `G${two2(svid + 1)}` : null;
4831
5190
  case 1:
4832
- return svid < 27 ? `R${two(svid + 1)}` : null;
5191
+ return svid < 27 ? `R${two2(svid + 1)}` : null;
4833
5192
  case 2:
4834
- return svid < 36 ? `E${two(svid + 1)}` : null;
5193
+ return svid < 36 ? `E${two2(svid + 1)}` : null;
4835
5194
  case 3:
4836
- return svid < 50 ? `C${two(svid + 1)}` : null;
5195
+ return svid < 50 ? `C${two2(svid + 1)}` : null;
4837
5196
  case 4:
4838
- return svid <= 38 ? `S${two(svid + 20)}` : null;
5197
+ return svid <= 38 ? `S${two2(svid + 20)}` : null;
4839
5198
  case 5:
4840
- return svid < 10 ? `J${two(svid + 1)}` : null;
5199
+ return svid < 10 ? `J${two2(svid + 1)}` : null;
4841
5200
  case 6:
4842
- return svid < 14 ? `I${two(svid + 1)}` : null;
5201
+ return svid < 14 ? `I${two2(svid + 1)}` : null;
4843
5202
  default:
4844
5203
  return null;
4845
5204
  }
4846
5205
  }
4847
- function svidToPrn(svid) {
4848
- if (svid >= 1 && svid <= 37) return svid <= 32 ? `G${two(svid)}` : null;
4849
- if (svid <= 61) return svid - 37 <= 27 ? `R${two(svid - 37)}` : null;
4850
- if (svid <= 62) return null;
4851
- if (svid <= 68) return svid - 38 <= 27 ? `R${two(svid - 38)}` : null;
4852
- if (svid <= 70) return null;
4853
- if (svid <= 106) return svid - 70 <= 36 ? `E${two(svid - 70)}` : null;
4854
- if (svid <= 119) return null;
4855
- if (svid <= 140) return `S${two(svid - 100)}`;
4856
- if (svid <= 180) return svid - 140 <= 50 ? `C${two(svid - 140)}` : null;
4857
- if (svid <= 190) return `J${two(svid - 180)}`;
4858
- if (svid <= 197) return svid - 190 <= 14 ? `I${two(svid - 190)}` : null;
4859
- if (svid <= 215) return `S${two(svid - 157)}`;
4860
- if (svid <= 222) return svid - 208 <= 14 ? `I${two(svid - 208)}` : null;
4861
- if (svid <= 245) return svid - 182 <= 50 ? `C${two(svid - 182)}` : null;
4862
- return null;
4863
- }
4864
5206
  function carrierFreq(sys, code, fcn) {
4865
5207
  const band = code.charCodeAt(0) - 48;
4866
5208
  switch (sys) {
@@ -4923,7 +5265,6 @@ function parseSbfMeas(data) {
4923
5265
  const epochs = [];
4924
5266
  const messageCounts = {};
4925
5267
  const obsCodes = {};
4926
- let badCrc = 0;
4927
5268
  let ref = freshRefEpoch(-1);
4928
5269
  let curTime = NaN;
4929
5270
  let curMeas = [];
@@ -4954,8 +5295,8 @@ function parseSbfMeas(data) {
4954
5295
  curTime = timeMs;
4955
5296
  }
4956
5297
  };
4957
- const decodeMeas3Ranges = (i2, tow) => {
4958
- const o = i2 + 8;
5298
+ const decodeMeas3Ranges = (i, tow) => {
5299
+ const o = i + 8;
4959
5300
  const constellations = view.getUint16(o + 8, true) & 127;
4960
5301
  const misc = data[o + 10];
4961
5302
  const version = data[o + 11];
@@ -5233,8 +5574,8 @@ function parseSbfMeas(data) {
5233
5574
  }
5234
5575
  }
5235
5576
  };
5236
- const decodeMeas3CN0 = (i2, len) => {
5237
- const flags = view.getUint16(i2 + 14, true);
5577
+ const decodeMeas3CN0 = (i, len) => {
5578
+ const flags = view.getUint16(i + 14, true);
5238
5579
  if ((flags & 7) !== 0) return;
5239
5580
  const maxNibbles = (len - 16) * 2;
5240
5581
  let off = 0;
@@ -5244,7 +5585,7 @@ function parseSbfMeas(data) {
5244
5585
  for (let k = 0; k < e.slots.length; k++) {
5245
5586
  const slot = e.slots[k];
5246
5587
  if (k > 0 && !slot) break;
5247
- const nib = (data[i2 + 16 + (off >> 1)] ?? 0) >> (off & 1) * 4 & 15;
5588
+ const nib = (data[i + 16 + (off >> 1)] ?? 0) >> (off & 1) * 4 & 15;
5248
5589
  if (slot && slot.cn0 !== null) slot.cn0 += nib * 0.0625 - 0.5;
5249
5590
  off++;
5250
5591
  }
@@ -5271,14 +5612,14 @@ function parseSbfMeas(data) {
5271
5612
  if ((v & 1) === 1) value = -value;
5272
5613
  return { value, size };
5273
5614
  };
5274
- const decodeMeas3Doppler = (i2, len) => {
5275
- const flags = view.getUint16(i2 + 14, true);
5615
+ const decodeMeas3Doppler = (i, len) => {
5616
+ const flags = view.getUint16(i + 14, true);
5276
5617
  if ((flags & 7) !== 0) return;
5277
5618
  let off = 0;
5278
5619
  for (const e of curSats) {
5279
5620
  if (off + 16 >= len) break;
5280
5621
  if (!e.prn) continue;
5281
- const master = readPrRate(i2 + 16, off);
5622
+ const master = readPrRate(i + 16, off);
5282
5623
  off += master.size;
5283
5624
  if (master.value === -268435455) continue;
5284
5625
  const refPrRate = ref.sats[e.navsys][e.svid]?.prRate ?? 0;
@@ -5288,20 +5629,20 @@ function parseSbfMeas(data) {
5288
5629
  for (let k = 1; k < e.slots.length; k++) {
5289
5630
  const slot = e.slots[k];
5290
5631
  if (!slot) break;
5291
- const slave = readPrRate(i2 + 16, off);
5632
+ const slave = readPrRate(i + 16, off);
5292
5633
  off += slave.size;
5293
5634
  if (m)
5294
5635
  slot.doppler = (mD * (CLIGHT / m.freq) * 1e3 - slave.value) * 1e-3 / (CLIGHT / slot.freq);
5295
5636
  }
5296
5637
  }
5297
5638
  };
5298
- const decodeMeasEpoch = (i2, len) => {
5299
- const n1 = data[i2 + 14];
5300
- const len1 = data[i2 + 15];
5301
- const len2 = data[i2 + 16];
5302
- if ((data[i2 + 17] & 128) !== 0) return;
5303
- const end = i2 + len;
5304
- let p = i2 + 20;
5639
+ const decodeMeasEpoch = (i, len) => {
5640
+ const n1 = data[i + 14];
5641
+ const len1 = data[i + 15];
5642
+ const len2 = data[i + 16];
5643
+ if ((data[i + 17] & 128) !== 0) return;
5644
+ const end = i + len;
5645
+ let p = i + 20;
5305
5646
  for (let b1 = 0; b1 < n1 && p + 20 <= end; b1++) {
5306
5647
  const ant = data[p + 1] >> 5;
5307
5648
  let sig = data[p + 1] & 31;
@@ -5388,50 +5729,288 @@ function parseSbfMeas(data) {
5388
5729
  }
5389
5730
  }
5390
5731
  };
5391
- let i = 0;
5392
- while (i + 8 <= data.length) {
5393
- if (data[i] !== 36 || data[i + 1] !== 64) {
5394
- i++;
5395
- continue;
5396
- }
5397
- const len = view.getUint16(i + 6, true);
5398
- if (len < 8 || len % 4 !== 0) {
5399
- i++;
5400
- continue;
5401
- }
5402
- if (i + len > data.length) break;
5403
- if (crc16(data, i + 4, i + len) !== view.getUint16(i + 2, true)) {
5404
- badCrc++;
5405
- i++;
5406
- continue;
5407
- }
5408
- const id = view.getUint16(i + 4, true) & 8191;
5732
+ const badCrc = scanSbfFrames(data, view, (id, i, len) => {
5409
5733
  const key = String(id);
5410
5734
  messageCounts[key] = (messageCounts[key] ?? 0) + 1;
5411
5735
  if ((id === 4027 || id === 4109 || id === 4110 || id === 4111) && len >= 16) {
5412
5736
  const tow = view.getUint32(i + 8, true);
5413
5737
  const wnc = view.getUint16(i + 12, true);
5414
5738
  if (tow !== 4294967295 && wnc !== 65535) {
5415
- ensureEpoch(GPS_EPOCH_MS2 + wnc * MS_PER_WEEK3 + tow);
5739
+ ensureEpoch(GPS_EPOCH_MS3 + wnc * MS_PER_WEEK4 + tow);
5416
5740
  if (id === 4109) decodeMeas3Ranges(i, tow);
5417
5741
  else if (id === 4110) decodeMeas3CN0(i, len);
5418
5742
  else if (id === 4111) decodeMeas3Doppler(i, len);
5419
5743
  else decodeMeasEpoch(i, len);
5420
5744
  }
5421
5745
  }
5422
- i += len;
5423
- }
5746
+ });
5424
5747
  flush();
5425
5748
  return { epochs, messageCounts, obsCodes, badCrc };
5426
5749
  }
5427
5750
 
5751
+ // src/novatel/frame.ts
5752
+ var OEM4_HLEN = 28;
5753
+ function crc32(data, start, len) {
5754
+ let crc = 0;
5755
+ for (let i = start; i < start + len; i++) {
5756
+ crc ^= data[i];
5757
+ for (let j = 0; j < 8; j++) {
5758
+ crc = crc & 1 ? crc >>> 1 ^ 3988292384 : crc >>> 1;
5759
+ }
5760
+ }
5761
+ return crc >>> 0;
5762
+ }
5763
+ function* oem4Frames(data, view, stats) {
5764
+ let i = 0;
5765
+ while (i + OEM4_HLEN + 4 <= data.length) {
5766
+ if (data[i] !== 170 || data[i + 1] !== 68 || data[i + 2] !== 18) {
5767
+ i++;
5768
+ continue;
5769
+ }
5770
+ const hlen = data[i + 3];
5771
+ const msgLen = view.getUint16(i + 8, true);
5772
+ const total = hlen + msgLen + 4;
5773
+ if (hlen < OEM4_HLEN || i + total > data.length) {
5774
+ i++;
5775
+ continue;
5776
+ }
5777
+ if (crc32(data, i, hlen + msgLen) !== view.getUint32(i + hlen + msgLen, true)) {
5778
+ stats.badCrc++;
5779
+ i++;
5780
+ continue;
5781
+ }
5782
+ yield {
5783
+ id: view.getUint16(i + 4, true),
5784
+ start: i,
5785
+ payload: i + hlen,
5786
+ msgLen,
5787
+ binary: (data[i + 6] >> 4 & 3) === 0,
5788
+ week: view.getUint16(i + 14, true),
5789
+ towMs: view.getUint32(i + 16, true)
5790
+ };
5791
+ i += total;
5792
+ }
5793
+ }
5794
+
5795
+ // src/navbits/index.ts
5796
+ var GPS_PI = 3.1415926535898;
5797
+ var GPS_EPOCH_MS4 = Date.UTC(1980, 0, 6);
5798
+ var SEC_PER_WEEK2 = 7 * 86400;
5799
+ function getBitU(buff, pos, len) {
5800
+ let bits = 0;
5801
+ for (let i = pos; i < pos + len; i++) {
5802
+ bits = bits * 2 + (buff[i >> 3] >> 7 - (i & 7) & 1);
5803
+ }
5804
+ return bits;
5805
+ }
5806
+ function getBitS(buff, pos, len) {
5807
+ const bits = getBitU(buff, pos, len);
5808
+ if (len <= 0 || bits < 2 ** (len - 1)) return bits;
5809
+ return bits - 2 ** len;
5810
+ }
5811
+ function decodeGpsLnavFrame(subframes, opts = {}) {
5812
+ if (subframes.length < 90) return null;
5813
+ const b = subframes;
5814
+ let i = 24;
5815
+ const tow1 = getBitU(b, i, 17) * 6;
5816
+ i += 17 + 2;
5817
+ const id1 = getBitU(b, i, 3);
5818
+ i += 3 + 2;
5819
+ const week10 = getBitU(b, i, 10);
5820
+ i += 10;
5821
+ i += 2;
5822
+ i += 4;
5823
+ const svHealth = getBitU(b, i, 6);
5824
+ i += 6;
5825
+ const iodc0 = getBitU(b, i, 2);
5826
+ i += 2;
5827
+ i += 1 + 87;
5828
+ const tgdRaw = getBitS(b, i, 8);
5829
+ i += 8;
5830
+ const iodc1 = getBitU(b, i, 8);
5831
+ i += 8;
5832
+ const tocSec = getBitU(b, i, 16) * 16;
5833
+ i += 16;
5834
+ const af2 = getBitS(b, i, 8) * 2 ** -55;
5835
+ i += 8;
5836
+ const af1 = getBitS(b, i, 16) * 2 ** -43;
5837
+ i += 16;
5838
+ const af0 = getBitS(b, i, 22) * 2 ** -31;
5839
+ i = 240 + 24;
5840
+ i += 17 + 2;
5841
+ const id2 = getBitU(b, i, 3);
5842
+ i += 3 + 2;
5843
+ const iode = getBitU(b, i, 8);
5844
+ i += 8;
5845
+ const crs = getBitS(b, i, 16) * 2 ** -5;
5846
+ i += 16;
5847
+ const deltaN = getBitS(b, i, 16) * 2 ** -43 * GPS_PI;
5848
+ i += 16;
5849
+ const m0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
5850
+ i += 32;
5851
+ const cuc = getBitS(b, i, 16) * 2 ** -29;
5852
+ i += 16;
5853
+ const e = getBitU(b, i, 32) * 2 ** -33;
5854
+ i += 32;
5855
+ const cus = getBitS(b, i, 16) * 2 ** -29;
5856
+ i += 16;
5857
+ const sqrtA = getBitU(b, i, 32) * 2 ** -19;
5858
+ i += 32;
5859
+ const toes = getBitU(b, i, 16) * 16;
5860
+ i = 480 + 24;
5861
+ i += 17 + 2;
5862
+ const id3 = getBitU(b, i, 3);
5863
+ i += 3 + 2;
5864
+ const cic = getBitS(b, i, 16) * 2 ** -29;
5865
+ i += 16;
5866
+ const omega0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
5867
+ i += 32;
5868
+ const cis = getBitS(b, i, 16) * 2 ** -29;
5869
+ i += 16;
5870
+ const i0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
5871
+ i += 32;
5872
+ const crc = getBitS(b, i, 16) * 2 ** -5;
5873
+ i += 16;
5874
+ const omega = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
5875
+ i += 32;
5876
+ const omegaDot = getBitS(b, i, 24) * 2 ** -43 * GPS_PI;
5877
+ i += 24;
5878
+ const iode3 = getBitU(b, i, 8);
5879
+ i += 8;
5880
+ const idot = getBitS(b, i, 14) * 2 ** -43 * GPS_PI;
5881
+ const iodc = iodc0 * 256 + iodc1;
5882
+ if (id1 !== 1 || id2 !== 2 || id3 !== 3) return null;
5883
+ if (iode3 !== iode || iode !== (iodc & 255)) return null;
5884
+ const ref = opts.refWeek ?? Math.floor((Date.now() - GPS_EPOCH_MS4) / 1e3 / SEC_PER_WEEK2);
5885
+ let week = week10 + 1024 * Math.round((ref - week10) / 1024);
5886
+ if (toes < tow1 - 302400) week++;
5887
+ else if (toes > tow1 + 302400) week--;
5888
+ const prn = opts.prn ?? "G00";
5889
+ const tocDate = new Date(
5890
+ GPS_EPOCH_MS4 + (week * SEC_PER_WEEK2 + tocSec) * 1e3
5891
+ );
5892
+ return {
5893
+ system: prn[0] === "J" ? "J" : "G",
5894
+ prn,
5895
+ tocDate,
5896
+ // Same seconds-of-week convention as parseNavFile (rinex/nav.ts).
5897
+ toc: tocDate.getTime() / 1e3 % SEC_PER_WEEK2,
5898
+ af0,
5899
+ af1,
5900
+ af2,
5901
+ iode,
5902
+ crs,
5903
+ deltaN,
5904
+ m0,
5905
+ cuc,
5906
+ e,
5907
+ cus,
5908
+ sqrtA,
5909
+ toe: toes,
5910
+ cic,
5911
+ omega0,
5912
+ cis,
5913
+ i0,
5914
+ crc,
5915
+ omega,
5916
+ omegaDot,
5917
+ idot,
5918
+ week,
5919
+ svHealth,
5920
+ tgd: tgdRaw === -128 ? 0 : tgdRaw * 2 ** -31
5921
+ // IS-GPS-200: -128 reserved
5922
+ };
5923
+ }
5924
+
5925
+ // src/novatel/nav.ts
5926
+ var ID_RAWEPHEM = 41;
5927
+ var ID_GLOEPHEMERIS = 723;
5928
+ var GPS_EPOCH_MS5 = Date.UTC(1980, 0, 6);
5929
+ var SEC_PER_WEEK3 = 7 * 86400;
5930
+ var SEC_PER_DAY = 86400;
5931
+ function decodeRawEphem(data, view, p) {
5932
+ const prn = view.getUint32(p, true);
5933
+ if (prn < 1 || prn > 32) return null;
5934
+ const refWeek = view.getUint32(p + 4, true);
5935
+ return decodeGpsLnavFrame(data.subarray(p + 12, p + 102), {
5936
+ prn: `G${String(prn).padStart(2, "0")}`,
5937
+ refWeek
5938
+ });
5939
+ }
5940
+ function decodeGloEphemeris(view, p) {
5941
+ const slot = view.getUint16(p, true) - 37;
5942
+ if (slot < 1 || slot > 27) return null;
5943
+ const freqNum = view.getUint16(p + 2, true) - 7;
5944
+ const week = view.getUint16(p + 6, true);
5945
+ const tow = Math.floor(view.getUint32(p + 8, true) / 1e3 + 0.5);
5946
+ const toff = view.getUint32(p + 12, true);
5947
+ const health = view.getUint32(p + 24, true) < 4 ? 0 : 1;
5948
+ let tof = view.getUint32(p + 124, true) - toff;
5949
+ tof += Math.floor(tow / SEC_PER_DAY) * SEC_PER_DAY;
5950
+ if (tof < tow - 43200) tof += SEC_PER_DAY;
5951
+ else if (tof > tow + 43200) tof -= SEC_PER_DAY;
5952
+ const toeGpsMs = GPS_EPOCH_MS5 + (week * SEC_PER_WEEK3 + tow) * 1e3;
5953
+ const tofGpsMs = GPS_EPOCH_MS5 + (week * SEC_PER_WEEK3 + tof) * 1e3;
5954
+ const tofUtcSec = (getUtcDate(new Date(tofGpsMs)).getTime() - GPS_EPOCH_MS5) / 1e3;
5955
+ return {
5956
+ system: "R",
5957
+ prn: `R${String(slot).padStart(2, "0")}`,
5958
+ tocDate: getUtcDate(new Date(toeGpsMs)),
5959
+ tauN: -view.getFloat64(p + 100, true),
5960
+ // RINEX stores −τ_n
5961
+ gammaN: view.getFloat64(p + 116, true),
5962
+ messageFrameTime: (tofUtcSec % SEC_PER_WEEK3 + SEC_PER_WEEK3) % SEC_PER_WEEK3,
5963
+ x: view.getFloat64(p + 28, true) / 1e3,
5964
+ y: view.getFloat64(p + 36, true) / 1e3,
5965
+ z: view.getFloat64(p + 44, true) / 1e3,
5966
+ xDot: view.getFloat64(p + 52, true) / 1e3,
5967
+ yDot: view.getFloat64(p + 60, true) / 1e3,
5968
+ zDot: view.getFloat64(p + 68, true) / 1e3,
5969
+ xAcc: view.getFloat64(p + 76, true) / 1e3,
5970
+ yAcc: view.getFloat64(p + 84, true) / 1e3,
5971
+ zAcc: view.getFloat64(p + 92, true) / 1e3,
5972
+ health,
5973
+ freqNum
5974
+ };
5975
+ }
5976
+ function parseNovatelNav(data) {
5977
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
5978
+ const stats = { badCrc: 0 };
5979
+ const ephemerides = [];
5980
+ const lastGps = /* @__PURE__ */ new Map();
5981
+ const lastGlo = /* @__PURE__ */ new Map();
5982
+ for (const frame of oem4Frames(data, view, stats)) {
5983
+ if (!frame.binary) continue;
5984
+ if (frame.id === ID_RAWEPHEM && frame.msgLen >= 102) {
5985
+ const eph = decodeRawEphem(data, view, frame.payload);
5986
+ if (!eph) continue;
5987
+ const prev = lastGps.get(eph.prn);
5988
+ if (prev && prev.iode === eph.iode && prev.tocDate.getTime() === eph.tocDate.getTime()) {
5989
+ continue;
5990
+ }
5991
+ lastGps.set(eph.prn, eph);
5992
+ ephemerides.push(eph);
5993
+ } else if (frame.id === ID_GLOEPHEMERIS && frame.msgLen >= 144) {
5994
+ const eph = decodeGloEphemeris(view, frame.payload);
5995
+ if (!eph) continue;
5996
+ const prev = lastGlo.get(eph.prn);
5997
+ if (prev && Math.abs(prev.tocDate.getTime() - eph.tocDate.getTime()) < 1e3 && prev.health === eph.health) {
5998
+ continue;
5999
+ }
6000
+ lastGlo.set(eph.prn, eph);
6001
+ ephemerides.push(eph);
6002
+ }
6003
+ }
6004
+ return { ephemerides, badCrc: stats.badCrc };
6005
+ }
6006
+
5428
6007
  // src/novatel/index.ts
5429
- var GPS_EPOCH_MS3 = Date.UTC(1980, 0, 6);
5430
- var MS_PER_WEEK4 = 7 * 864e5;
6008
+ var GPS_EPOCH_MS6 = Date.UTC(1980, 0, 6);
6009
+ var MS_PER_WEEK5 = 7 * 864e5;
5431
6010
  var HDR = 28;
5432
6011
  var ID_RANGE = 43;
5433
6012
  var ID_RANGECMP = 140;
5434
- var ID_GLOEPHEMERIS = 723;
6013
+ var ID_GLOEPHEMERIS2 = 723;
5435
6014
  var C_LIGHT2 = 299792458;
5436
6015
  var ADR_ROLL = 8388608;
5437
6016
  function carrierFreq2(sys, code, gloK) {
@@ -5459,16 +6038,6 @@ function carrierFreq2(sys, code, gloK) {
5459
6038
  function exsign(v, bits) {
5460
6039
  return v & 1 << bits - 1 ? v - 2 ** bits : v;
5461
6040
  }
5462
- function crc32(data, start, len) {
5463
- let crc = 0;
5464
- for (let i = start; i < start + len; i++) {
5465
- crc ^= data[i];
5466
- for (let j = 0; j < 8; j++) {
5467
- crc = crc & 1 ? crc >>> 1 ^ 3988292384 : crc >>> 1;
5468
- }
5469
- }
5470
- return crc >>> 0;
5471
- }
5472
6041
  var SIGNALS2 = {
5473
6042
  0: {
5474
6043
  0: ["G", "1C"],
@@ -5522,7 +6091,7 @@ function parseNovatelRange(data) {
5522
6091
  const hl = data[j + 3];
5523
6092
  const id = view.getUint16(j + 4, true);
5524
6093
  const ln = view.getUint16(j + 8, true);
5525
- if (id !== ID_GLOEPHEMERIS || hl < HDR || j + hl + ln + 4 > data.length)
6094
+ if (id !== ID_GLOEPHEMERIS2 || hl < HDR || j + hl + ln + 4 > data.length)
5526
6095
  continue;
5527
6096
  if (crc32(data, j, hl + ln) !== view.getUint32(j + hl + ln, true)) continue;
5528
6097
  const slot = view.getUint16(j + hl, true) - 37;
@@ -5606,7 +6175,7 @@ function parseNovatelRange(data) {
5606
6175
  if (!codes.includes(code)) codes.push(code);
5607
6176
  }
5608
6177
  epochs.push({
5609
- timeMs: GPS_EPOCH_MS3 + week * MS_PER_WEEK4 + towMs,
6178
+ timeMs: GPS_EPOCH_MS6 + week * MS_PER_WEEK5 + towMs,
5610
6179
  meas
5611
6180
  });
5612
6181
  }
@@ -5658,7 +6227,7 @@ function parseNovatelRange(data) {
5658
6227
  if (!codes.includes(code)) codes.push(code);
5659
6228
  }
5660
6229
  epochs.push({
5661
- timeMs: GPS_EPOCH_MS3 + week * MS_PER_WEEK4 + towMs,
6230
+ timeMs: GPS_EPOCH_MS6 + week * MS_PER_WEEK5 + towMs,
5662
6231
  meas
5663
6232
  });
5664
6233
  }
@@ -6017,10 +6586,10 @@ function selectBest(ephs, timeMs) {
6017
6586
  }
6018
6587
  return best;
6019
6588
  }
6020
- var GPS_EPOCH_MS4 = START_GPS_TIME.getTime();
6021
- var MS_PER_WEEK5 = 7 * 864e5;
6589
+ var GPS_EPOCH_MS7 = START_GPS_TIME.getTime();
6590
+ var MS_PER_WEEK6 = 7 * 864e5;
6022
6591
  var BDS_EPOCH_MS = START_BDS_TIME.getTime();
6023
- var GAL_EPOCH_MS = GPS_EPOCH_MS4 + 1024 * MS_PER_WEEK5;
6592
+ var GAL_EPOCH_MS = GPS_EPOCH_MS7 + 1024 * MS_PER_WEEK6;
6024
6593
  function ephInfoToEphemeris(info) {
6025
6594
  const sys = info.prn.charAt(0);
6026
6595
  if (sys === "R") {
@@ -6071,11 +6640,11 @@ function ephInfoToEphemeris(info) {
6071
6640
  } else if (sys === "E") {
6072
6641
  epochMs = GAL_EPOCH_MS;
6073
6642
  } else {
6074
- epochMs = GPS_EPOCH_MS4;
6075
- const weeksNow = (info.lastReceived - GPS_EPOCH_MS4) / MS_PER_WEEK5;
6643
+ epochMs = GPS_EPOCH_MS7;
6644
+ const weeksNow = (info.lastReceived - GPS_EPOCH_MS7) / MS_PER_WEEK6;
6076
6645
  week += 1024 * Math.round((weeksNow - week) / 1024);
6077
6646
  }
6078
- const tocDate = new Date(epochMs + week * MS_PER_WEEK5 + tocSec * 1e3);
6647
+ const tocDate = new Date(epochMs + week * MS_PER_WEEK6 + tocSec * 1e3);
6079
6648
  return {
6080
6649
  system: sys,
6081
6650
  prn: info.prn,
@@ -9028,6 +9597,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
9028
9597
  MILLISECONDS_IN_WEEK,
9029
9598
  MILLISECONDS_TT_TAI,
9030
9599
  MultipathAccumulator,
9600
+ OEM4_HLEN,
9031
9601
  OMEGA_E,
9032
9602
  REFERENCE_FRAMES,
9033
9603
  RINEX_CODES,
@@ -9071,6 +9641,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
9071
9641
  computeVisibility,
9072
9642
  computeVisibilityFromPositions,
9073
9643
  connectToMountpoint,
9644
+ crc32,
9074
9645
  createGzipLineSink,
9075
9646
  createStationMeta,
9076
9647
  createStreamStats,
@@ -9160,6 +9731,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
9160
9731
  msmEpochToDate,
9161
9732
  navTimesFromEph,
9162
9733
  nmeaCoordToDecimal,
9734
+ oem4Frames,
9163
9735
  padL,
9164
9736
  padR,
9165
9737
  parseAntex,
@@ -9167,9 +9739,12 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
9167
9739
  parseIonex,
9168
9740
  parseNavFile,
9169
9741
  parseNmeaFile,
9742
+ parseNovatelNav,
9170
9743
  parseNovatelRange,
9171
9744
  parseRinexStream,
9745
+ parseSbfAlmanac,
9172
9746
  parseSbfMeas,
9747
+ parseSbfNav,
9173
9748
  parseSinexBiasDcb,
9174
9749
  parseSourcetable,
9175
9750
  parseSp3,