gnss-js 1.35.0 → 1.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/sbf.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { S as SbfAlmanac, a as SbfAlmanacResult, b as SbfGlonassAlmanac, c as SbfKeplerAlmanac, d as SbfNavResult, p as parseSbfAlmanac, e as parseSbfNav } from './nav-BYmYoh9A.cjs';
2
- import { C as CnavEphemeris, K as KeplerEphemeris, G as GlonassEphemeris } from './nav-DImXUdbp.cjs';
2
+ import { K as KeplerEphemeris, C as CnavEphemeris, E as Ephemeris, G as GlonassEphemeris } from './nav-DImXUdbp.cjs';
3
3
 
4
4
  /**
5
5
  * Septentrio SBF framing shared by the measurement and navigation
@@ -58,6 +58,42 @@ interface SbfIonoUtcResult {
58
58
  */
59
59
  declare function parseSbfIonoUtc(data: Uint8Array): SbfIonoUtcResult;
60
60
 
61
+ /**
62
+ * Septentrio SBF raw GPS / QZSS LNAV navigation-bit blocks: GPSRawCA
63
+ * (4017) and QZSRawL1CA (4066) each carry one 300-bit L1 C/A (LNAV)
64
+ * subframe. Subframes 1–3 are assembled per satellite into a Keplerian
65
+ * ephemeris by the shared {@link GpsLnavAssembler} (also behind
66
+ * `parseUbxNav`).
67
+ *
68
+ * Block layout (mosaic-X5 / AsteRx reference guide §4.2.2): after the
69
+ * 8-byte SBF header, TOW u4 + WNc u2 (a full GPS week — no rollover to
70
+ * resolve), SVID u1, CRCPassed u1, ViterbiCnt u1, Source u1, FreqNr u1,
71
+ * RxChannel u1, then NAVBits as u4[10]. Each 32-bit word holds the 24
72
+ * source data bits d_n (already polarity-corrected for D30*) in bits
73
+ * 6–29 with the first received bit as the MSB — so extraction is the
74
+ * same `(word >>> 6) & 0xffffff` u-blox delivers, and the two share
75
+ * {@link GpsLnavAssembler}. Bits 0–5 are the parity bits (unused here:
76
+ * the receiver has already parity-checked, flagged by CRCPassed).
77
+ */
78
+
79
+ interface SbfGpsNavResult {
80
+ /** Assembled GPS/QZSS LNAV ephemerides in stream order, repeats suppressed. */
81
+ ephemerides: KeplerEphemeris[];
82
+ /** Completed 1/2/3 sets rejected by the IODC/IODE cross-check (dropped). */
83
+ badParity: number;
84
+ /** Total GPSRawCA/QZSRawL1CA blocks seen (with valid SBF framing). */
85
+ messages: number;
86
+ }
87
+ /**
88
+ * Decode every GPSRawCA (4017) / QZSRawL1CA (4066) block in an SBF byte
89
+ * stream and assemble the carried LNAV subframes into ephemerides
90
+ * (`system` 'G'/'J', same fields and conventions as `parseSbfNav`'s
91
+ * GPSNav/QZSNav records). Only subframes the receiver marked
92
+ * CRC/parity-valid (CRCPassed = 1) are used; the block's full WNc week
93
+ * resolves the 10-bit broadcast week directly.
94
+ */
95
+ declare function parseSbfGpsNav(data: Uint8Array): SbfGpsNavResult;
96
+
61
97
  /**
62
98
  * Septentrio SBF raw CNAV navigation-bit blocks: GPSRawL2C (4018) and
63
99
  * GPSRawL5 (4019) each carry one 300-bit GPS CNAV message.
@@ -98,6 +134,71 @@ interface SbfCnavResult {
98
134
  */
99
135
  declare function parseSbfCnav(data: Uint8Array): SbfCnavResult;
100
136
 
