gnss-js 1.66.0 → 2.1.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/README.md +144 -132
- package/dist/{chunk-2CMAFEHI.js → chunk-DWUQRJ37.js} +284 -139
- package/dist/{chunk-REULRNJ5.js → chunk-WVTDVPKA.js} +151 -188
- package/dist/{ephemeris-Ohl6NAfw.d.cts → ephemeris-BAnBLLB9.d.cts} +0 -1
- package/dist/{ephemeris-Ohl6NAfw.d.ts → ephemeris-BAnBLLB9.d.ts} +0 -1
- package/dist/has-BaXnQarR.d.cts +123 -0
- package/dist/has-BaXnQarR.d.ts +123 -0
- package/dist/index.cjs +444 -331
- package/dist/index.d.cts +5 -4
- package/dist/index.d.ts +5 -4
- package/dist/index.js +14 -4
- package/dist/orbit.d.cts +1 -1
- package/dist/orbit.d.ts +1 -1
- package/dist/positioning.cjs +286 -137
- package/dist/positioning.d.cts +162 -3
- package/dist/positioning.d.ts +162 -3
- package/dist/positioning.js +9 -1
- package/dist/rtcm3.cjs +181 -217
- package/dist/rtcm3.d.cts +28 -15
- package/dist/rtcm3.d.ts +28 -15
- package/dist/rtcm3.js +5 -3
- package/dist/sbf.d.cts +2 -123
- package/dist/sbf.d.ts +2 -123
- package/package.json +1 -1
|
@@ -59,9 +59,6 @@ var BitReader = class {
|
|
|
59
59
|
skip(n) {
|
|
60
60
|
this.bitPos += n;
|
|
61
61
|
}
|
|
62
|
-
get bitsLeft() {
|
|
63
|
-
return this.data.length * 8 - this.bitPos;
|
|
64
|
-
}
|
|
65
62
|
};
|
|
66
63
|
function crc24q(data, length) {
|
|
67
64
|
let crc = 0;
|
|
@@ -563,7 +560,7 @@ function decodeEphemeris(frame) {
|
|
|
563
560
|
}
|
|
564
561
|
}
|
|
565
562
|
|
|
566
|
-
// src/rtcm3/
|
|
563
|
+
// src/rtcm3/ssr-common.ts
|
|
567
564
|
var UPDATE_INTERVAL_S = [
|
|
568
565
|
1,
|
|
569
566
|
2,
|
|
@@ -582,6 +579,28 @@ var UPDATE_INTERVAL_S = [
|
|
|
582
579
|
7200,
|
|
583
580
|
10800
|
|
584
581
|
];
|
|
582
|
+
function ssrUraMm(v) {
|
|
583
|
+
if (v === 0) return null;
|
|
584
|
+
const cls = v >> 3 & 7;
|
|
585
|
+
const val = v & 7;
|
|
586
|
+
return 3 ** cls * (1 + val / 4) - 1;
|
|
587
|
+
}
|
|
588
|
+
function readSsrOrbit(r, sat) {
|
|
589
|
+
sat.iode = r.readU(8);
|
|
590
|
+
sat.deltaRadial = r.readS(22) * 1e-4;
|
|
591
|
+
sat.deltaAlongTrack = r.readS(20) * 4e-4;
|
|
592
|
+
sat.deltaCrossTrack = r.readS(20) * 4e-4;
|
|
593
|
+
sat.dotRadial = r.readS(21) * 1e-6;
|
|
594
|
+
sat.dotAlongTrack = r.readS(19) * 4e-6;
|
|
595
|
+
sat.dotCrossTrack = r.readS(19) * 4e-6;
|
|
596
|
+
}
|
|
597
|
+
function readSsrClock(r, sat) {
|
|
598
|
+
sat.c0 = r.readS(22) * 1e-4;
|
|
599
|
+
sat.c1 = r.readS(21) * 1e-6;
|
|
600
|
+
sat.c2 = r.readS(27) * 2e-8;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
// src/rtcm3/igs-ssr.ts
|
|
585
604
|
var SYSTEM_BY_BASE = {
|
|
586
605
|
20: "G",
|
|
587
606
|
40: "R",
|
|
@@ -605,12 +624,6 @@ function prnFor(system, id) {
|
|
|
605
624
|
if (system === "S") return `S${two(19 + id)}`;
|
|
606
625
|
return `${system}${two(id)}`;
|
|
607
626
|
}
|
|
608
|
-
function ssrUraMm(v) {
|
|
609
|
-
if (v === 0) return null;
|
|
610
|
-
const cls = v >> 3 & 7;
|
|
611
|
-
const val = v & 7;
|
|
612
|
-
return 3 ** cls * (1 + val / 4) - 1;
|
|
613
|
-
}
|
|
614
627
|
function decodeIgsSsr(frame) {
|
|
615
628
|
if (frame.messageType !== 4076) return null;
|
|
616
629
|
const r = new BitReader(frame.payload);
|
|
@@ -637,26 +650,12 @@ function decodeIgsSsr(frame) {
|
|
|
637
650
|
mwConsistency = r.readU(1) === 1;
|
|
638
651
|
}
|
|
639
652
|
const nsat = r.readU(6);
|
|
640
|
-
const readOrbit = (s) => {
|
|
641
|
-
s.iode = r.readU(8);
|
|
642
|
-
s.deltaRadial = r.readS(22) * 1e-4;
|
|
643
|
-
s.deltaAlongTrack = r.readS(20) * 4e-4;
|
|
644
|
-
s.deltaCrossTrack = r.readS(20) * 4e-4;
|
|
645
|
-
s.dotRadial = r.readS(21) * 1e-6;
|
|
646
|
-
s.dotAlongTrack = r.readS(19) * 4e-6;
|
|
647
|
-
s.dotCrossTrack = r.readS(19) * 4e-6;
|
|
648
|
-
};
|
|
649
|
-
const readClock = (s) => {
|
|
650
|
-
s.c0 = r.readS(22) * 1e-4;
|
|
651
|
-
s.c1 = r.readS(21) * 1e-6;
|
|
652
|
-
s.c2 = r.readS(27) * 2e-8;
|
|
653
|
-
};
|
|
654
653
|
const satellites = [];
|
|
655
654
|
for (let i = 0; i < nsat; i++) {
|
|
656
655
|
const id = r.readU(6);
|
|
657
656
|
const sat = { prn: prnFor(system, id) };
|
|
658
|
-
if (kind === "orbit" || kind === "combined")
|
|
659
|
-
if (kind === "clock" || kind === "combined")
|
|
657
|
+
if (kind === "orbit" || kind === "combined") readSsrOrbit(r, sat);
|
|
658
|
+
if (kind === "clock" || kind === "combined") readSsrClock(r, sat);
|
|
660
659
|
else if (kind === "ura")
|
|
661
660
|
sat.uraMm = ssrUraMm(r.readU(6));
|
|
662
661
|
else if (kind === "highRateClock")
|
|
@@ -749,116 +748,6 @@ function decodeIono(r, version, im) {
|
|
|
749
748
|
};
|
|
750
749
|
}
|
|
751
750
|
|
|
752
|
-
// src/rtcm3/legacy-obs.ts
|
|
753
|
-
var PRUNIT_GPS = 299792.458;
|
|
754
|
-
var PRUNIT_GLO = 599584.916;
|
|
755
|
-
var LAM_GPS_L1 = C_LIGHT / 157542e4;
|
|
756
|
-
var LAM_GPS_L2 = C_LIGHT / 12276e5;
|
|
757
|
-
var PPR_INVALID = -(2 ** 19);
|
|
758
|
-
var PR21_INVALID = -(2 ** 13);
|
|
759
|
-
function legacyLockSec(i) {
|
|
760
|
-
if (i < 24) return i;
|
|
761
|
-
if (i < 48) return 2 * i - 24;
|
|
762
|
-
if (i < 72) return 4 * i - 120;
|
|
763
|
-
if (i < 96) return 8 * i - 408;
|
|
764
|
-
if (i < 120) return 16 * i - 1176;
|
|
765
|
-
if (i < 127) return 32 * i - 3096;
|
|
766
|
-
return 937;
|
|
767
|
-
}
|
|
768
|
-
var two2 = (n) => n.toString().padStart(2, "0");
|
|
769
|
-
function decodeLegacyObs(frame) {
|
|
770
|
-
const type = frame.messageType;
|
|
771
|
-
const gps = type >= 1001 && type <= 1004;
|
|
772
|
-
const glo = type >= 1009 && type <= 1012;
|
|
773
|
-
if (!gps && !glo) return null;
|
|
774
|
-
const ext = type === 1002 || type === 1004 || type === 1010 || type === 1012;
|
|
775
|
-
const dual = type === 1003 || type === 1004 || type === 1011 || type === 1012;
|
|
776
|
-
const system = gps ? "G" : "R";
|
|
777
|
-
const r = new BitReader(frame.payload);
|
|
778
|
-
r.readU(12);
|
|
779
|
-
r.readU(12);
|
|
780
|
-
let epochMs;
|
|
781
|
-
let nsat;
|
|
782
|
-
if (gps) {
|
|
783
|
-
epochMs = r.readU(30);
|
|
784
|
-
r.readU(1);
|
|
785
|
-
nsat = r.readU(5);
|
|
786
|
-
r.readU(1);
|
|
787
|
-
r.readU(3);
|
|
788
|
-
} else {
|
|
789
|
-
const tk = r.readU(27);
|
|
790
|
-
r.readU(1);
|
|
791
|
-
nsat = r.readU(5);
|
|
792
|
-
r.readU(1);
|
|
793
|
-
r.readU(3);
|
|
794
|
-
const gloDow = new Date(Date.now() + 3 * 36e5).getUTCDay();
|
|
795
|
-
epochMs = (gloDow << 27 | tk) >>> 0;
|
|
796
|
-
}
|
|
797
|
-
const observations = [];
|
|
798
|
-
for (let s = 0; s < nsat; s++) {
|
|
799
|
-
const satId = r.readU(6);
|
|
800
|
-
const code1 = r.readU(1);
|
|
801
|
-
const freqCh = glo ? r.readU(5) : 0;
|
|
802
|
-
const pr1raw = r.readU(gps ? 24 : 25);
|
|
803
|
-
const ppr1 = r.readS(20);
|
|
804
|
-
const lock1 = r.readU(7);
|
|
805
|
-
let amb = 0;
|
|
806
|
-
let cnr1 = 0;
|
|
807
|
-
if (ext) {
|
|
808
|
-
amb = r.readU(gps ? 8 : 7);
|
|
809
|
-
cnr1 = r.readU(8);
|
|
810
|
-
}
|
|
811
|
-
let code2 = 0;
|
|
812
|
-
let pr21 = 0;
|
|
813
|
-
let ppr2 = 0;
|
|
814
|
-
let lock2 = 0;
|
|
815
|
-
let cnr2 = 0;
|
|
816
|
-
if (dual) {
|
|
817
|
-
code2 = r.readU(2);
|
|
818
|
-
pr21 = r.readS(14);
|
|
819
|
-
ppr2 = r.readS(20);
|
|
820
|
-
lock2 = r.readU(7);
|
|
821
|
-
if (ext) cnr2 = r.readU(8);
|
|
822
|
-
}
|
|
823
|
-
if (gps && (satId < 1 || satId > 32)) continue;
|
|
824
|
-
if (glo && (satId < 1 || satId > 24)) continue;
|
|
825
|
-
const prunit = gps ? PRUNIT_GPS : PRUNIT_GLO;
|
|
826
|
-
const pr1 = pr1raw * 0.02 + amb * prunit;
|
|
827
|
-
const k = freqCh - 7;
|
|
828
|
-
const lamL1 = gps ? LAM_GPS_L1 : C_LIGHT / (GLO_F1_BASE + k * GLO_F1_STEP);
|
|
829
|
-
const lamL2 = gps ? LAM_GPS_L2 : C_LIGHT / (GLO_F2_BASE + k * GLO_F2_STEP);
|
|
830
|
-
const signals = [];
|
|
831
|
-
{
|
|
832
|
-
const sig = {
|
|
833
|
-
rinexCode: gps ? code1 ? "1W" : "1C" : code1 ? "1P" : "1C",
|
|
834
|
-
pseudorange: pr1,
|
|
835
|
-
wavelength: lamL1,
|
|
836
|
-
lockTime: legacyLockSec(lock1)
|
|
837
|
-
};
|
|
838
|
-
if (ppr1 !== PPR_INVALID) sig.phase = (pr1 + ppr1 * 5e-4) / lamL1;
|
|
839
|
-
if (ext && cnr1 > 0) sig.cn0 = cnr1 * 0.25;
|
|
840
|
-
signals.push(sig);
|
|
841
|
-
}
|
|
842
|
-
if (dual) {
|
|
843
|
-
const sig = {
|
|
844
|
-
rinexCode: gps ? code2 === 0 ? "2X" : "2W" : code2 === 0 ? "2C" : "2P",
|
|
845
|
-
wavelength: lamL2,
|
|
846
|
-
lockTime: legacyLockSec(lock2)
|
|
847
|
-
};
|
|
848
|
-
if (pr21 !== PR21_INVALID) sig.pseudorange = pr1 + pr21 * 0.02;
|
|
849
|
-
if (ppr2 !== PPR_INVALID) sig.phase = (pr1 + ppr2 * 5e-4) / lamL2;
|
|
850
|
-
if (ext && cnr2 > 0) sig.cn0 = cnr2 * 0.25;
|
|
851
|
-
signals.push(sig);
|
|
852
|
-
}
|
|
853
|
-
observations.push({
|
|
854
|
-
prn: `${system}${two2(satId)}`,
|
|
855
|
-
system,
|
|
856
|
-
signals
|
|
857
|
-
});
|
|
858
|
-
}
|
|
859
|
-
return { messageType: type, epochMs, system, observations };
|
|
860
|
-
}
|
|
861
|
-
|
|
862
751
|
// src/rtcm3/msm.ts
|
|
863
752
|
var GPS_L1 = FREQ.G["1"];
|
|
864
753
|
var GPS_L2 = FREQ.G["2"];
|
|
@@ -1357,7 +1246,7 @@ function decodeMsmFull(frame) {
|
|
|
1357
1246
|
}
|
|
1358
1247
|
var GPS_EPOCH = START_GPS_TIME.getTime();
|
|
1359
1248
|
var MS_PER_WEEK = MILLISECONDS_IN_WEEK;
|
|
1360
|
-
function
|
|
1249
|
+
function obsEpochToDate(sys, epochMs, refTime = /* @__PURE__ */ new Date()) {
|
|
1361
1250
|
const refMs = refTime.getTime();
|
|
1362
1251
|
if (sys === "R") {
|
|
1363
1252
|
const dayOfWeek = epochMs >>> 27 & 7;
|
|
@@ -1393,25 +1282,120 @@ function resetGloFreqCache() {
|
|
|
1393
1282
|
gloFreqNum.fill(-128);
|
|
1394
1283
|
}
|
|
1395
1284
|
|
|
1285
|
+
// src/rtcm3/legacy-obs.ts
|
|
1286
|
+
var PRUNIT_GPS = 299792.458;
|
|
1287
|
+
var PRUNIT_GLO = 599584.916;
|
|
1288
|
+
var LAM_GPS_L1 = C_LIGHT / 157542e4;
|
|
1289
|
+
var LAM_GPS_L2 = C_LIGHT / 12276e5;
|
|
1290
|
+
var PPR_INVALID = -(2 ** 19);
|
|
1291
|
+
var PR21_INVALID = -(2 ** 13);
|
|
1292
|
+
function legacyLockSec(i) {
|
|
1293
|
+
if (i < 24) return i;
|
|
1294
|
+
if (i < 48) return 2 * i - 24;
|
|
1295
|
+
if (i < 72) return 4 * i - 120;
|
|
1296
|
+
if (i < 96) return 8 * i - 408;
|
|
1297
|
+
if (i < 120) return 16 * i - 1176;
|
|
1298
|
+
if (i < 127) return 32 * i - 3096;
|
|
1299
|
+
return 937;
|
|
1300
|
+
}
|
|
1301
|
+
var two2 = (n) => n.toString().padStart(2, "0");
|
|
1302
|
+
function decodeLegacyObs(frame) {
|
|
1303
|
+
const type = frame.messageType;
|
|
1304
|
+
const gps = type >= 1001 && type <= 1004;
|
|
1305
|
+
const glo = type >= 1009 && type <= 1012;
|
|
1306
|
+
if (!gps && !glo) return null;
|
|
1307
|
+
const ext = type === 1002 || type === 1004 || type === 1010 || type === 1012;
|
|
1308
|
+
const dual = type === 1003 || type === 1004 || type === 1011 || type === 1012;
|
|
1309
|
+
const system = gps ? "G" : "R";
|
|
1310
|
+
const r = new BitReader(frame.payload);
|
|
1311
|
+
r.readU(12);
|
|
1312
|
+
r.readU(12);
|
|
1313
|
+
let epochMs;
|
|
1314
|
+
let nsat;
|
|
1315
|
+
if (gps) {
|
|
1316
|
+
epochMs = r.readU(30);
|
|
1317
|
+
r.readU(1);
|
|
1318
|
+
nsat = r.readU(5);
|
|
1319
|
+
r.readU(1);
|
|
1320
|
+
r.readU(3);
|
|
1321
|
+
} else {
|
|
1322
|
+
const tk = r.readU(27);
|
|
1323
|
+
r.readU(1);
|
|
1324
|
+
nsat = r.readU(5);
|
|
1325
|
+
r.readU(1);
|
|
1326
|
+
r.readU(3);
|
|
1327
|
+
const gloDow = new Date(Date.now() + 3 * 36e5).getUTCDay();
|
|
1328
|
+
epochMs = (gloDow << 27 | tk) >>> 0;
|
|
1329
|
+
}
|
|
1330
|
+
const observations = [];
|
|
1331
|
+
for (let s = 0; s < nsat; s++) {
|
|
1332
|
+
const satId = r.readU(6);
|
|
1333
|
+
const code1 = r.readU(1);
|
|
1334
|
+
const freqCh = glo ? r.readU(5) : 0;
|
|
1335
|
+
const pr1raw = r.readU(gps ? 24 : 25);
|
|
1336
|
+
const ppr1 = r.readS(20);
|
|
1337
|
+
const lock1 = r.readU(7);
|
|
1338
|
+
let amb = 0;
|
|
1339
|
+
let cnr1 = 0;
|
|
1340
|
+
if (ext) {
|
|
1341
|
+
amb = r.readU(gps ? 8 : 7);
|
|
1342
|
+
cnr1 = r.readU(8);
|
|
1343
|
+
}
|
|
1344
|
+
let code2 = 0;
|
|
1345
|
+
let pr21 = 0;
|
|
1346
|
+
let ppr2 = 0;
|
|
1347
|
+
let lock2 = 0;
|
|
1348
|
+
let cnr2 = 0;
|
|
1349
|
+
if (dual) {
|
|
1350
|
+
code2 = r.readU(2);
|
|
1351
|
+
pr21 = r.readS(14);
|
|
1352
|
+
ppr2 = r.readS(20);
|
|
1353
|
+
lock2 = r.readU(7);
|
|
1354
|
+
if (ext) cnr2 = r.readU(8);
|
|
1355
|
+
}
|
|
1356
|
+
if (gps && (satId < 1 || satId > 32)) continue;
|
|
1357
|
+
if (glo && (satId < 1 || satId > 24)) continue;
|
|
1358
|
+
const prunit = gps ? PRUNIT_GPS : PRUNIT_GLO;
|
|
1359
|
+
const pr1 = pr1raw * 0.02 + amb * prunit;
|
|
1360
|
+
const k = freqCh - 7;
|
|
1361
|
+
const lamL1 = gps ? LAM_GPS_L1 : C_LIGHT / (GLO_F1_BASE + k * GLO_F1_STEP);
|
|
1362
|
+
const lamL2 = gps ? LAM_GPS_L2 : C_LIGHT / (GLO_F2_BASE + k * GLO_F2_STEP);
|
|
1363
|
+
const signals = [];
|
|
1364
|
+
{
|
|
1365
|
+
const sig = {
|
|
1366
|
+
rinexCode: gps ? code1 ? "1W" : "1C" : code1 ? "1P" : "1C",
|
|
1367
|
+
pseudorange: pr1,
|
|
1368
|
+
wavelength: lamL1,
|
|
1369
|
+
lockTime: legacyLockSec(lock1)
|
|
1370
|
+
};
|
|
1371
|
+
if (ppr1 !== PPR_INVALID) sig.phase = (pr1 + ppr1 * 5e-4) / lamL1;
|
|
1372
|
+
if (ext && cnr1 > 0) sig.cn0 = cnr1 * 0.25;
|
|
1373
|
+
signals.push(sig);
|
|
1374
|
+
}
|
|
1375
|
+
if (dual) {
|
|
1376
|
+
const sig = {
|
|
1377
|
+
rinexCode: gps ? code2 === 0 ? "2X" : "2W" : code2 === 0 ? "2C" : "2P",
|
|
1378
|
+
wavelength: lamL2,
|
|
1379
|
+
lockTime: legacyLockSec(lock2)
|
|
1380
|
+
};
|
|
1381
|
+
if (pr21 !== PR21_INVALID) sig.pseudorange = pr1 + pr21 * 0.02;
|
|
1382
|
+
if (ppr2 !== PPR_INVALID) sig.phase = (pr1 + ppr2 * 5e-4) / lamL2;
|
|
1383
|
+
if (ext && cnr2 > 0) sig.cn0 = cnr2 * 0.25;
|
|
1384
|
+
signals.push(sig);
|
|
1385
|
+
}
|
|
1386
|
+
observations.push({
|
|
1387
|
+
prn: `${system}${two2(satId)}`,
|
|
1388
|
+
system,
|
|
1389
|
+
signals
|
|
1390
|
+
});
|
|
1391
|
+
}
|
|
1392
|
+
return { messageType: type, epochMs, system, observations };
|
|
1393
|
+
}
|
|
1394
|
+
function decodeObs(frame) {
|
|
1395
|
+
return decodeMsmFull(frame) ?? decodeLegacyObs(frame);
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1396
1398
|
// src/rtcm3/ssr.ts
|
|
1397
|
-
var UPDATE_INTERVAL_S2 = [
|
|
1398
|
-
1,
|
|
1399
|
-
2,
|
|
1400
|
-
5,
|
|
1401
|
-
10,
|
|
1402
|
-
15,
|
|
1403
|
-
30,
|
|
1404
|
-
60,
|
|
1405
|
-
120,
|
|
1406
|
-
240,
|
|
1407
|
-
300,
|
|
1408
|
-
600,
|
|
1409
|
-
900,
|
|
1410
|
-
1800,
|
|
1411
|
-
3600,
|
|
1412
|
-
7200,
|
|
1413
|
-
10800
|
|
1414
|
-
];
|
|
1415
1399
|
var GPS_SIGNAL = {
|
|
1416
1400
|
0: "L1 C/A",
|
|
1417
1401
|
1: "L1 P",
|
|
@@ -1446,12 +1430,6 @@ var SSR_KIND = {
|
|
|
1446
1430
|
1067: { system: "R", kind: "ura" },
|
|
1447
1431
|
1068: { system: "R", kind: "highRateClock" }
|
|
1448
1432
|
};
|
|
1449
|
-
function ssrUraMm2(v) {
|
|
1450
|
-
if (v === 0) return null;
|
|
1451
|
-
const cls = v >> 3 & 7;
|
|
1452
|
-
const val = v & 7;
|
|
1453
|
-
return 3 ** cls * (1 + val / 4) - 1;
|
|
1454
|
-
}
|
|
1455
1433
|
var two3 = (n) => n.toString().padStart(2, "0");
|
|
1456
1434
|
function decodeSsr(frame) {
|
|
1457
1435
|
const spec = SSR_KIND[frame.messageType];
|
|
@@ -1461,7 +1439,7 @@ function decodeSsr(frame) {
|
|
|
1461
1439
|
const r = new BitReader(frame.payload);
|
|
1462
1440
|
r.readU(12);
|
|
1463
1441
|
const epochS = r.readU(gps ? 20 : 17);
|
|
1464
|
-
const updateIntervalS =
|
|
1442
|
+
const updateIntervalS = UPDATE_INTERVAL_S[r.readU(4)];
|
|
1465
1443
|
const multipleMessage = r.readU(1) === 1;
|
|
1466
1444
|
const hasDatum = kind === "orbit" || kind === "combined";
|
|
1467
1445
|
const referenceDatum = hasDatum ? r.readU(1) : void 0;
|
|
@@ -1471,30 +1449,14 @@ function decodeSsr(frame) {
|
|
|
1471
1449
|
const nsat = r.readU(6);
|
|
1472
1450
|
const sigName = gps ? GPS_SIGNAL : GLO_SIGNAL;
|
|
1473
1451
|
const satellites = [];
|
|
1474
|
-
const readOrbit = (sat) => {
|
|
1475
|
-
sat.deltaRadial = r.readS(22) * 1e-4;
|
|
1476
|
-
sat.deltaAlongTrack = r.readS(20) * 4e-4;
|
|
1477
|
-
sat.deltaCrossTrack = r.readS(20) * 4e-4;
|
|
1478
|
-
sat.dotRadial = r.readS(21) * 1e-6;
|
|
1479
|
-
sat.dotAlongTrack = r.readS(19) * 4e-6;
|
|
1480
|
-
sat.dotCrossTrack = r.readS(19) * 4e-6;
|
|
1481
|
-
};
|
|
1482
|
-
const readClock = (sat) => {
|
|
1483
|
-
sat.c0 = r.readS(22) * 1e-4;
|
|
1484
|
-
sat.c1 = r.readS(21) * 1e-6;
|
|
1485
|
-
sat.c2 = r.readS(27) * 2e-8;
|
|
1486
|
-
};
|
|
1487
1452
|
for (let i = 0; i < nsat; i++) {
|
|
1488
1453
|
const satId = gps ? r.readU(6) : r.readU(5);
|
|
1489
1454
|
const sat = { prn: `${system}${two3(satId)}` };
|
|
1490
|
-
if (kind === "orbit" || kind === "combined")
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
}
|
|
1494
|
-
if (kind === "combined") readClock(sat);
|
|
1495
|
-
else if (kind === "clock") readClock(sat);
|
|
1455
|
+
if (kind === "orbit" || kind === "combined") readSsrOrbit(r, sat);
|
|
1456
|
+
if (kind === "combined") readSsrClock(r, sat);
|
|
1457
|
+
else if (kind === "clock") readSsrClock(r, sat);
|
|
1496
1458
|
else if (kind === "ura")
|
|
1497
|
-
sat.uraMm =
|
|
1459
|
+
sat.uraMm = ssrUraMm(r.readU(6));
|
|
1498
1460
|
else if (kind === "highRateClock")
|
|
1499
1461
|
sat.highRateClock = r.readS(22) * 1e-4;
|
|
1500
1462
|
else if (kind === "codeBias") {
|
|
@@ -1862,9 +1824,9 @@ function updateStreamStats(stats, frames, rawBytes) {
|
|
|
1862
1824
|
entry.count++;
|
|
1863
1825
|
entry.lastSeen = now;
|
|
1864
1826
|
entry.totalBytes += frame.length + 6;
|
|
1865
|
-
const
|
|
1866
|
-
if (
|
|
1867
|
-
for (const obs of
|
|
1827
|
+
const obsEpoch = decodeObs(frame);
|
|
1828
|
+
if (obsEpoch) {
|
|
1829
|
+
for (const obs of obsEpoch.observations) {
|
|
1868
1830
|
const signals = [];
|
|
1869
1831
|
let bestCn0 = 0;
|
|
1870
1832
|
for (const sig of obs.signals) {
|
|
@@ -1873,7 +1835,7 @@ function updateStreamStats(stats, frames, rawBytes) {
|
|
|
1873
1835
|
if (sig.cn0 > bestCn0) bestCn0 = sig.cn0;
|
|
1874
1836
|
}
|
|
1875
1837
|
}
|
|
1876
|
-
if (signals.length > 0) {
|
|
1838
|
+
if (obs.signals.length > 0) {
|
|
1877
1839
|
stats.satellites.set(obs.prn, {
|
|
1878
1840
|
prn: obs.prn,
|
|
1879
1841
|
system: obs.system,
|
|
@@ -1922,11 +1884,12 @@ export {
|
|
|
1922
1884
|
readString,
|
|
1923
1885
|
decodeEphemeris,
|
|
1924
1886
|
decodeIgsSsr,
|
|
1925
|
-
decodeLegacyObs,
|
|
1926
1887
|
decodeMsmFull,
|
|
1927
|
-
|
|
1888
|
+
obsEpochToDate,
|
|
1928
1889
|
setGloFreqNumber,
|
|
1929
1890
|
resetGloFreqCache,
|
|
1891
|
+
decodeLegacyObs,
|
|
1892
|
+
decodeObs,
|
|
1930
1893
|
decodeSsr,
|
|
1931
1894
|
isSsrMessage,
|
|
1932
1895
|
decodeSystemParams,
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/** Constellations HAS corrects: GPS (GNSS ID 0), Galileo (GNSS ID 2). */
|
|
2
|
+
type HasSystem = 'G' | 'E';
|
|
3
|
+
/** One system's satellite/signal mask (ICD §6.4.3). */
|
|
4
|
+
interface HasSystemMask {
|
|
5
|
+
/** GNSS ID as broadcast: 0 GPS, 2 Galileo. */
|
|
6
|
+
gnssId: number;
|
|
7
|
+
system: HasSystem;
|
|
8
|
+
/** Masked satellites in mask order, e.g. ["E03", "E05", ...]. */
|
|
9
|
+
prns: string[];
|
|
10
|
+
/** Set bits of the 16-bit signal mask, ascending. */
|
|
11
|
+
signalIndices: number[];
|
|
12
|
+
/** ICD names for `signalIndices`. */
|
|
13
|
+
signals: string[];
|
|
14
|
+
/**
|
|
15
|
+
* Cell mask, [satellite][signal] in mask order — true when the
|
|
16
|
+
* sat×signal combination carries biases. Null when the cell-mask
|
|
17
|
+
* availability flag is 0 (all combinations available).
|
|
18
|
+
*/
|
|
19
|
+
cellMask: boolean[][] | null;
|
|
20
|
+
/** Nav-message index the corrections refer to (0 = LNAV / I/NAV). */
|
|
21
|
+
navMessage: number;
|
|
22
|
+
}
|
|
23
|
+
/** The satellite/signal mask block of one mask ID. */
|
|
24
|
+
interface HasMasks {
|
|
25
|
+
maskId: number;
|
|
26
|
+
systems: HasSystemMask[];
|
|
27
|
+
}
|
|
28
|
+
/** Orbit correction for one satellite (ICD §6.5). */
|
|
29
|
+
interface HasOrbitCorrection {
|
|
30
|
+
system: HasSystem;
|
|
31
|
+
prn: string;
|
|
32
|
+
/** Broadcast issue of data the deltas refer to (IODE / IODNav). */
|
|
33
|
+
gnssIod: number;
|
|
34
|
+
/** Delta radial in m (LSB 0.0025), null = data not available. */
|
|
35
|
+
deltaRadial: number | null;
|
|
36
|
+
/** Delta in-track in m (LSB 0.008), null = data not available. */
|
|
37
|
+
deltaInTrack: number | null;
|
|
38
|
+
/** Delta cross-track in m (LSB 0.008), null = data not available. */
|
|
39
|
+
deltaCrossTrack: number | null;
|
|
40
|
+
}
|
|
41
|
+
interface HasOrbitBlock {
|
|
42
|
+
validityIndex: number;
|
|
43
|
+
/** Validity interval in s (null = reserved index 15). */
|
|
44
|
+
validitySeconds: number | null;
|
|
45
|
+
corrections: HasOrbitCorrection[];
|
|
46
|
+
}
|
|
47
|
+
/** Clock correction for one satellite (ICD §6.6-6.7). */
|
|
48
|
+
interface HasClockCorrection {
|
|
49
|
+
system: HasSystem;
|
|
50
|
+
prn: string;
|
|
51
|
+
/**
|
|
52
|
+
* Delta clock C0 in m, multiplier folded in; positive means the
|
|
53
|
+
* satellite clock offset grows (add Δclock/c to the broadcast
|
|
54
|
+
* clock). Null when data not available or the satellite is flagged
|
|
55
|
+
* "shall not be used" (see `notUsable`).
|
|
56
|
+
*/
|
|
57
|
+
deltaClock: number | null;
|
|
58
|
+
/** True for the reserved "insufficient accuracy, do not use" value. */
|
|
59
|
+
notUsable: boolean;
|
|
60
|
+
}
|
|
61
|
+
interface HasClockBlock {
|
|
62
|
+
validityIndex: number;
|
|
63
|
+
validitySeconds: number | null;
|
|
64
|
+
/** Delta-clock C0 multiplier per system (1-4), in mask order. */
|
|
65
|
+
multipliers: {
|
|
66
|
+
system: HasSystem;
|
|
67
|
+
multiplier: number;
|
|
68
|
+
}[];
|
|
69
|
+
corrections: HasClockCorrection[];
|
|
70
|
+
}
|
|
71
|
+
/** Code or phase bias of one satellite × signal cell (ICD §6.8-6.9). */
|
|
72
|
+
interface HasSignalBias {
|
|
73
|
+
system: HasSystem;
|
|
74
|
+
prn: string;
|
|
75
|
+
signalIndex: number;
|
|
76
|
+
signal: string;
|
|
77
|
+
/** Bias in m (code, LSB 0.02) or cycles (phase, LSB 0.01); null = N/A. */
|
|
78
|
+
bias: number | null;
|
|
79
|
+
/** Phase-discontinuity indicator (phase biases only). */
|
|
80
|
+
discontinuity?: number;
|
|
81
|
+
}
|
|
82
|
+
interface HasBiasBlock {
|
|
83
|
+
validityIndex: number;
|
|
84
|
+
validitySeconds: number | null;
|
|
85
|
+
biases: HasSignalBias[];
|
|
86
|
+
}
|
|
87
|
+
/** Which sub-blocks the MT1 header flags as present (ICD §6.2). */
|
|
88
|
+
interface HasContentFlags {
|
|
89
|
+
mask: boolean;
|
|
90
|
+
orbit: boolean;
|
|
91
|
+
clockFullSet: boolean;
|
|
92
|
+
clockSubset: boolean;
|
|
93
|
+
codeBias: boolean;
|
|
94
|
+
phaseBias: boolean;
|
|
95
|
+
}
|
|
96
|
+
/** One decoded HAS MT1 message. */
|
|
97
|
+
interface HasMessage {
|
|
98
|
+
/** Receiver time of week (s) of the page completing the message. */
|
|
99
|
+
tow?: number;
|
|
100
|
+
/** HAS status of the carrying pages (0 test, 1 operational). */
|
|
101
|
+
status: number;
|
|
102
|
+
messageId: number;
|
|
103
|
+
/** Message size in pages (= pages used for the RS decode). */
|
|
104
|
+
messageSize: number;
|
|
105
|
+
/** Time of hour of the corrections, s (0-3599, ICD §6.2). */
|
|
106
|
+
toh: number;
|
|
107
|
+
maskId: number;
|
|
108
|
+
iodSetId: number;
|
|
109
|
+
flags: HasContentFlags;
|
|
110
|
+
/** The mask block in force (own or cached, see `maskFromCache`). */
|
|
111
|
+
masks?: HasMasks;
|
|
112
|
+
/** True when `masks` came from an earlier message with this mask ID. */
|
|
113
|
+
maskFromCache: boolean;
|
|
114
|
+
orbit?: HasOrbitBlock;
|
|
115
|
+
clockFullSet?: HasClockBlock;
|
|
116
|
+
clockSubset?: HasClockBlock;
|
|
117
|
+
codeBias?: HasBiasBlock;
|
|
118
|
+
phaseBias?: HasBiasBlock;
|
|
119
|
+
/** Null when fully parsed, else why the sub-blocks are missing. */
|
|
120
|
+
parseError: string | null;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export type { HasMessage as H, HasOrbitCorrection as a, HasClockCorrection as b };
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/** Constellations HAS corrects: GPS (GNSS ID 0), Galileo (GNSS ID 2). */
|
|
2
|
+
type HasSystem = 'G' | 'E';
|
|
3
|
+
/** One system's satellite/signal mask (ICD §6.4.3). */
|
|
4
|
+
interface HasSystemMask {
|
|
5
|
+
/** GNSS ID as broadcast: 0 GPS, 2 Galileo. */
|
|
6
|
+
gnssId: number;
|
|
7
|
+
system: HasSystem;
|
|
8
|
+
/** Masked satellites in mask order, e.g. ["E03", "E05", ...]. */
|
|
9
|
+
prns: string[];
|
|
10
|
+
/** Set bits of the 16-bit signal mask, ascending. */
|
|
11
|
+
signalIndices: number[];
|
|
12
|
+
/** ICD names for `signalIndices`. */
|
|
13
|
+
signals: string[];
|
|
14
|
+
/**
|
|
15
|
+
* Cell mask, [satellite][signal] in mask order — true when the
|
|
16
|
+
* sat×signal combination carries biases. Null when the cell-mask
|
|
17
|
+
* availability flag is 0 (all combinations available).
|
|
18
|
+
*/
|
|
19
|
+
cellMask: boolean[][] | null;
|
|
20
|
+
/** Nav-message index the corrections refer to (0 = LNAV / I/NAV). */
|
|
21
|
+
navMessage: number;
|
|
22
|
+
}
|
|
23
|
+
/** The satellite/signal mask block of one mask ID. */
|
|
24
|
+
interface HasMasks {
|
|
25
|
+
maskId: number;
|
|
26
|
+
systems: HasSystemMask[];
|
|
27
|
+
}
|
|
28
|
+
/** Orbit correction for one satellite (ICD §6.5). */
|
|
29
|
+
interface HasOrbitCorrection {
|
|
30
|
+
system: HasSystem;
|
|
31
|
+
prn: string;
|
|
32
|
+
/** Broadcast issue of data the deltas refer to (IODE / IODNav). */
|
|
33
|
+
gnssIod: number;
|
|
34
|
+
/** Delta radial in m (LSB 0.0025), null = data not available. */
|
|
35
|
+
deltaRadial: number | null;
|
|
36
|
+
/** Delta in-track in m (LSB 0.008), null = data not available. */
|
|
37
|
+
deltaInTrack: number | null;
|
|
38
|
+
/** Delta cross-track in m (LSB 0.008), null = data not available. */
|
|
39
|
+
deltaCrossTrack: number | null;
|
|
40
|
+
}
|
|
41
|
+
interface HasOrbitBlock {
|
|
42
|
+
validityIndex: number;
|
|
43
|
+
/** Validity interval in s (null = reserved index 15). */
|
|
44
|
+
validitySeconds: number | null;
|
|
45
|
+
corrections: HasOrbitCorrection[];
|
|
46
|
+
}
|
|
47
|
+
/** Clock correction for one satellite (ICD §6.6-6.7). */
|
|
48
|
+
interface HasClockCorrection {
|
|
49
|
+
system: HasSystem;
|
|
50
|
+
prn: string;
|
|
51
|
+
/**
|
|
52
|
+
* Delta clock C0 in m, multiplier folded in; positive means the
|
|
53
|
+
* satellite clock offset grows (add Δclock/c to the broadcast
|
|
54
|
+
* clock). Null when data not available or the satellite is flagged
|
|
55
|
+
* "shall not be used" (see `notUsable`).
|
|
56
|
+
*/
|
|
57
|
+
deltaClock: number | null;
|
|
58
|
+
/** True for the reserved "insufficient accuracy, do not use" value. */
|
|
59
|
+
notUsable: boolean;
|
|
60
|
+
}
|
|
61
|
+
interface HasClockBlock {
|
|
62
|
+
validityIndex: number;
|
|
63
|
+
validitySeconds: number | null;
|
|
64
|
+
/** Delta-clock C0 multiplier per system (1-4), in mask order. */
|
|
65
|
+
multipliers: {
|
|
66
|
+
system: HasSystem;
|
|
67
|
+
multiplier: number;
|
|
68
|
+
}[];
|
|
69
|
+
corrections: HasClockCorrection[];
|
|
70
|
+
}
|
|
71
|
+
/** Code or phase bias of one satellite × signal cell (ICD §6.8-6.9). */
|
|
72
|
+
interface HasSignalBias {
|
|
73
|
+
system: HasSystem;
|
|
74
|
+
prn: string;
|
|
75
|
+
signalIndex: number;
|
|
76
|
+
signal: string;
|
|
77
|
+
/** Bias in m (code, LSB 0.02) or cycles (phase, LSB 0.01); null = N/A. */
|
|
78
|
+
bias: number | null;
|
|
79
|
+
/** Phase-discontinuity indicator (phase biases only). */
|
|
80
|
+
discontinuity?: number;
|
|
81
|
+
}
|
|
82
|
+
interface HasBiasBlock {
|
|
83
|
+
validityIndex: number;
|
|
84
|
+
validitySeconds: number | null;
|
|
85
|
+
biases: HasSignalBias[];
|
|
86
|
+
}
|
|
87
|
+
/** Which sub-blocks the MT1 header flags as present (ICD §6.2). */
|
|
88
|
+
interface HasContentFlags {
|
|
89
|
+
mask: boolean;
|
|
90
|
+
orbit: boolean;
|
|
91
|
+
clockFullSet: boolean;
|
|
92
|
+
clockSubset: boolean;
|
|
93
|
+
codeBias: boolean;
|
|
94
|
+
phaseBias: boolean;
|
|
95
|
+
}
|
|
96
|
+
/** One decoded HAS MT1 message. */
|
|
97
|
+
interface HasMessage {
|
|
98
|
+
/** Receiver time of week (s) of the page completing the message. */
|
|
99
|
+
tow?: number;
|
|
100
|
+
/** HAS status of the carrying pages (0 test, 1 operational). */
|
|
101
|
+
status: number;
|
|
102
|
+
messageId: number;
|
|
103
|
+
/** Message size in pages (= pages used for the RS decode). */
|
|
104
|
+
messageSize: number;
|
|
105
|
+
/** Time of hour of the corrections, s (0-3599, ICD §6.2). */
|
|
106
|
+
toh: number;
|
|
107
|
+
maskId: number;
|
|
108
|
+
iodSetId: number;
|
|
109
|
+
flags: HasContentFlags;
|
|
110
|
+
/** The mask block in force (own or cached, see `maskFromCache`). */
|
|
111
|
+
masks?: HasMasks;
|
|
112
|
+
/** True when `masks` came from an earlier message with this mask ID. */
|
|
113
|
+
maskFromCache: boolean;
|
|
114
|
+
orbit?: HasOrbitBlock;
|
|
115
|
+
clockFullSet?: HasClockBlock;
|
|
116
|
+
clockSubset?: HasClockBlock;
|
|
117
|
+
codeBias?: HasBiasBlock;
|
|
118
|
+
phaseBias?: HasBiasBlock;
|
|
119
|
+
/** Null when fully parsed, else why the sub-blocks are missing. */
|
|
120
|
+
parseError: string | null;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export type { HasMessage as H, HasOrbitCorrection as a, HasClockCorrection as b };
|