gnss-js 1.35.0 → 1.37.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/binex.js +2 -2
- package/dist/{chunk-AFEDNWXI.js → chunk-24TKGUTY.js} +310 -111
- package/dist/{chunk-BLGBMRX7.js → chunk-3FG4XVCB.js} +136 -1
- package/dist/{chunk-F4CM6Q4F.js → chunk-5X4AG4MK.js} +2 -2
- package/dist/{chunk-5RNDQQ6J.js → chunk-6SWJTN6H.js} +2 -2
- package/dist/{chunk-OK4GGNOO.js → chunk-D25WNE43.js} +1 -1
- package/dist/{chunk-5AUK42AL.js → chunk-FA2UTLEQ.js} +2 -2
- package/dist/{chunk-IQ5OIMQD.js → chunk-V2D5KUKH.js} +33 -0
- package/dist/{chunk-726LQBGM.js → chunk-YUW33VXK.js} +1 -1
- package/dist/{chunk-FEOMYZEU.js → chunk-ZQDLYLQA.js} +9 -28
- package/dist/index.cjs +480 -132
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +15 -9
- package/dist/novatel.js +3 -3
- package/dist/positioning.cjs +137 -1
- package/dist/positioning.d.cts +62 -1
- package/dist/positioning.d.ts +62 -1
- package/dist/positioning.js +3 -1
- package/dist/rinex.js +3 -3
- package/dist/sbf.cjs +462 -107
- package/dist/sbf.d.cts +103 -14
- package/dist/sbf.d.ts +103 -14
- package/dist/sbf.js +8 -4
- package/dist/ubx.cjs +37 -24
- package/dist/ubx.js +4 -4
- package/package.json +1 -1
package/dist/sbf.cjs
CHANGED
|
@@ -20,11 +20,13 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/sbf/index.ts
|
|
21
21
|
var sbf_exports = {};
|
|
22
22
|
__export(sbf_exports, {
|
|
23
|
+
decodeSbfNavigation: () => decodeSbfNavigation,
|
|
23
24
|
parseSbfAlmanac: () => parseSbfAlmanac,
|
|
24
25
|
parseSbfBdsNav: () => parseSbfBdsNav,
|
|
25
26
|
parseSbfCnav: () => parseSbfCnav,
|
|
26
27
|
parseSbfGalNav: () => parseSbfGalNav,
|
|
27
28
|
parseSbfGloNav: () => parseSbfGloNav,
|
|
29
|
+
parseSbfGpsNav: () => parseSbfGpsNav,
|
|
28
30
|
parseSbfHas: () => parseSbfHas,
|
|
29
31
|
parseSbfIonoUtc: () => parseSbfIonoUtc,
|
|
30
32
|
parseSbfMeas: () => parseSbfMeas,
|
|
@@ -544,6 +546,199 @@ function getBitS(buff, pos, len) {
|
|
|
544
546
|
if (len <= 0 || bits < 2 ** (len - 1)) return bits;
|
|
545
547
|
return bits - 2 ** len;
|
|
546
548
|
}
|
|
549
|
+
function setBitU(buff, pos, len, data) {
|
|
550
|
+
let mask = 2 ** (len - 1);
|
|
551
|
+
for (let i = pos; i < pos + len; i++, mask /= 2) {
|
|
552
|
+
if (data >= mask) {
|
|
553
|
+
buff[i >> 3] |= 1 << 7 - (i & 7);
|
|
554
|
+
data -= mask;
|
|
555
|
+
} else {
|
|
556
|
+
buff[i >> 3] &= ~(1 << 7 - (i & 7));
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
var GpsLnavAssembler = class _GpsLnavAssembler {
|
|
561
|
+
buffers = /* @__PURE__ */ new Map();
|
|
562
|
+
last = /* @__PURE__ */ new Map();
|
|
563
|
+
/** Subframe ID (1–5) from the HOW word of a parity-stripped subframe. */
|
|
564
|
+
static subframeId(subframe) {
|
|
565
|
+
return getBitU(subframe, 43, 3);
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
568
|
+
* Push one parity-stripped 30-byte LNAV subframe for `prn`, resolving
|
|
569
|
+
* the 10-bit week against `refWeek`. See {@link LnavPush} for outcomes.
|
|
570
|
+
*/
|
|
571
|
+
push(prn, subframe, refWeek) {
|
|
572
|
+
const id = _GpsLnavAssembler.subframeId(subframe);
|
|
573
|
+
if (id < 1 || id > 3) return { kind: "skipped" };
|
|
574
|
+
let sf = this.buffers.get(prn);
|
|
575
|
+
if (!sf) {
|
|
576
|
+
sf = { buf: new Uint8Array(90), have: 0 };
|
|
577
|
+
this.buffers.set(prn, sf);
|
|
578
|
+
}
|
|
579
|
+
sf.buf.set(subframe, (id - 1) * 30);
|
|
580
|
+
sf.have |= 1 << id - 1;
|
|
581
|
+
if (id !== 3 || sf.have !== 7) return { kind: "incomplete" };
|
|
582
|
+
const eph = decodeGpsLnavFrame(sf.buf, { prn, refWeek });
|
|
583
|
+
if (!eph) return { kind: "decodeFailed" };
|
|
584
|
+
const prev = this.last.get(prn);
|
|
585
|
+
if (prev && prev.iode === eph.iode && prev.tocDate.getTime() === eph.tocDate.getTime()) {
|
|
586
|
+
return { kind: "duplicate" };
|
|
587
|
+
}
|
|
588
|
+
this.last.set(prn, eph);
|
|
589
|
+
return { kind: "eph", eph };
|
|
590
|
+
}
|
|
591
|
+
};
|
|
592
|
+
function decodeGpsLnavFrame(subframes, opts = {}) {
|
|
593
|
+
if (subframes.length < 90) return null;
|
|
594
|
+
const b = subframes;
|
|
595
|
+
let i = 24;
|
|
596
|
+
const tow1 = getBitU(b, i, 17) * 6;
|
|
597
|
+
i += 17 + 2;
|
|
598
|
+
const id1 = getBitU(b, i, 3);
|
|
599
|
+
i += 3 + 2;
|
|
600
|
+
const week10 = getBitU(b, i, 10);
|
|
601
|
+
i += 10;
|
|
602
|
+
i += 2;
|
|
603
|
+
i += 4;
|
|
604
|
+
const svHealth = getBitU(b, i, 6);
|
|
605
|
+
i += 6;
|
|
606
|
+
const iodc0 = getBitU(b, i, 2);
|
|
607
|
+
i += 2;
|
|
608
|
+
i += 1 + 87;
|
|
609
|
+
const tgdRaw = getBitS(b, i, 8);
|
|
610
|
+
i += 8;
|
|
611
|
+
const iodc1 = getBitU(b, i, 8);
|
|
612
|
+
i += 8;
|
|
613
|
+
const tocSec = getBitU(b, i, 16) * 16;
|
|
614
|
+
i += 16;
|
|
615
|
+
const af2 = getBitS(b, i, 8) * 2 ** -55;
|
|
616
|
+
i += 8;
|
|
617
|
+
const af1 = getBitS(b, i, 16) * 2 ** -43;
|
|
618
|
+
i += 16;
|
|
619
|
+
const af0 = getBitS(b, i, 22) * 2 ** -31;
|
|
620
|
+
i = 240 + 24;
|
|
621
|
+
i += 17 + 2;
|
|
622
|
+
const id2 = getBitU(b, i, 3);
|
|
623
|
+
i += 3 + 2;
|
|
624
|
+
const iode = getBitU(b, i, 8);
|
|
625
|
+
i += 8;
|
|
626
|
+
const crs = getBitS(b, i, 16) * 2 ** -5;
|
|
627
|
+
i += 16;
|
|
628
|
+
const deltaN = getBitS(b, i, 16) * 2 ** -43 * GPS_PI;
|
|
629
|
+
i += 16;
|
|
630
|
+
const m0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
631
|
+
i += 32;
|
|
632
|
+
const cuc = getBitS(b, i, 16) * 2 ** -29;
|
|
633
|
+
i += 16;
|
|
634
|
+
const e = getBitU(b, i, 32) * 2 ** -33;
|
|
635
|
+
i += 32;
|
|
636
|
+
const cus = getBitS(b, i, 16) * 2 ** -29;
|
|
637
|
+
i += 16;
|
|
638
|
+
const sqrtA = getBitU(b, i, 32) * 2 ** -19;
|
|
639
|
+
i += 32;
|
|
640
|
+
const toes = getBitU(b, i, 16) * 16;
|
|
641
|
+
i = 480 + 24;
|
|
642
|
+
i += 17 + 2;
|
|
643
|
+
const id3 = getBitU(b, i, 3);
|
|
644
|
+
i += 3 + 2;
|
|
645
|
+
const cic = getBitS(b, i, 16) * 2 ** -29;
|
|
646
|
+
i += 16;
|
|
647
|
+
const omega0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
648
|
+
i += 32;
|
|
649
|
+
const cis = getBitS(b, i, 16) * 2 ** -29;
|
|
650
|
+
i += 16;
|
|
651
|
+
const i0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
652
|
+
i += 32;
|
|
653
|
+
const crc = getBitS(b, i, 16) * 2 ** -5;
|
|
654
|
+
i += 16;
|
|
655
|
+
const omega = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
656
|
+
i += 32;
|
|
657
|
+
const omegaDot = getBitS(b, i, 24) * 2 ** -43 * GPS_PI;
|
|
658
|
+
i += 24;
|
|
659
|
+
const iode3 = getBitU(b, i, 8);
|
|
660
|
+
i += 8;
|
|
661
|
+
const idot = getBitS(b, i, 14) * 2 ** -43 * GPS_PI;
|
|
662
|
+
const iodc = iodc0 * 256 + iodc1;
|
|
663
|
+
if (id1 !== 1 || id2 !== 2 || id3 !== 3) return null;
|
|
664
|
+
if (iode3 !== iode || iode !== (iodc & 255)) return null;
|
|
665
|
+
const ref = opts.refWeek ?? Math.floor((Date.now() - GPS_EPOCH_MS2) / 1e3 / SEC_PER_WEEK2);
|
|
666
|
+
let week = week10 + 1024 * Math.round((ref - week10) / 1024);
|
|
667
|
+
if (toes < tow1 - 302400) week++;
|
|
668
|
+
else if (toes > tow1 + 302400) week--;
|
|
669
|
+
const prn = opts.prn ?? "G00";
|
|
670
|
+
const tocDate = new Date(
|
|
671
|
+
GPS_EPOCH_MS2 + (week * SEC_PER_WEEK2 + tocSec) * 1e3
|
|
672
|
+
);
|
|
673
|
+
return {
|
|
674
|
+
system: prn[0] === "J" ? "J" : "G",
|
|
675
|
+
prn,
|
|
676
|
+
tocDate,
|
|
677
|
+
// Same seconds-of-week convention as parseNavFile (rinex/nav.ts).
|
|
678
|
+
toc: tocDate.getTime() / 1e3 % SEC_PER_WEEK2,
|
|
679
|
+
af0,
|
|
680
|
+
af1,
|
|
681
|
+
af2,
|
|
682
|
+
iode,
|
|
683
|
+
crs,
|
|
684
|
+
deltaN,
|
|
685
|
+
m0,
|
|
686
|
+
cuc,
|
|
687
|
+
e,
|
|
688
|
+
cus,
|
|
689
|
+
sqrtA,
|
|
690
|
+
toe: toes,
|
|
691
|
+
cic,
|
|
692
|
+
omega0,
|
|
693
|
+
cis,
|
|
694
|
+
i0,
|
|
695
|
+
crc,
|
|
696
|
+
omega,
|
|
697
|
+
omegaDot,
|
|
698
|
+
idot,
|
|
699
|
+
week,
|
|
700
|
+
svHealth,
|
|
701
|
+
tgd: tgdRaw === -128 ? 0 : tgdRaw * 2 ** -31
|
|
702
|
+
// IS-GPS-200: -128 reserved
|
|
703
|
+
};
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
// src/sbf/rawnav-gps.ts
|
|
707
|
+
var WNC_DNU = 65535;
|
|
708
|
+
function extractSbfLnavSubframe(view, b) {
|
|
709
|
+
const sf = new Uint8Array(30);
|
|
710
|
+
for (let k = 0; k < 10; k++) {
|
|
711
|
+
const w = view.getUint32(b + 20 + 4 * k, true);
|
|
712
|
+
setBitU(sf, 24 * k, 24, w >>> 6 & 16777215);
|
|
713
|
+
}
|
|
714
|
+
return sf;
|
|
715
|
+
}
|
|
716
|
+
function feedGpsLnavBlock(view, b, assembler) {
|
|
717
|
+
const prn = svidToPrn(view.getUint8(b + 14));
|
|
718
|
+
if (!prn || prn[0] !== "G" && prn[0] !== "J") return {};
|
|
719
|
+
if (view.getUint8(b + 15) !== 1) return {};
|
|
720
|
+
const wnc = view.getUint16(b + 12, true);
|
|
721
|
+
if (wnc === WNC_DNU) return {};
|
|
722
|
+
const r = assembler.push(prn, extractSbfLnavSubframe(view, b), wnc);
|
|
723
|
+
if (r.kind === "eph") return { eph: r.eph };
|
|
724
|
+
if (r.kind === "decodeFailed") return { badParity: true };
|
|
725
|
+
return {};
|
|
726
|
+
}
|
|
727
|
+
function parseSbfGpsNav(data) {
|
|
728
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
729
|
+
const ephemerides = [];
|
|
730
|
+
const assembler = new GpsLnavAssembler();
|
|
731
|
+
let badParity = 0;
|
|
732
|
+
let messages = 0;
|
|
733
|
+
scanSbfFrames(data, view, (id, b, len) => {
|
|
734
|
+
if (id !== 4017 && id !== 4066 || len < 60) return;
|
|
735
|
+
messages++;
|
|
736
|
+
const r = feedGpsLnavBlock(view, b, assembler);
|
|
737
|
+
if (r.eph) ephemerides.push(r.eph);
|
|
738
|
+
else if (r.badParity) badParity++;
|
|
739
|
+
});
|
|
740
|
+
return { ephemerides, badParity, messages };
|
|
741
|
+
}
|
|
547
742
|
|
|
548
743
|
// src/navbits/cnav.ts
|
|
549
744
|
var GPS_EPOCH_MS3 = Date.UTC(1980, 0, 6);
|
|
@@ -742,37 +937,40 @@ var CnavAssembler = class {
|
|
|
742
937
|
};
|
|
743
938
|
|
|
744
939
|
// src/sbf/rawnav.ts
|
|
745
|
-
var
|
|
940
|
+
var CNAV_SIGNAL_OF_BLOCK = {
|
|
746
941
|
4018: "L2C",
|
|
747
942
|
4019: "L5"
|
|
748
943
|
};
|
|
944
|
+
function newCnavAssemblers() {
|
|
945
|
+
return { L2C: new CnavAssembler(), L5: new CnavAssembler() };
|
|
946
|
+
}
|
|
947
|
+
function feedCnavBlock(view, b, id, asm) {
|
|
948
|
+
const signal = CNAV_SIGNAL_OF_BLOCK[id];
|
|
949
|
+
if (!signal) return {};
|
|
950
|
+
const msg = new Uint8Array(40);
|
|
951
|
+
for (let k = 0; k < 10; k++) {
|
|
952
|
+
const w = view.getUint32(b + 20 + 4 * k, true);
|
|
953
|
+
msg[4 * k] = w >>> 24;
|
|
954
|
+
msg[4 * k + 1] = w >>> 16 & 255;
|
|
955
|
+
msg[4 * k + 2] = w >>> 8 & 255;
|
|
956
|
+
msg[4 * k + 3] = w & 255;
|
|
957
|
+
}
|
|
958
|
+
if (!cnavCrcOk(msg)) return { badCrc: true };
|
|
959
|
+
const eph = asm[signal].push(msg);
|
|
960
|
+
return eph ? { eph: { ...eph, signal } } : {};
|
|
961
|
+
}
|
|
749
962
|
function parseSbfCnav(data) {
|
|
750
963
|
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
751
964
|
const ephemerides = [];
|
|
752
|
-
const
|
|
753
|
-
L2C: new CnavAssembler(),
|
|
754
|
-
L5: new CnavAssembler()
|
|
755
|
-
};
|
|
965
|
+
const asm = newCnavAssemblers();
|
|
756
966
|
let badCrc = 0;
|
|
757
967
|
let messages = 0;
|
|
758
968
|
scanSbfFrames(data, view, (id, b, len) => {
|
|
759
|
-
|
|
760
|
-
if (!signal || len < 60) return;
|
|
969
|
+
if (!CNAV_SIGNAL_OF_BLOCK[id] || len < 60) return;
|
|
761
970
|
messages++;
|
|
762
|
-
const
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
msg[4 * k] = w >>> 24;
|
|
766
|
-
msg[4 * k + 1] = w >>> 16 & 255;
|
|
767
|
-
msg[4 * k + 2] = w >>> 8 & 255;
|
|
768
|
-
msg[4 * k + 3] = w & 255;
|
|
769
|
-
}
|
|
770
|
-
if (!cnavCrcOk(msg)) {
|
|
771
|
-
badCrc++;
|
|
772
|
-
return;
|
|
773
|
-
}
|
|
774
|
-
const eph = assemblers[signal].push(msg);
|
|
775
|
-
if (eph) ephemerides.push({ ...eph, signal });
|
|
971
|
+
const r = feedCnavBlock(view, b, id, asm);
|
|
972
|
+
if (r.eph) ephemerides.push(r.eph);
|
|
973
|
+
else if (r.badCrc) badCrc++;
|
|
776
974
|
});
|
|
777
975
|
return { ephemerides, badCrc, messages };
|
|
778
976
|
}
|
|
@@ -1088,50 +1286,51 @@ var GalFnavAssembler = class {
|
|
|
1088
1286
|
// src/sbf/rawnav-gal.ts
|
|
1089
1287
|
var INAV_SOURCES = [17, 21, 22];
|
|
1090
1288
|
var FNAV_SOURCES = [20, 22];
|
|
1289
|
+
function newGalAssemblers() {
|
|
1290
|
+
return { inav: new GalInavAssembler(), fnav: new GalFnavAssembler() };
|
|
1291
|
+
}
|
|
1292
|
+
function feedGalBlock(data, view, b, id, asm) {
|
|
1293
|
+
const prnStr = svidToPrn(data[b + 14]);
|
|
1294
|
+
if (!prnStr || prnStr[0] !== "E") return {};
|
|
1295
|
+
const prn = parseInt(prnStr.slice(1), 10);
|
|
1296
|
+
const source = data[b + 17] & 31;
|
|
1297
|
+
const page = new Uint8Array(32);
|
|
1298
|
+
for (let k = 0; k < 8; k++) {
|
|
1299
|
+
const w = view.getUint32(b + 20 + 4 * k, true);
|
|
1300
|
+
page[4 * k] = w >>> 24;
|
|
1301
|
+
page[4 * k + 1] = w >>> 16 & 255;
|
|
1302
|
+
page[4 * k + 2] = w >>> 8 & 255;
|
|
1303
|
+
page[4 * k + 3] = w & 255;
|
|
1304
|
+
}
|
|
1305
|
+
let eph;
|
|
1306
|
+
let src;
|
|
1307
|
+
if (id === 4023) {
|
|
1308
|
+
src = "inav";
|
|
1309
|
+
if (!INAV_SOURCES.includes(source)) return {};
|
|
1310
|
+
if (getBitU2(page, 0) !== 0 || getBitU2(page, 114) !== 1) return {};
|
|
1311
|
+
if (!galInavPageCrcOk(page)) return { badCrc: true };
|
|
1312
|
+
eph = asm.inav.push(prn, page);
|
|
1313
|
+
} else {
|
|
1314
|
+
src = "fnav";
|
|
1315
|
+
if (!FNAV_SOURCES.includes(source)) return {};
|
|
1316
|
+
if (isFnavDummy(page)) return {};
|
|
1317
|
+
if (!galFnavPageCrcOk(page)) return { badCrc: true };
|
|
1318
|
+
eph = asm.fnav.push(prn, page);
|
|
1319
|
+
}
|
|
1320
|
+
return eph ? { eph: { ...eph, source: src } } : {};
|
|
1321
|
+
}
|
|
1091
1322
|
function parseSbfGalNav(data) {
|
|
1092
1323
|
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
1093
1324
|
const ephemerides = [];
|
|
1094
|
-
const
|
|
1095
|
-
const fnav = new GalFnavAssembler();
|
|
1325
|
+
const asm = newGalAssemblers();
|
|
1096
1326
|
let badCrc = 0;
|
|
1097
1327
|
let messages = 0;
|
|
1098
1328
|
scanSbfFrames(data, view, (id, b, len) => {
|
|
1099
1329
|
if (id !== 4022 && id !== 4023 || len < 52) return;
|
|
1100
1330
|
messages++;
|
|
1101
|
-
const
|
|
1102
|
-
if (
|
|
1103
|
-
|
|
1104
|
-
const source = data[b + 17] & 31;
|
|
1105
|
-
const page = new Uint8Array(32);
|
|
1106
|
-
for (let k = 0; k < 8; k++) {
|
|
1107
|
-
const w = view.getUint32(b + 20 + 4 * k, true);
|
|
1108
|
-
page[4 * k] = w >>> 24;
|
|
1109
|
-
page[4 * k + 1] = w >>> 16 & 255;
|
|
1110
|
-
page[4 * k + 2] = w >>> 8 & 255;
|
|
1111
|
-
page[4 * k + 3] = w & 255;
|
|
1112
|
-
}
|
|
1113
|
-
let eph;
|
|
1114
|
-
let src;
|
|
1115
|
-
if (id === 4023) {
|
|
1116
|
-
src = "inav";
|
|
1117
|
-
if (!INAV_SOURCES.includes(source)) return;
|
|
1118
|
-
if (getBitU2(page, 0) !== 0 || getBitU2(page, 114) !== 1) return;
|
|
1119
|
-
if (!galInavPageCrcOk(page)) {
|
|
1120
|
-
badCrc++;
|
|
1121
|
-
return;
|
|
1122
|
-
}
|
|
1123
|
-
eph = inav.push(prn, page);
|
|
1124
|
-
} else {
|
|
1125
|
-
src = "fnav";
|
|
1126
|
-
if (!FNAV_SOURCES.includes(source)) return;
|
|
1127
|
-
if (isFnavDummy(page)) return;
|
|
1128
|
-
if (!galFnavPageCrcOk(page)) {
|
|
1129
|
-
badCrc++;
|
|
1130
|
-
return;
|
|
1131
|
-
}
|
|
1132
|
-
eph = fnav.push(prn, page);
|
|
1133
|
-
}
|
|
1134
|
-
if (eph) ephemerides.push({ ...eph, source: src });
|
|
1331
|
+
const r = feedGalBlock(data, view, b, id, asm);
|
|
1332
|
+
if (r.eph) ephemerides.push(r.eph);
|
|
1333
|
+
else if (r.badCrc) badCrc++;
|
|
1135
1334
|
});
|
|
1136
1335
|
return { ephemerides, badCrc, messages };
|
|
1137
1336
|
}
|
|
@@ -1587,7 +1786,26 @@ var GloStringAssembler = class {
|
|
|
1587
1786
|
var GPS_EPOCH_MS6 = Date.UTC(1980, 0, 6);
|
|
1588
1787
|
var MS_PER_WEEK3 = 7 * 86400 * 1e3;
|
|
1589
1788
|
var TOW_DNU = 4294967295;
|
|
1590
|
-
var
|
|
1789
|
+
var WNC_DNU2 = 65535;
|
|
1790
|
+
function feedBdsBlock(view, b, assembler) {
|
|
1791
|
+
const prn = svidToPrn(view.getUint8(b + 14));
|
|
1792
|
+
if (!prn || prn[0] !== "C") return {};
|
|
1793
|
+
const sf = new Uint8Array(38);
|
|
1794
|
+
for (let k = 0; k < 10; k++) {
|
|
1795
|
+
const w = view.getUint32(b + 20 + 4 * k, true);
|
|
1796
|
+
sf[4 * k] = w >>> 24;
|
|
1797
|
+
if (k < 9) {
|
|
1798
|
+
sf[4 * k + 1] = w >>> 16 & 255;
|
|
1799
|
+
sf[4 * k + 2] = w >>> 8 & 255;
|
|
1800
|
+
sf[4 * k + 3] = w & 255;
|
|
1801
|
+
} else {
|
|
1802
|
+
sf[37] = w >>> 16 & 240;
|
|
1803
|
+
}
|
|
1804
|
+
}
|
|
1805
|
+
if (!bdsSubframeParityOk(sf)) return { badCrc: true };
|
|
1806
|
+
const eph = assembler.push(prn, sf);
|
|
1807
|
+
return eph ? { eph } : {};
|
|
1808
|
+
}
|
|
1591
1809
|
function parseSbfBdsNav(data) {
|
|
1592
1810
|
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
1593
1811
|
const ephemerides = [];
|
|
@@ -1597,29 +1815,41 @@ function parseSbfBdsNav(data) {
|
|
|
1597
1815
|
scanSbfFrames(data, view, (id, b, len) => {
|
|
1598
1816
|
if (id !== 4047 || len < 60) return;
|
|
1599
1817
|
messages++;
|
|
1600
|
-
const
|
|
1601
|
-
if (
|
|
1602
|
-
|
|
1603
|
-
for (let k = 0; k < 10; k++) {
|
|
1604
|
-
const w = view.getUint32(b + 20 + 4 * k, true);
|
|
1605
|
-
sf[4 * k] = w >>> 24;
|
|
1606
|
-
if (k < 9) {
|
|
1607
|
-
sf[4 * k + 1] = w >>> 16 & 255;
|
|
1608
|
-
sf[4 * k + 2] = w >>> 8 & 255;
|
|
1609
|
-
sf[4 * k + 3] = w & 255;
|
|
1610
|
-
} else {
|
|
1611
|
-
sf[37] = w >>> 16 & 240;
|
|
1612
|
-
}
|
|
1613
|
-
}
|
|
1614
|
-
if (!bdsSubframeParityOk(sf)) {
|
|
1615
|
-
badCrc++;
|
|
1616
|
-
return;
|
|
1617
|
-
}
|
|
1618
|
-
const eph = assembler.push(prn, sf);
|
|
1619
|
-
if (eph) ephemerides.push(eph);
|
|
1818
|
+
const r = feedBdsBlock(view, b, assembler);
|
|
1819
|
+
if (r.eph) ephemerides.push(r.eph);
|
|
1820
|
+
else if (r.badCrc) badCrc++;
|
|
1620
1821
|
});
|
|
1621
1822
|
return { ephemerides, badCrc, messages };
|
|
1622
1823
|
}
|
|
1824
|
+
function feedGloBlock(view, b, assembler) {
|
|
1825
|
+
const prn = svidToPrn(view.getUint8(b + 14));
|
|
1826
|
+
if (!prn || prn[0] !== "R") return {};
|
|
1827
|
+
const towMs = view.getUint32(b + 8, true);
|
|
1828
|
+
const wnc = view.getUint16(b + 12, true);
|
|
1829
|
+
if (towMs === TOW_DNU || wnc === WNC_DNU2) return {};
|
|
1830
|
+
const str = new Uint8Array(11);
|
|
1831
|
+
for (let k = 0; k < 3; k++) {
|
|
1832
|
+
const w = view.getUint32(b + 20 + 4 * k, true);
|
|
1833
|
+
str[4 * k] = w >>> 24;
|
|
1834
|
+
if (k < 2) {
|
|
1835
|
+
str[4 * k + 1] = w >>> 16 & 255;
|
|
1836
|
+
str[4 * k + 2] = w >>> 8 & 255;
|
|
1837
|
+
str[4 * k + 3] = w & 255;
|
|
1838
|
+
} else {
|
|
1839
|
+
str[9] = w >>> 16 & 255;
|
|
1840
|
+
str[10] = w >>> 8 & 248;
|
|
1841
|
+
}
|
|
1842
|
+
}
|
|
1843
|
+
if (!testGloString(str)) return { badCrc: true };
|
|
1844
|
+
const eph = assembler.push(
|
|
1845
|
+
prn,
|
|
1846
|
+
str,
|
|
1847
|
+
new Date(GPS_EPOCH_MS6 + wnc * MS_PER_WEEK3 + towMs),
|
|
1848
|
+
view.getUint8(b + 18) - 8
|
|
1849
|
+
// FreqNr, offset by 8
|
|
1850
|
+
);
|
|
1851
|
+
return eph ? { eph } : {};
|
|
1852
|
+
}
|
|
1623
1853
|
function parseSbfGloNav(data) {
|
|
1624
1854
|
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
1625
1855
|
const ephemerides = [];
|
|
@@ -1629,38 +1859,161 @@ function parseSbfGloNav(data) {
|
|
|
1629
1859
|
scanSbfFrames(data, view, (id, b, len) => {
|
|
1630
1860
|
if (id !== 4026 || len < 32) return;
|
|
1631
1861
|
messages++;
|
|
1632
|
-
const
|
|
1633
|
-
if (
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1862
|
+
const r = feedGloBlock(view, b, assembler);
|
|
1863
|
+
if (r.eph) ephemerides.push(r.eph);
|
|
1864
|
+
else if (r.badCrc) badCrc++;
|
|
1865
|
+
});
|
|
1866
|
+
return { ephemerides, badCrc, messages };
|
|
1867
|
+
}
|
|
1868
|
+
|
|
1869
|
+
// src/sbf/navigation.ts
|
|
1870
|
+
var F4_DNU3 = -2e10;
|
|
1871
|
+
function ephKey(e) {
|
|
1872
|
+
const source = "source" in e ? e.source : "";
|
|
1873
|
+
return `${e.prn}|${e.tocDate.getTime()}|${source}`;
|
|
1874
|
+
}
|
|
1875
|
+
function decodeSbfNavigation(data) {
|
|
1876
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
1877
|
+
const ephemerides = [];
|
|
1878
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1879
|
+
const cnav = [];
|
|
1880
|
+
const ionoCorrections = {};
|
|
1881
|
+
let leapSeconds = null;
|
|
1882
|
+
const counts = {
|
|
1883
|
+
decodedNav: 0,
|
|
1884
|
+
gpsLnavRaw: 0,
|
|
1885
|
+
cnavRaw: 0,
|
|
1886
|
+
galRaw: 0,
|
|
1887
|
+
gloRaw: 0,
|
|
1888
|
+
bdsRaw: 0,
|
|
1889
|
+
badFrames: 0
|
|
1890
|
+
};
|
|
1891
|
+
const cnavAsm = newCnavAssemblers();
|
|
1892
|
+
const galAsm = newGalAssemblers();
|
|
1893
|
+
const gloAsm = new GloStringAssembler();
|
|
1894
|
+
const bdsAsm = new BdsAssembler();
|
|
1895
|
+
const lnavAsm = new GpsLnavAssembler();
|
|
1896
|
+
const addEph = (e) => {
|
|
1897
|
+
if (!e) return;
|
|
1898
|
+
const key = ephKey(e);
|
|
1899
|
+
if (seen.has(key)) return;
|
|
1900
|
+
seen.add(key);
|
|
1901
|
+
ephemerides.push(e);
|
|
1902
|
+
};
|
|
1903
|
+
const f4s = (b, n) => {
|
|
1904
|
+
const out = [];
|
|
1905
|
+
for (let k = 0; k < n; k++) {
|
|
1906
|
+
const v = view.getFloat32(b + 4 * k, true);
|
|
1907
|
+
if (v === F4_DNU3) return null;
|
|
1908
|
+
out.push(v);
|
|
1649
1909
|
}
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1910
|
+
return out;
|
|
1911
|
+
};
|
|
1912
|
+
scanSbfFrames(data, view, (id, b, len) => {
|
|
1913
|
+
switch (id) {
|
|
1914
|
+
/* ---- decoded ephemeris blocks ---- */
|
|
1915
|
+
case 5891:
|
|
1916
|
+
if (len >= 140) {
|
|
1917
|
+
counts.decodedNav++;
|
|
1918
|
+
addEph(decodeGpsQzsNav(view, b, "G"));
|
|
1919
|
+
}
|
|
1920
|
+
return;
|
|
1921
|
+
case 4095:
|
|
1922
|
+
if (len >= 140) {
|
|
1923
|
+
counts.decodedNav++;
|
|
1924
|
+
addEph(decodeGpsQzsNav(view, b, "J"));
|
|
1925
|
+
}
|
|
1926
|
+
return;
|
|
1927
|
+
case 4002:
|
|
1928
|
+
if (len >= 149) {
|
|
1929
|
+
counts.decodedNav++;
|
|
1930
|
+
addEph(decodeGalNav(view, b));
|
|
1931
|
+
}
|
|
1932
|
+
return;
|
|
1933
|
+
case 4081:
|
|
1934
|
+
if (len >= 140) {
|
|
1935
|
+
counts.decodedNav++;
|
|
1936
|
+
addEph(decodeBdsNav(view, b));
|
|
1937
|
+
}
|
|
1938
|
+
return;
|
|
1939
|
+
case 4004:
|
|
1940
|
+
if (len >= 96) {
|
|
1941
|
+
counts.decodedNav++;
|
|
1942
|
+
addEph(decodeGloNav(view, b));
|
|
1943
|
+
}
|
|
1944
|
+
return;
|
|
1945
|
+
/* ---- raw navigation-frame blocks ---- */
|
|
1946
|
+
case 4017:
|
|
1947
|
+
// GPSRawCA
|
|
1948
|
+
case 4066: {
|
|
1949
|
+
if (len < 60) return;
|
|
1950
|
+
counts.gpsLnavRaw++;
|
|
1951
|
+
const r = feedGpsLnavBlock(view, b, lnavAsm);
|
|
1952
|
+
if (r.eph) addEph(r.eph);
|
|
1953
|
+
else if (r.badParity) counts.badFrames++;
|
|
1954
|
+
return;
|
|
1955
|
+
}
|
|
1956
|
+
case 4018:
|
|
1957
|
+
// GPSRawL2C
|
|
1958
|
+
case 4019: {
|
|
1959
|
+
if (len < 60) return;
|
|
1960
|
+
counts.cnavRaw++;
|
|
1961
|
+
const r = feedCnavBlock(view, b, id, cnavAsm);
|
|
1962
|
+
if (r.eph) cnav.push(r.eph);
|
|
1963
|
+
else if (r.badCrc) counts.badFrames++;
|
|
1964
|
+
return;
|
|
1965
|
+
}
|
|
1966
|
+
case 4022:
|
|
1967
|
+
// GALRawFNAV
|
|
1968
|
+
case 4023: {
|
|
1969
|
+
if (len < 52) return;
|
|
1970
|
+
counts.galRaw++;
|
|
1971
|
+
const r = feedGalBlock(data, view, b, id, galAsm);
|
|
1972
|
+
if (r.eph) addEph(r.eph);
|
|
1973
|
+
else if (r.badCrc) counts.badFrames++;
|
|
1974
|
+
return;
|
|
1975
|
+
}
|
|
1976
|
+
case 4026: {
|
|
1977
|
+
if (len < 32) return;
|
|
1978
|
+
counts.gloRaw++;
|
|
1979
|
+
const r = feedGloBlock(view, b, gloAsm);
|
|
1980
|
+
if (r.eph) addEph(r.eph);
|
|
1981
|
+
else if (r.badCrc) counts.badFrames++;
|
|
1982
|
+
return;
|
|
1983
|
+
}
|
|
1984
|
+
case 4047: {
|
|
1985
|
+
if (len < 60) return;
|
|
1986
|
+
counts.bdsRaw++;
|
|
1987
|
+
const r = feedBdsBlock(view, b, bdsAsm);
|
|
1988
|
+
if (r.eph) addEph(r.eph);
|
|
1989
|
+
else if (r.badCrc) counts.badFrames++;
|
|
1990
|
+
return;
|
|
1991
|
+
}
|
|
1992
|
+
/* ---- iono / UTC ---- */
|
|
1993
|
+
case 5893:
|
|
1994
|
+
// GPSIon
|
|
1995
|
+
case 4120: {
|
|
1996
|
+
if (len < 48) return;
|
|
1997
|
+
const alpha = f4s(b + 16, 4);
|
|
1998
|
+
const beta = f4s(b + 32, 4);
|
|
1999
|
+
if (!alpha || !beta) return;
|
|
2000
|
+
const sys = id === 5893 ? "GPS" : "BDS";
|
|
2001
|
+
ionoCorrections[`${sys}A`] = alpha;
|
|
2002
|
+
ionoCorrections[`${sys}B`] = beta;
|
|
2003
|
+
return;
|
|
2004
|
+
}
|
|
2005
|
+
case 4030: {
|
|
2006
|
+
if (len < 28) return;
|
|
2007
|
+
const ai = f4s(b + 16, 3);
|
|
2008
|
+
if (ai) ionoCorrections["GAL"] = ai;
|
|
2009
|
+
return;
|
|
2010
|
+
}
|
|
2011
|
+
case 5894:
|
|
2012
|
+
if (len >= 37) leapSeconds = view.getInt8(b + 33);
|
|
2013
|
+
return;
|
|
1653
2014
|
}
|
|
1654
|
-
const eph = assembler.push(
|
|
1655
|
-
prn,
|
|
1656
|
-
str,
|
|
1657
|
-
new Date(GPS_EPOCH_MS6 + wnc * MS_PER_WEEK3 + towMs),
|
|
1658
|
-
view.getUint8(b + 18) - 8
|
|
1659
|
-
// FreqNr, offset by 8
|
|
1660
|
-
);
|
|
1661
|
-
if (eph) ephemerides.push(eph);
|
|
1662
2015
|
});
|
|
1663
|
-
return { ephemerides,
|
|
2016
|
+
return { ephemerides, cnav, ionoCorrections, leapSeconds, counts };
|
|
1664
2017
|
}
|
|
1665
2018
|
|
|
1666
2019
|
// src/navbits/rs255.ts
|
|
@@ -2855,11 +3208,13 @@ function parseSbfMeas(data) {
|
|
|
2855
3208
|
}
|
|
2856
3209
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2857
3210
|
0 && (module.exports = {
|
|
3211
|
+
decodeSbfNavigation,
|
|
2858
3212
|
parseSbfAlmanac,
|
|
2859
3213
|
parseSbfBdsNav,
|
|
2860
3214
|
parseSbfCnav,
|
|
2861
3215
|
parseSbfGalNav,
|
|
2862
3216
|
parseSbfGloNav,
|
|
3217
|
+
parseSbfGpsNav,
|
|
2863
3218
|
parseSbfHas,
|
|
2864
3219
|
parseSbfIonoUtc,
|
|
2865
3220
|
parseSbfMeas,
|