gnss-js 1.41.0 → 1.43.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/ubx.cjs CHANGED
@@ -1249,19 +1249,65 @@ var GloStringAssembler = class {
1249
1249
  }
1250
1250
  };
1251
1251
 
1252
- // src/ubx/rawnav.ts
1252
+ // src/navbits/sbas.ts
1253
1253
  var GPS_EPOCH_MS5 = Date.UTC(1980, 0, 6);
1254
- var SEC_PER_WEEK6 = 7 * 86400;
1254
+ var MS_PER_WEEK2 = 7 * 86400 * 1e3;
1255
1255
  var two2 = (n) => String(n).padStart(2, "0");
1256
+ var SBAS_MT_GEO_NAV = 9;
1257
+ function sbasMessageType(msg) {
1258
+ return getBitU(msg, 8, 6);
1259
+ }
1260
+ function sbasCrcOk(msg) {
1261
+ if (msg.length < 32) return false;
1262
+ return crc24q(msg, 226) === getBitU(msg, 226, 24);
1263
+ }
1264
+ function decodeSbasGeoNav(msg, prn, week, tow) {
1265
+ if (prn < 120 || prn > 158) return null;
1266
+ if (sbasMessageType(msg) !== SBAS_MT_GEO_NAV) return null;
1267
+ let t = getBitU(msg, 22, 13) * 16 - tow % 86400;
1268
+ if (t <= -43200) t += 86400;
1269
+ else if (t > 43200) t -= 86400;
1270
+ const t0Sec = tow + t;
1271
+ const ura = getBitU(msg, 35, 4);
1272
+ return {
1273
+ system: "S",
1274
+ prn: `S${two2(prn - 100)}`,
1275
+ tocDate: new Date(GPS_EPOCH_MS5 + week * MS_PER_WEEK2 + t0Sec * 1e3),
1276
+ tauN: getBitS(msg, 206, 12) * 2 ** -31,
1277
+ // a_Gf0, clock offset (s)
1278
+ gammaN: getBitS(msg, 218, 8) * 2 ** -39 / 2,
1279
+ // a_Gf1, clock drift (s/s)
1280
+ messageFrameTime: (tow % 86400 + 86400) % 86400,
1281
+ x: getBitS(msg, 39, 30) * 0.08 / 1e3,
1282
+ y: getBitS(msg, 69, 30) * 0.08 / 1e3,
1283
+ z: getBitS(msg, 99, 25) * 0.4 / 1e3,
1284
+ xDot: getBitS(msg, 124, 17) * 625e-6 / 1e3,
1285
+ yDot: getBitS(msg, 141, 17) * 625e-6 / 1e3,
1286
+ zDot: getBitS(msg, 158, 18) * 4e-3 / 1e3,
1287
+ xAcc: getBitS(msg, 176, 10) * 125e-7 / 1e3,
1288
+ yAcc: getBitS(msg, 186, 10) * 125e-7 / 1e3,
1289
+ zAcc: getBitS(msg, 196, 10) * 625e-7 / 1e3,
1290
+ health: ura === 15 ? 1 : 0,
1291
+ freqNum: 0
1292
+ };
1293
+ }
1294
+
1295
+ // src/ubx/rawnav.ts
1296
+ var GPS_EPOCH_MS6 = Date.UTC(1980, 0, 6);
1297
+ var SEC_PER_WEEK6 = 7 * 86400;
1298
+ var two3 = (n) => String(n).padStart(2, "0");
1256
1299
  function parseUbxRawNav(data, opts = {}) {
1257
1300
  const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
1258
1301
  const ephemerides = [];
1259
- const counts = { gal: 0, bds: 0, glo: 0 };
1302
+ const counts = { gal: 0, bds: 0, glo: 0, sbas: 0 };
1260
1303
  let badParity = 0;
1261
1304
  const inav = new GalInavAssembler();
1262
1305
  const bds = new BdsAssembler();
1263
1306
  const glo = new GloStringAssembler();
1264
1307
  let refDate = null;
1308
+ let refWeek = 0;
1309
+ let refTow = 0;
1310
+ const sbasSeen = /* @__PURE__ */ new Set();
1265
1311
  for (const f of ubxFrames(data)) {
1266
1312
  if (f.msgClass !== 2) continue;
1267
1313
  if (f.msgId === 21 && f.payload.length >= 16) {
@@ -1270,8 +1316,10 @@ function parseUbxRawNav(data, opts = {}) {
1270
1316
  if (week === 0 && opts.refWeek !== void 0) week = opts.refWeek;
1271
1317
  if (week > 0) {
1272
1318
  refDate = new Date(
1273
- GPS_EPOCH_MS5 + (week * SEC_PER_WEEK6 + rcvTow) * 1e3
1319
+ GPS_EPOCH_MS6 + (week * SEC_PER_WEEK6 + rcvTow) * 1e3
1274
1320
  );
1321
+ refWeek = week;
1322
+ refTow = rcvTow;
1275
1323
  }
1276
1324
  continue;
1277
1325
  }
@@ -1323,7 +1371,7 @@ function parseUbxRawNav(data, opts = {}) {
1323
1371
  badParity++;
1324
1372
  continue;
1325
1373
  }
1326
- const eph = bds.push(`C${two2(svId)}`, sf);
1374
+ const eph = bds.push(`C${two3(svId)}`, sf);
1327
1375
  if (eph) ephemerides.push(eph);
1328
1376
  } else if (gnssId === 6) {
1329
1377
  if (p.length < 8 + 16) continue;
@@ -1342,16 +1390,41 @@ function parseUbxRawNav(data, opts = {}) {
1342
1390
  continue;
1343
1391
  }
1344
1392
  if (!refDate) continue;
1345
- const eph = glo.push(`R${two2(svId)}`, str, refDate, p[3] - 7);
1393
+ const eph = glo.push(`R${two3(svId)}`, str, refDate, p[3] - 7);
1346
1394
  if (eph) ephemerides.push(eph);
1395
+ } else if (gnssId === 1) {
1396
+ if (p.length < 8 + 32) continue;
1397
+ counts.sbas++;
1398
+ if (svId < 120 || svId > 158) continue;
1399
+ const msg = new Uint8Array(32);
1400
+ for (let k = 0; k < 8; k++) {
1401
+ const w = view.getUint32(base + 4 * k, true);
1402
+ msg[4 * k] = w >>> 24;
1403
+ msg[4 * k + 1] = w >>> 16 & 255;
1404
+ msg[4 * k + 2] = w >>> 8 & 255;
1405
+ msg[4 * k + 3] = w & 255;
1406
+ }
1407
+ if (!sbasCrcOk(msg)) {
1408
+ badParity++;
1409
+ continue;
1410
+ }
1411
+ if (refWeek === 0) continue;
1412
+ const eph = decodeSbasGeoNav(msg, svId, refWeek, refTow);
1413
+ if (eph) {
1414
+ const key = `${eph.prn}@${eph.tocDate.getTime()}`;
1415
+ if (!sbasSeen.has(key)) {
1416
+ sbasSeen.add(key);
1417
+ ephemerides.push(eph);
1418
+ }
1419
+ }
1347
1420
  }
1348
1421
  }
1349
1422
  return { ephemerides, counts, badParity };
1350
1423
  }
