gnss-js 1.18.0 → 1.20.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-2IM5VXNI.js → chunk-7RKLWE6R.js} +23 -2
- package/dist/{chunk-QXZZNXE3.js → chunk-B5LU4746.js} +1 -1
- package/dist/{chunk-FEGLXNWA.js → chunk-DLXTTHRK.js} +2 -4
- package/dist/{chunk-OMVL3X7V.js → chunk-JNFV5BYB.js} +186 -8
- package/dist/{chunk-HXF7XVW7.js → chunk-NOQAAUGY.js} +297 -11
- package/dist/{chunk-CG7SF45F.js → chunk-VJEPOC76.js} +908 -14
- package/dist/{chunk-Y5IWUPJQ.js → chunk-WZDFZ76K.js} +151 -8
- package/dist/index.cjs +3283 -1908
- package/dist/index.d.cts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +25 -8
- package/dist/nav-BYmYoh9A.d.cts +137 -0
- package/dist/nav-CN8rxL4h.d.ts +137 -0
- package/dist/nav-DImXUdbp.d.cts +223 -0
- package/dist/nav-DImXUdbp.d.ts +223 -0
- package/dist/novatel.cjs +230 -15
- package/dist/novatel.d.cts +8 -1
- package/dist/novatel.d.ts +8 -1
- package/dist/novatel.js +2 -2
- package/dist/orbit.cjs +190 -8
- package/dist/orbit.d.cts +91 -2
- package/dist/orbit.d.ts +91 -2
- package/dist/orbit.js +9 -1
- package/dist/positioning.d.cts +2 -1
- package/dist/positioning.d.ts +2 -1
- package/dist/positioning.js +2 -2
- package/dist/rinex.cjs +304 -11
- package/dist/rinex.d.cts +45 -3
- package/dist/rinex.d.ts +45 -3
- package/dist/rinex.js +6 -1
- package/dist/sbf.cjs +908 -11
- package/dist/sbf.d.cts +114 -137
- package/dist/sbf.d.ts +114 -137
- package/dist/sbf.js +8 -3
- package/dist/ubx.d.cts +1 -2
- package/dist/ubx.d.ts +1 -2
- package/dist/ubx.js +2 -3
- package/package.json +1 -1
- package/dist/chunk-IQ5OIMQD.js +0 -148
- package/dist/cnav-CRns0ECn.d.cts +0 -96
- package/dist/cnav-CRns0ECn.d.ts +0 -96
- package/dist/nav-BAI1a9vK.d.cts +0 -108
- package/dist/nav-BAI1a9vK.d.ts +0 -108
package/dist/sbf.cjs
CHANGED
|
@@ -21,7 +21,10 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var sbf_exports = {};
|
|
22
22
|
__export(sbf_exports, {
|
|
23
23
|
parseSbfAlmanac: () => parseSbfAlmanac,
|
|
24
|
+
parseSbfBdsNav: () => parseSbfBdsNav,
|
|
24
25
|
parseSbfCnav: () => parseSbfCnav,
|
|
26
|
+
parseSbfGalNav: () => parseSbfGalNav,
|
|
27
|
+
parseSbfGloNav: () => parseSbfGloNav,
|
|
25
28
|
parseSbfIonoUtc: () => parseSbfIonoUtc,
|
|
26
29
|
parseSbfMeas: () => parseSbfMeas,
|
|
27
30
|
parseSbfNav: () => parseSbfNav,
|
|
@@ -176,6 +179,11 @@ function getGpsLeap(date) {
|
|
|
176
179
|
if (leap_seconds < 0) return 0;
|
|
177
180
|
return leap_seconds - 19;
|
|
178
181
|
}
|
|
182
|
+
function getUtcDate(date) {
|
|
183
|
+
const tai_date = getTaiDate(date);
|
|
184
|
+
const leap_seconds = getLeap(date);
|
|
185
|
+
return new Date(tai_date.getTime() - leap_seconds * MILLISECONDS_IN_SECOND);
|
|
186
|
+
}
|
|
179
187
|
|
|
180
188
|
// src/sbf/nav.ts
|
|
181
189
|
var PI = Math.PI;
|
|
@@ -768,10 +776,896 @@ function parseSbfCnav(data) {
|
|
|
768
776
|
return { ephemerides, badCrc, messages };
|
|
769
777
|
}
|
|
770
778
|
|
|
779
|
+
// src/navbits/gal.ts
|
|
780
|
+
var GPS_EPOCH_MS4 = Date.UTC(1980, 0, 6);
|
|
781
|
+
var SEC_PER_WEEK4 = 7 * 86400;
|
|
782
|
+
var HALF_WEEK2 = 302400;
|
|
783
|
+
var GST_GPS_WEEK_OFFSET = 1024;
|
|
784
|
+
function galInavPageCrcOk(page) {
|
|
785
|
+
if (page.length < 28) return false;
|
|
786
|
+
return crc24q(page, 196) === getBitU(page, 196, 24);
|
|
787
|
+
}
|
|
788
|
+
function galFnavPageCrcOk(page) {
|
|
789
|
+
if (page.length < 30) return false;
|
|
790
|
+
return crc24q(page, 214) === getBitU(page, 214, 24);
|
|
791
|
+
}
|
|
792
|
+
function gpsDate2(week, sec) {
|
|
793
|
+
return new Date(GPS_EPOCH_MS4 + (week * SEC_PER_WEEK4 + sec) * 1e3);
|
|
794
|
+
}
|
|
795
|
+
function weekOfToe(week, tow, toe) {
|
|
796
|
+
if (toe - tow > HALF_WEEK2) return week - 1;
|
|
797
|
+
if (toe - tow < -HALF_WEEK2) return week + 1;
|
|
798
|
+
return week;
|
|
799
|
+
}
|
|
800
|
+
var two2 = (n) => String(n).padStart(2, "0");
|
|
801
|
+
function decodeGalInavWords(words) {
|
|
802
|
+
if (words.length < 96) return null;
|
|
803
|
+
const b = words;
|
|
804
|
+
let i = 128;
|
|
805
|
+
const type1 = getBitU(b, i, 6);
|
|
806
|
+
i += 6;
|
|
807
|
+
const iodNav1 = getBitU(b, i, 10);
|
|
808
|
+
i += 10;
|
|
809
|
+
const toes = getBitU(b, i, 14) * 60;
|
|
810
|
+
i += 14;
|
|
811
|
+
const m0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
812
|
+
i += 32;
|
|
813
|
+
const e = getBitU(b, i, 32) * 2 ** -33;
|
|
814
|
+
i += 32;
|
|
815
|
+
const sqrtA = getBitU(b, i, 32) * 2 ** -19;
|
|
816
|
+
i = 128 * 2;
|
|
817
|
+
const type2 = getBitU(b, i, 6);
|
|
818
|
+
i += 6;
|
|
819
|
+
const iodNav2 = getBitU(b, i, 10);
|
|
820
|
+
i += 10;
|
|
821
|
+
const omega0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
822
|
+
i += 32;
|
|
823
|
+
const i0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
824
|
+
i += 32;
|
|
825
|
+
const omega = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
826
|
+
i += 32;
|
|
827
|
+
const idot = getBitS(b, i, 14) * 2 ** -43 * GPS_PI;
|
|
828
|
+
i = 128 * 3;
|
|
829
|
+
const type3 = getBitU(b, i, 6);
|
|
830
|
+
i += 6;
|
|
831
|
+
const iodNav3 = getBitU(b, i, 10);
|
|
832
|
+
i += 10;
|
|
833
|
+
const omegaDot = getBitS(b, i, 24) * 2 ** -43 * GPS_PI;
|
|
834
|
+
i += 24;
|
|
835
|
+
const deltaN = getBitS(b, i, 16) * 2 ** -43 * GPS_PI;
|
|
836
|
+
i += 16;
|
|
837
|
+
const cuc = getBitS(b, i, 16) * 2 ** -29;
|
|
838
|
+
i += 16;
|
|
839
|
+
const cus = getBitS(b, i, 16) * 2 ** -29;
|
|
840
|
+
i += 16;
|
|
841
|
+
const crc = getBitS(b, i, 16) * 2 ** -5;
|
|
842
|
+
i += 16;
|
|
843
|
+
const crs = getBitS(b, i, 16) * 2 ** -5;
|
|
844
|
+
i = 128 * 4;
|
|
845
|
+
const type4 = getBitU(b, i, 6);
|
|
846
|
+
i += 6;
|
|
847
|
+
const iodNav4 = getBitU(b, i, 10);
|
|
848
|
+
i += 10;
|
|
849
|
+
const svid = getBitU(b, i, 6);
|
|
850
|
+
i += 6;
|
|
851
|
+
const cic = getBitS(b, i, 16) * 2 ** -29;
|
|
852
|
+
i += 16;
|
|
853
|
+
const cis = getBitS(b, i, 16) * 2 ** -29;
|
|
854
|
+
i += 16;
|
|
855
|
+
const tocs = getBitU(b, i, 14) * 60;
|
|
856
|
+
i += 14;
|
|
857
|
+
const af0 = getBitS(b, i, 31) * 2 ** -34;
|
|
858
|
+
i += 31;
|
|
859
|
+
const af1 = getBitS(b, i, 21) * 2 ** -46;
|
|
860
|
+
i += 21;
|
|
861
|
+
const af2 = getBitS(b, i, 6) * 2 ** -59;
|
|
862
|
+
i = 128 * 5;
|
|
863
|
+
const type5 = getBitU(b, i, 6);
|
|
864
|
+
i += 6 + 11 + 11 + 14 + 5;
|
|
865
|
+
const bgdE5a = getBitS(b, i, 10) * 2 ** -32;
|
|
866
|
+
i += 10;
|
|
867
|
+
i += 10;
|
|
868
|
+
const e5bHs = getBitU(b, i, 2);
|
|
869
|
+
i += 2;
|
|
870
|
+
const e1bHs = getBitU(b, i, 2);
|
|
871
|
+
i += 2;
|
|
872
|
+
const e5bDvs = getBitU(b, i, 1);
|
|
873
|
+
i += 1;
|
|
874
|
+
const e1bDvs = getBitU(b, i, 1);
|
|
875
|
+
i += 1;
|
|
876
|
+
const gstWeek = getBitU(b, i, 12);
|
|
877
|
+
i += 12;
|
|
878
|
+
const tow = getBitU(b, i, 20);
|
|
879
|
+
if (type1 !== 1 || type2 !== 2 || type3 !== 3 || type4 !== 4 || type5 !== 5)
|
|
880
|
+
return null;
|
|
881
|
+
if (iodNav1 !== iodNav2 || iodNav1 !== iodNav3 || iodNav1 !== iodNav4)
|
|
882
|
+
return null;
|
|
883
|
+
if (svid < 1 || svid > 36) return null;
|
|
884
|
+
const week = weekOfToe(gstWeek, tow, toes) + GST_GPS_WEEK_OFFSET;
|
|
885
|
+
const tocDate = gpsDate2(week, tocs);
|
|
886
|
+
return {
|
|
887
|
+
system: "E",
|
|
888
|
+
prn: `E${two2(svid)}`,
|
|
889
|
+
toc: tocDate.getTime() / 1e3 % SEC_PER_WEEK4,
|
|
890
|
+
tocDate,
|
|
891
|
+
af0,
|
|
892
|
+
af1,
|
|
893
|
+
af2,
|
|
894
|
+
iode: iodNav1,
|
|
895
|
+
crs,
|
|
896
|
+
deltaN,
|
|
897
|
+
m0,
|
|
898
|
+
cuc,
|
|
899
|
+
e,
|
|
900
|
+
cus,
|
|
901
|
+
sqrtA,
|
|
902
|
+
toe: toes,
|
|
903
|
+
cic,
|
|
904
|
+
omega0,
|
|
905
|
+
cis,
|
|
906
|
+
i0,
|
|
907
|
+
crc,
|
|
908
|
+
omega,
|
|
909
|
+
omegaDot,
|
|
910
|
+
idot,
|
|
911
|
+
week,
|
|
912
|
+
svHealth: e5bHs << 7 | e5bDvs << 6 | e1bHs << 1 | e1bDvs,
|
|
913
|
+
tgd: bgdE5a
|
|
914
|
+
};
|
|
915
|
+
}
|
|
916
|
+
function decodeGalFnavPages(pages) {
|
|
917
|
+
if (pages.length < 124) return null;
|
|
918
|
+
const b = pages;
|
|
919
|
+
let i = 0;
|
|
920
|
+
const type1 = getBitU(b, i, 6);
|
|
921
|
+
i += 6;
|
|
922
|
+
const svid = getBitU(b, i, 6);
|
|
923
|
+
i += 6;
|
|
924
|
+
const iodNav1 = getBitU(b, i, 10);
|
|
925
|
+
i += 10;
|
|
926
|
+
const tocs = getBitU(b, i, 14) * 60;
|
|
927
|
+
i += 14;
|
|
928
|
+
const af0 = getBitS(b, i, 31) * 2 ** -34;
|
|
929
|
+
i += 31;
|
|
930
|
+
const af1 = getBitS(b, i, 21) * 2 ** -46;
|
|
931
|
+
i += 21;
|
|
932
|
+
const af2 = getBitS(b, i, 6) * 2 ** -59;
|
|
933
|
+
i += 6;
|
|
934
|
+
i += 8 + 11 + 11 + 14 + 5;
|
|
935
|
+
const bgdE5a = getBitS(b, i, 10) * 2 ** -32;
|
|
936
|
+
i += 10;
|
|
937
|
+
const e5aHs = getBitU(b, i, 2);
|
|
938
|
+
i += 2;
|
|
939
|
+
const gstWeek = getBitU(b, i, 12);
|
|
940
|
+
i += 12;
|
|
941
|
+
const tow = getBitU(b, i, 20);
|
|
942
|
+
i += 20;
|
|
943
|
+
const e5aDvs = getBitU(b, i, 1);
|
|
944
|
+
i = 31 * 8;
|
|
945
|
+
const type2 = getBitU(b, i, 6);
|
|
946
|
+
i += 6;
|
|
947
|
+
const iodNav2 = getBitU(b, i, 10);
|
|
948
|
+
i += 10;
|
|
949
|
+
const m0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
950
|
+
i += 32;
|
|
951
|
+
const omegaDot = getBitS(b, i, 24) * 2 ** -43 * GPS_PI;
|
|
952
|
+
i += 24;
|
|
953
|
+
const e = getBitU(b, i, 32) * 2 ** -33;
|
|
954
|
+
i += 32;
|
|
955
|
+
const sqrtA = getBitU(b, i, 32) * 2 ** -19;
|
|
956
|
+
i += 32;
|
|
957
|
+
const omega0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
958
|
+
i += 32;
|
|
959
|
+
const idot = getBitS(b, i, 14) * 2 ** -43 * GPS_PI;
|
|
960
|
+
i = 62 * 8;
|
|
961
|
+
const type3 = getBitU(b, i, 6);
|
|
962
|
+
i += 6;
|
|
963
|
+
const iodNav3 = getBitU(b, i, 10);
|
|
964
|
+
i += 10;
|
|
965
|
+
const i0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
966
|
+
i += 32;
|
|
967
|
+
const omega = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
968
|
+
i += 32;
|
|
969
|
+
const deltaN = getBitS(b, i, 16) * 2 ** -43 * GPS_PI;
|
|
970
|
+
i += 16;
|
|
971
|
+
const cuc = getBitS(b, i, 16) * 2 ** -29;
|
|
972
|
+
i += 16;
|
|
973
|
+
const cus = getBitS(b, i, 16) * 2 ** -29;
|
|
974
|
+
i += 16;
|
|
975
|
+
const crc = getBitS(b, i, 16) * 2 ** -5;
|
|
976
|
+
i += 16;
|
|
977
|
+
const crs = getBitS(b, i, 16) * 2 ** -5;
|
|
978
|
+
i += 16;
|
|
979
|
+
const toes = getBitU(b, i, 14) * 60;
|
|
980
|
+
i = 93 * 8;
|
|
981
|
+
const type4 = getBitU(b, i, 6);
|
|
982
|
+
i += 6;
|
|
983
|
+
const iodNav4 = getBitU(b, i, 10);
|
|
984
|
+
i += 10;
|
|
985
|
+
const cic = getBitS(b, i, 16) * 2 ** -29;
|
|
986
|
+
i += 16;
|
|
987
|
+
const cis = getBitS(b, i, 16) * 2 ** -29;
|
|
988
|
+
if (type1 !== 1 || type2 !== 2 || type3 !== 3 || type4 !== 4) return null;
|
|
989
|
+
if (iodNav1 !== iodNav2 || iodNav1 !== iodNav3 || iodNav1 !== iodNav4)
|
|
990
|
+
return null;
|
|
991
|
+
if (svid < 1 || svid > 36) return null;
|
|
992
|
+
const week = weekOfToe(gstWeek, tow, toes) + GST_GPS_WEEK_OFFSET;
|
|
993
|
+
const tocDate = gpsDate2(week, tocs);
|
|
994
|
+
return {
|
|
995
|
+
system: "E",
|
|
996
|
+
prn: `E${two2(svid)}`,
|
|
997
|
+
toc: tocDate.getTime() / 1e3 % SEC_PER_WEEK4,
|
|
998
|
+
tocDate,
|
|
999
|
+
af0,
|
|
1000
|
+
af1,
|
|
1001
|
+
af2,
|
|
1002
|
+
iode: iodNav1,
|
|
1003
|
+
crs,
|
|
1004
|
+
deltaN,
|
|
1005
|
+
m0,
|
|
1006
|
+
cuc,
|
|
1007
|
+
e,
|
|
1008
|
+
cus,
|
|
1009
|
+
sqrtA,
|
|
1010
|
+
toe: toes,
|
|
1011
|
+
cic,
|
|
1012
|
+
omega0,
|
|
1013
|
+
cis,
|
|
1014
|
+
i0,
|
|
1015
|
+
crc,
|
|
1016
|
+
omega,
|
|
1017
|
+
omegaDot,
|
|
1018
|
+
idot,
|
|
1019
|
+
week,
|
|
1020
|
+
svHealth: e5aHs << 4 | e5aDvs << 3,
|
|
1021
|
+
tgd: bgdE5a
|
|
1022
|
+
};
|
|
1023
|
+
}
|
|
1024
|
+
var dedupKey = (eph) => `${eph.iode}:${eph.toe}:${eph.tocDate.getTime()}`;
|
|
1025
|
+
var GalInavAssembler = class {
|
|
1026
|
+
sats = /* @__PURE__ */ new Map();
|
|
1027
|
+
/**
|
|
1028
|
+
* Push one I/NAV page pair for satellite `prn` (1-36): the 234-bit
|
|
1029
|
+
* even+odd concatenation, even part first with its 6 tail bits
|
|
1030
|
+
* removed, bit 0 = the even part's Even/Odd bit (≥ 17 bytes).
|
|
1031
|
+
* Returns the newly completed ephemeris, or null. Pages that are
|
|
1032
|
+
* not an even/odd nominal pair, alert pages and word types outside
|
|
1033
|
+
* 1-5 are ignored.
|
|
1034
|
+
*/
|
|
1035
|
+
push(prn, page) {
|
|
1036
|
+
if (prn < 1 || prn > 36 || page.length < 17) return null;
|
|
1037
|
+
if (getBitU(page, 0, 1) !== 0 || getBitU(page, 114, 1) !== 1) return null;
|
|
1038
|
+
if (getBitU(page, 1, 1) === 1 || getBitU(page, 115, 1) === 1) return null;
|
|
1039
|
+
const type = getBitU(page, 2, 6);
|
|
1040
|
+
if (type < 1 || type > 5) return null;
|
|
1041
|
+
let sat = this.sats.get(prn);
|
|
1042
|
+
if (!sat) {
|
|
1043
|
+
sat = { words: new Uint8Array(96) };
|
|
1044
|
+
this.sats.set(prn, sat);
|
|
1045
|
+
}
|
|
1046
|
+
for (let k = 0; k < 14; k++)
|
|
1047
|
+
sat.words[type * 16 + k] = getBitU(page, 2 + 8 * k, 8);
|
|
1048
|
+
sat.words[type * 16 + 14] = getBitU(page, 116, 8);
|
|
1049
|
+
sat.words[type * 16 + 15] = getBitU(page, 124, 8);
|
|
1050
|
+
if (type !== 5) return null;
|
|
1051
|
+
const eph = decodeGalInavWords(sat.words);
|
|
1052
|
+
if (!eph || eph.prn !== `E${two2(prn)}`) return null;
|
|
1053
|
+
const key = dedupKey(eph);
|
|
1054
|
+
if (key === sat.lastKey) return null;
|
|
1055
|
+
sat.lastKey = key;
|
|
1056
|
+
return eph;
|
|
1057
|
+
}
|
|
1058
|
+
};
|
|
1059
|
+
var GalFnavAssembler = class {
|
|
1060
|
+
sats = /* @__PURE__ */ new Map();
|
|
1061
|
+
/**
|
|
1062
|
+
* Push one F/NAV page for satellite `prn` (1-36): 244 bits with the
|
|
1063
|
+
* sync field stripped, bit 0 = first page-type bit (≥ 31 bytes).
|
|
1064
|
+
* Returns the newly completed ephemeris, or null. Dummy pages
|
|
1065
|
+
* (type 63) and page types outside 1-4 are ignored.
|
|
1066
|
+
*/
|
|
1067
|
+
push(prn, page) {
|
|
1068
|
+
if (prn < 1 || prn > 36 || page.length < 31) return null;
|
|
1069
|
+
const type = getBitU(page, 0, 6);
|
|
1070
|
+
if (type < 1 || type > 4) return null;
|
|
1071
|
+
let sat = this.sats.get(prn);
|
|
1072
|
+
if (!sat) {
|
|
1073
|
+
sat = { words: new Uint8Array(124) };
|
|
1074
|
+
this.sats.set(prn, sat);
|
|
1075
|
+
}
|
|
1076
|
+
sat.words.set(page.subarray(0, 31), (type - 1) * 31);
|
|
1077
|
+
if (type !== 4) return null;
|
|
1078
|
+
const eph = decodeGalFnavPages(sat.words);
|
|
1079
|
+
if (!eph || eph.prn !== `E${two2(prn)}`) return null;
|
|
1080
|
+
const key = dedupKey(eph);
|
|
1081
|
+
if (key === sat.lastKey) return null;
|
|
1082
|
+
sat.lastKey = key;
|
|
1083
|
+
return eph;
|
|
1084
|
+
}
|
|
1085
|
+
};
|
|
1086
|
+
|
|
1087
|
+
// src/sbf/rawnav-gal.ts
|
|
1088
|
+
var INAV_SOURCES = [17, 21, 22];
|
|
1089
|
+
var FNAV_SOURCES = [20, 22];
|
|
1090
|
+
function parseSbfGalNav(data) {
|
|
1091
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
1092
|
+
const ephemerides = [];
|
|
1093
|
+
const inav = new GalInavAssembler();
|
|
1094
|
+
const fnav = new GalFnavAssembler();
|
|
1095
|
+
let badCrc = 0;
|
|
1096
|
+
let messages = 0;
|
|
1097
|
+
scanSbfFrames(data, view, (id, b, len) => {
|
|
1098
|
+
if (id !== 4022 && id !== 4023 || len < 52) return;
|
|
1099
|
+
messages++;
|
|
1100
|
+
const prnStr = svidToPrn(data[b + 14]);
|
|
1101
|
+
if (!prnStr || prnStr[0] !== "E") return;
|
|
1102
|
+
const prn = parseInt(prnStr.slice(1), 10);
|
|
1103
|
+
const source = data[b + 17] & 31;
|
|
1104
|
+
const page = new Uint8Array(32);
|
|
1105
|
+
for (let k = 0; k < 8; k++) {
|
|
1106
|
+
const w = view.getUint32(b + 20 + 4 * k, true);
|
|
1107
|
+
page[4 * k] = w >>> 24;
|
|
1108
|
+
page[4 * k + 1] = w >>> 16 & 255;
|
|
1109
|
+
page[4 * k + 2] = w >>> 8 & 255;
|
|
1110
|
+
page[4 * k + 3] = w & 255;
|
|
1111
|
+
}
|
|
1112
|
+
let eph;
|
|
1113
|
+
let src;
|
|
1114
|
+
if (id === 4023) {
|
|
1115
|
+
src = "inav";
|
|
1116
|
+
if (!INAV_SOURCES.includes(source)) return;
|
|
1117
|
+
if (getBitU2(page, 0) !== 0 || getBitU2(page, 114) !== 1) return;
|
|
1118
|
+
if (!galInavPageCrcOk(page)) {
|
|
1119
|
+
badCrc++;
|
|
1120
|
+
return;
|
|
1121
|
+
}
|
|
1122
|
+
eph = inav.push(prn, page);
|
|
1123
|
+
} else {
|
|
1124
|
+
src = "fnav";
|
|
1125
|
+
if (!FNAV_SOURCES.includes(source)) return;
|
|
1126
|
+
if (isFnavDummy(page)) return;
|
|
1127
|
+
if (!galFnavPageCrcOk(page)) {
|
|
1128
|
+
badCrc++;
|
|
1129
|
+
return;
|
|
1130
|
+
}
|
|
1131
|
+
eph = fnav.push(prn, page);
|
|
1132
|
+
}
|
|
1133
|
+
if (eph) ephemerides.push({ ...eph, source: src });
|
|
1134
|
+
});
|
|
1135
|
+
return { ephemerides, badCrc, messages };
|
|
1136
|
+
}
|
|
1137
|
+
function getBitU2(buff, pos) {
|
|
1138
|
+
return buff[pos >> 3] >> 7 - (pos & 7) & 1;
|
|
1139
|
+
}
|
|
1140
|
+
function isFnavDummy(page) {
|
|
1141
|
+
return page[0] >> 2 === 63;
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
// src/navbits/bds.ts
|
|
1145
|
+
var BDT_EPOCH_MS2 = Date.UTC(2006, 0, 1);
|
|
1146
|
+
var SEC_PER_WEEK5 = 7 * 86400;
|
|
1147
|
+
var MS_PER_WEEK2 = SEC_PER_WEEK5 * 1e3;
|
|
1148
|
+
var HALF_WEEK3 = 302400;
|
|
1149
|
+
var sowOf2 = (dateMs) => dateMs / 1e3 % SEC_PER_WEEK5;
|
|
1150
|
+
var BDS_SUBFRAME_BYTES = 38;
|
|
1151
|
+
function getBitU22(b, p1, l1, p2, l2) {
|
|
1152
|
+
return getBitU(b, p1, l1) * 2 ** l2 + getBitU(b, p2, l2);
|
|
1153
|
+
}
|
|
1154
|
+
function getBitS2(b, p1, l1, p2, l2) {
|
|
1155
|
+
return getBitS(b, p1, l1) * 2 ** l2 + getBitU(b, p2, l2);
|
|
1156
|
+
}
|
|
1157
|
+
function getBitU3(b, p1, l1, p2, l2, p3, l3) {
|
|
1158
|
+
return getBitU(b, p1, l1) * 2 ** (l2 + l3) + getBitU(b, p2, l2) * 2 ** l3 + getBitU(b, p3, l3);
|
|
1159
|
+
}
|
|
1160
|
+
function getBitS3(b, p1, l1, p2, l2, p3, l3) {
|
|
1161
|
+
return getBitS(b, p1, l1) * 2 ** (l2 + l3) + getBitU(b, p2, l2) * 2 ** l3 + getBitU(b, p3, l3);
|
|
1162
|
+
}
|
|
1163
|
+
var mergeS = (hi, lo, n) => hi * 2 ** n + lo;
|
|
1164
|
+
function bchOk(cw) {
|
|
1165
|
+
for (let i = 14; i >= 4; i--) {
|
|
1166
|
+
if (cw & 1 << i) cw ^= 19 << i - 4;
|
|
1167
|
+
}
|
|
1168
|
+
return cw === 0;
|
|
1169
|
+
}
|
|
1170
|
+
function bdsSubframeParityOk(subframe) {
|
|
1171
|
+
if (subframe.length < BDS_SUBFRAME_BYTES) return false;
|
|
1172
|
+
if (!bchOk(getBitU(subframe, 15, 15))) return false;
|
|
1173
|
+
for (let w = 1; w < 10; w++) {
|
|
1174
|
+
const base = 30 * w;
|
|
1175
|
+
const cw1 = getBitU(subframe, base, 11) * 16 + getBitU(subframe, base + 22, 4);
|
|
1176
|
+
const cw2 = getBitU(subframe, base + 11, 11) * 16 + getBitU(subframe, base + 26, 4);
|
|
1177
|
+
if (!bchOk(cw1) || !bchOk(cw2)) return false;
|
|
1178
|
+
}
|
|
1179
|
+
return true;
|
|
1180
|
+
}
|
|
1181
|
+
function buildBdsEphemeris(prn, f) {
|
|
1182
|
+
let week = f.week;
|
|
1183
|
+
if (f.toes < f.sow - HALF_WEEK3) week++;
|
|
1184
|
+
else if (f.toes > f.sow + HALF_WEEK3) week--;
|
|
1185
|
+
const tocDate = new Date(BDT_EPOCH_MS2 + week * MS_PER_WEEK2 + f.tocSec * 1e3);
|
|
1186
|
+
return {
|
|
1187
|
+
system: "C",
|
|
1188
|
+
prn,
|
|
1189
|
+
toc: sowOf2(tocDate.getTime()),
|
|
1190
|
+
tocDate,
|
|
1191
|
+
af0: f.af0,
|
|
1192
|
+
af1: f.af1,
|
|
1193
|
+
af2: f.af2,
|
|
1194
|
+
// AODE is not in the ephemeris subframes; RTKLIB derives the RINEX
|
|
1195
|
+
// IODE/AODE slot from toc per the BDS ICD update schedule.
|
|
1196
|
+
iode: Math.floor(f.tocSec / 720) % 240,
|
|
1197
|
+
crs: f.crs,
|
|
1198
|
+
deltaN: f.deltaN,
|
|
1199
|
+
m0: f.m0,
|
|
1200
|
+
cuc: f.cuc,
|
|
1201
|
+
e: f.e,
|
|
1202
|
+
cus: f.cus,
|
|
1203
|
+
sqrtA: f.sqrtA,
|
|
1204
|
+
toe: f.toes,
|
|
1205
|
+
cic: f.cic,
|
|
1206
|
+
omega0: f.omega0,
|
|
1207
|
+
cis: f.cis,
|
|
1208
|
+
i0: f.i0,
|
|
1209
|
+
crc: f.crc,
|
|
1210
|
+
omega: f.omega,
|
|
1211
|
+
omegaDot: f.omegaDot,
|
|
1212
|
+
idot: f.idot,
|
|
1213
|
+
week,
|
|
1214
|
+
// RINEX BDS week field is the BDT week of toe
|
|
1215
|
+
svHealth: f.svh,
|
|
1216
|
+
// SatH1
|
|
1217
|
+
tgd: f.tgd1
|
|
1218
|
+
// TGD1 (B1) — RINEX slot
|
|
1219
|
+
};
|
|
1220
|
+
}
|
|
1221
|
+
function decodeBdsD1Frame(subframes, opts = {}) {
|
|
1222
|
+
if (subframes.length < 3 * BDS_SUBFRAME_BYTES) return null;
|
|
1223
|
+
const b = subframes;
|
|
1224
|
+
let i = 8 * 38 * 0;
|
|
1225
|
+
const frn1 = getBitU(b, i + 15, 3);
|
|
1226
|
+
const sow1 = getBitU22(b, i + 18, 8, i + 30, 12);
|
|
1227
|
+
const svh = getBitU(b, i + 42, 1);
|
|
1228
|
+
const week = getBitU(b, i + 60, 13);
|
|
1229
|
+
const tocSec = getBitU22(b, i + 73, 9, i + 90, 8) * 8;
|
|
1230
|
+
const tgd1 = getBitS(b, i + 98, 10) * 0.1 * 1e-9;
|
|
1231
|
+
const af2 = getBitS(b, i + 214, 11) * 2 ** -66;
|
|
1232
|
+
const af0 = getBitS2(b, i + 225, 7, i + 240, 17) * 2 ** -33;
|
|
1233
|
+
const af1 = getBitS2(b, i + 257, 5, i + 270, 17) * 2 ** -50;
|
|
1234
|
+
i = 8 * 38 * 1;
|
|
1235
|
+
const frn2 = getBitU(b, i + 15, 3);
|
|
1236
|
+
const sow2 = getBitU22(b, i + 18, 8, i + 30, 12);
|
|
1237
|
+
const deltaN = getBitS2(b, i + 42, 10, i + 60, 6) * 2 ** -43 * GPS_PI;
|
|
1238
|
+
const cuc = getBitS2(b, i + 66, 16, i + 90, 2) * 2 ** -31;
|
|
1239
|
+
const m0 = getBitS2(b, i + 92, 20, i + 120, 12) * 2 ** -31 * GPS_PI;
|
|
1240
|
+
const e = getBitU22(b, i + 132, 10, i + 150, 22) * 2 ** -33;
|
|
1241
|
+
const cus = getBitS(b, i + 180, 18) * 2 ** -31;
|
|
1242
|
+
const crc = getBitS2(b, i + 198, 4, i + 210, 14) * 2 ** -6;
|
|
1243
|
+
const crs = getBitS2(b, i + 224, 8, i + 240, 10) * 2 ** -6;
|
|
1244
|
+
const sqrtA = getBitU22(b, i + 250, 12, i + 270, 20) * 2 ** -19;
|
|
1245
|
+
const toe1 = getBitU(b, i + 290, 2);
|
|
1246
|
+
i = 8 * 38 * 2;
|
|
1247
|
+
const frn3 = getBitU(b, i + 15, 3);
|
|
1248
|
+
const sow3 = getBitU22(b, i + 18, 8, i + 30, 12);
|
|
1249
|
+
const toe2 = getBitU22(b, i + 42, 10, i + 60, 5);
|
|
1250
|
+
const i0 = getBitS2(b, i + 65, 17, i + 90, 15) * 2 ** -31 * GPS_PI;
|
|
1251
|
+
const cic = getBitS2(b, i + 105, 7, i + 120, 11) * 2 ** -31;
|
|
1252
|
+
const omegaDot = getBitS2(b, i + 131, 11, i + 150, 13) * 2 ** -43 * GPS_PI;
|
|
1253
|
+
const cis = getBitS2(b, i + 163, 9, i + 180, 9) * 2 ** -31;
|
|
1254
|
+
const idot = getBitS2(b, i + 189, 13, i + 210, 1) * 2 ** -43 * GPS_PI;
|
|
1255
|
+
const omega0 = getBitS2(b, i + 211, 21, i + 240, 11) * 2 ** -31 * GPS_PI;
|
|
1256
|
+
const omega = getBitS2(b, i + 251, 11, i + 270, 21) * 2 ** -31 * GPS_PI;
|
|
1257
|
+
const toes = (toe1 * 2 ** 15 + toe2) * 8;
|
|
1258
|
+
if (frn1 !== 1 || frn2 !== 2 || frn3 !== 3) return null;
|
|
1259
|
+
if (sow2 !== sow1 + 6 || sow3 !== sow2 + 6) return null;
|
|
1260
|
+
if (tocSec !== toes) return null;
|
|
1261
|
+
return buildBdsEphemeris(opts.prn ?? "C00", {
|
|
1262
|
+
week,
|
|
1263
|
+
sow: sow1,
|
|
1264
|
+
toes,
|
|
1265
|
+
tocSec,
|
|
1266
|
+
svh,
|
|
1267
|
+
tgd1,
|
|
1268
|
+
af0,
|
|
1269
|
+
af1,
|
|
1270
|
+
af2,
|
|
1271
|
+
crs,
|
|
1272
|
+
deltaN,
|
|
1273
|
+
m0,
|
|
1274
|
+
cuc,
|
|
1275
|
+
e,
|
|
1276
|
+
cus,
|
|
1277
|
+
sqrtA,
|
|
1278
|
+
cic,
|
|
1279
|
+
omega0,
|
|
1280
|
+
cis,
|
|
1281
|
+
i0,
|
|
1282
|
+
crc,
|
|
1283
|
+
omega,
|
|
1284
|
+
omegaDot,
|
|
1285
|
+
idot
|
|
1286
|
+
});
|
|
1287
|
+
}
|
|
1288
|
+
function decodeBdsD2Frame(pages, opts = {}) {
|
|
1289
|
+
if (pages.length < 10 * BDS_SUBFRAME_BYTES) return null;
|
|
1290
|
+
const b = pages;
|
|
1291
|
+
let i = 8 * 38 * 0;
|
|
1292
|
+
const pgn1 = getBitU(b, i + 42, 4);
|
|
1293
|
+
const sow1 = getBitU22(b, i + 18, 8, i + 30, 12);
|
|
1294
|
+
const svh = getBitU(b, i + 46, 1);
|
|
1295
|
+
const week = getBitU(b, i + 64, 13);
|
|
1296
|
+
const tocSec = getBitU22(b, i + 77, 5, i + 90, 12) * 8;
|
|
1297
|
+
const tgd1 = getBitS(b, i + 102, 10) * 0.1 * 1e-9;
|
|
1298
|
+
i = 8 * 38 * 2;
|
|
1299
|
+
const pgn3 = getBitU(b, i + 42, 4);
|
|
1300
|
+
const sow3 = getBitU22(b, i + 18, 8, i + 30, 12);
|
|
1301
|
+
const af0 = getBitS2(b, i + 100, 12, i + 120, 12) * 2 ** -33;
|
|
1302
|
+
const af1p3 = getBitS(b, i + 132, 4);
|
|
1303
|
+
i = 8 * 38 * 3;
|
|
1304
|
+
const pgn4 = getBitU(b, i + 42, 4);
|
|
1305
|
+
const sow4 = getBitU22(b, i + 18, 8, i + 30, 12);
|
|
1306
|
+
const af1p4 = getBitU22(b, i + 46, 6, i + 60, 12);
|
|
1307
|
+
const af2 = getBitS2(b, i + 72, 10, i + 90, 1) * 2 ** -66;
|
|
1308
|
+
const deltaN = getBitS(b, i + 96, 16) * 2 ** -43 * GPS_PI;
|
|
1309
|
+
const cucp4 = getBitS(b, i + 120, 14);
|
|
1310
|
+
i = 8 * 38 * 4;
|
|
1311
|
+
const pgn5 = getBitU(b, i + 42, 4);
|
|
1312
|
+
const sow5 = getBitU22(b, i + 18, 8, i + 30, 12);
|
|
1313
|
+
const cucp5 = getBitU(b, i + 46, 4);
|
|
1314
|
+
const m0 = getBitS3(b, i + 50, 2, i + 60, 22, i + 90, 8) * 2 ** -31 * GPS_PI;
|
|
1315
|
+
const cus = getBitS2(b, i + 98, 14, i + 120, 4) * 2 ** -31;
|
|
1316
|
+
const ep5 = getBitS(b, i + 124, 10);
|
|
1317
|
+
i = 8 * 38 * 5;
|
|
1318
|
+
const pgn6 = getBitU(b, i + 42, 4);
|
|
1319
|
+
const sow6 = getBitU22(b, i + 18, 8, i + 30, 12);
|
|
1320
|
+
const ep6 = getBitU22(b, i + 46, 6, i + 60, 16);
|
|
1321
|
+
const sqrtA = getBitU3(b, i + 76, 6, i + 90, 22, i + 120, 4) * 2 ** -19;
|
|
1322
|
+
const cicp6 = getBitS(b, i + 124, 10);
|
|
1323
|
+
i = 8 * 38 * 6;
|
|
1324
|
+
const pgn7 = getBitU(b, i + 42, 4);
|
|
1325
|
+
const sow7 = getBitU22(b, i + 18, 8, i + 30, 12);
|
|
1326
|
+
const cicp7 = getBitU22(b, i + 46, 6, i + 60, 2);
|
|
1327
|
+
const cis = getBitS(b, i + 62, 18) * 2 ** -31;
|
|
1328
|
+
const toes = getBitU22(b, i + 80, 2, i + 90, 15) * 8;
|
|
1329
|
+
const i0p7 = getBitS2(b, i + 105, 7, i + 120, 14);
|
|
1330
|
+
i = 8 * 38 * 7;
|
|
1331
|
+
const pgn8 = getBitU(b, i + 42, 4);
|
|
1332
|
+
const sow8 = getBitU22(b, i + 18, 8, i + 30, 12);
|
|
1333
|
+
const i0p8 = getBitU22(b, i + 46, 6, i + 60, 5);
|
|
1334
|
+
const crc = getBitS2(b, i + 65, 17, i + 90, 1) * 2 ** -6;
|
|
1335
|
+
const crs = getBitS(b, i + 91, 18) * 2 ** -6;
|
|
1336
|
+
const omegaDotP8 = getBitS2(b, i + 109, 3, i + 120, 16);
|
|
1337
|
+
i = 8 * 38 * 8;
|
|
1338
|
+
const pgn9 = getBitU(b, i + 42, 4);
|
|
1339
|
+
const sow9 = getBitU22(b, i + 18, 8, i + 30, 12);
|
|
1340
|
+
const omegaDotP9 = getBitU(b, i + 46, 5);
|
|
1341
|
+
const omega0 = getBitS3(b, i + 51, 1, i + 60, 22, i + 90, 9) * 2 ** -31 * GPS_PI;
|
|
1342
|
+
const omegaP9 = getBitS2(b, i + 99, 13, i + 120, 14);
|
|
1343
|
+
i = 8 * 38 * 9;
|
|
1344
|
+
const pgn10 = getBitU(b, i + 42, 4);
|
|
1345
|
+
const sow10 = getBitU22(b, i + 18, 8, i + 30, 12);
|
|
1346
|
+
const omegaP10 = getBitU(b, i + 46, 5);
|
|
1347
|
+
const idot = getBitS2(b, i + 51, 1, i + 60, 13) * 2 ** -43 * GPS_PI;
|
|
1348
|
+
if (pgn1 !== 1 || pgn3 !== 3 || pgn4 !== 4 || pgn5 !== 5 || pgn6 !== 6 || pgn7 !== 7 || pgn8 !== 8 || pgn9 !== 9 || pgn10 !== 10) {
|
|
1349
|
+
return null;
|
|
1350
|
+
}
|
|
1351
|
+
if (sow3 !== sow1 + 6 || sow4 !== sow3 + 3 || sow5 !== sow4 + 3 || sow6 !== sow5 + 3 || sow7 !== sow6 + 3 || sow8 !== sow7 + 3 || sow9 !== sow8 + 3 || sow10 !== sow9 + 3) {
|
|
1352
|
+
return null;
|
|
1353
|
+
}
|
|
1354
|
+
if (tocSec !== toes) return null;
|
|
1355
|
+
return buildBdsEphemeris(opts.prn ?? "C00", {
|
|
1356
|
+
week,
|
|
1357
|
+
sow: sow1,
|
|
1358
|
+
toes,
|
|
1359
|
+
tocSec,
|
|
1360
|
+
svh,
|
|
1361
|
+
tgd1,
|
|
1362
|
+
af0,
|
|
1363
|
+
af1: mergeS(af1p3, af1p4, 18) * 2 ** -50,
|
|
1364
|
+
af2,
|
|
1365
|
+
crs,
|
|
1366
|
+
deltaN,
|
|
1367
|
+
m0,
|
|
1368
|
+
cuc: mergeS(cucp4, cucp5, 4) * 2 ** -31,
|
|
1369
|
+
e: mergeS(ep5, ep6, 22) * 2 ** -33,
|
|
1370
|
+
cus,
|
|
1371
|
+
sqrtA,
|
|
1372
|
+
cic: mergeS(cicp6, cicp7, 8) * 2 ** -31,
|
|
1373
|
+
omega0,
|
|
1374
|
+
cis,
|
|
1375
|
+
i0: mergeS(i0p7, i0p8, 11) * 2 ** -31 * GPS_PI,
|
|
1376
|
+
crc,
|
|
1377
|
+
omega: mergeS(omegaP9, omegaP10, 5) * 2 ** -31 * GPS_PI,
|
|
1378
|
+
omegaDot: mergeS(omegaDotP8, omegaDotP9, 5) * 2 ** -43 * GPS_PI,
|
|
1379
|
+
idot
|
|
1380
|
+
});
|
|
1381
|
+
}
|
|
1382
|
+
function isBdsGeoPrn(prn) {
|
|
1383
|
+
return prn < 6 || prn > 58;
|
|
1384
|
+
}
|
|
1385
|
+
var BdsAssembler = class {
|
|
1386
|
+
sats = /* @__PURE__ */ new Map();
|
|
1387
|
+
/**
|
|
1388
|
+
* Push one 300-bit subframe (38+ bytes, bit 0 = first bit of the
|
|
1389
|
+
* preamble) for the satellite `prn` ("C06"). Returns the newly
|
|
1390
|
+
* completed ephemeris, or null.
|
|
1391
|
+
*/
|
|
1392
|
+
push(prn, subframe) {
|
|
1393
|
+
if (subframe.length < BDS_SUBFRAME_BYTES) return null;
|
|
1394
|
+
const num = parseInt(prn.slice(1), 10);
|
|
1395
|
+
if (!Number.isFinite(num) || num < 1 || num > 63) return null;
|
|
1396
|
+
const id = getBitU(subframe, 15, 3);
|
|
1397
|
+
if (id < 1 || id > 5) return null;
|
|
1398
|
+
let sat = this.sats.get(prn);
|
|
1399
|
+
if (!sat) {
|
|
1400
|
+
sat = { buf: new Uint8Array(10 * BDS_SUBFRAME_BYTES) };
|
|
1401
|
+
this.sats.set(prn, sat);
|
|
1402
|
+
}
|
|
1403
|
+
let eph = null;
|
|
1404
|
+
if (!isBdsGeoPrn(num)) {
|
|
1405
|
+
sat.buf.set(subframe.subarray(0, BDS_SUBFRAME_BYTES), (id - 1) * 38);
|
|
1406
|
+
if (id === 3) eph = decodeBdsD1Frame(sat.buf, { prn });
|
|
1407
|
+
} else {
|
|
1408
|
+
if (id !== 1) return null;
|
|
1409
|
+
const pgn = getBitU(subframe, 42, 4);
|
|
1410
|
+
if (pgn < 1 || pgn > 10) return null;
|
|
1411
|
+
sat.buf.set(subframe.subarray(0, BDS_SUBFRAME_BYTES), (pgn - 1) * 38);
|
|
1412
|
+
if (pgn === 10) eph = decodeBdsD2Frame(sat.buf, { prn });
|
|
1413
|
+
}
|
|
1414
|
+
if (!eph) return null;
|
|
1415
|
+
const key = `${eph.week}:${eph.toe}`;
|
|
1416
|
+
if (key === sat.lastKey) return null;
|
|
1417
|
+
sat.lastKey = key;
|
|
1418
|
+
return eph;
|
|
1419
|
+
}
|
|
1420
|
+
};
|
|
1421
|
+
|
|
1422
|
+
// src/navbits/glo.ts
|
|
1423
|
+
var GPS_EPOCH_MS5 = Date.UTC(1980, 0, 6);
|
|
1424
|
+
var SEC_PER_WEEK6 = 7 * 86400;
|
|
1425
|
+
var SEC_PER_DAY = 86400;
|
|
1426
|
+
var GLO_STRING_BYTES = 10;
|
|
1427
|
+
function getBitG(b, pos, len) {
|
|
1428
|
+
const value = getBitU(b, pos + 1, len - 1);
|
|
1429
|
+
return getBitU(b, pos, 1) && value !== 0 ? -value : value;
|
|
1430
|
+
}
|
|
1431
|
+
var HAMMING_MASKS = [
|
|
1432
|
+
[85, 85, 90, 170, 170, 170, 181, 85, 106, 216, 8],
|
|
1433
|
+
[102, 102, 108, 204, 204, 204, 217, 153, 179, 104, 16],
|
|
1434
|
+
[135, 135, 143, 15, 15, 15, 30, 30, 60, 112, 32],
|
|
1435
|
+
[7, 248, 15, 240, 15, 240, 31, 224, 63, 128, 64],
|
|
1436
|
+
[248, 0, 15, 255, 240, 0, 31, 255, 192, 0, 128],
|
|
1437
|
+
[0, 0, 15, 255, 255, 255, 224, 0, 0, 1, 0],
|
|
1438
|
+
[255, 255, 240, 0, 0, 0, 0, 0, 0, 2, 0],
|
|
1439
|
+
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 248]
|
|
1440
|
+
];
|
|
1441
|
+
function testGloString(buff) {
|
|
1442
|
+
if (buff.length < 11) return false;
|
|
1443
|
+
let n = 0;
|
|
1444
|
+
let cs = 0;
|
|
1445
|
+
for (const mask of HAMMING_MASKS) {
|
|
1446
|
+
cs = 0;
|
|
1447
|
+
for (let j = 0; j < 11; j++) {
|
|
1448
|
+
let x = buff[j] & mask[j];
|
|
1449
|
+
x ^= x >> 4;
|
|
1450
|
+
x ^= x >> 2;
|
|
1451
|
+
x ^= x >> 1;
|
|
1452
|
+
cs ^= x & 1;
|
|
1453
|
+
}
|
|
1454
|
+
if (cs) n++;
|
|
1455
|
+
}
|
|
1456
|
+
return n === 0 || n === 2 && cs === 1;
|
|
1457
|
+
}
|
|
1458
|
+
function decodeGloStrings(strings, refDate, opts = {}) {
|
|
1459
|
+
if (strings.length < 4 * GLO_STRING_BYTES) return null;
|
|
1460
|
+
const b = strings;
|
|
1461
|
+
let i = 1;
|
|
1462
|
+
const frn1 = getBitU(b, i, 4);
|
|
1463
|
+
i += 4 + 2;
|
|
1464
|
+
i += 2;
|
|
1465
|
+
const tkH = getBitU(b, i, 5);
|
|
1466
|
+
i += 5;
|
|
1467
|
+
const tkM = getBitU(b, i, 6);
|
|
1468
|
+
i += 6;
|
|
1469
|
+
const tkS = getBitU(b, i, 1) * 30;
|
|
1470
|
+
i += 1;
|
|
1471
|
+
const xDot = getBitG(b, i, 24) * 2 ** -20;
|
|
1472
|
+
i += 24;
|
|
1473
|
+
const xAcc = getBitG(b, i, 5) * 2 ** -30;
|
|
1474
|
+
i += 5;
|
|
1475
|
+
const x = getBitG(b, i, 27) * 2 ** -11;
|
|
1476
|
+
i = 80 + 1;
|
|
1477
|
+
const frn2 = getBitU(b, i, 4);
|
|
1478
|
+
i += 4;
|
|
1479
|
+
const bn = getBitU(b, i, 1);
|
|
1480
|
+
i += 1 + 2;
|
|
1481
|
+
i += 1;
|
|
1482
|
+
const tb = getBitU(b, i, 7);
|
|
1483
|
+
i += 7 + 5;
|
|
1484
|
+
const yDot = getBitG(b, i, 24) * 2 ** -20;
|
|
1485
|
+
i += 24;
|
|
1486
|
+
const yAcc = getBitG(b, i, 5) * 2 ** -30;
|
|
1487
|
+
i += 5;
|
|
1488
|
+
const y = getBitG(b, i, 27) * 2 ** -11;
|
|
1489
|
+
i = 160 + 1;
|
|
1490
|
+
const frn3 = getBitU(b, i, 4);
|
|
1491
|
+
i += 4;
|
|
1492
|
+
i += 1;
|
|
1493
|
+
const gammaN = getBitG(b, i, 11) * 2 ** -40;
|
|
1494
|
+
i += 11 + 1;
|
|
1495
|
+
i += 2;
|
|
1496
|
+
i += 1;
|
|
1497
|
+
const zDot = getBitG(b, i, 24) * 2 ** -20;
|
|
1498
|
+
i += 24;
|
|
1499
|
+
const zAcc = getBitG(b, i, 5) * 2 ** -30;
|
|
1500
|
+
i += 5;
|
|
1501
|
+
const z = getBitG(b, i, 27) * 2 ** -11;
|
|
1502
|
+
i = 240 + 1;
|
|
1503
|
+
const frn4 = getBitU(b, i, 4);
|
|
1504
|
+
i += 4;
|
|
1505
|
+
const tauN = getBitG(b, i, 22) * 2 ** -30;
|
|
1506
|
+
i += 22;
|
|
1507
|
+
i += 5;
|
|
1508
|
+
i += 5;
|
|
1509
|
+
i += 14;
|
|
1510
|
+
i += 1;
|
|
1511
|
+
i += 4;
|
|
1512
|
+
i += 3;
|
|
1513
|
+
i += 11;
|
|
1514
|
+
const slot = getBitU(b, i, 5);
|
|
1515
|
+
if (frn1 !== 1 || frn2 !== 2 || frn3 !== 3 || frn4 !== 4) return null;
|
|
1516
|
+
if (slot < 1 || slot > 27) return null;
|
|
1517
|
+
const utcSec = (getUtcDate(refDate).getTime() - GPS_EPOCH_MS5) / 1e3;
|
|
1518
|
+
const week = Math.floor(utcSec / SEC_PER_WEEK6);
|
|
1519
|
+
let tow = utcSec - week * SEC_PER_WEEK6;
|
|
1520
|
+
const tod = tow % SEC_PER_DAY;
|
|
1521
|
+
tow -= tod;
|
|
1522
|
+
let tof = tkH * 3600 + tkM * 60 + tkS - 10800;
|
|
1523
|
+
if (tof < tod - 43200) tof += SEC_PER_DAY;
|
|
1524
|
+
else if (tof > tod + 43200) tof -= SEC_PER_DAY;
|
|
1525
|
+
let toe = tb * 900 - 10800;
|
|
1526
|
+
if (toe < tod - 43200) toe += SEC_PER_DAY;
|
|
1527
|
+
else if (toe > tod + 43200) toe -= SEC_PER_DAY;
|
|
1528
|
+
return {
|
|
1529
|
+
system: "R",
|
|
1530
|
+
prn: `R${String(slot).padStart(2, "0")}`,
|
|
1531
|
+
// RINEX GLONASS epochs are UTC: build the UTC toe Date directly.
|
|
1532
|
+
tocDate: new Date(GPS_EPOCH_MS5 + (week * SEC_PER_WEEK6 + tow + toe) * 1e3),
|
|
1533
|
+
tauN: -tauN,
|
|
1534
|
+
// RINEX stores −τn; the SIS carries τn (ICD sign)
|
|
1535
|
+
gammaN,
|
|
1536
|
+
// v3 message frame time: seconds of the UTC week (RTKLIB tof).
|
|
1537
|
+
messageFrameTime: ((tow + tof) % SEC_PER_WEEK6 + SEC_PER_WEEK6) % SEC_PER_WEEK6,
|
|
1538
|
+
x,
|
|
1539
|
+
xDot,
|
|
1540
|
+
xAcc,
|
|
1541
|
+
y,
|
|
1542
|
+
yDot,
|
|
1543
|
+
yAcc,
|
|
1544
|
+
z,
|
|
1545
|
+
zDot,
|
|
1546
|
+
zAcc,
|
|
1547
|
+
// MSB of the 3-bit Bn word — the unhealthy flag RINEX carries
|
|
1548
|
+
health: bn,
|
|
1549
|
+
freqNum: opts.freqNum ?? 0
|
|
1550
|
+
};
|
|
1551
|
+
}
|
|
1552
|
+
var GloStringAssembler = class {
|
|
1553
|
+
sats = /* @__PURE__ */ new Map();
|
|
1554
|
+
/**
|
|
1555
|
+
* Push one navigation string (10+ bytes, bit 0 = string bit 85) for
|
|
1556
|
+
* the satellite `prn` ("R09"), received at the GPS-scale `time`.
|
|
1557
|
+
* Returns the newly completed ephemeris, or null. The decoded
|
|
1558
|
+
* string-4 slot number must match `prn`, or nothing is emitted.
|
|
1559
|
+
*/
|
|
1560
|
+
push(prn, str, time, freqNum = 0) {
|
|
1561
|
+
if (str.length < GLO_STRING_BYTES) return null;
|
|
1562
|
+
const m = getBitU(str, 1, 4);
|
|
1563
|
+
if (m < 1) return null;
|
|
1564
|
+
const sec = Math.floor(time.getTime() / 1e3);
|
|
1565
|
+
let sat = this.sats.get(prn);
|
|
1566
|
+
if (!sat) {
|
|
1567
|
+
sat = { buf: new Uint8Array(4 * GLO_STRING_BYTES), batchSec: sec };
|
|
1568
|
+
this.sats.set(prn, sat);
|
|
1569
|
+
} else if (Math.abs(sec - sat.batchSec) > 30) {
|
|
1570
|
+
sat.buf.fill(0);
|
|
1571
|
+
sat.batchSec = sec;
|
|
1572
|
+
}
|
|
1573
|
+
if (m > 4) return null;
|
|
1574
|
+
sat.buf.set(str.subarray(0, GLO_STRING_BYTES), (m - 1) * 10);
|
|
1575
|
+
if (m !== 4) return null;
|
|
1576
|
+
const eph = decodeGloStrings(sat.buf, time, { freqNum });
|
|
1577
|
+
if (!eph || eph.prn !== prn) return null;
|
|
1578
|
+
const key = `${eph.tocDate.getTime()}:${eph.health}`;
|
|
1579
|
+
if (key === sat.lastKey) return null;
|
|
1580
|
+
sat.lastKey = key;
|
|
1581
|
+
return eph;
|
|
1582
|
+
}
|
|
1583
|
+
};
|
|
1584
|
+
|
|
1585
|
+
// src/sbf/rawnav-bds.ts
|
|
1586
|
+
var GPS_EPOCH_MS6 = Date.UTC(1980, 0, 6);
|
|
1587
|
+
var MS_PER_WEEK3 = 7 * 86400 * 1e3;
|
|
1588
|
+
var TOW_DNU = 4294967295;
|
|
1589
|
+
var WNC_DNU = 65535;
|
|
1590
|
+
function parseSbfBdsNav(data) {
|
|
1591
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
1592
|
+
const ephemerides = [];
|
|
1593
|
+
const assembler = new BdsAssembler();
|
|
1594
|
+
let badCrc = 0;
|
|
1595
|
+
let messages = 0;
|
|
1596
|
+
scanSbfFrames(data, view, (id, b, len) => {
|
|
1597
|
+
if (id !== 4047 || len < 60) return;
|
|
1598
|
+
messages++;
|
|
1599
|
+
const prn = svidToPrn(view.getUint8(b + 14));
|
|
1600
|
+
if (!prn || prn[0] !== "C") return;
|
|
1601
|
+
const sf = new Uint8Array(38);
|
|
1602
|
+
for (let k = 0; k < 10; k++) {
|
|
1603
|
+
const w = view.getUint32(b + 20 + 4 * k, true);
|
|
1604
|
+
sf[4 * k] = w >>> 24;
|
|
1605
|
+
if (k < 9) {
|
|
1606
|
+
sf[4 * k + 1] = w >>> 16 & 255;
|
|
1607
|
+
sf[4 * k + 2] = w >>> 8 & 255;
|
|
1608
|
+
sf[4 * k + 3] = w & 255;
|
|
1609
|
+
} else {
|
|
1610
|
+
sf[37] = w >>> 16 & 240;
|
|
1611
|
+
}
|
|
1612
|
+
}
|
|
1613
|
+
if (!bdsSubframeParityOk(sf)) {
|
|
1614
|
+
badCrc++;
|
|
1615
|
+
return;
|
|
1616
|
+
}
|
|
1617
|
+
const eph = assembler.push(prn, sf);
|
|
1618
|
+
if (eph) ephemerides.push(eph);
|
|
1619
|
+
});
|
|
1620
|
+
return { ephemerides, badCrc, messages };
|
|
1621
|
+
}
|
|
1622
|
+
function parseSbfGloNav(data) {
|
|
1623
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
1624
|
+
const ephemerides = [];
|
|
1625
|
+
const assembler = new GloStringAssembler();
|
|
1626
|
+
let badCrc = 0;
|
|
1627
|
+
let messages = 0;
|
|
1628
|
+
scanSbfFrames(data, view, (id, b, len) => {
|
|
1629
|
+
if (id !== 4026 || len < 32) return;
|
|
1630
|
+
messages++;
|
|
1631
|
+
const prn = svidToPrn(view.getUint8(b + 14));
|
|
1632
|
+
if (!prn || prn[0] !== "R") return;
|
|
1633
|
+
const towMs = view.getUint32(b + 8, true);
|
|
1634
|
+
const wnc = view.getUint16(b + 12, true);
|
|
1635
|
+
if (towMs === TOW_DNU || wnc === WNC_DNU) return;
|
|
1636
|
+
const str = new Uint8Array(11);
|
|
1637
|
+
for (let k = 0; k < 3; k++) {
|
|
1638
|
+
const w = view.getUint32(b + 20 + 4 * k, true);
|
|
1639
|
+
str[4 * k] = w >>> 24;
|
|
1640
|
+
if (k < 2) {
|
|
1641
|
+
str[4 * k + 1] = w >>> 16 & 255;
|
|
1642
|
+
str[4 * k + 2] = w >>> 8 & 255;
|
|
1643
|
+
str[4 * k + 3] = w & 255;
|
|
1644
|
+
} else {
|
|
1645
|
+
str[9] = w >>> 16 & 255;
|
|
1646
|
+
str[10] = w >>> 8 & 248;
|
|
1647
|
+
}
|
|
1648
|
+
}
|
|
1649
|
+
if (!testGloString(str)) {
|
|
1650
|
+
badCrc++;
|
|
1651
|
+
return;
|
|
1652
|
+
}
|
|
1653
|
+
const eph = assembler.push(
|
|
1654
|
+
prn,
|
|
1655
|
+
str,
|
|
1656
|
+
new Date(GPS_EPOCH_MS6 + wnc * MS_PER_WEEK3 + towMs),
|
|
1657
|
+
view.getUint8(b + 18) - 8
|
|
1658
|
+
// FreqNr, offset by 8
|
|
1659
|
+
);
|
|
1660
|
+
if (eph) ephemerides.push(eph);
|
|
1661
|
+
});
|
|
1662
|
+
return { ephemerides, badCrc, messages };
|
|
1663
|
+
}
|
|
1664
|
+
|
|
771
1665
|
// src/sbf/index.ts
|
|
772
1666
|
var CLIGHT = 299792458;
|
|
773
|
-
var
|
|
774
|
-
var
|
|
1667
|
+
var GPS_EPOCH_MS7 = Date.UTC(1980, 0, 6);
|
|
1668
|
+
var MS_PER_WEEK4 = 7 * 864e5;
|
|
775
1669
|
var M3_SYS = ["G", "R", "E", "C", "S", "J", "I"];
|
|
776
1670
|
var M3_PR_BASE = [19e6, 19e6, 22e6, 2e7, 34e6, 34e6, 34e6];
|
|
777
1671
|
var M3_INTERVALS = [
|
|
@@ -870,23 +1764,23 @@ var MEAS2_SIG = [
|
|
|
870
1764
|
["J", "1E"],
|
|
871
1765
|
["J", "5P"]
|
|
872
1766
|
];
|
|
873
|
-
var
|
|
1767
|
+
var two3 = (n) => String(n).padStart(2, "0");
|
|
874
1768
|
function m3Prn(navsys, svid) {
|
|
875
1769
|
switch (navsys) {
|
|
876
1770
|
case 0:
|
|
877
|
-
return svid < 32 ? `G${
|
|
1771
|
+
return svid < 32 ? `G${two3(svid + 1)}` : null;
|
|
878
1772
|
case 1:
|
|
879
|
-
return svid < 27 ? `R${
|
|
1773
|
+
return svid < 27 ? `R${two3(svid + 1)}` : null;
|
|
880
1774
|
case 2:
|
|
881
|
-
return svid < 36 ? `E${
|
|
1775
|
+
return svid < 36 ? `E${two3(svid + 1)}` : null;
|
|
882
1776
|
case 3:
|
|
883
|
-
return svid < 50 ? `C${
|
|
1777
|
+
return svid < 50 ? `C${two3(svid + 1)}` : null;
|
|
884
1778
|
case 4:
|
|
885
|
-
return svid <= 38 ? `S${
|
|
1779
|
+
return svid <= 38 ? `S${two3(svid + 20)}` : null;
|
|
886
1780
|
case 5:
|
|
887
|
-
return svid < 10 ? `J${
|
|
1781
|
+
return svid < 10 ? `J${two3(svid + 1)}` : null;
|
|
888
1782
|
case 6:
|
|
889
|
-
return svid < 14 ? `I${
|
|
1783
|
+
return svid < 14 ? `I${two3(svid + 1)}` : null;
|
|
890
1784
|
default:
|
|
891
1785
|
return null;
|
|
892
1786
|
}
|
|
@@ -1424,7 +2318,7 @@ function parseSbfMeas(data) {
|
|
|
1424
2318
|
const tow = view.getUint32(i + 8, true);
|
|
1425
2319
|
const wnc = view.getUint16(i + 12, true);
|
|
1426
2320
|
if (tow !== 4294967295 && wnc !== 65535) {
|
|
1427
|
-
ensureEpoch(
|
|
2321
|
+
ensureEpoch(GPS_EPOCH_MS7 + wnc * MS_PER_WEEK4 + tow);
|
|
1428
2322
|
if (id === 4109) decodeMeas3Ranges(i, tow);
|
|
1429
2323
|
else if (id === 4110) decodeMeas3CN0(i, len);
|
|
1430
2324
|
else if (id === 4111) decodeMeas3Doppler(i, len);
|
|
@@ -1438,7 +2332,10 @@ function parseSbfMeas(data) {
|
|
|
1438
2332
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1439
2333
|
0 && (module.exports = {
|
|
1440
2334
|
parseSbfAlmanac,
|
|
2335
|
+
parseSbfBdsNav,
|
|
1441
2336
|
parseSbfCnav,
|
|
2337
|
+
parseSbfGalNav,
|
|
2338
|
+
parseSbfGloNav,
|
|
1442
2339
|
parseSbfIonoUtc,
|
|
1443
2340
|
parseSbfMeas,
|
|
1444
2341
|
parseSbfNav,
|