gnss-js 1.36.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-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 +343 -131
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +12 -8
- package/dist/novatel.js +3 -3
- 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/binex.js
CHANGED
|
@@ -7,16 +7,18 @@ import {
|
|
|
7
7
|
galFnavPageCrcOk,
|
|
8
8
|
galInavPageCrcOk,
|
|
9
9
|
testGloString
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-FA2UTLEQ.js";
|
|
11
11
|
import {
|
|
12
12
|
CnavAssembler,
|
|
13
13
|
cnavCrcOk,
|
|
14
14
|
crc24q
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-YUW33VXK.js";
|
|
16
16
|
import {
|
|
17
|
+
GpsLnavAssembler,
|
|
17
18
|
getBitS,
|
|
18
|
-
getBitU
|
|
19
|
-
|
|
19
|
+
getBitU,
|
|
20
|
+
setBitU
|
|
21
|
+
} from "./chunk-V2D5KUKH.js";
|
|
20
22
|
import {
|
|
21
23
|
getGpsLeap
|
|
22
24
|
} from "./chunk-HVXYFUCB.js";
|
|
@@ -423,38 +425,78 @@ function parseSbfIonoUtc(data) {
|
|
|
423
425
|
return { ionoCorrections, leapSeconds };
|
|
424
426
|
}
|
|
425
427
|
|
|
428
|
+
// src/sbf/rawnav-gps.ts
|
|
429
|
+
var WNC_DNU = 65535;
|
|
430
|
+
function extractSbfLnavSubframe(view, b) {
|
|
431
|
+
const sf = new Uint8Array(30);
|
|
432
|
+
for (let k = 0; k < 10; k++) {
|
|
433
|
+
const w = view.getUint32(b + 20 + 4 * k, true);
|
|
434
|
+
setBitU(sf, 24 * k, 24, w >>> 6 & 16777215);
|
|
435
|
+
}
|
|
436
|
+
return sf;
|
|
437
|
+
}
|
|
438
|
+
function feedGpsLnavBlock(view, b, assembler) {
|
|
439
|
+
const prn = svidToPrn(view.getUint8(b + 14));
|
|
440
|
+
if (!prn || prn[0] !== "G" && prn[0] !== "J") return {};
|
|
441
|
+
if (view.getUint8(b + 15) !== 1) return {};
|
|
442
|
+
const wnc = view.getUint16(b + 12, true);
|
|
443
|
+
if (wnc === WNC_DNU) return {};
|
|
444
|
+
const r = assembler.push(prn, extractSbfLnavSubframe(view, b), wnc);
|
|
445
|
+
if (r.kind === "eph") return { eph: r.eph };
|
|
446
|
+
if (r.kind === "decodeFailed") return { badParity: true };
|
|
447
|
+
return {};
|
|
448
|
+
}
|
|
449
|
+
function parseSbfGpsNav(data) {
|
|
450
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
451
|
+
const ephemerides = [];
|
|
452
|
+
const assembler = new GpsLnavAssembler();
|
|
453
|
+
let badParity = 0;
|
|
454
|
+
let messages = 0;
|
|
455
|
+
scanSbfFrames(data, view, (id, b, len) => {
|
|
456
|
+
if (id !== 4017 && id !== 4066 || len < 60) return;
|
|
457
|
+
messages++;
|
|
458
|
+
const r = feedGpsLnavBlock(view, b, assembler);
|
|
459
|
+
if (r.eph) ephemerides.push(r.eph);
|
|
460
|
+
else if (r.badParity) badParity++;
|
|
461
|
+
});
|
|
462
|
+
return { ephemerides, badParity, messages };
|
|
463
|
+
}
|
|
464
|
+
|
|
426
465
|
// src/sbf/rawnav.ts
|
|
427
|
-
var
|
|
466
|
+
var CNAV_SIGNAL_OF_BLOCK = {
|
|
428
467
|
4018: "L2C",
|
|
429
468
|
4019: "L5"
|
|
430
469
|
};
|
|
470
|
+
function newCnavAssemblers() {
|
|
471
|
+
return { L2C: new CnavAssembler(), L5: new CnavAssembler() };
|
|
472
|
+
}
|
|
473
|
+
function feedCnavBlock(view, b, id, asm) {
|
|
474
|
+
const signal = CNAV_SIGNAL_OF_BLOCK[id];
|
|
475
|
+
if (!signal) return {};
|
|
476
|
+
const msg = new Uint8Array(40);
|
|
477
|
+
for (let k = 0; k < 10; k++) {
|
|
478
|
+
const w = view.getUint32(b + 20 + 4 * k, true);
|
|
479
|
+
msg[4 * k] = w >>> 24;
|
|
480
|
+
msg[4 * k + 1] = w >>> 16 & 255;
|
|
481
|
+
msg[4 * k + 2] = w >>> 8 & 255;
|
|
482
|
+
msg[4 * k + 3] = w & 255;
|
|
483
|
+
}
|
|
484
|
+
if (!cnavCrcOk(msg)) return { badCrc: true };
|
|
485
|
+
const eph = asm[signal].push(msg);
|
|
486
|
+
return eph ? { eph: { ...eph, signal } } : {};
|
|
487
|
+
}
|
|
431
488
|
function parseSbfCnav(data) {
|
|
432
489
|
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
433
490
|
const ephemerides = [];
|
|
434
|
-
const
|
|
435
|
-
L2C: new CnavAssembler(),
|
|
436
|
-
L5: new CnavAssembler()
|
|
437
|
-
};
|
|
491
|
+
const asm = newCnavAssemblers();
|
|
438
492
|
let badCrc = 0;
|
|
439
493
|
let messages = 0;
|
|
440
494
|
scanSbfFrames(data, view, (id, b, len) => {
|
|
441
|
-
|
|
442
|
-
if (!signal || len < 60) return;
|
|
495
|
+
if (!CNAV_SIGNAL_OF_BLOCK[id] || len < 60) return;
|
|
443
496
|
messages++;
|
|
444
|
-
const
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
msg[4 * k] = w >>> 24;
|
|
448
|
-
msg[4 * k + 1] = w >>> 16 & 255;
|
|
449
|
-
msg[4 * k + 2] = w >>> 8 & 255;
|
|
450
|
-
msg[4 * k + 3] = w & 255;
|
|
451
|
-
}
|
|
452
|
-
if (!cnavCrcOk(msg)) {
|
|
453
|
-
badCrc++;
|
|
454
|
-
return;
|
|
455
|
-
}
|
|
456
|
-
const eph = assemblers[signal].push(msg);
|
|
457
|
-
if (eph) ephemerides.push({ ...eph, signal });
|
|
497
|
+
const r = feedCnavBlock(view, b, id, asm);
|
|
498
|
+
if (r.eph) ephemerides.push(r.eph);
|
|
499
|
+
else if (r.badCrc) badCrc++;
|
|
458
500
|
});
|
|
459
501
|
return { ephemerides, badCrc, messages };
|
|
460
502
|
}
|
|
@@ -462,50 +504,51 @@ function parseSbfCnav(data) {
|
|
|
462
504
|
// src/sbf/rawnav-gal.ts
|
|
463
505
|
var INAV_SOURCES = [17, 21, 22];
|
|
464
506
|
var FNAV_SOURCES = [20, 22];
|
|
507
|
+
function newGalAssemblers() {
|
|
508
|
+
return { inav: new GalInavAssembler(), fnav: new GalFnavAssembler() };
|
|
509
|
+
}
|
|
510
|
+
function feedGalBlock(data, view, b, id, asm) {
|
|
511
|
+
const prnStr = svidToPrn(data[b + 14]);
|
|
512
|
+
if (!prnStr || prnStr[0] !== "E") return {};
|
|
513
|
+
const prn = parseInt(prnStr.slice(1), 10);
|
|
514
|
+
const source = data[b + 17] & 31;
|
|
515
|
+
const page = new Uint8Array(32);
|
|
516
|
+
for (let k = 0; k < 8; k++) {
|
|
517
|
+
const w = view.getUint32(b + 20 + 4 * k, true);
|
|
518
|
+
page[4 * k] = w >>> 24;
|
|
519
|
+
page[4 * k + 1] = w >>> 16 & 255;
|
|
520
|
+
page[4 * k + 2] = w >>> 8 & 255;
|
|
521
|
+
page[4 * k + 3] = w & 255;
|
|
522
|
+
}
|
|
523
|
+
let eph;
|
|
524
|
+
let src;
|
|
525
|
+
if (id === 4023) {
|
|
526
|
+
src = "inav";
|
|
527
|
+
if (!INAV_SOURCES.includes(source)) return {};
|
|
528
|
+
if (getBitU2(page, 0) !== 0 || getBitU2(page, 114) !== 1) return {};
|
|
529
|
+
if (!galInavPageCrcOk(page)) return { badCrc: true };
|
|
530
|
+
eph = asm.inav.push(prn, page);
|
|
531
|
+
} else {
|
|
532
|
+
src = "fnav";
|
|
533
|
+
if (!FNAV_SOURCES.includes(source)) return {};
|
|
534
|
+
if (isFnavDummy(page)) return {};
|
|
535
|
+
if (!galFnavPageCrcOk(page)) return { badCrc: true };
|
|
536
|
+
eph = asm.fnav.push(prn, page);
|
|
537
|
+
}
|
|
538
|
+
return eph ? { eph: { ...eph, source: src } } : {};
|
|
539
|
+
}
|
|
465
540
|
function parseSbfGalNav(data) {
|
|
466
541
|
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
467
542
|
const ephemerides = [];
|
|
468
|
-
const
|
|
469
|
-
const fnav = new GalFnavAssembler();
|
|
543
|
+
const asm = newGalAssemblers();
|
|
470
544
|
let badCrc = 0;
|
|
471
545
|
let messages = 0;
|
|
472
546
|
scanSbfFrames(data, view, (id, b, len) => {
|
|
473
547
|
if (id !== 4022 && id !== 4023 || len < 52) return;
|
|
474
548
|
messages++;
|
|
475
|
-
const
|
|
476
|
-
if (
|
|
477
|
-
|
|
478
|
-
const source = data[b + 17] & 31;
|
|
479
|
-
const page = new Uint8Array(32);
|
|
480
|
-
for (let k = 0; k < 8; k++) {
|
|
481
|
-
const w = view.getUint32(b + 20 + 4 * k, true);
|
|
482
|
-
page[4 * k] = w >>> 24;
|
|
483
|
-
page[4 * k + 1] = w >>> 16 & 255;
|
|
484
|
-
page[4 * k + 2] = w >>> 8 & 255;
|
|
485
|
-
page[4 * k + 3] = w & 255;
|
|
486
|
-
}
|
|
487
|
-
let eph;
|
|
488
|
-
let src;
|
|
489
|
-
if (id === 4023) {
|
|
490
|
-
src = "inav";
|
|
491
|
-
if (!INAV_SOURCES.includes(source)) return;
|
|
492
|
-
if (getBitU2(page, 0) !== 0 || getBitU2(page, 114) !== 1) return;
|
|
493
|
-
if (!galInavPageCrcOk(page)) {
|
|
494
|
-
badCrc++;
|
|
495
|
-
return;
|
|
496
|
-
}
|
|
497
|
-
eph = inav.push(prn, page);
|
|
498
|
-
} else {
|
|
499
|
-
src = "fnav";
|
|
500
|
-
if (!FNAV_SOURCES.includes(source)) return;
|
|
501
|
-
if (isFnavDummy(page)) return;
|
|
502
|
-
if (!galFnavPageCrcOk(page)) {
|
|
503
|
-
badCrc++;
|
|
504
|
-
return;
|
|
505
|
-
}
|
|
506
|
-
eph = fnav.push(prn, page);
|
|
507
|
-
}
|
|
508
|
-
if (eph) ephemerides.push({ ...eph, source: src });
|
|
549
|
+
const r = feedGalBlock(data, view, b, id, asm);
|
|
550
|
+
if (r.eph) ephemerides.push(r.eph);
|
|
551
|
+
else if (r.badCrc) badCrc++;
|
|
509
552
|
});
|
|
510
553
|
return { ephemerides, badCrc, messages };
|
|
511
554
|
}
|
|
@@ -520,7 +563,26 @@ function isFnavDummy(page) {
|
|
|
520
563
|
var GPS_EPOCH_MS2 = Date.UTC(1980, 0, 6);
|
|
521
564
|
var MS_PER_WEEK2 = 7 * 86400 * 1e3;
|
|
522
565
|
var TOW_DNU = 4294967295;
|
|
523
|
-
var
|
|
566
|
+
var WNC_DNU2 = 65535;
|
|
567
|
+
function feedBdsBlock(view, b, assembler) {
|
|
568
|
+
const prn = svidToPrn(view.getUint8(b + 14));
|
|
569
|
+
if (!prn || prn[0] !== "C") return {};
|
|
570
|
+
const sf = new Uint8Array(38);
|
|
571
|
+
for (let k = 0; k < 10; k++) {
|
|
572
|
+
const w = view.getUint32(b + 20 + 4 * k, true);
|
|
573
|
+
sf[4 * k] = w >>> 24;
|
|
574
|
+
if (k < 9) {
|
|
575
|
+
sf[4 * k + 1] = w >>> 16 & 255;
|
|
576
|
+
sf[4 * k + 2] = w >>> 8 & 255;
|
|
577
|
+
sf[4 * k + 3] = w & 255;
|
|
578
|
+
} else {
|
|
579
|
+
sf[37] = w >>> 16 & 240;
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
if (!bdsSubframeParityOk(sf)) return { badCrc: true };
|
|
583
|
+
const eph = assembler.push(prn, sf);
|
|
584
|
+
return eph ? { eph } : {};
|
|
585
|
+
}
|
|
524
586
|
function parseSbfBdsNav(data) {
|
|
525
587
|
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
526
588
|
const ephemerides = [];
|
|
@@ -530,29 +592,41 @@ function parseSbfBdsNav(data) {
|
|
|
530
592
|
scanSbfFrames(data, view, (id, b, len) => {
|
|
531
593
|
if (id !== 4047 || len < 60) return;
|
|
532
594
|
messages++;
|
|
533
|
-
const
|
|
534
|
-
if (
|
|
535
|
-
|
|
536
|
-
for (let k = 0; k < 10; k++) {
|
|
537
|
-
const w = view.getUint32(b + 20 + 4 * k, true);
|
|
538
|
-
sf[4 * k] = w >>> 24;
|
|
539
|
-
if (k < 9) {
|
|
540
|
-
sf[4 * k + 1] = w >>> 16 & 255;
|
|
541
|
-
sf[4 * k + 2] = w >>> 8 & 255;
|
|
542
|
-
sf[4 * k + 3] = w & 255;
|
|
543
|
-
} else {
|
|
544
|
-
sf[37] = w >>> 16 & 240;
|
|
545
|
-
}
|
|
546
|
-
}
|
|
547
|
-
if (!bdsSubframeParityOk(sf)) {
|
|
548
|
-
badCrc++;
|
|
549
|
-
return;
|
|
550
|
-
}
|
|
551
|
-
const eph = assembler.push(prn, sf);
|
|
552
|
-
if (eph) ephemerides.push(eph);
|
|
595
|
+
const r = feedBdsBlock(view, b, assembler);
|
|
596
|
+
if (r.eph) ephemerides.push(r.eph);
|
|
597
|
+
else if (r.badCrc) badCrc++;
|
|
553
598
|
});
|
|
554
599
|
return { ephemerides, badCrc, messages };
|
|
555
600
|
}
|
|
601
|
+
function feedGloBlock(view, b, assembler) {
|
|
602
|
+
const prn = svidToPrn(view.getUint8(b + 14));
|
|
603
|
+
if (!prn || prn[0] !== "R") return {};
|
|
604
|
+
const towMs = view.getUint32(b + 8, true);
|
|
605
|
+
const wnc = view.getUint16(b + 12, true);
|
|
606
|
+
if (towMs === TOW_DNU || wnc === WNC_DNU2) return {};
|
|
607
|
+
const str = new Uint8Array(11);
|
|
608
|
+
for (let k = 0; k < 3; k++) {
|
|
609
|
+
const w = view.getUint32(b + 20 + 4 * k, true);
|
|
610
|
+
str[4 * k] = w >>> 24;
|
|
611
|
+
if (k < 2) {
|
|
612
|
+
str[4 * k + 1] = w >>> 16 & 255;
|
|
613
|
+
str[4 * k + 2] = w >>> 8 & 255;
|
|
614
|
+
str[4 * k + 3] = w & 255;
|
|
615
|
+
} else {
|
|
616
|
+
str[9] = w >>> 16 & 255;
|
|
617
|
+
str[10] = w >>> 8 & 248;
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
if (!testGloString(str)) return { badCrc: true };
|
|
621
|
+
const eph = assembler.push(
|
|
622
|
+
prn,
|
|
623
|
+
str,
|
|
624
|
+
new Date(GPS_EPOCH_MS2 + wnc * MS_PER_WEEK2 + towMs),
|
|
625
|
+
view.getUint8(b + 18) - 8
|
|
626
|
+
// FreqNr, offset by 8
|
|
627
|
+
);
|
|
628
|
+
return eph ? { eph } : {};
|
|
629
|
+
}
|
|
556
630
|
function parseSbfGloNav(data) {
|
|
557
631
|
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
558
632
|
const ephemerides = [];
|
|
@@ -562,38 +636,161 @@ function parseSbfGloNav(data) {
|
|
|
562
636
|
scanSbfFrames(data, view, (id, b, len) => {
|
|
563
637
|
if (id !== 4026 || len < 32) return;
|
|
564
638
|
messages++;
|
|
565
|
-
const
|
|
566
|
-
if (
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
639
|
+
const r = feedGloBlock(view, b, assembler);
|
|
640
|
+
if (r.eph) ephemerides.push(r.eph);
|
|
641
|
+
else if (r.badCrc) badCrc++;
|
|
642
|
+
});
|
|
643
|
+
return { ephemerides, badCrc, messages };
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
// src/sbf/navigation.ts
|
|
647
|
+
var F4_DNU3 = -2e10;
|
|
648
|
+
function ephKey(e) {
|
|
649
|
+
const source = "source" in e ? e.source : "";
|
|
650
|
+
return `${e.prn}|${e.tocDate.getTime()}|${source}`;
|
|
651
|
+
}
|
|
652
|
+
function decodeSbfNavigation(data) {
|
|
653
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
654
|
+
const ephemerides = [];
|
|
655
|
+
const seen = /* @__PURE__ */ new Set();
|
|
656
|
+
const cnav = [];
|
|
657
|
+
const ionoCorrections = {};
|
|
658
|
+
let leapSeconds = null;
|
|
659
|
+
const counts = {
|
|
660
|
+
decodedNav: 0,
|
|
661
|
+
gpsLnavRaw: 0,
|
|
662
|
+
cnavRaw: 0,
|
|
663
|
+
galRaw: 0,
|
|
664
|
+
gloRaw: 0,
|
|
665
|
+
bdsRaw: 0,
|
|
666
|
+
badFrames: 0
|
|
667
|
+
};
|
|
668
|
+
const cnavAsm = newCnavAssemblers();
|
|
669
|
+
const galAsm = newGalAssemblers();
|
|
670
|
+
const gloAsm = new GloStringAssembler();
|
|
671
|
+
const bdsAsm = new BdsAssembler();
|
|
672
|
+
const lnavAsm = new GpsLnavAssembler();
|
|
673
|
+
const addEph = (e) => {
|
|
674
|
+
if (!e) return;
|
|
675
|
+
const key = ephKey(e);
|
|
676
|
+
if (seen.has(key)) return;
|
|
677
|
+
seen.add(key);
|
|
678
|
+
ephemerides.push(e);
|
|
679
|
+
};
|
|
680
|
+
const f4s = (b, n) => {
|
|
681
|
+
const out = [];
|
|
682
|
+
for (let k = 0; k < n; k++) {
|
|
683
|
+
const v = view.getFloat32(b + 4 * k, true);
|
|
684
|
+
if (v === F4_DNU3) return null;
|
|
685
|
+
out.push(v);
|
|
582
686
|
}
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
687
|
+
return out;
|
|
688
|
+
};
|
|
689
|
+
scanSbfFrames(data, view, (id, b, len) => {
|
|
690
|
+
switch (id) {
|
|
691
|
+
/* ---- decoded ephemeris blocks ---- */
|
|
692
|
+
case 5891:
|
|
693
|
+
if (len >= 140) {
|
|
694
|
+
counts.decodedNav++;
|
|
695
|
+
addEph(decodeGpsQzsNav(view, b, "G"));
|
|
696
|
+
}
|
|
697
|
+
return;
|
|
698
|
+
case 4095:
|
|
699
|
+
if (len >= 140) {
|
|
700
|
+
counts.decodedNav++;
|
|
701
|
+
addEph(decodeGpsQzsNav(view, b, "J"));
|
|
702
|
+
}
|
|
703
|
+
return;
|
|
704
|
+
case 4002:
|
|
705
|
+
if (len >= 149) {
|
|
706
|
+
counts.decodedNav++;
|
|
707
|
+
addEph(decodeGalNav(view, b));
|
|
708
|
+
}
|
|
709
|
+
return;
|
|
710
|
+
case 4081:
|
|
711
|
+
if (len >= 140) {
|
|
712
|
+
counts.decodedNav++;
|
|
713
|
+
addEph(decodeBdsNav(view, b));
|
|
714
|
+
}
|
|
715
|
+
return;
|
|
716
|
+
case 4004:
|
|
717
|
+
if (len >= 96) {
|
|
718
|
+
counts.decodedNav++;
|
|
719
|
+
addEph(decodeGloNav(view, b));
|
|
720
|
+
}
|
|
721
|
+
return;
|
|
722
|
+
/* ---- raw navigation-frame blocks ---- */
|
|
723
|
+
case 4017:
|
|
724
|
+
// GPSRawCA
|
|
725
|
+
case 4066: {
|
|
726
|
+
if (len < 60) return;
|
|
727
|
+
counts.gpsLnavRaw++;
|
|
728
|
+
const r = feedGpsLnavBlock(view, b, lnavAsm);
|
|
729
|
+
if (r.eph) addEph(r.eph);
|
|
730
|
+
else if (r.badParity) counts.badFrames++;
|
|
731
|
+
return;
|
|
732
|
+
}
|
|
733
|
+
case 4018:
|
|
734
|
+
// GPSRawL2C
|
|
735
|
+
case 4019: {
|
|
736
|
+
if (len < 60) return;
|
|
737
|
+
counts.cnavRaw++;
|
|
738
|
+
const r = feedCnavBlock(view, b, id, cnavAsm);
|
|
739
|
+
if (r.eph) cnav.push(r.eph);
|
|
740
|
+
else if (r.badCrc) counts.badFrames++;
|
|
741
|
+
return;
|
|
742
|
+
}
|
|
743
|
+
case 4022:
|
|
744
|
+
// GALRawFNAV
|
|
745
|
+
case 4023: {
|
|
746
|
+
if (len < 52) return;
|
|
747
|
+
counts.galRaw++;
|
|
748
|
+
const r = feedGalBlock(data, view, b, id, galAsm);
|
|
749
|
+
if (r.eph) addEph(r.eph);
|
|
750
|
+
else if (r.badCrc) counts.badFrames++;
|
|
751
|
+
return;
|
|
752
|
+
}
|
|
753
|
+
case 4026: {
|
|
754
|
+
if (len < 32) return;
|
|
755
|
+
counts.gloRaw++;
|
|
756
|
+
const r = feedGloBlock(view, b, gloAsm);
|
|
757
|
+
if (r.eph) addEph(r.eph);
|
|
758
|
+
else if (r.badCrc) counts.badFrames++;
|
|
759
|
+
return;
|
|
760
|
+
}
|
|
761
|
+
case 4047: {
|
|
762
|
+
if (len < 60) return;
|
|
763
|
+
counts.bdsRaw++;
|
|
764
|
+
const r = feedBdsBlock(view, b, bdsAsm);
|
|
765
|
+
if (r.eph) addEph(r.eph);
|
|
766
|
+
else if (r.badCrc) counts.badFrames++;
|
|
767
|
+
return;
|
|
768
|
+
}
|
|
769
|
+
/* ---- iono / UTC ---- */
|
|
770
|
+
case 5893:
|
|
771
|
+
// GPSIon
|
|
772
|
+
case 4120: {
|
|
773
|
+
if (len < 48) return;
|
|
774
|
+
const alpha = f4s(b + 16, 4);
|
|
775
|
+
const beta = f4s(b + 32, 4);
|
|
776
|
+
if (!alpha || !beta) return;
|
|
777
|
+
const sys = id === 5893 ? "GPS" : "BDS";
|
|
778
|
+
ionoCorrections[`${sys}A`] = alpha;
|
|
779
|
+
ionoCorrections[`${sys}B`] = beta;
|
|
780
|
+
return;
|
|
781
|
+
}
|
|
782
|
+
case 4030: {
|
|
783
|
+
if (len < 28) return;
|
|
784
|
+
const ai = f4s(b + 16, 3);
|
|
785
|
+
if (ai) ionoCorrections["GAL"] = ai;
|
|
786
|
+
return;
|
|
787
|
+
}
|
|
788
|
+
case 5894:
|
|
789
|
+
if (len >= 37) leapSeconds = view.getInt8(b + 33);
|
|
790
|
+
return;
|
|
586
791
|
}
|
|
587
|
-
const eph = assembler.push(
|
|
588
|
-
prn,
|
|
589
|
-
str,
|
|
590
|
-
new Date(GPS_EPOCH_MS2 + wnc * MS_PER_WEEK2 + towMs),
|
|
591
|
-
view.getUint8(b + 18) - 8
|
|
592
|
-
// FreqNr, offset by 8
|
|
593
|
-
);
|
|
594
|
-
if (eph) ephemerides.push(eph);
|
|
595
792
|
});
|
|
596
|
-
return { ephemerides,
|
|
793
|
+
return { ephemerides, cnav, ionoCorrections, leapSeconds, counts };
|
|
597
794
|
}
|
|
598
795
|
|
|
599
796
|
// src/navbits/rs255.ts
|
|
@@ -1793,10 +1990,12 @@ export {
|
|
|
1793
1990
|
parseSbfNav,
|
|
1794
1991
|
parseSbfAlmanac,
|
|
1795
1992
|
parseSbfIonoUtc,
|
|
1993
|
+
parseSbfGpsNav,
|
|
1796
1994
|
parseSbfCnav,
|
|
1797
1995
|
parseSbfGalNav,
|
|
1798
1996
|
parseSbfBdsNav,
|
|
1799
1997
|
parseSbfGloNav,
|
|
1998
|
+
decodeSbfNavigation,
|
|
1800
1999
|
parseSbfHas,
|
|
1801
2000
|
parseSbfMeas
|
|
1802
2001
|
};
|
|
@@ -25,6 +25,38 @@ function setBitU(buff, pos, len, data) {
|
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
|
+
var GpsLnavAssembler = class _GpsLnavAssembler {
|
|
29
|
+
buffers = /* @__PURE__ */ new Map();
|
|
30
|
+
last = /* @__PURE__ */ new Map();
|
|
31
|
+
/** Subframe ID (1–5) from the HOW word of a parity-stripped subframe. */
|
|
32
|
+
static subframeId(subframe) {
|
|
33
|
+
return getBitU(subframe, 43, 3);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Push one parity-stripped 30-byte LNAV subframe for `prn`, resolving
|
|
37
|
+
* the 10-bit week against `refWeek`. See {@link LnavPush} for outcomes.
|
|
38
|
+
*/
|
|
39
|
+
push(prn, subframe, refWeek) {
|
|
40
|
+
const id = _GpsLnavAssembler.subframeId(subframe);
|
|
41
|
+
if (id < 1 || id > 3) return { kind: "skipped" };
|
|
42
|
+
let sf = this.buffers.get(prn);
|
|
43
|
+
if (!sf) {
|
|
44
|
+
sf = { buf: new Uint8Array(90), have: 0 };
|
|
45
|
+
this.buffers.set(prn, sf);
|
|
46
|
+
}
|
|
47
|
+
sf.buf.set(subframe, (id - 1) * 30);
|
|
48
|
+
sf.have |= 1 << id - 1;
|
|
49
|
+
if (id !== 3 || sf.have !== 7) return { kind: "incomplete" };
|
|
50
|
+
const eph = decodeGpsLnavFrame(sf.buf, { prn, refWeek });
|
|
51
|
+
if (!eph) return { kind: "decodeFailed" };
|
|
52
|
+
const prev = this.last.get(prn);
|
|
53
|
+
if (prev && prev.iode === eph.iode && prev.tocDate.getTime() === eph.tocDate.getTime()) {
|
|
54
|
+
return { kind: "duplicate" };
|
|
55
|
+
}
|
|
56
|
+
this.last.set(prn, eph);
|
|
57
|
+
return { kind: "eph", eph };
|
|
58
|
+
}
|
|
59
|
+
};
|
|
28
60
|
function decodeGpsLnavFrame(subframes, opts = {}) {
|
|
29
61
|
if (subframes.length < 90) return null;
|
|
30
62
|
const b = subframes;
|
|
@@ -144,5 +176,6 @@ export {
|
|
|
144
176
|
getBitU,
|
|
145
177
|
getBitS,
|
|
146
178
|
setBitU,
|
|
179
|
+
GpsLnavAssembler,
|
|
147
180
|
decodeGpsLnavFrame
|
|
148
181
|
};
|
|
@@ -5,17 +5,17 @@ import {
|
|
|
5
5
|
bdsSubframeParityOk,
|
|
6
6
|
galInavPageCrcOk,
|
|
7
7
|
testGloString
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-FA2UTLEQ.js";
|
|
9
9
|
import {
|
|
10
10
|
CnavAssembler,
|
|
11
11
|
cnavCrcOk
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-YUW33VXK.js";
|
|
13
13
|
import {
|
|
14
|
-
|
|
14
|
+
GpsLnavAssembler,
|
|
15
15
|
getBitS,
|
|
16
16
|
getBitU,
|
|
17
17
|
setBitU
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-V2D5KUKH.js";
|
|
19
19
|
|
|
20
20
|
// src/ubx/frame.ts
|
|
21
21
|
function* ubxFrames(data, stats = { badChecksums: 0 }) {
|
|
@@ -92,38 +92,19 @@ function parseUbxNav(data, opts = {}) {
|
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
94
|
if (refWeek === void 0) return { ephemerides, badParity };
|
|
95
|
-
const
|
|
96
|
-
const last = /* @__PURE__ */ new Map();
|
|
95
|
+
const assembler = new GpsLnavAssembler();
|
|
97
96
|
for (const f of ubxFrames(data)) {
|
|
98
97
|
if (f.msgClass !== 2 || f.msgId !== 19) continue;
|
|
99
98
|
const lnav = readLnavSubframe(view, f);
|
|
100
99
|
if (!lnav) continue;
|
|
101
|
-
const { prn,
|
|
100
|
+
const { prn, buff, id } = lnav;
|
|
102
101
|
if (id < 1 || id > 5) {
|
|
103
102
|
badParity++;
|
|
104
103
|
continue;
|
|
105
104
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
if (!sf) {
|
|
110
|
-
sf = { buf: new Uint8Array(90), have: 0 };
|
|
111
|
-
subframes.set(key, sf);
|
|
112
|
-
}
|
|
113
|
-
sf.buf.set(buff, (id - 1) * 30);
|
|
114
|
-
sf.have |= 1 << id - 1;
|
|
115
|
-
if (id !== 3 || sf.have !== 7) continue;
|
|
116
|
-
const eph = decodeGpsLnavFrame(sf.buf, { prn, refWeek });
|
|
117
|
-
if (!eph) {
|
|
118
|
-
badParity++;
|
|
119
|
-
continue;
|
|
120
|
-
}
|
|
121
|
-
const prev = last.get(prn);
|
|
122
|
-
if (prev && prev.iode === eph.iode && prev.tocDate.getTime() === eph.tocDate.getTime()) {
|
|
123
|
-
continue;
|
|
124
|
-
}
|
|
125
|
-
last.set(prn, eph);
|
|
126
|
-
ephemerides.push(eph);
|
|
105
|
+
const r = assembler.push(prn, buff, refWeek);
|
|
106
|
+
if (r.kind === "eph") ephemerides.push(r.eph);
|
|
107
|
+
else if (r.kind === "decodeFailed") badParity++;
|
|
127
108
|
}
|
|
128
109
|
return { ephemerides, badParity };
|
|
129
110
|
}
|