1351
1424
 
1352
1425
  // src/ubx/index.ts
1353
- var GPS_EPOCH_MS6 = Date.UTC(1980, 0, 6);
1354
- var MS_PER_WEEK2 = 7 * 864e5;
1426
+ var GPS_EPOCH_MS7 = Date.UTC(1980, 0, 6);
1427
+ var MS_PER_WEEK3 = 7 * 864e5;
1355
1428
  var SIGNALS = {
1356
1429
  0: { 0: ["G", "1C"], 3: ["G", "2X"], 4: ["G", "2X"] },
1357
1430
  // GPS L1C/A, L2CL, L2CM
@@ -1367,20 +1440,20 @@ var SIGNALS = {
1367
1440
  // GLONASS L1OF, L2OF
1368
1441
  };
1369
1442
  function prnFor(gnssId, svId) {
1370
- const two3 = (n) => String(n).padStart(2, "0");
1443
+ const two4 = (n) => String(n).padStart(2, "0");
1371
1444
  switch (gnssId) {
1372
1445
  case 0:
1373
- return svId >= 1 && svId <= 32 ? `G${two3(svId)}` : null;
1446
+ return svId >= 1 && svId <= 32 ? `G${two4(svId)}` : null;
1374
1447
  case 1:
1375
- return svId >= 120 && svId <= 158 ? `S${two3(svId - 100)}` : null;
1448
+ return svId >= 120 && svId <= 158 ? `S${two4(svId - 100)}` : null;
1376
1449
  case 2:
1377
- return svId >= 1 && svId <= 36 ? `E${two3(svId)}` : null;
1450
+ return svId >= 1 && svId <= 36 ? `E${two4(svId)}` : null;
1378
1451
  case 3:
1379
- return svId >= 1 && svId <= 63 ? `C${two3(svId)}` : null;
1452
+ return svId >= 1 && svId <= 63 ? `C${two4(svId)}` : null;
1380
1453
  case 5:
1381
- return svId >= 1 && svId <= 10 ? `J${two3(svId)}` : null;
1454
+ return svId >= 1 && svId <= 10 ? `J${two4(svId)}` : null;
1382
1455
  case 6:
1383
- return svId >= 1 && svId <= 32 ? `R${two3(svId)}` : null;
1456
+ return svId >= 1 && svId <= 32 ? `R${two4(svId)}` : null;
1384
1457
  default:
1385
1458
  return null;
1386
1459
  }
@@ -1433,7 +1506,7 @@ function parseUbxRawx(data) {
1433
1506
  if (!codes.includes(sig[1])) codes.push(sig[1]);
1434
1507
  }
1435
1508
  epochs.push({
1436
- timeMs: GPS_EPOCH_MS6 + week * MS_PER_WEEK2 + Math.round(rcvTow * 1e3),
1509
+ timeMs: GPS_EPOCH_MS7 + week * MS_PER_WEEK3 + Math.round(rcvTow * 1e3),
1437
1510
  leapS: leapValid ? leapS : null,
1438
1511
  meas
1439
1512
  });
package/dist/ubx.d.cts CHANGED
@@ -149,10 +149,10 @@ declare function parseUbxCnav(data: Uint8Array): UbxCnavResult;
149
149
 
150
150
  /**
151
151
  * u-blox UBX raw navigation-message decoding for the non-GPS
152
- * constellations: Galileo I/NAV (E1B/E5b), BeiDou D1/D2 (B1I/B2I) and
153
- * GLONASS L1/L2 C/A strings from RXM-SFRBX (class 0x02, id 0x13).
154
- * GPS/QZSS LNAV stays in `parseUbxNav` (./nav.ts) and GPS CNAV in
155
- * `parseUbxCnav` (./cnav.ts).
152
+ * constellations: Galileo I/NAV (E1B/E5b), BeiDou D1/D2 (B1I/B2I),
153
+ * GLONASS L1/L2 C/A strings and SBAS L1 C/A GEO navigation (message
154
+ * type 9) from RXM-SFRBX (class 0x02, id 0x13). GPS/QZSS LNAV stays in
155
+ * `parseUbxNav` (./nav.ts) and GPS CNAV in `parseUbxCnav` (./cnav.ts).
156
156
  *
157
157
  * The per-constellation word repack is a port of RTKLIB demo5
158
158
  * (rtklibexplorer fork, src/rcv/ublox.c: decode_rxmsfrbx routing into
@@ -233,20 +233,23 @@ interface UbxRawNavResult {
233
233
  /**
234
234
  * Broadcast ephemerides in stream order, unchanged rebroadcasts
235
235
  * suppressed: Galileo I/NAV (`system: 'E'`, RINEX I/NAV clock set),
236
- * BeiDou D1/D2 (`system: 'C'`, BDT epochs/weeks) and GLONASS
237
- * (`system: 'R'`, UTC epochs, km state vectors).
236
+ * BeiDou D1/D2 (`system: 'C'`, BDT epochs/weeks), GLONASS
237
+ * (`system: 'R'`, UTC epochs, km state vectors) and SBAS GEO
238
+ * (`system: 'S'`, GPS-scale epochs, km state vectors).
238
239
  */
239
240
  ephemerides: Ephemeris[];
240
241
  /** RXM-SFRBX messages routed to each constellation's decoder:
241
242
  * `gal` = E1B + E5b I/NAV pages, `bds` = B1I + B2I subframes,
242
- * `glo` = L1 + L2 C/A strings. */
243
+ * `glo` = L1 + L2 C/A strings, `sbas` = L1 C/A GEO messages. */
243
244
  counts: {
244
245
  gal: number;
245
246
  bds: number;
246
247
  glo: number;
248
+ sbas: number;
247
249
  };
248
250
  /** Messages dropped for a failed integrity check: I/NAV page
249
- * CRC-24Q, BDS BCH(15,11,1) word parity, GLONASS Hamming (KX). */
251
+ * CRC-24Q, BDS BCH(15,11,1) word parity, GLONASS Hamming (KX),
252
+ * SBAS CRC-24Q. */
250
253
  badParity: number;
251
254
  }
252
255
  /**
package/dist/ubx.d.ts CHANGED
@@ -149,10 +149,10 @@ declare function parseUbxCnav(data: Uint8Array): UbxCnavResult;
149
149
 
150
150
  /**
151
151
  * u-blox UBX raw navigation-message decoding for the non-GPS
152
- * constellations: Galileo I/NAV (E1B/E5b), BeiDou D1/D2 (B1I/B2I) and
153
- * GLONASS L1/L2 C/A strings from RXM-SFRBX (class 0x02, id 0x13).
154
- * GPS/QZSS LNAV stays in `parseUbxNav` (./nav.ts) and GPS CNAV in
155
- * `parseUbxCnav` (./cnav.ts).
152
+ * constellations: Galileo I/NAV (E1B/E5b), BeiDou D1/D2 (B1I/B2I),
153
+ * GLONASS L1/L2 C/A strings and SBAS L1 C/A GEO navigation (message
154
+ * type 9) from RXM-SFRBX (class 0x02, id 0x13). GPS/QZSS LNAV stays in
155
+ * `parseUbxNav` (./nav.ts) and GPS CNAV in `parseUbxCnav` (./cnav.ts).
156
156
  *
157
157
  * The per-constellation word repack is a port of RTKLIB demo5
158
158
  * (rtklibexplorer fork, src/rcv/ublox.c: decode_rxmsfrbx routing into
@@ -233,20 +233,23 @@ interface UbxRawNavResult {
233
233
  /**
234
234
  * Broadcast ephemerides in stream order, unchanged rebroadcasts
235
235
  * suppressed: Galileo I/NAV (`system: 'E'`, RINEX I/NAV clock set),
236
- * BeiDou D1/D2 (`system: 'C'`, BDT epochs/weeks) and GLONASS
237
- * (`system: 'R'`, UTC epochs, km state vectors).
236
+ * BeiDou D1/D2 (`system: 'C'`, BDT epochs/weeks), GLONASS
237
+ * (`system: 'R'`, UTC epochs, km state vectors) and SBAS GEO
238
+ * (`system: 'S'`, GPS-scale epochs, km state vectors).
238
239
  */
239
240
  ephemerides: Ephemeris[];
240
241
  /** RXM-SFRBX messages routed to each constellation's decoder:
241
242
  * `gal` = E1B + E5b I/NAV pages, `bds` = B1I + B2I subframes,
242
- * `glo` = L1 + L2 C/A strings. */
243
+ * `glo` = L1 + L2 C/A strings, `sbas` = L1 C/A GEO messages. */
243
244
  counts: {
244
245
  gal: number;
245
246
  bds: number;
246
247
  glo: number;
248
+ sbas: number;
247
249
  };
248
250
  /** Messages dropped for a failed integrity check: I/NAV page
249
- * CRC-24Q, BDS BCH(15,11,1) word parity, GLONASS Hamming (KX). */
251
+ * CRC-24Q, BDS BCH(15,11,1) word parity, GLONASS Hamming (KX),
252
+ * SBAS CRC-24Q. */
250
253
  badParity: number;
251
254
  }
252
255
  /**
package/dist/ubx.js CHANGED
@@ -5,8 +5,8 @@ import {
5
5
  parseUbxRawNav,
6
6
  parseUbxRawx,
7
7
  ubxFrames
8
- } from "./chunk-ZQDLYLQA.js";
9
- import "./chunk-FA2UTLEQ.js";
8
+ } from "./chunk-Z5VLTH33.js";
9
+ import "./chunk-QV3XGDUU.js";
10
10
  import "./chunk-YUW33VXK.js";
11
11
  import "./chunk-V2D5KUKH.js";
12
12
  import "./chunk-HVXYFUCB.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gnss-js",
3
- "version": "1.41.0",
3
+ "version": "1.43.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,