137
+ /**
138
+ * One-pass SBF navigation decoder.
139
+ *
140
+ * A Septentrio broadcasts navigation data as a mix of *decoded* blocks
141
+ * (GPSNav/GALNav/GLONav/BDSNav/QZSNav — already-parsed ephemeris) and
142
+ * *raw* navigation-frame blocks (GPSRawCA, GALRawINAV/FNAV, GLORawCA,
143
+ * BDSRaw, GPSRawL2C/L5) whose bits must be assembled — and which class a
144
+ * given receiver emits depends on its configuration. The granular
145
+ * `parseSbf*` functions each re-scan the whole stream for one class;
146
+ * this decoder walks the byte stream **once**, routing every navigation
147
+ * block through a single dispatch to the same per-block `feed*` helpers,
148
+ * and returns the merged, de-duplicated result. It is the decoder a
149
+ * consumer that just wants "all the ephemeris in this SBF" should call.
150
+ *
151
+ * Merge/de-dup: assemblers already suppress repeats of an unchanged
152
+ * issue of data within a scan; across the decoded and raw paths, records
153
+ * are de-duped by (prn, time-of-clock, Galileo I/NAV-vs-F/NAV source),
154
+ * so a stream carrying both a decoded GALNav block and the raw I/NAV
155
+ * pages for the same epoch yields one record, while the distinct Galileo
156
+ * I/NAV and F/NAV clock sets are both kept.
157
+ */
158
+
159
+ /** Per-source diagnostics — how many blocks of each class were seen. */
160
+ interface SbfNavCounts {
161
+ /** Decoded ephemeris blocks (GPSNav/GALNav/GLONav/BDSNav/QZSNav). */
162
+ decodedNav: number;
163
+ /** Raw GPS/QZSS LNAV blocks (GPSRawCA/QZSRawL1CA). */
164
+ gpsLnavRaw: number;
165
+ /** Raw GPS CNAV blocks (GPSRawL2C/L5). */
166
+ cnavRaw: number;
167
+ /** Raw Galileo page blocks (GALRawINAV/FNAV). */
168
+ galRaw: number;
169
+ /** Raw GLONASS string blocks (GLORawCA). */
170
+ gloRaw: number;
171
+ /** Raw BeiDou D1/D2 subframe blocks (BDSRaw). */
172
+ bdsRaw: number;
173
+ /** Frames dropped by a CRC/parity check across all raw decoders. */
174
+ badFrames: number;
175
+ }
176
+ interface SbfNavigation {
177
+ /**
178
+ * Legacy Keplerian + GLONASS ephemerides, merged from the decoded Nav
179
+ * blocks and the raw GAL I/NAV+F/NAV, GLO strings, BDS D1/D2 and
180
+ * GPS/QZSS LNAV assemblers, de-duped as described in the module header.
181
+ */
182
+ ephemerides: Ephemeris[];
183
+ /** GPS L2C/L5 CNAV ephemerides (RINEX-4 nav records). */
184
+ cnav: SbfCnavEphemeris[];
185
+ /**
186
+ * Iono coefficient sets keyed like `NavHeader.ionoCorrections`
187
+ * (GPSA/GPSB, GAL, BDSA/BDSB); the last valid block of each type wins.
188
+ */
189
+ ionoCorrections: Record<string, number[]>;
190
+ /** GPS-UTC ΔtLS from the last GPSUtc block, if any. */
191
+ leapSeconds: number | null;
192
+ counts: SbfNavCounts;
193
+ }
194
+ /**
195
+ * Decode every navigation block in an SBF byte stream in a single pass:
196
+ * decoded ephemeris blocks, raw GPS/QZSS LNAV, GPS CNAV, Galileo I/NAV +
197
+ * F/NAV, GLONASS strings, BeiDou D1/D2, and the Klobuchar/NeQuick iono +
198
+ * GPS-UTC leap-second blocks. See the module header for merge semantics.
199
+ */
200
+ declare function decodeSbfNavigation(data: Uint8Array): SbfNavigation;
201
+
101
202
  /**
102
203
  * Septentrio SBF raw Galileo navigation-page blocks: GALRawINAV (4023)
103
204
  * carries one I/NAV nominal page pair (234 bits: the 114-bit even part
@@ -195,18 +296,6 @@ interface SbfGloNavResult {
195
296
  /** Total GLORawCA blocks seen (with valid SBF framing). */
