gnss-js 1.42.0 → 1.44.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.
@@ -6,6 +6,10 @@ import {
6
6
  galInavPageCrcOk,
7
7
  testGloString
8
8
  } from "./chunk-FA2UTLEQ.js";
9
+ import {
10
+ decodeSbasGeoNav,
11
+ sbasCrcOk
12
+ } from "./chunk-ZIGMN3E5.js";
9
13
  import {
10
14
  CnavAssembler,
11
15
  cnavCrcOk
@@ -178,12 +182,15 @@ var two = (n) => String(n).padStart(2, "0");
178
182
  function parseUbxRawNav(data, opts = {}) {
179
183
  const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
180
184
  const ephemerides = [];
181
- const counts = { gal: 0, bds: 0, glo: 0 };
185
+ const counts = { gal: 0, bds: 0, glo: 0, sbas: 0 };
182
186
  let badParity = 0;
183
187
  const inav = new GalInavAssembler();
184
188
  const bds = new BdsAssembler();
185
189
  const glo = new GloStringAssembler();
186
190
  let refDate = null;
191
+ let refWeek = 0;
192
+ let refTow = 0;
193
+ const sbasSeen = /* @__PURE__ */ new Set();
187
194
  for (const f of ubxFrames(data)) {
188
195
  if (f.msgClass !== 2) continue;
189
196
  if (f.msgId === 21 && f.payload.length >= 16) {
@@ -194,6 +201,8 @@ function parseUbxRawNav(data, opts = {}) {
194
201
  refDate = new Date(
195
202
  GPS_EPOCH_MS + (week * SEC_PER_WEEK + rcvTow) * 1e3
196
203
  );
204
+ refWeek = week;
205
+ refTow = rcvTow;
197
206
  }
198
207
  continue;
199
208
  }
@@ -266,6 +275,31 @@ function parseUbxRawNav(data, opts = {}) {
266
275
  if (!refDate) continue;
267
276
  const eph = glo.push(`R${two(svId)}`, str, refDate, p[3] - 7);
268
277
  if (eph) ephemerides.push(eph);
278
+ } else if (gnssId === 1) {
279
+ if (p.length < 8 + 32) continue;
280
+ counts.sbas++;
281
+ if (svId < 120 || svId > 158) continue;
282
+ const msg = new Uint8Array(32);
283
+ for (let k = 0; k < 8; k++) {
284
+ const w = view.getUint32(base + 4 * k, true);
285
+ msg[4 * k] = w >>> 24;
286
+ msg[4 * k + 1] = w >>> 16 & 255;
287
+ msg[4 * k + 2] = w >>> 8 & 255;
288
+ msg[4 * k + 3] = w & 255;
289
+ }
290
+ if (!sbasCrcOk(msg)) {
291
+ badParity++;
292
+ continue;
293
+ }
294
+ if (refWeek === 0) continue;
295
+ const eph = decodeSbasGeoNav(msg, svId, refWeek, refTow);
296
+ if (eph) {
297
+ const key = `${eph.prn}@${eph.tocDate.getTime()}`;
298
+ if (!sbasSeen.has(key)) {
299
+ sbasSeen.add(key);
300
+ ephemerides.push(eph);
301
+ }
302
+ }
269
303
  }
270
304
  }
271
305
  return { ephemerides, counts, badParity };
@@ -8,6 +8,10 @@ import {
8
8
  galInavPageCrcOk,
9
9
  testGloString
10
10
  } from "./chunk-FA2UTLEQ.js";
11
+ import {
12
+ decodeSbasGeoNav,
13
+ sbasCrcOk
14
+ } from "./chunk-ZIGMN3E5.js";
11
15
  import {
12
16
  geodeticToEcef
13
17
  } from "./chunk-37QNKGTC.js";
@@ -700,6 +704,49 @@ function parseSbfGloNav(data) {
700
704
  return { ephemerides, badCrc, messages };
701
705
  }
702
706
 
707
+ // src/sbf/rawnav-sbas.ts
708
+ function feedGeoBlock(view, b) {
709
+ const tow = view.getUint32(b + 8, true);
710
+ const wnc = view.getUint16(b + 12, true);
711
+ const svid = view.getUint8(b + 14);
712
+ const prnStr = svidToPrn(svid);
713
+ if (!prnStr || prnStr[0] !== "S") return {};
714
+ const msg = new Uint8Array(32);
715
+ for (let k = 0; k < 8; k++) {
716
+ const w = view.getUint32(b + 20 + 4 * k, true);
717
+ msg[4 * k] = w >>> 24;
718
+ msg[4 * k + 1] = w >>> 16 & 255;
719
+ msg[4 * k + 2] = w >>> 8 & 255;
720
+ msg[4 * k + 3] = w & 255;
721
+ }
722
+ if (!sbasCrcOk(msg)) return { badCrc: true };
723
+ const prn = Number(prnStr.slice(1)) + 100;
724
+ const eph = decodeSbasGeoNav(msg, prn, wnc, tow / 1e3);
725
+ return eph ? { eph } : {};
726
+ }
727
+ function parseSbfGeoNav(data) {
728
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
729
+ const ephemerides = [];
730
+ const seen = /* @__PURE__ */ new Set();
731
+ let badCrc = 0;
732
+ let messages = 0;
733
+ scanSbfFrames(data, view, (id, b, len) => {
734
+ if (id !== 4020 || len < 52) return;
735
+ messages++;
736
+ const r = feedGeoBlock(view, b);
737
+ if (r.eph) {
738
+ const key = `${r.eph.prn}|${r.eph.tocDate.getTime()}`;
739
+ if (!seen.has(key)) {
740
+ seen.add(key);
741
+ ephemerides.push(r.eph);
742
+ }
743
+ } else if (r.badCrc) {
744
+ badCrc++;
745
+ }
746
+ });
747
+ return { ephemerides, badCrc, messages };
748
+ }
749
+
703
750
  // src/sbf/navigation.ts
704
751
  var F4_DNU4 = -2e10;
705
752
  function ephKey(e) {
@@ -720,6 +767,7 @@ function decodeSbfNavigation(data) {
720
767
  galRaw: 0,
721
768
  gloRaw: 0,
722
769
  bdsRaw: 0,
770
+ sbasRaw: 0,
723
771
  badFrames: 0
724
772
  };
725
773
  const cnavAsm = newCnavAssemblers();
@@ -823,6 +871,14 @@ function decodeSbfNavigation(data) {
823
871
  else if (r.badCrc) counts.badFrames++;
824
872
  return;
825
873
  }
874
+ case 4020: {
875
+ if (len < 52) return;
876
+ counts.sbasRaw++;
877
+ const r = feedGeoBlock(view, b);
878
+ if (r.eph) addEph(r.eph);
879
+ else if (r.badCrc) counts.badFrames++;
880
+ return;
881
+ }
826
882
  /* ---- iono / UTC ---- */
827
883
  case 5893:
828
884
  // GPSIon
@@ -2053,6 +2109,8 @@ export {
2053
2109
  parseSbfGalNav,
2054
2110
  parseSbfBdsNav,
2055
2111
  parseSbfGloNav,
2112
+ feedGeoBlock,
2113
+ parseSbfGeoNav,
2056
2114
  decodeSbfNavigation,
2057
2115
  parseSbfHas,
2058
2116
  parseSbfMeas
@@ -1,3 +1,6 @@
1
+ import {
2
+ decodeSbasGeoNav
3
+ } from "./chunk-ZIGMN3E5.js";
1
4
  import {
2
5
  CnavAssembler,
3
6
  cnavCrcOk
@@ -62,6 +65,8 @@ var ID_GALEPHEMERIS = 1122;
62
65
  var ID_QZSSEPHEMERIS = 1336;
63
66
  var ID_GPSEPHEM = 7;
64
67
  var ID_BDSEPHEMERIS = 1696;
68
+ var ID_RAWWAASFRAME = 287;
69
+ var ID_RAWSBASFRAME = 973;
65
70
  var GPS_EPOCH_MS = Date.UTC(1980, 0, 6);
66
71
  var BDT_EPOCH_MS = Date.UTC(2006, 0, 1);
67
72
  var SEC_PER_WEEK = 7 * 86400;
@@ -323,6 +328,20 @@ function parseNovatelNav(data) {
323
328
  }
324
329
  lastGlo.set(eph.prn, eph);
325
330
  ephemerides.push(eph);
331
+ } else if ((frame.id === ID_RAWSBASFRAME || frame.id === ID_RAWWAASFRAME) && frame.msgLen >= 41) {
332
+ if (frame.week === 0) continue;
333
+ const p = frame.payload;
334
+ const prn = view.getUint32(p + 4, true);
335
+ const msg = new Uint8Array(32);
336
+ msg.set(data.subarray(p + 12, p + 41));
337
+ const eph = decodeSbasGeoNav(msg, prn, frame.week, frame.towMs / 1e3);
338
+ if (!eph) continue;
339
+ const prev = lastGlo.get(eph.prn);
340
+ if (prev && Math.abs(prev.tocDate.getTime() - eph.tocDate.getTime()) < 1e3 && prev.health === eph.health) {
341
+ continue;
342
+ }
343
+ lastGlo.set(eph.prn, eph);
344
+ ephemerides.push(eph);
326
345
  }
327
346
  }
328
347
  return {
@@ -0,0 +1,55 @@
1
+ import {
2
+ crc24q
3
+ } from "./chunk-YUW33VXK.js";
4
+ import {
5
+ getBitS,
6
+ getBitU
7
+ } from "./chunk-V2D5KUKH.js";
8
+
9
+ // src/navbits/sbas.ts
10
+ var GPS_EPOCH_MS = Date.UTC(1980, 0, 6);
11
+ var MS_PER_WEEK = 7 * 86400 * 1e3;
12
+ var two = (n) => String(n).padStart(2, "0");
13
+ var SBAS_MT_GEO_NAV = 9;
14
+ function sbasMessageType(msg) {
15
+ return getBitU(msg, 8, 6);
16
+ }
17
+ function sbasCrcOk(msg) {
18
+ if (msg.length < 32) return false;
19
+ return crc24q(msg, 226) === getBitU(msg, 226, 24);
20
+ }
21
+ function decodeSbasGeoNav(msg, prn, week, tow) {
22
+ if (prn < 120 || prn > 158) return null;
23
+ if (sbasMessageType(msg) !== SBAS_MT_GEO_NAV) return null;
24
+ let t = getBitU(msg, 22, 13) * 16 - tow % 86400;
25
+ if (t <= -43200) t += 86400;
26
+ else if (t > 43200) t -= 86400;
27
+ const t0Sec = tow + t;
28
+ const ura = getBitU(msg, 35, 4);
29
+ return {
30
+ system: "S",
31
+ prn: `S${two(prn - 100)}`,
32
+ tocDate: new Date(GPS_EPOCH_MS + week * MS_PER_WEEK + t0Sec * 1e3),
33
+ tauN: getBitS(msg, 206, 12) * 2 ** -31,
34
+ // a_Gf0, clock offset (s)
35
+ gammaN: getBitS(msg, 218, 8) * 2 ** -39 / 2,
36
+ // a_Gf1, clock drift (s/s)
37
+ messageFrameTime: (tow % 86400 + 86400) % 86400,
38
+ x: getBitS(msg, 39, 30) * 0.08 / 1e3,
39
+ y: getBitS(msg, 69, 30) * 0.08 / 1e3,
40
+ z: getBitS(msg, 99, 25) * 0.4 / 1e3,
41
+ xDot: getBitS(msg, 124, 17) * 625e-6 / 1e3,
42
+ yDot: getBitS(msg, 141, 17) * 625e-6 / 1e3,
43
+ zDot: getBitS(msg, 158, 18) * 4e-3 / 1e3,
44
+ xAcc: getBitS(msg, 176, 10) * 125e-7 / 1e3,
45
+ yAcc: getBitS(msg, 186, 10) * 125e-7 / 1e3,
46
+ zAcc: getBitS(msg, 196, 10) * 625e-7 / 1e3,
47
+ health: ura === 15 ? 1 : 0,
48
+ freqNum: 0
49
+ };
50
+ }
51
+
52
+ export {
53
+ sbasCrcOk,
54
+ decodeSbasGeoNav
55
+ };