gnss-js 1.14.1 → 1.16.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/chunk-4LVD4DYL.js +146 -0
- package/dist/{chunk-5IXK25MX.js → chunk-6CX6EXRK.js} +120 -26
- package/dist/{chunk-SWKWJEGY.js → chunk-R33A2VA7.js} +142 -15
- package/dist/{chunk-YIHO74OS.js → chunk-YPOVPXNK.js} +392 -67
- package/dist/index.cjs +804 -124
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +26 -5
- package/dist/novatel.cjs +357 -14
- package/dist/novatel.d.cts +69 -1
- package/dist/novatel.d.ts +69 -1
- package/dist/novatel.js +12 -1
- package/dist/sbf.cjs +482 -68
- package/dist/sbf.d.cts +155 -1
- package/dist/sbf.d.ts +155 -1
- package/dist/sbf.js +13 -3
- package/dist/ubx.cjs +262 -29
- package/dist/ubx.d.cts +81 -1
- package/dist/ubx.d.ts +81 -1
- package/dist/ubx.js +8 -3
- package/package.json +1 -1
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,12 +218,16 @@ __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,
|
|
230
|
+
parseUbxNav: () => parseUbxNav,
|
|
224
231
|
parseUbxRawx: () => parseUbxRawx,
|
|
225
232
|
phiAltBOC: () => phiAltBOC,
|
|
226
233
|
phiBOCc: () => phiBOCc,
|
|
@@ -234,6 +241,8 @@ __export(src_exports, {
|
|
|
234
241
|
rhumbLine: () => rhumbLine,
|
|
235
242
|
rtcm3Constellation: () => rtcm3Constellation,
|
|
236
243
|
satClockCorrection: () => satClockCorrection,
|
|
244
|
+
sbfCrc16: () => crc16,
|
|
245
|
+
scanSbfFrames: () => scanSbfFrames,
|
|
237
246
|
selectEphemeris: () => selectEphemeris,
|
|
238
247
|
setGloFreqNumber: () => setGloFreqNumber,
|
|
239
248
|
setRtcm3DebugHandler: () => setRtcm3DebugHandler,
|
|
@@ -243,6 +252,7 @@ __export(src_exports, {
|
|
|
243
252
|
systemCmp: () => systemCmp,
|
|
244
253
|
systemName: () => systemName,
|
|
245
254
|
transformFrame: () => transformFrame,
|
|
255
|
+
ubxFrames: () => ubxFrames,
|
|
246
256
|
updateStationMeta: () => updateStationMeta,
|
|
247
257
|
updateStreamStats: () => updateStreamStats,
|
|
248
258
|
verifyChecksum: () => verifyChecksum,
|
|
@@ -4592,8 +4602,255 @@ function updateStreamStats(stats, frames, rawBytes) {
|
|
|
4592
4602
|
}
|
|
4593
4603
|
}
|
|
4594
4604
|
|
|
4595
|
-
// src/ubx/
|
|
4605
|
+
// src/ubx/frame.ts
|
|
4606
|
+
function* ubxFrames(data, stats = { badChecksums: 0 }) {
|
|
4607
|
+
let i = 0;
|
|
4608
|
+
while (i + 8 <= data.length) {
|
|
4609
|
+
if (data[i] !== 181 || data[i + 1] !== 98) {
|
|
4610
|
+
i++;
|
|
4611
|
+
continue;
|
|
4612
|
+
}
|
|
4613
|
+
const len = data[i + 4] | data[i + 5] << 8;
|
|
4614
|
+
const end = i + 6 + len + 2;
|
|
4615
|
+
if (end > data.length) break;
|
|
4616
|
+
let ckA = 0;
|
|
4617
|
+
let ckB = 0;
|
|
4618
|
+
for (let j = i + 2; j < i + 6 + len; j++) {
|
|
4619
|
+
ckA = ckA + data[j] & 255;
|
|
4620
|
+
ckB = ckB + ckA & 255;
|
|
4621
|
+
}
|
|
4622
|
+
if (ckA !== data[i + 6 + len] || ckB !== data[i + 7 + len]) {
|
|
4623
|
+
stats.badChecksums++;
|
|
4624
|
+
i++;
|
|
4625
|
+
continue;
|
|
4626
|
+
}
|
|
4627
|
+
yield {
|
|
4628
|
+
msgClass: data[i + 2],
|
|
4629
|
+
msgId: data[i + 3],
|
|
4630
|
+
payload: data.subarray(i + 6, i + 6 + len),
|
|
4631
|
+
payloadStart: i + 6
|
|
4632
|
+
};
|
|
4633
|
+
i = end;
|
|
4634
|
+
}
|
|
4635
|
+
}
|
|
4636
|
+
|
|
4637
|
+
// src/navbits/index.ts
|
|
4638
|
+
var GPS_PI = 3.1415926535898;
|
|
4596
4639
|
var GPS_EPOCH_MS = Date.UTC(1980, 0, 6);
|
|
4640
|
+
var SEC_PER_WEEK = 7 * 86400;
|
|
4641
|
+
function getBitU(buff, pos, len) {
|
|
4642
|
+
let bits = 0;
|
|
4643
|
+
for (let i = pos; i < pos + len; i++) {
|
|
4644
|
+
bits = bits * 2 + (buff[i >> 3] >> 7 - (i & 7) & 1);
|
|
4645
|
+
}
|
|
4646
|
+
return bits;
|
|
4647
|
+
}
|
|
4648
|
+
function getBitS(buff, pos, len) {
|
|
4649
|
+
const bits = getBitU(buff, pos, len);
|
|
4650
|
+
if (len <= 0 || bits < 2 ** (len - 1)) return bits;
|
|
4651
|
+
return bits - 2 ** len;
|
|
4652
|
+
}
|
|
4653
|
+
function setBitU(buff, pos, len, data) {
|
|
4654
|
+
let mask = 2 ** (len - 1);
|
|
4655
|
+
for (let i = pos; i < pos + len; i++, mask /= 2) {
|
|
4656
|
+
if (data >= mask) {
|
|
4657
|
+
buff[i >> 3] |= 1 << 7 - (i & 7);
|
|
4658
|
+
data -= mask;
|
|
4659
|
+
} else {
|
|
4660
|
+
buff[i >> 3] &= ~(1 << 7 - (i & 7));
|
|
4661
|
+
}
|
|
4662
|
+
}
|
|
4663
|
+
}
|
|
4664
|
+
function decodeGpsLnavFrame(subframes, opts = {}) {
|
|
4665
|
+
if (subframes.length < 90) return null;
|
|
4666
|
+
const b = subframes;
|
|
4667
|
+
let i = 24;
|
|
4668
|
+
const tow1 = getBitU(b, i, 17) * 6;
|
|
4669
|
+
i += 17 + 2;
|
|
4670
|
+
const id1 = getBitU(b, i, 3);
|
|
4671
|
+
i += 3 + 2;
|
|
4672
|
+
const week10 = getBitU(b, i, 10);
|
|
4673
|
+
i += 10;
|
|
4674
|
+
i += 2;
|
|
4675
|
+
i += 4;
|
|
4676
|
+
const svHealth = getBitU(b, i, 6);
|
|
4677
|
+
i += 6;
|
|
4678
|
+
const iodc0 = getBitU(b, i, 2);
|
|
4679
|
+
i += 2;
|
|
4680
|
+
i += 1 + 87;
|
|
4681
|
+
const tgdRaw = getBitS(b, i, 8);
|
|
4682
|
+
i += 8;
|
|
4683
|
+
const iodc1 = getBitU(b, i, 8);
|
|
4684
|
+
i += 8;
|
|
4685
|
+
const tocSec = getBitU(b, i, 16) * 16;
|
|
4686
|
+
i += 16;
|
|
4687
|
+
const af2 = getBitS(b, i, 8) * 2 ** -55;
|
|
4688
|
+
i += 8;
|
|
4689
|
+
const af1 = getBitS(b, i, 16) * 2 ** -43;
|
|
4690
|
+
i += 16;
|
|
4691
|
+
const af0 = getBitS(b, i, 22) * 2 ** -31;
|
|
4692
|
+
i = 240 + 24;
|
|
4693
|
+
i += 17 + 2;
|
|
4694
|
+
const id2 = getBitU(b, i, 3);
|
|
4695
|
+
i += 3 + 2;
|
|
4696
|
+
const iode = getBitU(b, i, 8);
|
|
4697
|
+
i += 8;
|
|
4698
|
+
const crs = getBitS(b, i, 16) * 2 ** -5;
|
|
4699
|
+
i += 16;
|
|
4700
|
+
const deltaN = getBitS(b, i, 16) * 2 ** -43 * GPS_PI;
|
|
4701
|
+
i += 16;
|
|
4702
|
+
const m0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
4703
|
+
i += 32;
|
|
4704
|
+
const cuc = getBitS(b, i, 16) * 2 ** -29;
|
|
4705
|
+
i += 16;
|
|
4706
|
+
const e = getBitU(b, i, 32) * 2 ** -33;
|
|
4707
|
+
i += 32;
|
|
4708
|
+
const cus = getBitS(b, i, 16) * 2 ** -29;
|
|
4709
|
+
i += 16;
|
|
4710
|
+
const sqrtA = getBitU(b, i, 32) * 2 ** -19;
|
|
4711
|
+
i += 32;
|
|
4712
|
+
const toes = getBitU(b, i, 16) * 16;
|
|
4713
|
+
i = 480 + 24;
|
|
4714
|
+
i += 17 + 2;
|
|
4715
|
+
const id3 = getBitU(b, i, 3);
|
|
4716
|
+
i += 3 + 2;
|
|
4717
|
+
const cic = getBitS(b, i, 16) * 2 ** -29;
|
|
4718
|
+
i += 16;
|
|
4719
|
+
const omega0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
4720
|
+
i += 32;
|
|
4721
|
+
const cis = getBitS(b, i, 16) * 2 ** -29;
|
|
4722
|
+
i += 16;
|
|
4723
|
+
const i0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
4724
|
+
i += 32;
|
|
4725
|
+
const crc = getBitS(b, i, 16) * 2 ** -5;
|
|
4726
|
+
i += 16;
|
|
4727
|
+
const omega = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
4728
|
+
i += 32;
|
|
4729
|
+
const omegaDot = getBitS(b, i, 24) * 2 ** -43 * GPS_PI;
|
|
4730
|
+
i += 24;
|
|
4731
|
+
const iode3 = getBitU(b, i, 8);
|
|
4732
|
+
i += 8;
|
|
4733
|
+
const idot = getBitS(b, i, 14) * 2 ** -43 * GPS_PI;
|
|
4734
|
+
const iodc = iodc0 * 256 + iodc1;
|
|
4735
|
+
if (id1 !== 1 || id2 !== 2 || id3 !== 3) return null;
|
|
4736
|
+
if (iode3 !== iode || iode !== (iodc & 255)) return null;
|
|
4737
|
+
const ref = opts.refWeek ?? Math.floor((Date.now() - GPS_EPOCH_MS) / 1e3 / SEC_PER_WEEK);
|
|
4738
|
+
let week = week10 + 1024 * Math.round((ref - week10) / 1024);
|
|
4739
|
+
if (toes < tow1 - 302400) week++;
|
|
4740
|
+
else if (toes > tow1 + 302400) week--;
|
|
4741
|
+
const prn = opts.prn ?? "G00";
|
|
4742
|
+
const tocDate = new Date(
|
|
4743
|
+
GPS_EPOCH_MS + (week * SEC_PER_WEEK + tocSec) * 1e3
|
|
4744
|
+
);
|
|
4745
|
+
return {
|
|
4746
|
+
system: prn[0] === "J" ? "J" : "G",
|
|
4747
|
+
prn,
|
|
4748
|
+
tocDate,
|
|
4749
|
+
// Same seconds-of-week convention as parseNavFile (rinex/nav.ts).
|
|
4750
|
+
toc: tocDate.getTime() / 1e3 % SEC_PER_WEEK,
|
|
4751
|
+
af0,
|
|
4752
|
+
af1,
|
|
4753
|
+
af2,
|
|
4754
|
+
iode,
|
|
4755
|
+
crs,
|
|
4756
|
+
deltaN,
|
|
4757
|
+
m0,
|
|
4758
|
+
cuc,
|
|
4759
|
+
e,
|
|
4760
|
+
cus,
|
|
4761
|
+
sqrtA,
|
|
4762
|
+
toe: toes,
|
|
4763
|
+
cic,
|
|
4764
|
+
omega0,
|
|
4765
|
+
cis,
|
|
4766
|
+
i0,
|
|
4767
|
+
crc,
|
|
4768
|
+
omega,
|
|
4769
|
+
omegaDot,
|
|
4770
|
+
idot,
|
|
4771
|
+
week,
|
|
4772
|
+
svHealth,
|
|
4773
|
+
tgd: tgdRaw === -128 ? 0 : tgdRaw * 2 ** -31
|
|
4774
|
+
// IS-GPS-200: -128 reserved
|
|
4775
|
+
};
|
|
4776
|
+
}
|
|
4777
|
+
|
|
4778
|
+
// src/ubx/nav.ts
|
|
4779
|
+
var PREAMB_CNAV = 139;
|
|
4780
|
+
function parseUbxNav(data, opts = {}) {
|
|
4781
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
4782
|
+
const ephemerides = [];
|
|
4783
|
+
let badParity = 0;
|
|
4784
|
+
let refWeek = opts.refWeek;
|
|
4785
|
+
if (refWeek === void 0) {
|
|
4786
|
+
for (const f of ubxFrames(data)) {
|
|
4787
|
+
if (f.msgClass === 2 && f.msgId === 21 && f.payload.length >= 16) {
|
|
4788
|
+
const week = view.getUint16(f.payloadStart + 8, true);
|
|
4789
|
+
if (week > 0) {
|
|
4790
|
+
refWeek = week;
|
|
4791
|
+
break;
|
|
4792
|
+
}
|
|
4793
|
+
}
|
|
4794
|
+
}
|
|
4795
|
+
}
|
|
4796
|
+
if (refWeek === void 0) return { ephemerides, badParity };
|
|
4797
|
+
const subframes = /* @__PURE__ */ new Map();
|
|
4798
|
+
const last = /* @__PURE__ */ new Map();
|
|
4799
|
+
for (const f of ubxFrames(data)) {
|
|
4800
|
+
if (f.msgClass !== 2 || f.msgId !== 19) continue;
|
|
4801
|
+
const p = f.payload;
|
|
4802
|
+
if (p.length < 8) continue;
|
|
4803
|
+
const gnssId = p[0];
|
|
4804
|
+
const svId = p[1];
|
|
4805
|
+
let prn;
|
|
4806
|
+
if (gnssId === 0 && svId >= 1 && svId <= 32) {
|
|
4807
|
+
prn = `G${String(svId).padStart(2, "0")}`;
|
|
4808
|
+
} else if (gnssId === 5 && svId >= 1 && svId <= 10) {
|
|
4809
|
+
if (p.length === 44) continue;
|
|
4810
|
+
prn = `J${String(svId).padStart(2, "0")}`;
|
|
4811
|
+
} else {
|
|
4812
|
+
continue;
|
|
4813
|
+
}
|
|
4814
|
+
if (p.length < 8 + 40) continue;
|
|
4815
|
+
const base = f.payloadStart + 8;
|
|
4816
|
+
if (view.getUint32(base, true) >>> 24 === PREAMB_CNAV) continue;
|
|
4817
|
+
const buff = new Uint8Array(30);
|
|
4818
|
+
for (let k = 0; k < 10; k++) {
|
|
4819
|
+
const dwrd = view.getUint32(base + 4 * k, true);
|
|
4820
|
+
setBitU(buff, 24 * k, 24, dwrd >>> 6 & 16777215);
|
|
4821
|
+
}
|
|
4822
|
+
const id = getBitU(buff, 43, 3);
|
|
4823
|
+
if (id < 1 || id > 5) {
|
|
4824
|
+
badParity++;
|
|
4825
|
+
continue;
|
|
4826
|
+
}
|
|
4827
|
+
if (id > 3) continue;
|
|
4828
|
+
const key = gnssId * 256 + svId;
|
|
4829
|
+
let sf = subframes.get(key);
|
|
4830
|
+
if (!sf) {
|
|
4831
|
+
sf = { buf: new Uint8Array(90), have: 0 };
|
|
4832
|
+
subframes.set(key, sf);
|
|
4833
|
+
}
|
|
4834
|
+
sf.buf.set(buff, (id - 1) * 30);
|
|
4835
|
+
sf.have |= 1 << id - 1;
|
|
4836
|
+
if (id !== 3 || sf.have !== 7) continue;
|
|
4837
|
+
const eph = decodeGpsLnavFrame(sf.buf, { prn, refWeek });
|
|
4838
|
+
if (!eph) {
|
|
4839
|
+
badParity++;
|
|
4840
|
+
continue;
|
|
4841
|
+
}
|
|
4842
|
+
const prev = last.get(prn);
|
|
4843
|
+
if (prev && prev.iode === eph.iode && prev.tocDate.getTime() === eph.tocDate.getTime()) {
|
|
4844
|
+
continue;
|
|
4845
|
+
}
|
|
4846
|
+
last.set(prn, eph);
|
|
4847
|
+
ephemerides.push(eph);
|
|
4848
|
+
}
|
|
4849
|
+
return { ephemerides, badParity };
|
|
4850
|
+
}
|
|
4851
|
+
|
|
4852
|
+
// src/ubx/index.ts
|
|
4853
|
+
var GPS_EPOCH_MS2 = Date.UTC(1980, 0, 6);
|
|
4597
4854
|
var MS_PER_WEEK2 = 7 * 864e5;
|
|
4598
4855
|
var SIGNALS = {
|
|
4599
4856
|
0: { 0: ["G", "1C"], 3: ["G", "2X"], 4: ["G", "2X"] },
|
|
@@ -4610,20 +4867,20 @@ var SIGNALS = {
|
|
|
4610
4867
|
// GLONASS L1OF, L2OF
|
|
4611
4868
|
};
|
|
4612
4869
|
function prnFor(gnssId, svId) {
|
|
4613
|
-
const
|
|
4870
|
+
const two3 = (n) => String(n).padStart(2, "0");
|
|
4614
4871
|
switch (gnssId) {
|
|
4615
4872
|
case 0:
|
|
4616
|
-
return svId >= 1 && svId <= 32 ? `G${
|
|
4873
|
+
return svId >= 1 && svId <= 32 ? `G${two3(svId)}` : null;
|
|
4617
4874
|
case 1:
|
|
4618
|
-
return svId >= 120 && svId <= 158 ? `S${
|
|
4875
|
+
return svId >= 120 && svId <= 158 ? `S${two3(svId - 100)}` : null;
|
|
4619
4876
|
case 2:
|
|
4620
|
-
return svId >= 1 && svId <= 36 ? `E${
|
|
4877
|
+
return svId >= 1 && svId <= 36 ? `E${two3(svId)}` : null;
|
|
4621
4878
|
case 3:
|
|
4622
|
-
return svId >= 1 && svId <= 63 ? `C${
|
|
4879
|
+
return svId >= 1 && svId <= 63 ? `C${two3(svId)}` : null;
|
|
4623
4880
|
case 5:
|
|
4624
|
-
return svId >= 1 && svId <= 10 ? `J${
|
|
4881
|
+
return svId >= 1 && svId <= 10 ? `J${two3(svId)}` : null;
|
|
4625
4882
|
case 6:
|
|
4626
|
-
return svId >= 1 && svId <= 32 ? `R${
|
|
4883
|
+
return svId >= 1 && svId <= 32 ? `R${two3(svId)}` : null;
|
|
4627
4884
|
default:
|
|
4628
4885
|
return null;
|
|
4629
4886
|
}
|
|
@@ -4633,33 +4890,14 @@ function parseUbxRawx(data) {
|
|
|
4633
4890
|
const epochs = [];
|
|
4634
4891
|
const messageCounts = {};
|
|
4635
4892
|
const obsCodes = {};
|
|
4636
|
-
|
|
4637
|
-
|
|
4638
|
-
|
|
4639
|
-
|
|
4640
|
-
i++;
|
|
4641
|
-
continue;
|
|
4642
|
-
}
|
|
4643
|
-
const cls = data[i + 2];
|
|
4644
|
-
const id = data[i + 3];
|
|
4645
|
-
const len = data[i + 4] | data[i + 5] << 8;
|
|
4646
|
-
const end = i + 6 + len + 2;
|
|
4647
|
-
if (end > data.length) break;
|
|
4648
|
-
let ckA = 0;
|
|
4649
|
-
let ckB = 0;
|
|
4650
|
-
for (let j = i + 2; j < i + 6 + len; j++) {
|
|
4651
|
-
ckA = ckA + data[j] & 255;
|
|
4652
|
-
ckB = ckB + ckA & 255;
|
|
4653
|
-
}
|
|
4654
|
-
if (ckA !== data[i + 6 + len] || ckB !== data[i + 7 + len]) {
|
|
4655
|
-
badChecksums++;
|
|
4656
|
-
i++;
|
|
4657
|
-
continue;
|
|
4658
|
-
}
|
|
4893
|
+
const stats = { badChecksums: 0 };
|
|
4894
|
+
for (const frame of ubxFrames(data, stats)) {
|
|
4895
|
+
const { msgClass: cls, msgId: id } = frame;
|
|
4896
|
+
const len = frame.payload.length;
|
|
4659
4897
|
const key = `${cls.toString(16).padStart(2, "0")}-${id.toString(16).padStart(2, "0")}`;
|
|
4660
4898
|
messageCounts[key] = (messageCounts[key] ?? 0) + 1;
|
|
4661
4899
|
if (cls === 2 && id === 21 && len >= 16) {
|
|
4662
|
-
const p =
|
|
4900
|
+
const p = frame.payloadStart;
|
|
4663
4901
|
const rcvTow = view.getFloat64(p, true);
|
|
4664
4902
|
const week = view.getUint16(p + 8, true);
|
|
4665
4903
|
const leapS = view.getInt8(p + 10);
|
|
@@ -4695,20 +4933,16 @@ function parseUbxRawx(data) {
|
|
|
4695
4933
|
if (!codes.includes(sig[1])) codes.push(sig[1]);
|
|
4696
4934
|
}
|
|
4697
4935
|
epochs.push({
|
|
4698
|
-
timeMs:
|
|
4936
|
+
timeMs: GPS_EPOCH_MS2 + week * MS_PER_WEEK2 + Math.round(rcvTow * 1e3),
|
|
4699
4937
|
leapS: leapValid ? leapS : null,
|
|
4700
4938
|
meas
|
|
4701
4939
|
});
|
|
4702
4940
|
}
|
|
4703
|
-
i = end;
|
|
4704
4941
|
}
|
|
4705
|
-
return { epochs, messageCounts, obsCodes, badChecksums };
|
|
4942
|
+
return { epochs, messageCounts, obsCodes, badChecksums: stats.badChecksums };
|
|
4706
4943
|
}
|
|
4707
4944
|
|
|
4708
|
-
// src/sbf/
|
|
4709
|
-
var CLIGHT = 299792458;
|
|
4710
|
-
var GPS_EPOCH_MS2 = Date.UTC(1980, 0, 6);
|
|
4711
|
-
var MS_PER_WEEK3 = 7 * 864e5;
|
|
4945
|
+
// src/sbf/frame.ts
|
|
4712
4946
|
var CRC_TABLE = (() => {
|
|
4713
4947
|
const t = new Uint16Array(256);
|
|
4714
4948
|
for (let n = 0; n < 256; n++) {
|
|
@@ -4725,6 +4959,362 @@ function crc16(data, start, end) {
|
|
|
4725
4959
|
crc = (crc << 8 ^ CRC_TABLE[(crc >> 8 ^ data[i]) & 255]) & 65535;
|
|
4726
4960
|
return crc;
|
|
4727
4961
|
}
|
|
4962
|
+
function scanSbfFrames(data, view, onBlock) {
|
|
4963
|
+
let badCrc = 0;
|
|
4964
|
+
let i = 0;
|
|
4965
|
+
while (i + 8 <= data.length) {
|
|
4966
|
+
if (data[i] !== 36 || data[i + 1] !== 64) {
|
|
4967
|
+
i++;
|
|
4968
|
+
continue;
|
|
4969
|
+
}
|
|
4970
|
+
const len = view.getUint16(i + 6, true);
|
|
4971
|
+
if (len < 8 || len % 4 !== 0) {
|
|
4972
|
+
i++;
|
|
4973
|
+
continue;
|
|
4974
|
+
}
|
|
4975
|
+
if (i + len > data.length) break;
|
|
4976
|
+
if (crc16(data, i + 4, i + len) !== view.getUint16(i + 2, true)) {
|
|
4977
|
+
badCrc++;
|
|
4978
|
+
i++;
|
|
4979
|
+
continue;
|
|
4980
|
+
}
|
|
4981
|
+
onBlock(view.getUint16(i + 4, true) & 8191, i, len);
|
|
4982
|
+
i += len;
|
|
4983
|
+
}
|
|
4984
|
+
return badCrc;
|
|
4985
|
+
}
|
|
4986
|
+
var two = (n) => String(n).padStart(2, "0");
|
|
4987
|
+
function svidToPrn(svid) {
|
|
4988
|
+
if (svid >= 1 && svid <= 37) return svid <= 32 ? `G${two(svid)}` : null;
|
|
4989
|
+
if (svid <= 61) return svid - 37 <= 27 ? `R${two(svid - 37)}` : null;
|
|
4990
|
+
if (svid <= 62) return null;
|
|
4991
|
+
if (svid <= 68) return svid - 38 <= 27 ? `R${two(svid - 38)}` : null;
|
|
4992
|
+
if (svid <= 70) return null;
|
|
4993
|
+
if (svid <= 106) return svid - 70 <= 36 ? `E${two(svid - 70)}` : null;
|
|
4994
|
+
if (svid <= 119) return null;
|
|
4995
|
+
if (svid <= 140) return `S${two(svid - 100)}`;
|
|
4996
|
+
if (svid <= 180) return svid - 140 <= 50 ? `C${two(svid - 140)}` : null;
|
|
4997
|
+
if (svid <= 190) return `J${two(svid - 180)}`;
|
|
4998
|
+
if (svid <= 197) return svid - 190 <= 14 ? `I${two(svid - 190)}` : null;
|
|
4999
|
+
if (svid <= 215) return `S${two(svid - 157)}`;
|
|
5000
|
+
if (svid <= 222) return svid - 208 <= 14 ? `I${two(svid - 208)}` : null;
|
|
5001
|
+
if (svid <= 245) return svid - 182 <= 50 ? `C${two(svid - 182)}` : null;
|
|
5002
|
+
return null;
|
|
5003
|
+
}
|
|
5004
|
+
|
|
5005
|
+
// src/sbf/nav.ts
|
|
5006
|
+
var PI2 = Math.PI;
|
|
5007
|
+
var GPS_EPOCH_MS3 = Date.UTC(1980, 0, 6);
|
|
5008
|
+
var BDT_EPOCH_MS = Date.UTC(2006, 0, 1);
|
|
5009
|
+
var SEC_PER_WEEK2 = 7 * 86400;
|
|
5010
|
+
var MS_PER_WEEK3 = SEC_PER_WEEK2 * 1e3;
|
|
5011
|
+
var F4_DNU = -2e10;
|
|
5012
|
+
var U4_DNU = 4294967295;
|
|
5013
|
+
function adjustWeek(refWeek, wn, mod) {
|
|
5014
|
+
let offset = refWeek % mod - wn;
|
|
5015
|
+
if (offset > mod / 2) offset -= mod;
|
|
5016
|
+
if (offset < -(mod / 2 - 1)) offset += mod;
|
|
5017
|
+
return refWeek - offset;
|
|
5018
|
+
}
|
|
5019
|
+
var gpsMs = (week, sec) => GPS_EPOCH_MS3 + week * MS_PER_WEEK3 + sec * 1e3;
|
|
5020
|
+
var sowOf = (dateMs) => dateMs / 1e3 % SEC_PER_WEEK2;
|
|
5021
|
+
function decodeGpsQzsNav(view, b, sys) {
|
|
5022
|
+
const svid = view.getUint8(b + 14);
|
|
5023
|
+
const prn = sys === "G" ? svid : svid - 180;
|
|
5024
|
+
const max = sys === "G" ? 32 : 10;
|
|
5025
|
+
if (prn < 1 || prn > max) return null;
|
|
5026
|
+
const wnc = view.getUint16(b + 12, true);
|
|
5027
|
+
const tgdRaw = view.getFloat32(b + 28, true);
|
|
5028
|
+
const tocs = view.getUint32(b + 32, true);
|
|
5029
|
+
const toes = view.getUint32(b + 88, true);
|
|
5030
|
+
const wnToc = adjustWeek(wnc, view.getUint16(b + 136, true), 1024);
|
|
5031
|
+
const tocDate = new Date(gpsMs(wnToc, tocs));
|
|
5032
|
+
return {
|
|
5033
|
+
system: sys,
|
|
5034
|
+
prn: `${sys}${String(prn).padStart(2, "0")}`,
|
|
5035
|
+
toc: sowOf(tocDate.getTime()),
|
|
5036
|
+
tocDate,
|
|
5037
|
+
af0: view.getFloat32(b + 44, true),
|
|
5038
|
+
af1: view.getFloat32(b + 40, true),
|
|
5039
|
+
af2: view.getFloat32(b + 36, true),
|
|
5040
|
+
iode: view.getUint8(b + 24),
|
|
5041
|
+
crs: view.getFloat32(b + 48, true),
|
|
5042
|
+
deltaN: view.getFloat32(b + 52, true) * PI2,
|
|
5043
|
+
m0: view.getFloat64(b + 56, true) * PI2,
|
|
5044
|
+
cuc: view.getFloat32(b + 64, true),
|
|
5045
|
+
e: view.getFloat64(b + 68, true),
|
|
5046
|
+
cus: view.getFloat32(b + 76, true),
|
|
5047
|
+
sqrtA: view.getFloat64(b + 80, true),
|
|
5048
|
+
toe: toes,
|
|
5049
|
+
cic: view.getFloat32(b + 92, true),
|
|
5050
|
+
omega0: view.getFloat64(b + 96, true) * PI2,
|
|
5051
|
+
cis: view.getFloat32(b + 104, true),
|
|
5052
|
+
i0: view.getFloat64(b + 108, true) * PI2,
|
|
5053
|
+
crc: view.getFloat32(b + 116, true),
|
|
5054
|
+
omega: view.getFloat64(b + 120, true) * PI2,
|
|
5055
|
+
omegaDot: view.getFloat32(b + 128, true) * PI2,
|
|
5056
|
+
idot: view.getFloat32(b + 132, true) * PI2,
|
|
5057
|
+
// RINEX "GPS week to go with toe": RTKLIB writes WNc for GPS and
|
|
5058
|
+
// the week of toc for QZSS — mirrored here so records compare
|
|
5059
|
+
// 1:1 against convbin output. wnToe is still used for `toe` above.
|
|
5060
|
+
week: sys === "G" ? wnc : wnToc,
|
|
5061
|
+
svHealth: view.getUint8(b + 20),
|
|
5062
|
+
tgd: tgdRaw !== F4_DNU ? tgdRaw : 0
|
|
5063
|
+
};
|
|
5064
|
+
}
|
|
5065
|
+
function decodeGalNav(view, b) {
|
|
5066
|
+
const prn = view.getUint8(b + 14) - 70;
|
|
5067
|
+
if (prn < 1 || prn > 36) return null;
|
|
5068
|
+
const source = view.getUint8(b + 15);
|
|
5069
|
+
if (source !== 2 && source !== 16) return null;
|
|
5070
|
+
const wnc = view.getUint16(b + 12, true);
|
|
5071
|
+
const toes = view.getUint32(b + 100, true);
|
|
5072
|
+
const tocs = view.getUint32(b + 104, true);
|
|
5073
|
+
const wnToc = adjustWeek(wnc, view.getUint16(b + 126, true), 4096);
|
|
5074
|
+
const tocDate = new Date(gpsMs(wnToc, tocs));
|
|
5075
|
+
const health = view.getUint16(b + 130, true);
|
|
5076
|
+
let svh = 0;
|
|
5077
|
+
if (health & 1) svh |= health >> 1 & 7;
|
|
5078
|
+
if (health & 16) svh |= (health >> 5 & 7) << 6;
|
|
5079
|
+
if (health & 256) svh |= (health >> 9 & 7) << 3;
|
|
5080
|
+
const bgdE5a = view.getFloat32(b + 136, true);
|
|
5081
|
+
return {
|
|
5082
|
+
system: "E",
|
|
5083
|
+
prn: `E${String(prn).padStart(2, "0")}`,
|
|
5084
|
+
toc: sowOf(tocDate.getTime()),
|
|
5085
|
+
tocDate,
|
|
5086
|
+
af0: view.getFloat64(b + 116, true),
|
|
5087
|
+
af1: view.getFloat32(b + 112, true),
|
|
5088
|
+
af2: view.getFloat32(b + 108, true),
|
|
5089
|
+
iode: view.getUint16(b + 128, true),
|
|
5090
|
+
// IODnav
|
|
5091
|
+
crs: view.getFloat32(b + 88, true),
|
|
5092
|
+
deltaN: view.getFloat32(b + 72, true) * PI2,
|
|
5093
|
+
m0: view.getFloat64(b + 24, true) * PI2,
|
|
5094
|
+
cuc: view.getFloat32(b + 76, true),
|
|
5095
|
+
e: view.getFloat64(b + 32, true),
|
|
5096
|
+
cus: view.getFloat32(b + 80, true),
|
|
5097
|
+
sqrtA: view.getFloat64(b + 16, true),
|
|
5098
|
+
toe: toes,
|
|
5099
|
+
cic: view.getFloat32(b + 92, true),
|
|
5100
|
+
omega0: view.getFloat64(b + 56, true) * PI2,
|
|
5101
|
+
cis: view.getFloat32(b + 96, true),
|
|
5102
|
+
i0: view.getFloat64(b + 40, true) * PI2,
|
|
5103
|
+
crc: view.getFloat32(b + 84, true),
|
|
5104
|
+
omega: view.getFloat64(b + 48, true) * PI2,
|
|
5105
|
+
omegaDot: view.getFloat32(b + 64, true) * PI2,
|
|
5106
|
+
idot: view.getFloat32(b + 68, true) * PI2,
|
|
5107
|
+
week: wnc,
|
|
5108
|
+
// RINEX GAL week is GPS-aligned and continuous
|
|
5109
|
+
svHealth: svh,
|
|
5110
|
+
tgd: bgdE5a !== F4_DNU ? bgdE5a : 0
|
|
5111
|
+
// BGD E5a/E1 (RINEX slot)
|
|
5112
|
+
};
|
|
5113
|
+
}
|
|
5114
|
+
function decodeBdsNav(view, b) {
|
|
5115
|
+
const prn = svidToPrn(view.getUint8(b + 14));
|
|
5116
|
+
if (!prn || prn[0] !== "C") return null;
|
|
5117
|
+
const bdsWeekRef = view.getUint16(b + 12, true) - 1356;
|
|
5118
|
+
const tgd1 = view.getFloat32(b + 24, true);
|
|
5119
|
+
const tocs = view.getUint32(b + 32, true);
|
|
5120
|
+
const toes = view.getUint32(b + 88, true);
|
|
5121
|
+
const wnToc = adjustWeek(bdsWeekRef, view.getUint16(b + 136, true), 8192);
|
|
5122
|
+
const wnToe = adjustWeek(bdsWeekRef, view.getUint16(b + 138, true), 8192);
|
|
5123
|
+
const tocDate = new Date(BDT_EPOCH_MS + wnToc * MS_PER_WEEK3 + tocs * 1e3);
|
|
5124
|
+
return {
|
|
5125
|
+
system: "C",
|
|
5126
|
+
prn,
|
|
5127
|
+
toc: sowOf(tocDate.getTime()),
|
|
5128
|
+
tocDate,
|
|
5129
|
+
af0: view.getFloat32(b + 44, true),
|
|
5130
|
+
af1: view.getFloat32(b + 40, true),
|
|
5131
|
+
af2: view.getFloat32(b + 36, true),
|
|
5132
|
+
iode: view.getUint8(b + 21),
|
|
5133
|
+
// AODE
|
|
5134
|
+
crs: view.getFloat32(b + 48, true),
|
|
5135
|
+
deltaN: view.getFloat32(b + 52, true) * PI2,
|
|
5136
|
+
m0: view.getFloat64(b + 56, true) * PI2,
|
|
5137
|
+
cuc: view.getFloat32(b + 64, true),
|
|
5138
|
+
e: view.getFloat64(b + 68, true),
|
|
5139
|
+
cus: view.getFloat32(b + 76, true),
|
|
5140
|
+
sqrtA: view.getFloat64(b + 80, true),
|
|
5141
|
+
toe: toes,
|
|
5142
|
+
cic: view.getFloat32(b + 92, true),
|
|
5143
|
+
omega0: view.getFloat64(b + 96, true) * PI2,
|
|
5144
|
+
cis: view.getFloat32(b + 104, true),
|
|
5145
|
+
i0: view.getFloat64(b + 108, true) * PI2,
|
|
5146
|
+
crc: view.getFloat32(b + 116, true),
|
|
5147
|
+
omega: view.getFloat64(b + 120, true) * PI2,
|
|
5148
|
+
omegaDot: view.getFloat32(b + 128, true) * PI2,
|
|
5149
|
+
idot: view.getFloat32(b + 132, true) * PI2,
|
|
5150
|
+
week: wnToe,
|
|
5151
|
+
// RINEX BDS week field is the BDT week
|
|
5152
|
+
svHealth: view.getUint8(b + 19),
|
|
5153
|
+
// SatH1
|
|
5154
|
+
tgd: tgd1 !== F4_DNU ? tgd1 : 0
|
|
5155
|
+
// TGD1 B1/B3 (RINEX slot)
|
|
5156
|
+
};
|
|
5157
|
+
}
|
|
5158
|
+
function decodeGloNav(view, b) {
|
|
5159
|
+
const prn = svidToPrn(view.getUint8(b + 14));
|
|
5160
|
+
if (!prn || prn[0] !== "R") return null;
|
|
5161
|
+
const wnc = view.getUint16(b + 12, true);
|
|
5162
|
+
const toes = view.getUint32(b + 76, true);
|
|
5163
|
+
const wnToe = adjustWeek(wnc, view.getUint16(b + 80, true), 1024);
|
|
5164
|
+
const toeGpsMs = gpsMs(wnToe, toes);
|
|
5165
|
+
const leapMs = getGpsLeap(new Date(toeGpsMs)) * 1e3;
|
|
5166
|
+
const tocDate = new Date(toeGpsMs - leapMs);
|
|
5167
|
+
const tofGpsMs = gpsMs(wnc, 0) + view.getUint32(b + 8, true);
|
|
5168
|
+
const tofLeapMs = getGpsLeap(new Date(tofGpsMs)) * 1e3;
|
|
5169
|
+
const messageFrameTime = (tofGpsMs - tofLeapMs - GPS_EPOCH_MS3) / 1e3 % SEC_PER_WEEK2;
|
|
5170
|
+
return {
|
|
5171
|
+
system: "R",
|
|
5172
|
+
prn,
|
|
5173
|
+
tocDate,
|
|
5174
|
+
// RINEX stores −τn as the clock bias; SBF carries τn (ICD sign)
|
|
5175
|
+
tauN: -view.getFloat32(b + 68, true),
|
|
5176
|
+
gammaN: view.getFloat32(b + 64, true),
|
|
5177
|
+
messageFrameTime,
|
|
5178
|
+
x: view.getFloat64(b + 16, true),
|
|
5179
|
+
// SBF unit is km, like RINEX
|
|
5180
|
+
xDot: view.getFloat32(b + 40, true),
|
|
5181
|
+
xAcc: view.getFloat32(b + 52, true),
|
|
5182
|
+
y: view.getFloat64(b + 24, true),
|
|
5183
|
+
yDot: view.getFloat32(b + 44, true),
|
|
5184
|
+
yAcc: view.getFloat32(b + 56, true),
|
|
5185
|
+
z: view.getFloat64(b + 32, true),
|
|
5186
|
+
zDot: view.getFloat32(b + 48, true),
|
|
5187
|
+
zAcc: view.getFloat32(b + 60, true),
|
|
5188
|
+
// MSB of the 3-bit Bn word — the unhealthy flag RINEX carries
|
|
5189
|
+
health: view.getUint8(b + 85) >> 2,
|
|
5190
|
+
freqNum: view.getUint8(b + 15) - 8
|
|
5191
|
+
};
|
|
5192
|
+
}
|
|
5193
|
+
function parseSbfNav(data) {
|
|
5194
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
5195
|
+
const ephemerides = [];
|
|
5196
|
+
const badCrc = scanSbfFrames(data, view, (id, b, len) => {
|
|
5197
|
+
let eph = null;
|
|
5198
|
+
if (id === 5891 && len >= 140) eph = decodeGpsQzsNav(view, b, "G");
|
|
5199
|
+
else if (id === 4095 && len >= 140) eph = decodeGpsQzsNav(view, b, "J");
|
|
5200
|
+
else if (id === 4002 && len >= 149) eph = decodeGalNav(view, b);
|
|
5201
|
+
else if (id === 4081 && len >= 140) eph = decodeBdsNav(view, b);
|
|
5202
|
+
else if (id === 4004 && len >= 96) eph = decodeGloNav(view, b);
|
|
5203
|
+
if (eph) ephemerides.push(eph);
|
|
5204
|
+
});
|
|
5205
|
+
return { ephemerides, badCrc };
|
|
5206
|
+
}
|
|
5207
|
+
var GAL_SQRT_A_NOMINAL = Math.sqrt(296e5);
|
|
5208
|
+
var GAL_I_NOMINAL = 56 / 180 * PI2;
|
|
5209
|
+
var I_REF_03 = 0.3 * PI2;
|
|
5210
|
+
function decodeGpsGalAlm(view, b, sys) {
|
|
5211
|
+
const wnc = view.getUint16(b + 12, true);
|
|
5212
|
+
const toa = view.getUint32(b + 20, true);
|
|
5213
|
+
if (toa === U4_DNU) return null;
|
|
5214
|
+
let prn;
|
|
5215
|
+
let weekAlm;
|
|
5216
|
+
let i0;
|
|
5217
|
+
let sqrtA = view.getFloat32(b + 32, true);
|
|
5218
|
+
let health;
|
|
5219
|
+
if (sys === "G") {
|
|
5220
|
+
prn = view.getUint8(b + 14);
|
|
5221
|
+
if (prn < 1 || prn > 32) return null;
|
|
5222
|
+
weekAlm = adjustWeek(wnc, view.getUint8(b + 56), 256);
|
|
5223
|
+
i0 = I_REF_03 + view.getFloat32(b + 24, true) * PI2;
|
|
5224
|
+
health = view.getUint8(b + 58);
|
|
5225
|
+
} else {
|
|
5226
|
+
prn = view.getUint8(b + 57) - 70;
|
|
5227
|
+
if (prn < 1 || prn > 36) return null;
|
|
5228
|
+
weekAlm = adjustWeek(wnc, view.getUint8(b + 56), 4);
|
|
5229
|
+
i0 = GAL_I_NOMINAL + view.getFloat32(b + 24, true) * PI2;
|
|
5230
|
+
sqrtA += GAL_SQRT_A_NOMINAL;
|
|
5231
|
+
health = view.getUint16(b + 58, true);
|
|
5232
|
+
}
|
|
5233
|
+
return {
|
|
5234
|
+
system: sys,
|
|
5235
|
+
prn: `${sys}${String(prn).padStart(2, "0")}`,
|
|
5236
|
+
weekAlm,
|
|
5237
|
+
toaSec: toa,
|
|
5238
|
+
sqrtA,
|
|
5239
|
+
e: view.getFloat32(b + 16, true),
|
|
5240
|
+
i0OrDeltaI: i0,
|
|
5241
|
+
omega0: view.getFloat32(b + 36, true) * PI2,
|
|
5242
|
+
omega: view.getFloat32(b + 40, true) * PI2,
|
|
5243
|
+
m0: view.getFloat32(b + 44, true) * PI2,
|
|
5244
|
+
omegaDot: view.getFloat32(b + 28, true) * PI2,
|
|
5245
|
+
af0: view.getFloat32(b + 52, true),
|
|
5246
|
+
af1: view.getFloat32(b + 48, true),
|
|
5247
|
+
health
|
|
5248
|
+
};
|
|
5249
|
+
}
|
|
5250
|
+
function decodeBdsAlm(view, b) {
|
|
5251
|
+
const prnStr = svidToPrn(view.getUint8(b + 14));
|
|
5252
|
+
if (!prnStr || prnStr[0] !== "C") return null;
|
|
5253
|
+
const prn = parseInt(prnStr.slice(1), 10);
|
|
5254
|
+
const toa = view.getUint32(b + 16, true);
|
|
5255
|
+
if (toa === U4_DNU) return null;
|
|
5256
|
+
const bdsWeekRef = view.getUint16(b + 12, true) - 1356;
|
|
5257
|
+
const geo = prn <= 5 || prn >= 59;
|
|
5258
|
+
return {
|
|
5259
|
+
system: "C",
|
|
5260
|
+
prn: prnStr,
|
|
5261
|
+
weekAlm: adjustWeek(bdsWeekRef, view.getUint8(b + 15), 256),
|
|
5262
|
+
toaSec: toa,
|
|
5263
|
+
sqrtA: view.getFloat32(b + 20, true),
|
|
5264
|
+
e: view.getFloat32(b + 24, true),
|
|
5265
|
+
i0OrDeltaI: (geo ? 0 : I_REF_03) + view.getFloat32(b + 44, true) * PI2,
|
|
5266
|
+
omega0: view.getFloat32(b + 36, true) * PI2,
|
|
5267
|
+
omega: view.getFloat32(b + 28, true) * PI2,
|
|
5268
|
+
m0: view.getFloat32(b + 32, true) * PI2,
|
|
5269
|
+
omegaDot: view.getFloat32(b + 40, true) * PI2,
|
|
5270
|
+
af0: view.getFloat32(b + 48, true),
|
|
5271
|
+
af1: view.getFloat32(b + 52, true),
|
|
5272
|
+
health: view.getUint16(b + 56, true)
|
|
5273
|
+
};
|
|
5274
|
+
}
|
|
5275
|
+
function decodeGloAlm(view, b) {
|
|
5276
|
+
const prn = svidToPrn(view.getUint8(b + 14));
|
|
5277
|
+
if (!prn || prn[0] !== "R") return null;
|
|
5278
|
+
const wnc = view.getUint16(b + 12, true);
|
|
5279
|
+
const toa = view.getUint32(b + 20, true);
|
|
5280
|
+
if (toa === U4_DNU) return null;
|
|
5281
|
+
return {
|
|
5282
|
+
system: "R",
|
|
5283
|
+
prn,
|
|
5284
|
+
freqNr: view.getUint8(b + 15) - 8,
|
|
5285
|
+
weekAlm: adjustWeek(wnc, view.getUint8(b + 52), 256),
|
|
5286
|
+
toaSec: toa,
|
|
5287
|
+
epsilon: view.getFloat32(b + 16, true),
|
|
5288
|
+
deltaI: view.getFloat32(b + 24, true) * PI2,
|
|
5289
|
+
lambda: view.getFloat32(b + 28, true) * PI2,
|
|
5290
|
+
tLambda: view.getFloat32(b + 32, true),
|
|
5291
|
+
omega: view.getFloat32(b + 36, true) * PI2,
|
|
5292
|
+
deltaT: view.getFloat32(b + 40, true),
|
|
5293
|
+
deltaTDot: view.getFloat32(b + 44, true),
|
|
5294
|
+
tau: view.getFloat32(b + 48, true),
|
|
5295
|
+
health: view.getUint8(b + 53),
|
|
5296
|
+
nDay: view.getUint16(b + 54, true),
|
|
5297
|
+
n4: view.getUint8(b + 57)
|
|
5298
|
+
};
|
|
5299
|
+
}
|
|
5300
|
+
function parseSbfAlmanac(data) {
|
|
5301
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
5302
|
+
const almanacs = [];
|
|
5303
|
+
const badCrc = scanSbfFrames(data, view, (id, b, len) => {
|
|
5304
|
+
let alm = null;
|
|
5305
|
+
if (id === 5892 && len >= 60) alm = decodeGpsGalAlm(view, b, "G");
|
|
5306
|
+
else if (id === 4003 && len >= 61) alm = decodeGpsGalAlm(view, b, "E");
|
|
5307
|
+
else if (id === 4119 && len >= 60) alm = decodeBdsAlm(view, b);
|
|
5308
|
+
else if (id === 4005 && len >= 60) alm = decodeGloAlm(view, b);
|
|
5309
|
+
if (alm) almanacs.push(alm);
|
|
5310
|
+
});
|
|
5311
|
+
return { almanacs, badCrc };
|
|
5312
|
+
}
|
|
5313
|
+
|
|
5314
|
+
// src/sbf/index.ts
|
|
5315
|
+
var CLIGHT = 299792458;
|
|
5316
|
+
var GPS_EPOCH_MS4 = Date.UTC(1980, 0, 6);
|
|
5317
|
+
var MS_PER_WEEK4 = 7 * 864e5;
|
|
4728
5318
|
var M3_SYS = ["G", "R", "E", "C", "S", "J", "I"];
|
|
4729
5319
|
var M3_PR_BASE = [19e6, 19e6, 22e6, 2e7, 34e6, 34e6, 34e6];
|
|
4730
5320
|
var M3_INTERVALS = [
|
|
@@ -4823,44 +5413,27 @@ var MEAS2_SIG = [
|
|
|
4823
5413
|
["J", "1E"],
|
|
4824
5414
|
["J", "5P"]
|
|
4825
5415
|
];
|
|
4826
|
-
var
|
|
5416
|
+
var two2 = (n) => String(n).padStart(2, "0");
|
|
4827
5417
|
function m3Prn(navsys, svid) {
|
|
4828
5418
|
switch (navsys) {
|
|
4829
5419
|
case 0:
|
|
4830
|
-
return svid < 32 ? `G${
|
|
5420
|
+
return svid < 32 ? `G${two2(svid + 1)}` : null;
|
|
4831
5421
|
case 1:
|
|
4832
|
-
return svid < 27 ? `R${
|
|
5422
|
+
return svid < 27 ? `R${two2(svid + 1)}` : null;
|
|
4833
5423
|
case 2:
|
|
4834
|
-
return svid < 36 ? `E${
|
|
5424
|
+
return svid < 36 ? `E${two2(svid + 1)}` : null;
|
|
4835
5425
|
case 3:
|
|
4836
|
-
return svid < 50 ? `C${
|
|
5426
|
+
return svid < 50 ? `C${two2(svid + 1)}` : null;
|
|
4837
5427
|
case 4:
|
|
4838
|
-
return svid <= 38 ? `S${
|
|
5428
|
+
return svid <= 38 ? `S${two2(svid + 20)}` : null;
|
|
4839
5429
|
case 5:
|
|
4840
|
-
return svid < 10 ? `J${
|
|
5430
|
+
return svid < 10 ? `J${two2(svid + 1)}` : null;
|
|
4841
5431
|
case 6:
|
|
4842
|
-
return svid < 14 ? `I${
|
|
5432
|
+
return svid < 14 ? `I${two2(svid + 1)}` : null;
|
|
4843
5433
|
default:
|
|
4844
5434
|
return null;
|
|
4845
5435
|
}
|
|
4846
5436
|
}
|
|
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
5437
|
function carrierFreq(sys, code, fcn) {
|
|
4865
5438
|
const band = code.charCodeAt(0) - 48;
|
|
4866
5439
|
switch (sys) {
|
|
@@ -4923,7 +5496,6 @@ function parseSbfMeas(data) {
|
|
|
4923
5496
|
const epochs = [];
|
|
4924
5497
|
const messageCounts = {};
|
|
4925
5498
|
const obsCodes = {};
|
|
4926
|
-
let badCrc = 0;
|
|
4927
5499
|
let ref = freshRefEpoch(-1);
|
|
4928
5500
|
let curTime = NaN;
|
|
4929
5501
|
let curMeas = [];
|
|
@@ -4954,8 +5526,8 @@ function parseSbfMeas(data) {
|
|
|
4954
5526
|
curTime = timeMs;
|
|
4955
5527
|
}
|
|
4956
5528
|
};
|
|
4957
|
-
const decodeMeas3Ranges = (
|
|
4958
|
-
const o =
|
|
5529
|
+
const decodeMeas3Ranges = (i, tow) => {
|
|
5530
|
+
const o = i + 8;
|
|
4959
5531
|
const constellations = view.getUint16(o + 8, true) & 127;
|
|
4960
5532
|
const misc = data[o + 10];
|
|
4961
5533
|
const version = data[o + 11];
|
|
@@ -5233,8 +5805,8 @@ function parseSbfMeas(data) {
|
|
|
5233
5805
|
}
|
|
5234
5806
|
}
|
|
5235
5807
|
};
|
|
5236
|
-
const decodeMeas3CN0 = (
|
|
5237
|
-
const flags = view.getUint16(
|
|
5808
|
+
const decodeMeas3CN0 = (i, len) => {
|
|
5809
|
+
const flags = view.getUint16(i + 14, true);
|
|
5238
5810
|
if ((flags & 7) !== 0) return;
|
|
5239
5811
|
const maxNibbles = (len - 16) * 2;
|
|
5240
5812
|
let off = 0;
|
|
@@ -5244,7 +5816,7 @@ function parseSbfMeas(data) {
|
|
|
5244
5816
|
for (let k = 0; k < e.slots.length; k++) {
|
|
5245
5817
|
const slot = e.slots[k];
|
|
5246
5818
|
if (k > 0 && !slot) break;
|
|
5247
|
-
const nib = (data[
|
|
5819
|
+
const nib = (data[i + 16 + (off >> 1)] ?? 0) >> (off & 1) * 4 & 15;
|
|
5248
5820
|
if (slot && slot.cn0 !== null) slot.cn0 += nib * 0.0625 - 0.5;
|
|
5249
5821
|
off++;
|
|
5250
5822
|
}
|
|
@@ -5271,14 +5843,14 @@ function parseSbfMeas(data) {
|
|
|
5271
5843
|
if ((v & 1) === 1) value = -value;
|
|
5272
5844
|
return { value, size };
|
|
5273
5845
|
};
|
|
5274
|
-
const decodeMeas3Doppler = (
|
|
5275
|
-
const flags = view.getUint16(
|
|
5846
|
+
const decodeMeas3Doppler = (i, len) => {
|
|
5847
|
+
const flags = view.getUint16(i + 14, true);
|
|
5276
5848
|
if ((flags & 7) !== 0) return;
|
|
5277
5849
|
let off = 0;
|
|
5278
5850
|
for (const e of curSats) {
|
|
5279
5851
|
if (off + 16 >= len) break;
|
|
5280
5852
|
if (!e.prn) continue;
|
|
5281
|
-
const master = readPrRate(
|
|
5853
|
+
const master = readPrRate(i + 16, off);
|
|
5282
5854
|
off += master.size;
|
|
5283
5855
|
if (master.value === -268435455) continue;
|
|
5284
5856
|
const refPrRate = ref.sats[e.navsys][e.svid]?.prRate ?? 0;
|
|
@@ -5288,20 +5860,20 @@ function parseSbfMeas(data) {
|
|
|
5288
5860
|
for (let k = 1; k < e.slots.length; k++) {
|
|
5289
5861
|
const slot = e.slots[k];
|
|
5290
5862
|
if (!slot) break;
|
|
5291
|
-
const slave = readPrRate(
|
|
5863
|
+
const slave = readPrRate(i + 16, off);
|
|
5292
5864
|
off += slave.size;
|
|
5293
5865
|
if (m)
|
|
5294
5866
|
slot.doppler = (mD * (CLIGHT / m.freq) * 1e3 - slave.value) * 1e-3 / (CLIGHT / slot.freq);
|
|
5295
5867
|
}
|
|
5296
5868
|
}
|
|
5297
5869
|
};
|
|
5298
|
-
const decodeMeasEpoch = (
|
|
5299
|
-
const n1 = data[
|
|
5300
|
-
const len1 = data[
|
|
5301
|
-
const len2 = data[
|
|
5302
|
-
if ((data[
|
|
5303
|
-
const end =
|
|
5304
|
-
let p =
|
|
5870
|
+
const decodeMeasEpoch = (i, len) => {
|
|
5871
|
+
const n1 = data[i + 14];
|
|
5872
|
+
const len1 = data[i + 15];
|
|
5873
|
+
const len2 = data[i + 16];
|
|
5874
|
+
if ((data[i + 17] & 128) !== 0) return;
|
|
5875
|
+
const end = i + len;
|
|
5876
|
+
let p = i + 20;
|
|
5305
5877
|
for (let b1 = 0; b1 < n1 && p + 20 <= end; b1++) {
|
|
5306
5878
|
const ant = data[p + 1] >> 5;
|
|
5307
5879
|
let sig = data[p + 1] & 31;
|
|
@@ -5388,50 +5960,158 @@ function parseSbfMeas(data) {
|
|
|
5388
5960
|
}
|
|
5389
5961
|
}
|
|
5390
5962
|
};
|
|
5391
|
-
|
|
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;
|
|
5963
|
+
const badCrc = scanSbfFrames(data, view, (id, i, len) => {
|
|
5409
5964
|
const key = String(id);
|
|
5410
5965
|
messageCounts[key] = (messageCounts[key] ?? 0) + 1;
|
|
5411
5966
|
if ((id === 4027 || id === 4109 || id === 4110 || id === 4111) && len >= 16) {
|
|
5412
5967
|
const tow = view.getUint32(i + 8, true);
|
|
5413
5968
|
const wnc = view.getUint16(i + 12, true);
|
|
5414
5969
|
if (tow !== 4294967295 && wnc !== 65535) {
|
|
5415
|
-
ensureEpoch(
|
|
5970
|
+
ensureEpoch(GPS_EPOCH_MS4 + wnc * MS_PER_WEEK4 + tow);
|
|
5416
5971
|
if (id === 4109) decodeMeas3Ranges(i, tow);
|
|
5417
5972
|
else if (id === 4110) decodeMeas3CN0(i, len);
|
|
5418
5973
|
else if (id === 4111) decodeMeas3Doppler(i, len);
|
|
5419
5974
|
else decodeMeasEpoch(i, len);
|
|
5420
5975
|
}
|
|
5421
5976
|
}
|
|
5422
|
-
|
|
5423
|
-
}
|
|
5977
|
+
});
|
|
5424
5978
|
flush();
|
|
5425
5979
|
return { epochs, messageCounts, obsCodes, badCrc };
|
|
5426
5980
|
}
|
|
5427
5981
|
|
|
5982
|
+
// src/novatel/frame.ts
|
|
5983
|
+
var OEM4_HLEN = 28;
|
|
5984
|
+
function crc32(data, start, len) {
|
|
5985
|
+
let crc = 0;
|
|
5986
|
+
for (let i = start; i < start + len; i++) {
|
|
5987
|
+
crc ^= data[i];
|
|
5988
|
+
for (let j = 0; j < 8; j++) {
|
|
5989
|
+
crc = crc & 1 ? crc >>> 1 ^ 3988292384 : crc >>> 1;
|
|
5990
|
+
}
|
|
5991
|
+
}
|
|
5992
|
+
return crc >>> 0;
|
|
5993
|
+
}
|
|
5994
|
+
function* oem4Frames(data, view, stats) {
|
|
5995
|
+
let i = 0;
|
|
5996
|
+
while (i + OEM4_HLEN + 4 <= data.length) {
|
|
5997
|
+
if (data[i] !== 170 || data[i + 1] !== 68 || data[i + 2] !== 18) {
|
|
5998
|
+
i++;
|
|
5999
|
+
continue;
|
|
6000
|
+
}
|
|
6001
|
+
const hlen = data[i + 3];
|
|
6002
|
+
const msgLen = view.getUint16(i + 8, true);
|
|
6003
|
+
const total = hlen + msgLen + 4;
|
|
6004
|
+
if (hlen < OEM4_HLEN || i + total > data.length) {
|
|
6005
|
+
i++;
|
|
6006
|
+
continue;
|
|
6007
|
+
}
|
|
6008
|
+
if (crc32(data, i, hlen + msgLen) !== view.getUint32(i + hlen + msgLen, true)) {
|
|
6009
|
+
stats.badCrc++;
|
|
6010
|
+
i++;
|
|
6011
|
+
continue;
|
|
6012
|
+
}
|
|
6013
|
+
yield {
|
|
6014
|
+
id: view.getUint16(i + 4, true),
|
|
6015
|
+
start: i,
|
|
6016
|
+
payload: i + hlen,
|
|
6017
|
+
msgLen,
|
|
6018
|
+
binary: (data[i + 6] >> 4 & 3) === 0,
|
|
6019
|
+
week: view.getUint16(i + 14, true),
|
|
6020
|
+
towMs: view.getUint32(i + 16, true)
|
|
6021
|
+
};
|
|
6022
|
+
i += total;
|
|
6023
|
+
}
|
|
6024
|
+
}
|
|
6025
|
+
|
|
6026
|
+
// src/novatel/nav.ts
|
|
6027
|
+
var ID_RAWEPHEM = 41;
|
|
6028
|
+
var ID_GLOEPHEMERIS = 723;
|
|
6029
|
+
var GPS_EPOCH_MS5 = Date.UTC(1980, 0, 6);
|
|
6030
|
+
var SEC_PER_WEEK3 = 7 * 86400;
|
|
6031
|
+
var SEC_PER_DAY = 86400;
|
|
6032
|
+
function decodeRawEphem(data, view, p) {
|
|
6033
|
+
const prn = view.getUint32(p, true);
|
|
6034
|
+
if (prn < 1 || prn > 32) return null;
|
|
6035
|
+
const refWeek = view.getUint32(p + 4, true);
|
|
6036
|
+
return decodeGpsLnavFrame(data.subarray(p + 12, p + 102), {
|
|
6037
|
+
prn: `G${String(prn).padStart(2, "0")}`,
|
|
6038
|
+
refWeek
|
|
6039
|
+
});
|
|
6040
|
+
}
|
|
6041
|
+
function decodeGloEphemeris(view, p) {
|
|
6042
|
+
const slot = view.getUint16(p, true) - 37;
|
|
6043
|
+
if (slot < 1 || slot > 27) return null;
|
|
6044
|
+
const freqNum = view.getUint16(p + 2, true) - 7;
|
|
6045
|
+
const week = view.getUint16(p + 6, true);
|
|
6046
|
+
const tow = Math.floor(view.getUint32(p + 8, true) / 1e3 + 0.5);
|
|
6047
|
+
const toff = view.getUint32(p + 12, true);
|
|
6048
|
+
const health = view.getUint32(p + 24, true) < 4 ? 0 : 1;
|
|
6049
|
+
let tof = view.getUint32(p + 124, true) - toff;
|
|
6050
|
+
tof += Math.floor(tow / SEC_PER_DAY) * SEC_PER_DAY;
|
|
6051
|
+
if (tof < tow - 43200) tof += SEC_PER_DAY;
|
|
6052
|
+
else if (tof > tow + 43200) tof -= SEC_PER_DAY;
|
|
6053
|
+
const toeGpsMs = GPS_EPOCH_MS5 + (week * SEC_PER_WEEK3 + tow) * 1e3;
|
|
6054
|
+
const tofGpsMs = GPS_EPOCH_MS5 + (week * SEC_PER_WEEK3 + tof) * 1e3;
|
|
6055
|
+
const tofUtcSec = (getUtcDate(new Date(tofGpsMs)).getTime() - GPS_EPOCH_MS5) / 1e3;
|
|
6056
|
+
return {
|
|
6057
|
+
system: "R",
|
|
6058
|
+
prn: `R${String(slot).padStart(2, "0")}`,
|
|
6059
|
+
tocDate: getUtcDate(new Date(toeGpsMs)),
|
|
6060
|
+
tauN: -view.getFloat64(p + 100, true),
|
|
6061
|
+
// RINEX stores −τ_n
|
|
6062
|
+
gammaN: view.getFloat64(p + 116, true),
|
|
6063
|
+
messageFrameTime: (tofUtcSec % SEC_PER_WEEK3 + SEC_PER_WEEK3) % SEC_PER_WEEK3,
|
|
6064
|
+
x: view.getFloat64(p + 28, true) / 1e3,
|
|
6065
|
+
y: view.getFloat64(p + 36, true) / 1e3,
|
|
6066
|
+
z: view.getFloat64(p + 44, true) / 1e3,
|
|
6067
|
+
xDot: view.getFloat64(p + 52, true) / 1e3,
|
|
6068
|
+
yDot: view.getFloat64(p + 60, true) / 1e3,
|
|
6069
|
+
zDot: view.getFloat64(p + 68, true) / 1e3,
|
|
6070
|
+
xAcc: view.getFloat64(p + 76, true) / 1e3,
|
|
6071
|
+
yAcc: view.getFloat64(p + 84, true) / 1e3,
|
|
6072
|
+
zAcc: view.getFloat64(p + 92, true) / 1e3,
|
|
6073
|
+
health,
|
|
6074
|
+
freqNum
|
|
6075
|
+
};
|
|
6076
|
+
}
|
|
6077
|
+
function parseNovatelNav(data) {
|
|
6078
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
6079
|
+
const stats = { badCrc: 0 };
|
|
6080
|
+
const ephemerides = [];
|
|
6081
|
+
const lastGps = /* @__PURE__ */ new Map();
|
|
6082
|
+
const lastGlo = /* @__PURE__ */ new Map();
|
|
6083
|
+
for (const frame of oem4Frames(data, view, stats)) {
|
|
6084
|
+
if (!frame.binary) continue;
|
|
6085
|
+
if (frame.id === ID_RAWEPHEM && frame.msgLen >= 102) {
|
|
6086
|
+
const eph = decodeRawEphem(data, view, frame.payload);
|
|
6087
|
+
if (!eph) continue;
|
|
6088
|
+
const prev = lastGps.get(eph.prn);
|
|
6089
|
+
if (prev && prev.iode === eph.iode && prev.tocDate.getTime() === eph.tocDate.getTime()) {
|
|
6090
|
+
continue;
|
|
6091
|
+
}
|
|
6092
|
+
lastGps.set(eph.prn, eph);
|
|
6093
|
+
ephemerides.push(eph);
|
|
6094
|
+
} else if (frame.id === ID_GLOEPHEMERIS && frame.msgLen >= 144) {
|
|
6095
|
+
const eph = decodeGloEphemeris(view, frame.payload);
|
|
6096
|
+
if (!eph) continue;
|
|
6097
|
+
const prev = lastGlo.get(eph.prn);
|
|
6098
|
+
if (prev && Math.abs(prev.tocDate.getTime() - eph.tocDate.getTime()) < 1e3 && prev.health === eph.health) {
|
|
6099
|
+
continue;
|
|
6100
|
+
}
|
|
6101
|
+
lastGlo.set(eph.prn, eph);
|
|
6102
|
+
ephemerides.push(eph);
|
|
6103
|
+
}
|
|
6104
|
+
}
|
|
6105
|
+
return { ephemerides, badCrc: stats.badCrc };
|
|
6106
|
+
}
|
|
6107
|
+
|
|
5428
6108
|
// src/novatel/index.ts
|
|
5429
|
-
var
|
|
5430
|
-
var
|
|
6109
|
+
var GPS_EPOCH_MS6 = Date.UTC(1980, 0, 6);
|
|
6110
|
+
var MS_PER_WEEK5 = 7 * 864e5;
|
|
5431
6111
|
var HDR = 28;
|
|
5432
6112
|
var ID_RANGE = 43;
|
|
5433
6113
|
var ID_RANGECMP = 140;
|
|
5434
|
-
var
|
|
6114
|
+
var ID_GLOEPHEMERIS2 = 723;
|
|
5435
6115
|
var C_LIGHT2 = 299792458;
|
|
5436
6116
|
var ADR_ROLL = 8388608;
|
|
5437
6117
|
function carrierFreq2(sys, code, gloK) {
|
|
@@ -5459,16 +6139,6 @@ function carrierFreq2(sys, code, gloK) {
|
|
|
5459
6139
|
function exsign(v, bits) {
|
|
5460
6140
|
return v & 1 << bits - 1 ? v - 2 ** bits : v;
|
|
5461
6141
|
}
|
|
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
6142
|
var SIGNALS2 = {
|
|
5473
6143
|
0: {
|
|
5474
6144
|
0: ["G", "1C"],
|
|
@@ -5522,7 +6192,7 @@ function parseNovatelRange(data) {
|
|
|
5522
6192
|
const hl = data[j + 3];
|
|
5523
6193
|
const id = view.getUint16(j + 4, true);
|
|
5524
6194
|
const ln = view.getUint16(j + 8, true);
|
|
5525
|
-
if (id !==
|
|
6195
|
+
if (id !== ID_GLOEPHEMERIS2 || hl < HDR || j + hl + ln + 4 > data.length)
|
|
5526
6196
|
continue;
|
|
5527
6197
|
if (crc32(data, j, hl + ln) !== view.getUint32(j + hl + ln, true)) continue;
|
|
5528
6198
|
const slot = view.getUint16(j + hl, true) - 37;
|
|
@@ -5606,7 +6276,7 @@ function parseNovatelRange(data) {
|
|
|
5606
6276
|
if (!codes.includes(code)) codes.push(code);
|
|
5607
6277
|
}
|
|
5608
6278
|
epochs.push({
|
|
5609
|
-
timeMs:
|
|
6279
|
+
timeMs: GPS_EPOCH_MS6 + week * MS_PER_WEEK5 + towMs,
|
|
5610
6280
|
meas
|
|
5611
6281
|
});
|
|
5612
6282
|
}
|
|
@@ -5658,7 +6328,7 @@ function parseNovatelRange(data) {
|
|
|
5658
6328
|
if (!codes.includes(code)) codes.push(code);
|
|
5659
6329
|
}
|
|
5660
6330
|
epochs.push({
|
|
5661
|
-
timeMs:
|
|
6331
|
+
timeMs: GPS_EPOCH_MS6 + week * MS_PER_WEEK5 + towMs,
|
|
5662
6332
|
meas
|
|
5663
6333
|
});
|
|
5664
6334
|
}
|
|
@@ -6017,10 +6687,10 @@ function selectBest(ephs, timeMs) {
|
|
|
6017
6687
|
}
|
|
6018
6688
|
return best;
|
|
6019
6689
|
}
|
|
6020
|
-
var
|
|
6021
|
-
var
|
|
6690
|
+
var GPS_EPOCH_MS7 = START_GPS_TIME.getTime();
|
|
6691
|
+
var MS_PER_WEEK6 = 7 * 864e5;
|
|
6022
6692
|
var BDS_EPOCH_MS = START_BDS_TIME.getTime();
|
|
6023
|
-
var GAL_EPOCH_MS =
|
|
6693
|
+
var GAL_EPOCH_MS = GPS_EPOCH_MS7 + 1024 * MS_PER_WEEK6;
|
|
6024
6694
|
function ephInfoToEphemeris(info) {
|
|
6025
6695
|
const sys = info.prn.charAt(0);
|
|
6026
6696
|
if (sys === "R") {
|
|
@@ -6071,11 +6741,11 @@ function ephInfoToEphemeris(info) {
|
|
|
6071
6741
|
} else if (sys === "E") {
|
|
6072
6742
|
epochMs = GAL_EPOCH_MS;
|
|
6073
6743
|
} else {
|
|
6074
|
-
epochMs =
|
|
6075
|
-
const weeksNow = (info.lastReceived -
|
|
6744
|
+
epochMs = GPS_EPOCH_MS7;
|
|
6745
|
+
const weeksNow = (info.lastReceived - GPS_EPOCH_MS7) / MS_PER_WEEK6;
|
|
6076
6746
|
week += 1024 * Math.round((weeksNow - week) / 1024);
|
|
6077
6747
|
}
|
|
6078
|
-
const tocDate = new Date(epochMs + week *
|
|
6748
|
+
const tocDate = new Date(epochMs + week * MS_PER_WEEK6 + tocSec * 1e3);
|
|
6079
6749
|
return {
|
|
6080
6750
|
system: sys,
|
|
6081
6751
|
prn: info.prn,
|
|
@@ -9028,6 +9698,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
9028
9698
|
MILLISECONDS_IN_WEEK,
|
|
9029
9699
|
MILLISECONDS_TT_TAI,
|
|
9030
9700
|
MultipathAccumulator,
|
|
9701
|
+
OEM4_HLEN,
|
|
9031
9702
|
OMEGA_E,
|
|
9032
9703
|
REFERENCE_FRAMES,
|
|
9033
9704
|
RINEX_CODES,
|
|
@@ -9071,6 +9742,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
9071
9742
|
computeVisibility,
|
|
9072
9743
|
computeVisibilityFromPositions,
|
|
9073
9744
|
connectToMountpoint,
|
|
9745
|
+
crc32,
|
|
9074
9746
|
createGzipLineSink,
|
|
9075
9747
|
createStationMeta,
|
|
9076
9748
|
createStreamStats,
|
|
@@ -9160,6 +9832,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
9160
9832
|
msmEpochToDate,
|
|
9161
9833
|
navTimesFromEph,
|
|
9162
9834
|
nmeaCoordToDecimal,
|
|
9835
|
+
oem4Frames,
|
|
9163
9836
|
padL,
|
|
9164
9837
|
padR,
|
|
9165
9838
|
parseAntex,
|
|
@@ -9167,12 +9840,16 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
9167
9840
|
parseIonex,
|
|
9168
9841
|
parseNavFile,
|
|
9169
9842
|
parseNmeaFile,
|
|
9843
|
+
parseNovatelNav,
|
|
9170
9844
|
parseNovatelRange,
|
|
9171
9845
|
parseRinexStream,
|
|
9846
|
+
parseSbfAlmanac,
|
|
9172
9847
|
parseSbfMeas,
|
|
9848
|
+
parseSbfNav,
|
|
9173
9849
|
parseSinexBiasDcb,
|
|
9174
9850
|
parseSourcetable,
|
|
9175
9851
|
parseSp3,
|
|
9852
|
+
parseUbxNav,
|
|
9176
9853
|
parseUbxRawx,
|
|
9177
9854
|
phiAltBOC,
|
|
9178
9855
|
phiBOCc,
|
|
@@ -9186,6 +9863,8 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
9186
9863
|
rhumbLine,
|
|
9187
9864
|
rtcm3Constellation,
|
|
9188
9865
|
satClockCorrection,
|
|
9866
|
+
sbfCrc16,
|
|
9867
|
+
scanSbfFrames,
|
|
9189
9868
|
selectEphemeris,
|
|
9190
9869
|
setGloFreqNumber,
|
|
9191
9870
|
setRtcm3DebugHandler,
|
|
@@ -9195,6 +9874,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
9195
9874
|
systemCmp,
|
|
9196
9875
|
systemName,
|
|
9197
9876
|
transformFrame,
|
|
9877
|
+
ubxFrames,
|
|
9198
9878
|
updateStationMeta,
|
|
9199
9879
|
updateStreamStats,
|
|
9200
9880
|
verifyChecksum,
|