196
297
  messages: number;
197
298
  }
198
- /**
199
- * Decode every GLORawCA (4026) block in an SBF byte stream and
200
- * assemble the carried navigation strings into ephemerides (same
201
- * conventions as `parseSbfNav`'s GLONav records: UTC `tocDate`, RINEX
202
- * `tauN` sign, km state vectors, `messageFrameTime` in seconds of the
203
- * UTC week — here from the broadcast tk, see the oracle notes in
204
- * test/bdsglo-raw.test.ts). The block's TOW/WNc time stamp resolves
205
- * the GLONASS day; blocks without one (do-not-use) are skipped, as
206
- * are SVID-62 blocks (GLONASS satellite with unknown slot number).
207
- * L1 C/A and L2 C/A strings are identical and share one assembler
208
- * per slot, as in RTKLIB.
209
- */
210
299
  declare function parseSbfGloNav(data: Uint8Array): SbfGloNavResult;
211
300
 
212
301
  /** Constellations HAS corrects: GPS (GNSS ID 0), Galileo (GNSS ID 2). */
@@ -444,4 +533,4 @@ interface SbfParseResult {
444
533
  */
445
534
  declare function parseSbfMeas(data: Uint8Array): SbfParseResult;
446
535
 
447
- export { CnavEphemeris, type HasMessage, type SbfBdsNavResult, type SbfCnavEphemeris, type SbfCnavResult, type SbfGalEphemeris, type SbfGalNavResult, type SbfGloNavResult, type SbfHasMessage, type SbfHasResult, type SbfIonoUtcResult, type SbfMeasEpoch, type SbfMeasurement, type SbfParseResult, parseSbfBdsNav, parseSbfCnav, parseSbfGalNav, parseSbfGloNav, parseSbfHas, parseSbfIonoUtc, parseSbfMeas, crc16 as sbfCrc16, scanSbfFrames };
536
+ export { CnavEphemeris, type HasMessage, type SbfBdsNavResult, type SbfCnavEphemeris, type SbfCnavResult, type SbfGalEphemeris, type SbfGalNavResult, type SbfGloNavResult, type SbfGpsNavResult, type SbfHasMessage, type SbfHasResult, type SbfIonoUtcResult, type SbfMeasEpoch, type SbfMeasurement, type SbfNavCounts, type SbfNavigation, type SbfParseResult, decodeSbfNavigation, parseSbfBdsNav, parseSbfCnav, parseSbfGalNav, parseSbfGloNav, parseSbfGpsNav, parseSbfHas, parseSbfIonoUtc, parseSbfMeas, crc16 as sbfCrc16, scanSbfFrames };
package/dist/sbf.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { S as SbfAlmanac, a as SbfAlmanacResult, b as SbfGlonassAlmanac, c as SbfKeplerAlmanac, d as SbfNavResult, p as parseSbfAlmanac, e as parseSbfNav } from './nav-CN8rxL4h.js';
2
- import { C as CnavEphemeris, K as KeplerEphemeris, G as GlonassEphemeris } from './nav-DImXUdbp.js';
2
+ import { K as KeplerEphemeris, C as CnavEphemeris, E as Ephemeris, G as GlonassEphemeris } from './nav-DImXUdbp.js';
3
3
 
4
4
  /**
5
5
  * Septentrio SBF framing shared by the measurement and navigation
@@ -58,6 +58,42 @@ interface SbfIonoUtcResult {
58
58
  */
59
59
  declare function parseSbfIonoUtc(data: Uint8Array): SbfIonoUtcResult;
60
60
 
61
+ /**
62
+ * Septentrio SBF raw GPS / QZSS LNAV navigation-bit blocks: GPSRawCA
63
+ * (4017) and QZSRawL1CA (4066) each carry one 300-bit L1 C/A (LNAV)
64
+ * subframe. Subframes 1–3 are assembled per satellite into a Keplerian
65
+ * ephemeris by the shared {@link GpsLnavAssembler} (also behind
66
+ * `parseUbxNav`).
67
+ *
68
+ * Block layout (mosaic-X5 / AsteRx reference guide §4.2.2): after the
69
+ * 8-byte SBF header, TOW u4 + WNc u2 (a full GPS week — no rollover to
70
+ * resolve), SVID u1, CRCPassed u1, ViterbiCnt u1, Source u1, FreqNr u1,
71
+ * RxChannel u1, then NAVBits as u4[10]. Each 32-bit word holds the 24
72
+ * source data bits d_n (already polarity-corrected for D30*) in bits
73
+ * 6–29 with the first received bit as the MSB — so extraction is the
74
+ * same `(word >>> 6) & 0xffffff` u-blox delivers, and the two share
75
+ * {@link GpsLnavAssembler}. Bits 0–5 are the parity bits (unused here:
76
+ * the receiver has already parity-checked, flagged by CRCPassed).
77
+ */
78
+
79
+ interface SbfGpsNavResult {
80
+ /** Assembled GPS/QZSS LNAV ephemerides in stream order, repeats suppressed. */
81
+ ephemerides: KeplerEphemeris[];
82
+ /** Completed 1/2/3 sets rejected by the IODC/IODE cross-check (dropped). */
83
+ badParity: number;
84
+ /** Total GPSRawCA/QZSRawL1CA blocks seen (with valid SBF framing). */
85
+ messages: number;
86
+ }
87
+ /**
88
+ * Decode every GPSRawCA (4017) / QZSRawL1CA (4066) block in an SBF byte
89
+ * stream and assemble the carried LNAV subframes into ephemerides
90
+ * (`system` 'G'/'J', same fields and conventions as `parseSbfNav`'s
91
+ * GPSNav/QZSNav records). Only subframes the receiver marked
92
+ * CRC/parity-valid (CRCPassed = 1) are used; the block's full WNc week
93
+ * resolves the 10-bit broadcast week directly.
94
+ */
95
+ declare function parseSbfGpsNav(data: Uint8Array): SbfGpsNavResult;
96
+
61
97
  /**
62
98
  * Septentrio SBF raw CNAV navigation-bit blocks: GPSRawL2C (4018) and
63
99
  * GPSRawL5 (4019) each carry one 300-bit GPS CNAV message.
@@ -98,6 +134,71 @@ interface SbfCnavResult {
98
134
  */
99
135
  declare function parseSbfCnav(data: Uint8Array): SbfCnavResult;
100
136
 
137
+ /**
138
+ * One-pass SBF navigation decoder.
139
+ *
140
+ * A Septentrio broadcasts navigation data as a mix of *decoded* blocks
141
+ * (GPSNav/GALNav/GLONav/BDSNav/QZSNav — already-parsed ephemeris) and
142
+ * *raw* navigation-frame blocks (GPSRawCA, GALRawINAV/FNAV, GLORawCA,
143
+ * BDSRaw, GPSRawL2C/L5) whose bits must be assembled — and which class a
144
+ * given receiver emits depends on its configuration. The granular
145
+ * `parseSbf*` functions each re-scan the whole stream for one class;
146
+ * this decoder walks the byte stream **once**, routing every navigation
147
+ * block through a single dispatch to the same per-block `feed*` helpers,
148
+ * and returns the merged, de-duplicated result. It is the decoder a
149
+ * consumer that just wants "all the ephemeris in this SBF" should call.
150
+ *
151
+ * Merge/de-dup: assemblers already suppress repeats of an unchanged
152
+ * issue of data within a scan; across the decoded and raw paths, records
153
+ * are de-duped by (prn, time-of-clock, Galileo I/NAV-vs-F/NAV source),
154
+ * so a stream carrying both a decoded GALNav block and the raw I/NAV
155
+ * pages for the same epoch yields one record, while the distinct Galileo
156
+ * I/NAV and F/NAV clock sets are both kept.
157
+ */
158
+
159
+ /** Per-source diagnostics — how many blocks of each class were seen. */
160
+ interface SbfNavCounts {
161
+ /** Decoded ephemeris blocks (GPSNav/GALNav/GLONav/BDSNav/QZSNav). */
162
+ decodedNav: number;
163
+ /** Raw GPS/QZSS LNAV blocks (GPSRawCA/QZSRawL1CA). */
164
+ gpsLnavRaw: number;
165
+ /** Raw GPS CNAV blocks (GPSRawL2C/L5). */
166
+ cnavRaw: number;
167
+ /** Raw Galileo page blocks (GALRawINAV/FNAV). */
168
+ galRaw: number;
169
+ /** Raw GLONASS string blocks (GLORawCA). */
170
+ gloRaw: number;
171
+ /** Raw BeiDou D1/D2 subframe blocks (BDSRaw). */
172
+ bdsRaw: number;
173
+ /** Frames dropped by a CRC/parity check across all raw decoders. */
174
+ badFrames: number;
175
+ }
176
+ interface SbfNavigation {
177
+ /**
178
+ * Legacy Keplerian + GLONASS ephemerides, merged from the decoded Nav
179
+ * blocks and the raw GAL I/NAV+F/NAV, GLO strings, BDS D1/D2 and
180
+ * GPS/QZSS LNAV assemblers, de-duped as described in the module header.
181
+ */
182
+ ephemerides: Ephemeris[];
183
+ /** GPS L2C/L5 CNAV ephemerides (RINEX-4 nav records). */
184
+ cnav: SbfCnavEphemeris[];
185
+ /**
186
+ * Iono coefficient sets keyed like `NavHeader.ionoCorrections`
187
+ * (GPSA/GPSB, GAL, BDSA/BDSB); the last valid block of each type wins.
188
+ */
189
+ ionoCorrections: Record<string, number[]>;
190
+ /** GPS-UTC ΔtLS from the last GPSUtc block, if any. */
191
+ leapSeconds: number | null;
192
+ counts: SbfNavCounts;
193
+ }
194
+ /**
195
+ * Decode every navigation block in an SBF byte stream in a single pass:
196
+ * decoded ephemeris blocks, raw GPS/QZSS LNAV, GPS CNAV, Galileo I/NAV +
197
+ * F/NAV, GLONASS strings, BeiDou D1/D2, and the Klobuchar/NeQuick iono +
198
+ * GPS-UTC leap-second blocks. See the module header for merge semantics.
199
+ */
200
+ declare function decodeSbfNavigation(data: Uint8Array): SbfNavigation;
201
+
101
202
  /**
102
203
  * Septentrio SBF raw Galileo navigation-page blocks: GALRawINAV (4023)
103
204
  * carries one I/NAV nominal page pair (234 bits: the 114-bit even part
@@ -195,18 +296,6 @@ interface SbfGloNavResult {
195
296
  /** Total GLORawCA blocks seen (with valid SBF framing). */
196
297
  messages: number;
197
298
  }
