gnss-js 1.20.0 → 1.22.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/index.d.cts CHANGED
@@ -9,8 +9,8 @@ export { E as EpochSummary, P as ParseOptions, R as RinexHeader, a as RinexResul
9
9
  export { C as CnavEphemeris, E as Ephemeris, G as GlonassEphemeris, K as KeplerEphemeris, N as NavHeader, a as NavResult, R as RinexCnavEphemeris, p as parseNavFile } from './nav-DImXUdbp.cjs';
10
10
  export { B as BitReader, E as EphemerisInfo, R as Rtcm3DebugHandler, a as Rtcm3Decoder, b as Rtcm3Frame, d as decodeEphemeris, r as readString, c as reportDecodeError, s as setRtcm3DebugHandler } from './ephemeris-Ohl6NAfw.cjs';
11
11
  export { MessageTypeStats, MsmEpoch, MsmSatObs, MsmSignal, RTCM3_MESSAGE_NAMES, SatCn0, SignalCn0, StationMeta, StreamStats, createStationMeta, createStreamStats, decodeMsmFull, msmEpochToDate, resetGloFreqCache, rtcm3Constellation, setGloFreqNumber, updateStationMeta, updateStreamStats } from './rtcm3.cjs';
12
- export { UbxCnavResult, UbxFrame, UbxIonoUtcResult, UbxMeasurement, UbxNavOptions, UbxNavResult, UbxParseResult, UbxRawxEpoch, parseUbxCnav, parseUbxIonoUtc, parseUbxNav, parseUbxRawx, ubxFrames } from './ubx.cjs';
13
- export { SbfBdsNavResult, SbfCnavEphemeris, SbfCnavResult, SbfGalEphemeris, SbfGalNavResult, SbfGloNavResult, SbfIonoUtcResult, SbfMeasEpoch, SbfMeasurement, SbfParseResult, parseSbfBdsNav, parseSbfCnav, parseSbfGalNav, parseSbfGloNav, parseSbfIonoUtc, parseSbfMeas, sbfCrc16, scanSbfFrames } from './sbf.cjs';
12
+ export { UbxCnavResult, UbxFrame, UbxIonoUtcResult, UbxMeasurement, UbxNavOptions, UbxNavResult, UbxParseResult, UbxRawNavOptions, UbxRawNavResult, UbxRawxEpoch, parseUbxCnav, parseUbxIonoUtc, parseUbxNav, parseUbxRawNav, parseUbxRawx, ubxFrames } from './ubx.cjs';
13
+ export { HasMessage, SbfBdsNavResult, SbfCnavEphemeris, SbfCnavResult, SbfGalEphemeris, SbfGalNavResult, SbfGloNavResult, SbfHasMessage, SbfHasResult, SbfIonoUtcResult, SbfMeasEpoch, SbfMeasurement, SbfParseResult, parseSbfBdsNav, parseSbfCnav, parseSbfGalNav, parseSbfGloNav, parseSbfHas, parseSbfIonoUtc, parseSbfMeas, sbfCrc16, scanSbfFrames } from './sbf.cjs';
14
14
  export { NovatelEpoch, NovatelMeasurement, NovatelNavResult, NovatelParseResult, OEM4_HLEN, Oem4Frame, crc32, oem4Frames, parseNovatelNav, parseNovatelRange } from './novatel.cjs';
15
15
  export { AllPositionsData, AlmanacPosition, DopValues, EpochSkyData, SatAzEl, SatPoint, SatPosition, VisibilityPass, VisibilityResult, almanacEpochMs, almanacSatPosition, computeAllPositions, computeDop, computeLiveSkyPositions, computeSatPosition, computeVisibility, computeVisibilityFromPositions, dopplerHz, ecefToAzEl, ephInfoToEphemeris, glonassAlmanacEpochMs, glonassAlmanacPosition, glonassPosition, keplerPosition, maskRadForAzimuth, navTimesFromEph, rangeRate, selectEphemeris } from './orbit.cjs';
16
16
  export { Helmert14, REFERENCE_FRAMES, ReferenceFrame, applyHelmert, dateToEpoch, transformFrame } from './frames.cjs';
package/dist/index.d.ts CHANGED
@@ -9,8 +9,8 @@ export { E as EpochSummary, P as ParseOptions, R as RinexHeader, a as RinexResul
9
9
  export { C as CnavEphemeris, E as Ephemeris, G as GlonassEphemeris, K as KeplerEphemeris, N as NavHeader, a as NavResult, R as RinexCnavEphemeris, p as parseNavFile } from './nav-DImXUdbp.js';
10
10
  export { B as BitReader, E as EphemerisInfo, R as Rtcm3DebugHandler, a as Rtcm3Decoder, b as Rtcm3Frame, d as decodeEphemeris, r as readString, c as reportDecodeError, s as setRtcm3DebugHandler } from './ephemeris-Ohl6NAfw.js';
11
11
  export { MessageTypeStats, MsmEpoch, MsmSatObs, MsmSignal, RTCM3_MESSAGE_NAMES, SatCn0, SignalCn0, StationMeta, StreamStats, createStationMeta, createStreamStats, decodeMsmFull, msmEpochToDate, resetGloFreqCache, rtcm3Constellation, setGloFreqNumber, updateStationMeta, updateStreamStats } from './rtcm3.js';
12
- export { UbxCnavResult, UbxFrame, UbxIonoUtcResult, UbxMeasurement, UbxNavOptions, UbxNavResult, UbxParseResult, UbxRawxEpoch, parseUbxCnav, parseUbxIonoUtc, parseUbxNav, parseUbxRawx, ubxFrames } from './ubx.js';
13
- export { SbfBdsNavResult, SbfCnavEphemeris, SbfCnavResult, SbfGalEphemeris, SbfGalNavResult, SbfGloNavResult, SbfIonoUtcResult, SbfMeasEpoch, SbfMeasurement, SbfParseResult, parseSbfBdsNav, parseSbfCnav, parseSbfGalNav, parseSbfGloNav, parseSbfIonoUtc, parseSbfMeas, sbfCrc16, scanSbfFrames } from './sbf.js';
12
+ export { UbxCnavResult, UbxFrame, UbxIonoUtcResult, UbxMeasurement, UbxNavOptions, UbxNavResult, UbxParseResult, UbxRawNavOptions, UbxRawNavResult, UbxRawxEpoch, parseUbxCnav, parseUbxIonoUtc, parseUbxNav, parseUbxRawNav, parseUbxRawx, ubxFrames } from './ubx.js';
13
+ export { HasMessage, SbfBdsNavResult, SbfCnavEphemeris, SbfCnavResult, SbfGalEphemeris, SbfGalNavResult, SbfGloNavResult, SbfHasMessage, SbfHasResult, SbfIonoUtcResult, SbfMeasEpoch, SbfMeasurement, SbfParseResult, parseSbfBdsNav, parseSbfCnav, parseSbfGalNav, parseSbfGloNav, parseSbfHas, parseSbfIonoUtc, parseSbfMeas, sbfCrc16, scanSbfFrames } from './sbf.js';
14
14
  export { NovatelEpoch, NovatelMeasurement, NovatelNavResult, NovatelParseResult, OEM4_HLEN, Oem4Frame, crc32, oem4Frames, parseNovatelNav, parseNovatelRange } from './novatel.js';
15
15
  export { AllPositionsData, AlmanacPosition, DopValues, EpochSkyData, SatAzEl, SatPoint, SatPosition, VisibilityPass, VisibilityResult, almanacEpochMs, almanacSatPosition, computeAllPositions, computeDop, computeLiveSkyPositions, computeSatPosition, computeVisibility, computeVisibilityFromPositions, dopplerHz, ecefToAzEl, ephInfoToEphemeris, glonassAlmanacEpochMs, glonassAlmanacPosition, glonassPosition, keplerPosition, maskRadForAzimuth, navTimesFromEph, rangeRate, selectEphemeris } from './orbit.js';
16
16
  export { Helmert14, REFERENCE_FRAMES, ReferenceFrame, applyHelmert, dateToEpoch, transformFrame } from './frames.js';
package/dist/index.js CHANGED
@@ -37,9 +37,10 @@ import {
37
37
  parseUbxCnav,
38
38
  parseUbxIonoUtc,
39
39
  parseUbxNav,
40
+ parseUbxRawNav,
40
41
  parseUbxRawx,
41
42
  ubxFrames
42
- } from "./chunk-DLXTTHRK.js";
43
+ } from "./chunk-MCAVU3XL.js";
43
44
  import {
44
45
  crc16,
45
46
  parseSbfAlmanac,
@@ -47,11 +48,13 @@ import {
47
48
  parseSbfCnav,
48
49
  parseSbfGalNav,
49
50
  parseSbfGloNav,
51
+ parseSbfHas,
50
52
  parseSbfIonoUtc,
51
53
  parseSbfMeas,
52
54
  parseSbfNav,
53
55
  scanSbfFrames
54
- } from "./chunk-VJEPOC76.js";
56
+ } from "./chunk-PZNVFCKJ.js";
57
+ import "./chunk-VTX3VCL4.js";
55
58
  import {
56
59
  OEM4_HLEN,
57
60
  crc32,
@@ -509,6 +512,7 @@ export {
509
512
  parseSbfCnav,
510
513
  parseSbfGalNav,
511
514
  parseSbfGloNav,
515
+ parseSbfHas,
512
516
  parseSbfIonoUtc,
513
517
  parseSbfMeas,
514
518
  parseSbfNav,
@@ -518,6 +522,7 @@ export {
518
522
  parseUbxCnav,
519
523
  parseUbxIonoUtc,
520
524
  parseUbxNav,
525
+ parseUbxRawNav,
521
526
  parseUbxRawx,
522
527
  phiAltBOC,
523
528
  phiBOCc,
package/dist/sbf.cjs CHANGED
@@ -25,6 +25,7 @@ __export(sbf_exports, {
25
25
  parseSbfCnav: () => parseSbfCnav,
26
26
  parseSbfGalNav: () => parseSbfGalNav,
27
27
  parseSbfGloNav: () => parseSbfGloNav,
28
+ parseSbfHas: () => parseSbfHas,
28
29
  parseSbfIonoUtc: () => parseSbfIonoUtc,
29
30
  parseSbfMeas: () => parseSbfMeas,
30
31
  parseSbfNav: () => parseSbfNav,
@@ -1662,6 +1663,529 @@ function parseSbfGloNav(data) {
1662
1663
  return { ephemerides, badCrc, messages };
1663
1664
  }
1664
1665
 
1666
+ // src/navbits/rs255.ts
1667
+ var RS255_N = 255;
1668
+ var RS255_K = 32;
1669
+ var EXP = new Uint8Array(510);
1670
+ var LOG = new Int16Array(256).fill(-1);
1671
+ {
1672
+ let x = 1;
1673
+ for (let i = 0; i < 255; i++) {
1674
+ EXP[i] = x;
1675
+ LOG[x] = i;
1676
+ x <<= 1;
1677
+ if (x & 256) x ^= 285;
1678
+ }
1679
+ for (let i = 255; i < 510; i++) EXP[i] = EXP[i - 255];
1680
+ }
1681
+ var gfMul = (a, b) => a === 0 || b === 0 ? 0 : EXP[LOG[a] + LOG[b]];
1682
+ var gfInv = (a) => EXP[255 - LOG[a]];
1683
+ var GEN_POLY = (() => {
1684
+ let g = new Uint8Array([1]);
1685
+ for (let i = 1; i <= 223; i++) {
1686
+ const root = EXP[i];
1687
+ const next = new Uint8Array(g.length + 1);
1688
+ for (let j = 0; j < g.length; j++) {
1689
+ next[j] ^= g[j];
1690
+ next[j + 1] ^= gfMul(g[j], root);
1691
+ }
1692
+ g = next;
1693
+ }
1694
+ return g;
1695
+ })();
1696
+ function rs255Encode(info) {
1697
+ if (info.length > RS255_K)
1698
+ throw new RangeError(`rs255Encode: info length ${info.length} > 32`);
1699
+ const cw = new Uint8Array(RS255_N);
1700
+ cw.set(info, 0);
1701
+ const work = new Uint8Array(RS255_N);
1702
+ work.set(info, 0);
1703
+ for (let i = 0; i < RS255_K; i++) {
1704
+ const coef = work[i];
1705
+ if (coef === 0) continue;
1706
+ for (let j = 1; j < GEN_POLY.length; j++)
1707
+ work[i + j] ^= gfMul(GEN_POLY[j], coef);
1708
+ }
1709
+ cw.set(work.subarray(RS255_K), RS255_K);
1710
+ return cw;
1711
+ }
1712
+ var genMatrix = null;
1713
+ function generatorMatrix() {
1714
+ if (genMatrix) return genMatrix;
1715
+ const rows = [];
1716
+ for (let r = 0; r < RS255_N; r++) rows.push(new Uint8Array(RS255_K));
1717
+ for (let c = 0; c < RS255_K; c++) {
1718
+ const e = new Uint8Array(RS255_K);
1719
+ e[c] = 1;
1720
+ const cw = rs255Encode(e);
1721
+ for (let r = 0; r < RS255_N; r++) rows[r][c] = cw[r];
1722
+ }
1723
+ genMatrix = rows;
1724
+ return rows;
1725
+ }
1726
+ function rs255DecodeErasures(pages, k) {
1727
+ if (k < 1 || k > RS255_K) return null;
1728
+ const seen = /* @__PURE__ */ new Set();
1729
+ const use = [];
1730
+ for (const p of pages) {
1731
+ if (p.pageId < 1 || p.pageId > RS255_N || seen.has(p.pageId)) continue;
1732
+ seen.add(p.pageId);
1733
+ use.push(p);
1734
+ if (use.length === k) break;
1735
+ }
1736
+ if (use.length < k) return null;
1737
+ const width = use[0].octets.length;
1738
+ if (use.some((p) => p.octets.length !== width)) return null;
1739
+ const G = generatorMatrix();
1740
+ const a = use.map((p) => G[p.pageId - 1].slice(0, k));
1741
+ const inv = use.map((_, r) => {
1742
+ const row = new Uint8Array(k);
1743
+ row[r] = 1;
1744
+ return row;
1745
+ });
1746
+ for (let c = 0; c < k; c++) {
1747
+ let pivot = -1;
1748
+ for (let r = c; r < k; r++)
1749
+ if (a[r][c] !== 0) {
1750
+ pivot = r;
1751
+ break;
1752
+ }
1753
+ if (pivot < 0) return null;
1754
+ [a[c], a[pivot]] = [a[pivot], a[c]];
1755
+ [inv[c], inv[pivot]] = [inv[pivot], inv[c]];
1756
+ const s = gfInv(a[c][c]);
1757
+ for (let j = 0; j < k; j++) {
1758
+ a[c][j] = gfMul(a[c][j], s);
1759
+ inv[c][j] = gfMul(inv[c][j], s);
1760
+ }
1761
+ for (let r = 0; r < k; r++) {
1762
+ if (r === c || a[r][c] === 0) continue;
1763
+ const f = a[r][c];
1764
+ for (let j = 0; j < k; j++) {
1765
+ a[r][j] ^= gfMul(a[c][j], f);
1766
+ inv[r][j] ^= gfMul(inv[c][j], f);
1767
+ }
1768
+ }
1769
+ }
1770
+ const out = new Uint8Array(k * width);
1771
+ for (let r = 0; r < k; r++)
1772
+ for (let c = 0; c < width; c++) {
1773
+ let v = 0;
1774
+ for (let j = 0; j < k; j++) v ^= gfMul(inv[r][j], use[j].octets[c]);
1775
+ out[r * width + c] = v;
1776
+ }
1777
+ return out;
1778
+ }
1779
+
1780
+ // src/navbits/has.ts
1781
+ var HAS_DUMMY_HEADER = 11484099;
1782
+ var HAS_VALIDITY_SECONDS = [
1783
+ 5,
1784
+ 10,
1785
+ 15,
1786
+ 20,
1787
+ 30,
1788
+ 60,
1789
+ 90,
1790
+ 120,
1791
+ 180,
1792
+ 240,
1793
+ 300,
1794
+ 600,
1795
+ 900,
1796
+ 1800,
1797
+ 3600,
1798
+ null
1799
+ ];
1800
+ var HAS_GPS_SIGNALS = [
1801
+ "L1 C/A",
1802
+ "Reserved",
1803
+ "Reserved",
1804
+ "L1C(D)",
1805
+ "L1C(P)",
1806
+ "L1C(D+P)",
1807
+ "L2 CM",
1808
+ "L2 CL",
1809
+ "L2 CM+CL",
1810
+ "L2 P",
1811
+ "Reserved",
1812
+ "L5 I",
1813
+ "L5 Q",
1814
+ "L5 I+Q",
1815
+ "Reserved",
1816
+ "Reserved"
1817
+ ];
1818
+ var HAS_GALILEO_SIGNALS = [
1819
+ "E1-B",
1820
+ "E1-C",
1821
+ "E1-B+E1-C",
1822
+ "E5a-I",
1823
+ "E5a-Q",
1824
+ "E5a-I+E5a-Q",
1825
+ "E5b-I",
1826
+ "E5b-Q",
1827
+ "E5b-I+E5b-Q",
1828
+ "E5-I",
1829
+ "E5-Q",
1830
+ "E5-I+E5-Q",
1831
+ "E6-B",
1832
+ "E6-C",
1833
+ "E6-B+E6-C",
1834
+ "Reserved"
1835
+ ];
1836
+ var SYSTEM_OF_GNSS_ID = { 0: "G", 2: "E" };
1837
+ var IOD_BITS = { G: 8, E: 10 };
1838
+ function hasPageCrcOk(page) {
1839
+ if (page.length < 61) return false;
1840
+ return crc24q(page, 462) === getBitU(page, 462, 24);
1841
+ }
1842
+ function parseHasPage(page) {
1843
+ if (getBitU(page, 14, 24) === HAS_DUMMY_HEADER) return null;
1844
+ const body = new Uint8Array(53);
1845
+ for (let i = 0; i < 53; i++) body[i] = getBitU(page, 38 + 8 * i, 8);
1846
+ return {
1847
+ status: getBitU(page, 14, 2),
1848
+ messageType: getBitU(page, 18, 2),
1849
+ messageId: getBitU(page, 20, 5),
1850
+ messageSize: getBitU(page, 25, 5) + 1,
1851
+ pageId: getBitU(page, 30, 8),
1852
+ body
1853
+ };
1854
+ }
1855
+ var Cursor = class {
1856
+ constructor(buf, bits) {
1857
+ this.buf = buf;
1858
+ this.bits = bits;
1859
+ }
1860
+ pos = 0;
1861
+ u(len) {
1862
+ if (this.pos + len > this.bits) throw new RangeError("truncated");
1863
+ const v = getBitU(this.buf, this.pos, len);
1864
+ this.pos += len;
1865
+ return v;
1866
+ }
1867
+ s(len) {
1868
+ if (this.pos + len > this.bits) throw new RangeError("truncated");
1869
+ const v = getBitS(this.buf, this.pos, len);
1870
+ this.pos += len;
1871
+ return v;
1872
+ }
1873
+ };
1874
+ var prnOf = (system, idx) => `${system}${String(idx + 1).padStart(2, "0")}`;
1875
+ function parseMaskBlock(c, maskId) {
1876
+ const nSys = c.u(4);
1877
+ const systems = [];
1878
+ for (let s = 0; s < nSys; s++) {
1879
+ const gnssId = c.u(4);
1880
+ const system = SYSTEM_OF_GNSS_ID[gnssId];
1881
+ if (system === void 0) throw new RangeError(`unknown GNSS ID ${gnssId}`);
1882
+ const prns = [];
1883
+ for (let b = 0; b < 40; b++) if (c.u(1)) prns.push(prnOf(system, b));
1884
+ const signalIndices = [];
1885
+ for (let b = 0; b < 16; b++) if (c.u(1)) signalIndices.push(b);
1886
+ const signalNames = system === "G" ? HAS_GPS_SIGNALS : HAS_GALILEO_SIGNALS;
1887
+ let cellMask = null;
1888
+ if (c.u(1)) {
1889
+ cellMask = prns.map(() => signalIndices.map(() => c.u(1) === 1));
1890
+ }
1891
+ systems.push({
1892
+ gnssId,
1893
+ system,
1894
+ prns,
1895
+ signalIndices,
1896
+ signals: signalIndices.map((i) => signalNames[i]),
1897
+ cellMask,
1898
+ navMessage: c.u(3)
1899
+ });
1900
+ }
1901
+ c.u(6);
1902
+ return { maskId, systems };
1903
+ }
1904
+ function parseOrbitBlock(c, masks) {
1905
+ const validityIndex = c.u(4);
1906
+ const corrections = [];
1907
+ for (const sys of masks.systems) {
1908
+ for (const prn of sys.prns) {
1909
+ const gnssIod = c.u(IOD_BITS[sys.system]);
1910
+ const rad = c.s(13);
1911
+ const inT = c.s(12);
1912
+ const cross = c.s(12);
1913
+ corrections.push({
1914
+ system: sys.system,
1915
+ prn,
1916
+ gnssIod,
1917
+ deltaRadial: rad === -4096 ? null : rad * 25e-4,
1918
+ deltaInTrack: inT === -2048 ? null : inT * 8e-3,
1919
+ deltaCrossTrack: cross === -2048 ? null : cross * 8e-3
1920
+ });
1921
+ }
1922
+ }
1923
+ return {
1924
+ validityIndex,
1925
+ validitySeconds: HAS_VALIDITY_SECONDS[validityIndex],
1926
+ corrections
1927
+ };
1928
+ }
1929
+ function clockValue(c, system, prn, multiplier) {
1930
+ const raw = c.s(13);
1931
+ return {
1932
+ system,
1933
+ prn,
1934
+ deltaClock: raw === -4096 || raw === 4095 ? null : raw * 25e-4 * multiplier,
1935
+ notUsable: raw === 4095
1936
+ };
1937
+ }
1938
+ function parseClockFullBlock(c, masks) {
1939
+ const validityIndex = c.u(4);
1940
+ const multipliers = masks.systems.map((sys) => ({
1941
+ system: sys.system,
1942
+ multiplier: c.u(2) + 1
1943
+ }));
1944
+ const corrections = [];
1945
+ for (let s = 0; s < masks.systems.length; s++) {
1946
+ const sys = masks.systems[s];
1947
+ for (const prn of sys.prns)
1948
+ corrections.push(
1949
+ clockValue(c, sys.system, prn, multipliers[s].multiplier)
1950
+ );
1951
+ }
1952
+ return {
1953
+ validityIndex,
1954
+ validitySeconds: HAS_VALIDITY_SECONDS[validityIndex],
1955
+ multipliers,
1956
+ corrections
1957
+ };
1958
+ }
1959
+ function parseClockSubsetBlock(c, masks) {
1960
+ const validityIndex = c.u(4);
1961
+ const nSys = c.u(4);
1962
+ const multipliers = [];
1963
+ const corrections = [];
1964
+ for (let s = 0; s < nSys; s++) {
1965
+ const gnssId = c.u(4);
1966
+ const sys = masks.systems.find((m) => m.gnssId === gnssId);
1967
+ if (!sys) throw new RangeError(`subset GNSS ID ${gnssId} not in mask`);
1968
+ const multiplier = c.u(2) + 1;
1969
+ multipliers.push({ system: sys.system, multiplier });
1970
+ const selected = [];
1971
+ for (const prn of sys.prns) if (c.u(1)) selected.push(prn);
1972
+ for (const prn of selected)
1973
+ corrections.push(clockValue(c, sys.system, prn, multiplier));
1974
+ }
1975
+ return {
1976
+ validityIndex,
1977
+ validitySeconds: HAS_VALIDITY_SECONDS[validityIndex],
1978
+ multipliers,
1979
+ corrections
1980
+ };
1981
+ }
1982
+ function parseBiasBlock(c, masks, kind) {
1983
+ const validityIndex = c.u(4);
1984
+ const biases = [];
1985
+ for (const sys of masks.systems) {
1986
+ for (let s = 0; s < sys.prns.length; s++) {
1987
+ for (let g = 0; g < sys.signalIndices.length; g++) {
1988
+ if (sys.cellMask && !sys.cellMask[s][g]) continue;
1989
+ const raw = c.s(11);
1990
+ const entry = {
1991
+ system: sys.system,
1992
+ prn: sys.prns[s],
1993
+ signalIndex: sys.signalIndices[g],
1994
+ signal: sys.signals[g],
1995
+ bias: raw === -1024 ? null : raw * (kind === "code" ? 0.02 : 0.01)
1996
+ };
1997
+ if (kind === "phase") entry.discontinuity = c.u(2);
1998
+ biases.push(entry);
1999
+ }
2000
+ }
2001
+ }
2002
+ return {
2003
+ validityIndex,
2004
+ validitySeconds: HAS_VALIDITY_SECONDS[validityIndex],
2005
+ biases
2006
+ };
2007
+ }
2008
+ function parseHasMt1(payload, header, cachedMasks) {
2009
+ const c = new Cursor(payload, payload.length * 8);
2010
+ const toh = c.u(12);
2011
+ const flags = {
2012
+ mask: c.u(1) === 1,
2013
+ orbit: c.u(1) === 1,
2014
+ clockFullSet: c.u(1) === 1,
2015
+ clockSubset: c.u(1) === 1,
2016
+ codeBias: c.u(1) === 1,
2017
+ phaseBias: c.u(1) === 1
2018
+ };
2019
+ c.u(4);
2020
+ const maskId = c.u(5);
2021
+ const iodSetId = c.u(5);
2022
+ const msg = {
2023
+ ...header,
2024
+ toh,
2025
+ maskId,
2026
+ iodSetId,
2027
+ flags,
2028
+ maskFromCache: false,
2029
+ parseError: null
2030
+ };
2031
+ try {
2032
+ let masks;
2033
+ if (flags.mask) {
2034
+ masks = parseMaskBlock(c, maskId);
2035
+ } else if (cachedMasks) {
2036
+ masks = cachedMasks;
2037
+ msg.maskFromCache = true;
2038
+ } else {
2039
+ msg.parseError = "mask-unavailable";
2040
+ return msg;
2041
+ }
2042
+ msg.masks = masks;
2043
+ if (flags.orbit) msg.orbit = parseOrbitBlock(c, masks);
2044
+ if (flags.clockFullSet) msg.clockFullSet = parseClockFullBlock(c, masks);
2045
+ if (flags.clockSubset) msg.clockSubset = parseClockSubsetBlock(c, masks);
2046
+ if (flags.codeBias) msg.codeBias = parseBiasBlock(c, masks, "code");
2047
+ if (flags.phaseBias) msg.phaseBias = parseBiasBlock(c, masks, "phase");
2048
+ } catch (e) {
2049
+ msg.parseError = e instanceof Error ? e.message : String(e);
2050
+ }
2051
+ return msg;
2052
+ }
2053
+ var HasAssembler = class {
2054
+ slots = /* @__PURE__ */ new Map();
2055
+ lastMessageId = -1;
2056
+ maskCache = /* @__PURE__ */ new Map();
2057
+ /** Pages a message may span before its slot is restarted (s). */
2058
+ timeoutSec;
2059
+ stats = {
2060
+ pages: 0,
2061
+ dummyPages: 0,
2062
+ skippedPages: 0,
2063
+ duplicatePages: 0,
2064
+ resets: 0,
2065
+ messages: 0,
2066
+ parseErrors: 0
2067
+ };
2068
+ constructor(opts = {}) {
2069
+ this.timeoutSec = opts.timeoutSec ?? 30;
2070
+ }
2071
+ /**
2072
+ * Push one 492-bit C/NAV page (≥ 61 bytes; check the CRC first with
2073
+ * `hasPageCrcOk`). `tow` — a receiver time of week in seconds, any
2074
+ * origin as long as it is common to all pages — enables the slot
2075
+ * timeout and is stamped on completed messages.
2076
+ */
2077
+ push(page, tow) {
2078
+ const p = parseHasPage(page);
2079
+ if (!p) {
2080
+ this.stats.dummyPages++;
2081
+ return null;
2082
+ }
2083
+ this.stats.pages++;
2084
+ if (p.messageType !== 1 || p.status > 1 || p.pageId === 0) {
2085
+ this.stats.skippedPages++;
2086
+ return null;
2087
+ }
2088
+ if (p.messageId === this.lastMessageId) return null;
2089
+ let slot = this.slots.get(p.messageId);
2090
+ const timedOut = slot?.firstTow !== void 0 && tow !== void 0 && tow - slot.firstTow > this.timeoutSec;
2091
+ if (slot && (slot.messageSize !== p.messageSize || timedOut)) {
2092
+ this.stats.resets++;
2093
+ slot = void 0;
2094
+ }
2095
+ if (!slot) {
2096
+ slot = {
2097
+ messageSize: p.messageSize,
2098
+ status: p.status,
2099
+ pages: [],
2100
+ bodies: /* @__PURE__ */ new Map(),
2101
+ firstTow: tow
2102
+ };
2103
+ this.slots.set(p.messageId, slot);
2104
+ }
2105
+ const bodyKey = Array.from(
2106
+ p.body,
2107
+ (b) => b.toString(16).padStart(2, "0")
2108
+ ).join("");
2109
+ const existing = slot.bodies.get(p.pageId);
2110
+ if (existing !== void 0) {
2111
+ if (existing === bodyKey) {
2112
+ this.stats.duplicatePages++;
2113
+ return null;
2114
+ }
2115
+ this.stats.resets++;
2116
+ slot.pages = [];
2117
+ slot.bodies.clear();
2118
+ slot.firstTow = tow;
2119
+ }
2120
+ slot.bodies.set(p.pageId, bodyKey);
2121
+ slot.pages.push({ pageId: p.pageId, octets: p.body });
2122
+ if (slot.pages.length < slot.messageSize) return null;
2123
+ const payload = rs255DecodeErasures(slot.pages, slot.messageSize);
2124
+ if (!payload) return null;
2125
+ this.slots.delete(p.messageId);
2126
+ this.lastMessageId = p.messageId;
2127
+ const msg = parseHasMt1(
2128
+ payload,
2129
+ {
2130
+ status: slot.status,
2131
+ messageId: p.messageId,
2132
+ messageSize: slot.messageSize
2133
+ },
2134
+ void 0
2135
+ );
2136
+ const resolved = msg.parseError === "mask-unavailable" && this.maskCache.has(msg.maskId) ? parseHasMt1(
2137
+ payload,
2138
+ {
2139
+ status: slot.status,
2140
+ messageId: p.messageId,
2141
+ messageSize: slot.messageSize
2142
+ },
2143
+ this.maskCache.get(msg.maskId)
2144
+ ) : msg;
2145
+ if (resolved.flags.mask && resolved.masks)
2146
+ this.maskCache.set(resolved.maskId, resolved.masks);
2147
+ if (tow !== void 0) resolved.tow = tow;
2148
+ this.stats.messages++;
2149
+ if (resolved.parseError !== null) this.stats.parseErrors++;
2150
+ return resolved;
2151
+ }
2152
+ };
2153
+
2154
+ // src/sbf/rawnav-has.ts
2155
+ function parseSbfHas(data) {
2156
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
2157
+ const assembler = new HasAssembler();
2158
+ const messages = [];
2159
+ let pagesSeen = 0;
2160
+ let pagesBadCrc = 0;
2161
+ scanSbfFrames(data, view, (id, b, len) => {
2162
+ if (id !== 4024 || len < 84) return;
2163
+ pagesSeen++;
2164
+ const page = new Uint8Array(64);
2165
+ for (let k = 0; k < 16; k++) {
2166
+ const w = view.getUint32(b + 20 + 4 * k, true);
2167
+ page[4 * k] = w >>> 24;
2168
+ page[4 * k + 1] = w >>> 16 & 255;
2169
+ page[4 * k + 2] = w >>> 8 & 255;
2170
+ page[4 * k + 3] = w & 255;
2171
+ }
2172
+ if (!hasPageCrcOk(page)) {
2173
+ pagesBadCrc++;
2174
+ return;
2175
+ }
2176
+ const tow = view.getUint32(b + 8, true) / 1e3;
2177
+ const msg = assembler.push(page, tow);
2178
+ if (msg) messages.push({ ...msg, tow, wnc: view.getUint16(b + 12, true) });
2179
+ });
2180
+ return {
2181
+ messages,
2182
+ pagesSeen,
2183
+ pagesBadCrc,
2184
+ pagesDummy: assembler.stats.dummyPages,
2185
+ pagesHas: assembler.stats.pages
2186
+ };
2187
+ }
2188
+
1665
2189
  // src/sbf/index.ts
1666
2190
  var CLIGHT = 299792458;
1667
2191
  var GPS_EPOCH_MS7 = Date.UTC(1980, 0, 6);
@@ -2336,6 +2860,7 @@ function parseSbfMeas(data) {
2336
2860
  parseSbfCnav,
2337
2861
  parseSbfGalNav,
2338
2862
  parseSbfGloNav,
2863
+ parseSbfHas,
2339
2864
  parseSbfIonoUtc,
2340
2865
  parseSbfMeas,
2341
2866
  parseSbfNav,