198
- /**
199
- * Decode every GLORawCA (4026) block in an SBF byte stream and
200
- * assemble the carried navigation strings into ephemerides (same
201
- * conventions as `parseSbfNav`'s GLONav records: UTC `tocDate`, RINEX
202
- * `tauN` sign, km state vectors, `messageFrameTime` in seconds of the
203
- * UTC week — here from the broadcast tk, see the oracle notes in
204
- * test/bdsglo-raw.test.ts). The block's TOW/WNc time stamp resolves
205
- * the GLONASS day; blocks without one (do-not-use) are skipped, as
206
- * are SVID-62 blocks (GLONASS satellite with unknown slot number).
207
- * L1 C/A and L2 C/A strings are identical and share one assembler
208
- * per slot, as in RTKLIB.
209
- */
210
299
  declare function parseSbfGloNav(data: Uint8Array): SbfGloNavResult;
211
300
 
212
301
  /** Constellations HAS corrects: GPS (GNSS ID 0), Galileo (GNSS ID 2). */
@@ -444,4 +533,4 @@ interface SbfParseResult {
444
533
  */
445
534
  declare function parseSbfMeas(data: Uint8Array): SbfParseResult;
446
535
 
447
- export { CnavEphemeris, type HasMessage, type SbfBdsNavResult, type SbfCnavEphemeris, type SbfCnavResult, type SbfGalEphemeris, type SbfGalNavResult, type SbfGloNavResult, type SbfHasMessage, type SbfHasResult, type SbfIonoUtcResult, type SbfMeasEpoch, type SbfMeasurement, type SbfParseResult, parseSbfBdsNav, parseSbfCnav, parseSbfGalNav, parseSbfGloNav, parseSbfHas, parseSbfIonoUtc, parseSbfMeas, crc16 as sbfCrc16, scanSbfFrames };
536
+ export { CnavEphemeris, type HasMessage, type SbfBdsNavResult, type SbfCnavEphemeris, type SbfCnavResult, type SbfGalEphemeris, type SbfGalNavResult, type SbfGloNavResult, type SbfGpsNavResult, type SbfHasMessage, type SbfHasResult, type SbfIonoUtcResult, type SbfMeasEpoch, type SbfMeasurement, type SbfNavCounts, type SbfNavigation, type SbfParseResult, decodeSbfNavigation, parseSbfBdsNav, parseSbfCnav, parseSbfGalNav, parseSbfGloNav, parseSbfGpsNav, parseSbfHas, parseSbfIonoUtc, parseSbfMeas, crc16 as sbfCrc16, scanSbfFrames };
package/dist/sbf.js CHANGED
@@ -1,27 +1,31 @@
1
1
  import {
2
2
  crc16,
3
+ decodeSbfNavigation,
3
4
  parseSbfAlmanac,
4
5
  parseSbfBdsNav,
5
6
  parseSbfCnav,
6
7
  parseSbfGalNav,
7
8
  parseSbfGloNav,
9
+ parseSbfGpsNav,
8
10
  parseSbfHas,
9
11
  parseSbfIonoUtc,
10
12
  parseSbfMeas,
11
13
  parseSbfNav,
12
14
  scanSbfFrames
13
- } from "./chunk-AFEDNWXI.js";
14
- import "./chunk-5AUK42AL.js";
15
- import "./chunk-726LQBGM.js";
16
- import "./chunk-IQ5OIMQD.js";
15
+ } from "./chunk-24TKGUTY.js";
16
+ import "./chunk-FA2UTLEQ.js";
17
+ import "./chunk-YUW33VXK.js";
18
+ import "./chunk-V2D5KUKH.js";
17
19
  import "./chunk-HVXYFUCB.js";
18
20
  import "./chunk-LEEU5OIO.js";
19
21
  export {
22
+ decodeSbfNavigation,
20
23
  parseSbfAlmanac,
21
24
  parseSbfBdsNav,
22
25
  parseSbfCnav,
23
26
  parseSbfGalNav,
24
27
  parseSbfGloNav,
28
+ parseSbfGpsNav,
25
29
  parseSbfHas,
26
30
  parseSbfIonoUtc,
27
31
  parseSbfMeas,
package/dist/ubx.cjs CHANGED
@@ -88,6 +88,38 @@ function setBitU(buff, pos, len, data) {
88
88
  }
89
89
  }
90
90
  }
91
+ var GpsLnavAssembler = class _GpsLnavAssembler {
92
+ buffers = /* @__PURE__ */ new Map();
93
+ last = /* @__PURE__ */ new Map();
94
+ /** Subframe ID (1–5) from the HOW word of a parity-stripped subframe. */
95
+ static subframeId(subframe) {
96
+ return getBitU(subframe, 43, 3);
97
+ }
98
+ /**
99
+ * Push one parity-stripped 30-byte LNAV subframe for `prn`, resolving
100
+ * the 10-bit week against `refWeek`. See {@link LnavPush} for outcomes.
101
+ */
102
+ push(prn, subframe, refWeek) {
103
+ const id = _GpsLnavAssembler.subframeId(subframe);
104
+ if (id < 1 || id > 3) return { kind: "skipped" };
105
+ let sf = this.buffers.get(prn);
106
+ if (!sf) {
107
+ sf = { buf: new Uint8Array(90), have: 0 };
108
+ this.buffers.set(prn, sf);
109
+ }
110
+ sf.buf.set(subframe, (id - 1) * 30);
111
+ sf.have |= 1 << id - 1;
112
+ if (id !== 3 || sf.have !== 7) return { kind: "incomplete" };
113
+ const eph = decodeGpsLnavFrame(sf.buf, { prn, refWeek });
114
+ if (!eph) return { kind: "decodeFailed" };
115
+ const prev = this.last.get(prn);
116
+ if (prev && prev.iode === eph.iode && prev.tocDate.getTime() === eph.tocDate.getTime()) {
117
+ return { kind: "duplicate" };
118
+ }
119
+ this.last.set(prn, eph);
120
+ return { kind: "eph", eph };
121
+ }
122
+ };
91
123
  function decodeGpsLnavFrame(subframes, opts = {}) {
92
124
  if (subframes.length < 90) return null;
93
125
  const b = subframes;
@@ -245,38 +277,19 @@ function parseUbxNav(data, opts = {}) {
245
277
  }
246
278
  }
247
279
  if (refWeek === void 0) return { ephemerides, badParity };
248
- const subframes = /* @__PURE__ */ new Map();
249
- const last = /* @__PURE__ */ new Map();
280
+ const assembler = new GpsLnavAssembler();
250
281
  for (const f of ubxFrames(data)) {
251
282
  if (f.msgClass !== 2 || f.msgId !== 19) continue;
252
283
  const lnav = readLnavSubframe(view, f);
253
284
  if (!lnav) continue;
254
- const { prn, gnssId, svId, buff, id } = lnav;
285
+ const { prn, buff, id } = lnav;
255
286
  if (id < 1 || id > 5) {
256
287
  badParity++;
257
288
  continue;
258
289
  }
259
- if (id > 3) continue;
260
- const key = gnssId * 256 + svId;
261
- let sf = subframes.get(key);
262
- if (!sf) {
263
- sf = { buf: new Uint8Array(90), have: 0 };
264
- subframes.set(key, sf);
265
- }
266
- sf.buf.set(buff, (id - 1) * 30);
267
- sf.have |= 1 << id - 1;
268
- if (id !== 3 || sf.have !== 7) continue;
269
- const eph = decodeGpsLnavFrame(sf.buf, { prn, refWeek });
270
- if (!eph) {
271
- badParity++;
272
- continue;
273
- }
274
- const prev = last.get(prn);
275
- if (prev && prev.iode === eph.iode && prev.tocDate.getTime() === eph.tocDate.getTime()) {
276
- continue;
277
- }
278
- last.set(prn, eph);
279
- ephemerides.push(eph);
290
+ const r = assembler.push(prn, buff, refWeek);
291
+ if (r.kind === "eph") ephemerides.push(r.eph);
292
+ else if (r.kind === "decodeFailed") badParity++;
280
293
  }
281
294
  return { ephemerides, badParity };
282
295
  }
package/dist/ubx.js CHANGED
@@ -5,10 +5,10 @@ import {
5
5
  parseUbxRawNav,
6
6
  parseUbxRawx,
7
7
  ubxFrames
8
- } from "./chunk-FEOMYZEU.js";
9
- import "./chunk-5AUK42AL.js";
10
- import "./chunk-726LQBGM.js";
11
- import "./chunk-IQ5OIMQD.js";
8
+ } from "./chunk-ZQDLYLQA.js";
9
+ import "./chunk-FA2UTLEQ.js";
10
+ import "./chunk-YUW33VXK.js";
11
+ import "./chunk-V2D5KUKH.js";
12
12
  import "./chunk-HVXYFUCB.js";
13
13
  import "./chunk-LEEU5OIO.js";
14
14
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gnss-js",
3
- "version": "1.35.0",
3
+ "version": "1.37.0",
4
4
  "description": "Comprehensive GNSS library for JavaScript — time scales, coordinates, RINEX parsing, RTCM3 decoding, orbit computation, and signal analysis",
5
5
  "type": "module",
6
6
  "sideEffects": false,