gnss-js 2.10.1 → 2.12.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.
Files changed (55) hide show
  1. package/README.md +16 -1
  2. package/dist/analysis.cjs +24 -25
  3. package/dist/analysis.js +2 -2
  4. package/dist/{clk-DGVBGRzA.d.cts → bias-sinex-OGMw9xEZ.d.cts} +66 -1
  5. package/dist/{clk-DGVBGRzA.d.ts → bias-sinex-OGMw9xEZ.d.ts} +66 -1
  6. package/dist/binex.d.cts +1 -1
  7. package/dist/binex.d.ts +1 -1
  8. package/dist/{chunk-56HM5B6T.js → chunk-2DJ4XENO.js} +177 -9
  9. package/dist/{chunk-GH7MYXON.js → chunk-2KQMCJ5Z.js} +7 -5
  10. package/dist/chunk-E3Y6YKQM.js +65 -0
  11. package/dist/{chunk-3U5AX7PY.js → chunk-FEABDV5P.js} +24 -25
  12. package/dist/{chunk-WQX354KD.js → chunk-H3AKFD25.js} +1 -1
  13. package/dist/{chunk-YUW33VXK.js → chunk-HUXQABJI.js} +2 -0
  14. package/dist/{chunk-74IVYOQV.js → chunk-HWHD5E6V.js} +128 -78
  15. package/dist/{chunk-KUSUN7DP.js → chunk-MFCPYUEI.js} +1 -1
  16. package/dist/{chunk-3KSDL3CO.js → chunk-NIJ6WFQJ.js} +6 -321
  17. package/dist/chunk-NL2ORX75.js +319 -0
  18. package/dist/{chunk-K3GLUWZI.js → chunk-RWFJEVLJ.js} +590 -296
  19. package/dist/{chunk-SEYH4BEN.js → chunk-SZP4TLYR.js} +2 -2
  20. package/dist/chunk-TWGZTRBL.js +323 -0
  21. package/dist/index.cjs +1315 -460
  22. package/dist/index.d.cts +5 -5
  23. package/dist/index.d.ts +5 -5
  24. package/dist/index.js +20 -12
  25. package/dist/{nav-DImXUdbp.d.cts → nav-COp0Vmlw.d.cts} +83 -2
  26. package/dist/{nav-DImXUdbp.d.ts → nav-COp0Vmlw.d.ts} +83 -2
  27. package/dist/{nav-BYmYoh9A.d.cts → nav-CvZXmumD.d.cts} +1 -1
  28. package/dist/{nav-CN8rxL4h.d.ts → nav-D2DFlVpa.d.ts} +1 -1
  29. package/dist/novatel.d.cts +1 -1
  30. package/dist/novatel.d.ts +1 -1
  31. package/dist/novatel.js +3 -3
  32. package/dist/orbit.d.cts +2 -2
  33. package/dist/orbit.d.ts +2 -2
  34. package/dist/osnma.cjs +1336 -0
  35. package/dist/osnma.d.cts +273 -0
  36. package/dist/osnma.d.ts +273 -0
  37. package/dist/osnma.js +1216 -0
  38. package/dist/positioning.cjs +585 -291
  39. package/dist/positioning.d.cts +116 -6
  40. package/dist/positioning.d.ts +116 -6
  41. package/dist/positioning.js +3 -3
  42. package/dist/rinex.cjs +210 -36
  43. package/dist/rinex.d.cts +10 -55
  44. package/dist/rinex.d.ts +10 -55
  45. package/dist/rinex.js +6 -3
  46. package/dist/sbf.cjs +420 -24
  47. package/dist/sbf.d.cts +46 -5
  48. package/dist/sbf.d.ts +46 -5
  49. package/dist/sbf.js +12 -6
  50. package/dist/trimble.d.cts +1 -1
  51. package/dist/trimble.d.ts +1 -1
  52. package/dist/ubx.d.cts +1 -1
  53. package/dist/ubx.d.ts +1 -1
  54. package/dist/ubx.js +5 -4
  55. package/package.json +6 -1
package/dist/sbf.cjs CHANGED
@@ -30,6 +30,7 @@ __export(sbf_exports, {
30
30
  isSbasL1Preamble: () => isSbasL1Preamble,
31
31
  isSbasL5Correction: () => isSbasL5Correction,
32
32
  parseSbfAlmanac: () => parseSbfAlmanac,
33
+ parseSbfBdsCnav: () => parseSbfBdsCnav,
33
34
  parseSbfBdsNav: () => parseSbfBdsNav,
34
35
  parseSbfCnav: () => parseSbfCnav,
35
36
  parseSbfGalNav: () => parseSbfGalNav,
@@ -942,7 +943,7 @@ var isc = (b, pos) => {
942
943
  return raw === -4096 ? null : raw * 2 ** -35;
943
944
  };
944
945
  function decodeClock(b, msgType) {
945
- const clock = {
946
+ const clock2 = {
946
947
  msgType,
947
948
  top: getBitU(b, 38, 11) * 300,
948
949
  uraNed0: getBitS(b, 49, 5),
@@ -954,26 +955,26 @@ function decodeClock(b, msgType) {
954
955
  af2: getBitS(b, 117, 10) * 2 ** -60
955
956
  };
956
957
  if (msgType === 30) {
957
- clock.tgd = isc(b, 127);
958
- clock.iscL1ca = isc(b, 140);
959
- clock.iscL2c = isc(b, 153);
960
- clock.iscL5i5 = isc(b, 166);
961
- clock.iscL5q5 = isc(b, 179);
962
- clock.ionoAlpha = [
958
+ clock2.tgd = isc(b, 127);
959
+ clock2.iscL1ca = isc(b, 140);
960
+ clock2.iscL2c = isc(b, 153);
961
+ clock2.iscL5i5 = isc(b, 166);
962
+ clock2.iscL5q5 = isc(b, 179);
963
+ clock2.ionoAlpha = [
963
964
  getBitS(b, 192, 8) * 2 ** -30,
964
965
  getBitS(b, 200, 8) * 2 ** -27,
965
966
  getBitS(b, 208, 8) * 2 ** -24,
966
967
  getBitS(b, 216, 8) * 2 ** -24
967
968
  ];
968
- clock.ionoBeta = [
969
+ clock2.ionoBeta = [
969
970
  getBitS(b, 224, 8) * 2 ** 11,
970
971
  getBitS(b, 232, 8) * 2 ** 14,
971
972
  getBitS(b, 240, 8) * 2 ** 16,
972
973
  getBitS(b, 248, 8) * 2 ** 16
973
974
  ];
974
- clock.wnOp = getBitU(b, 256, 8);
975
+ clock2.wnOp = getBitU(b, 256, 8);
975
976
  }
976
- return clock;
977
+ return clock2;
977
978
  }
978
979
  function resolveWeek(week, towSec, sec) {
979
980
  if (sec < towSec - HALF_WEEK) return week + 1;
@@ -1011,10 +1012,10 @@ var CnavAssembler = class {
1011
1012
  return this.tryEmit(prn, sat);
1012
1013
  }
1013
1014
  tryEmit(prn, sat) {
1014
- const { t10, t11, clock, extras } = sat;
1015
- if (!t10 || !t11 || !clock) return null;
1016
- if (t10.toe !== t11.toe || clock.toc !== t10.toe) return null;
1017
- const key = `${t10.week}:${t10.toe}:${clock.af0}:${clock.af1}`;
1015
+ const { t10, t11, clock: clock2, extras } = sat;
1016
+ if (!t10 || !t11 || !clock2) return null;
1017
+ if (t10.toe !== t11.toe || clock2.toc !== t10.toe) return null;
1018
+ const key = `${t10.week}:${t10.toe}:${clock2.af0}:${clock2.af1}`;
1018
1019
  if (key === sat.lastKey) return null;
1019
1020
  sat.lastKey = key;
1020
1021
  const weekToe = resolveWeek(t10.week, t10.tow, t10.toe);
@@ -1025,9 +1026,9 @@ var CnavAssembler = class {
1025
1026
  week: t10.week,
1026
1027
  health: t10.health,
1027
1028
  uraEd: t10.uraEd,
1028
- uraNed0: clock.uraNed0,
1029
- uraNed1: clock.uraNed1,
1030
- uraNed2: clock.uraNed2,
1029
+ uraNed0: clock2.uraNed0,
1030
+ uraNed1: clock2.uraNed1,
1031
+ uraNed2: clock2.uraNed2,
1031
1032
  top: t10.top,
1032
1033
  toe: t10.toe,
1033
1034
  toeDate: gpsDate(weekToe, t10.toe),
@@ -1050,12 +1051,12 @@ var CnavAssembler = class {
1050
1051
  crc: t11.crc,
1051
1052
  cus: t11.cus,
1052
1053
  cuc: t11.cuc,
1053
- toc: clock.toc,
1054
- tocDate: gpsDate(weekToe, clock.toc),
1055
- af0: clock.af0,
1056
- af1: clock.af1,
1057
- af2: clock.af2,
1058
- clockMsgType: clock.msgType,
1054
+ toc: clock2.toc,
1055
+ tocDate: gpsDate(weekToe, clock2.toc),
1056
+ af0: clock2.af0,
1057
+ af1: clock2.af1,
1058
+ af2: clock2.af2,
1059
+ clockMsgType: clock2.msgType,
1059
1060
  tgd: extras?.tgd ?? null,
1060
1061
  iscL1ca: extras?.iscL1ca ?? null,
1061
1062
  iscL2c: extras?.iscL2c ?? null,
@@ -2168,6 +2169,378 @@ function parseSbfGloNav(data) {
2168
2169
  return { ephemerides, badCrc, messages };
2169
2170
  }
2170
2171
 
2172
+ // src/navbits/bds-cnav.ts
2173
+ var BDT_EPOCH_MS3 = Date.UTC(2006, 0, 1);
2174
+ var SEC_PER_WEEK8 = 7 * 86400;
2175
+ var HALF_WEEK4 = 302400;
2176
+ var BDS_CNAV_A_REF_MEO = 27906100;
2177
+ var BDS_CNAV_A_REF_IGSO_GEO = 42162200;
2178
+ function bdsCnavAref(satType) {
2179
+ return satType === 3 ? BDS_CNAV_A_REF_MEO : BDS_CNAV_A_REF_IGSO_GEO;
2180
+ }
2181
+ function ephI(b, p) {
2182
+ return {
2183
+ toe: getBitU(b, p, 11) * 300,
2184
+ satType: getBitU(b, p + 11, 2),
2185
+ deltaA: getBitS(b, p + 13, 26) * 2 ** -9,
2186
+ aDot: getBitS(b, p + 39, 25) * 2 ** -21,
2187
+ deltaN0: getBitS(b, p + 64, 17) * 2 ** -44 * GPS_PI,
2188
+ deltaN0Dot: getBitS(b, p + 81, 23) * 2 ** -57 * GPS_PI,
2189
+ m0: getBitS33(b, p + 104) * 2 ** -32 * GPS_PI,
2190
+ e: getBitU33(b, p + 137) * 2 ** -34,
2191
+ omega: getBitS33(b, p + 170) * 2 ** -32 * GPS_PI
2192
+ };
2193
+ }
2194
+ function ephII(b, p) {
2195
+ return {
2196
+ omega0: getBitS33(b, p) * 2 ** -32 * GPS_PI,
2197
+ i0: getBitS33(b, p + 33) * 2 ** -32 * GPS_PI,
2198
+ omegaDot: getBitS(b, p + 66, 19) * 2 ** -44 * GPS_PI,
2199
+ i0Dot: getBitS(b, p + 85, 15) * 2 ** -44 * GPS_PI,
2200
+ cis: getBitS(b, p + 100, 16) * 2 ** -30,
2201
+ cic: getBitS(b, p + 116, 16) * 2 ** -30,
2202
+ crs: getBitS(b, p + 132, 24) * 2 ** -8,
2203
+ crc: getBitS(b, p + 156, 24) * 2 ** -8,
2204
+ cus: getBitS(b, p + 180, 21) * 2 ** -30,
2205
+ cuc: getBitS(b, p + 201, 21) * 2 ** -30
2206
+ };
2207
+ }
2208
+ function clock(b, p) {
2209
+ return {
2210
+ toc: getBitU(b, p, 11) * 300,
2211
+ af0: getBitS(b, p + 11, 25) * 2 ** -34,
2212
+ af1: getBitS(b, p + 36, 22) * 2 ** -50,
2213
+ af2: getBitS(b, p + 58, 11) * 2 ** -66
2214
+ };
2215
+ }
2216
+ function sisaiOc(b, p) {
2217
+ return {
2218
+ top: getBitU(b, p, 11) * 300,
2219
+ ocb: getBitS(b, p + 11, 5),
2220
+ oc1: getBitS(b, p + 16, 3),
2221
+ oc2: getBitS(b, p + 19, 3)
2222
+ };
2223
+ }
2224
+ var delay = (b, p) => getBitS(b, p, 12) * 2 ** -34;
2225
+ function crcOk(msg, dataBits) {
2226
+ const need = Math.ceil((dataBits + 24) / 8);
2227
+ return msg.length >= need && crc24q(msg, dataBits) === getBitU(msg, dataBits, 24);
2228
+ }
2229
+ var bdsCnav1Sf2CrcOk = (sf2) => crcOk(sf2, 576);
2230
+ var bdsCnav1Sf3CrcOk = (sf3) => crcOk(sf3, 240);
2231
+ var bdsCnav2CrcOk = (msg) => crcOk(msg, 264);
2232
+ var bdsCnav3CrcOk = (msg) => crcOk(msg, 462);
2233
+ function resolveWeek2(week, towSec, sec) {
2234
+ if (sec < towSec - HALF_WEEK4) return week + 1;
2235
+ if (sec > towSec + HALF_WEEK4) return week - 1;
2236
+ return week;
2237
+ }
2238
+ function bdtDate(week, sec) {
2239
+ return new Date(BDT_EPOCH_MS3 + (week * SEC_PER_WEEK8 + sec) * 1e3);
2240
+ }
2241
+ var emptyStatus = () => ({
2242
+ top: null,
2243
+ sisaiOe: null,
2244
+ sisaiOcb: null,
2245
+ sisaiOc1: null,
2246
+ sisaiOc2: null,
2247
+ sismai: null,
2248
+ health: null,
2249
+ integrityFlags: null
2250
+ });
2251
+ function applyOc(s, oc) {
2252
+ s.top = oc.top;
2253
+ s.sisaiOcb = oc.ocb;
2254
+ s.sisaiOc1 = oc.oc1;
2255
+ s.sisaiOc2 = oc.oc2;
2256
+ }
2257
+ function build(message, prn, wn, tTm, e1, e2, c, d, s) {
2258
+ const week = resolveWeek2(wn, tTm, e1.toe);
2259
+ const weekToc = resolveWeek2(wn, tTm, c.toc);
2260
+ return {
2261
+ system: "C",
2262
+ prn,
2263
+ message,
2264
+ week,
2265
+ toe: e1.toe,
2266
+ toeDate: bdtDate(week, e1.toe),
2267
+ toc: c.toc,
2268
+ tocDate: bdtDate(weekToc, c.toc),
2269
+ satType: e1.satType,
2270
+ a: bdsCnavAref(e1.satType) + e1.deltaA,
2271
+ deltaA: e1.deltaA,
2272
+ aDot: e1.aDot,
2273
+ deltaN0: e1.deltaN0,
2274
+ deltaN0Dot: e1.deltaN0Dot,
2275
+ m0: e1.m0,
2276
+ e: e1.e,
2277
+ omega: e1.omega,
2278
+ ...e2,
2279
+ af0: c.af0,
2280
+ af1: c.af1,
2281
+ af2: c.af2,
2282
+ ...d,
2283
+ ...s,
2284
+ tow: tTm
2285
+ };
2286
+ }
2287
+ var prnLabel = (prn) => `C${String(prn).padStart(2, "0")}`;
2288
+ var BdsCnav1Assembler = class {
2289
+ status = /* @__PURE__ */ new Map();
2290
+ lastKey = /* @__PURE__ */ new Map();
2291
+ /**
2292
+ * Push one frame's CRC-valid subframes (bit-0 aligned; pass null for
2293
+ * a subframe that failed its CRC) for satellite `prn` (1-63). `tTm`
2294
+ * is the frame's transmit time, s of the BDT week. Returns the newly
2295
+ * seen ephemeris, or null.
2296
+ */
2297
+ push(prn, sf2, sf3, tTm) {
2298
+ let s = this.status.get(prn);
2299
+ if (!s) this.status.set(prn, s = emptyStatus());
2300
+ if (sf3) {
2301
+ const page = getBitU(sf3, 0, 6);
2302
+ if (page >= 1 && page <= 4) {
2303
+ s.health = getBitU(sf3, 6, 2);
2304
+ s.integrityFlags = getBitU(sf3, 8, 3);
2305
+ s.sismai = getBitU(sf3, 11, 4);
2306
+ if (page === 1) {
2307
+ s.sisaiOe = getBitU(sf3, 15, 5);
2308
+ applyOc(s, sisaiOc(sf3, 20));
2309
+ } else if (page === 3) s.sisaiOe = getBitU(sf3, 15, 5);
2310
+ else applyOc(s, sisaiOc(sf3, 15));
2311
+ }
2312
+ }
2313
+ if (!sf2) return null;
2314
+ const wn = getBitU(sf2, 0, 13);
2315
+ const iodc = getBitU(sf2, 21, 10);
2316
+ const iode = getBitU(sf2, 31, 8);
2317
+ const e1 = ephI(sf2, 39);
2318
+ const c = clock(sf2, 464);
2319
+ const key = `${wn}:${iodc}:${iode}:${e1.toe}:${c.toc}`;
2320
+ if (this.lastKey.get(prn) === key) return null;
2321
+ this.lastKey.set(prn, key);
2322
+ return build(
2323
+ "CNV1",
2324
+ prnLabel(prn),
2325
+ wn,
2326
+ tTm,
2327
+ e1,
2328
+ ephII(sf2, 242),
2329
+ c,
2330
+ {
2331
+ iode,
2332
+ iodc,
2333
+ tgdB1Cp: delay(sf2, 557),
2334
+ tgdB2ap: delay(sf2, 533),
2335
+ iscB1Cd: delay(sf2, 545),
2336
+ iscB2ad: null,
2337
+ tgdB2bI: null
2338
+ },
2339
+ { ...s }
2340
+ );
2341
+ }
2342
+ };
2343
+ var BdsCnav2Assembler = class {
2344
+ sats = /* @__PURE__ */ new Map();
2345
+ /**
2346
+ * Push one CRC-valid 288-bit message (bit 0 = first PRN bit, the
2347
+ * preamble stripped). Returns the newly completed ephemeris, or null.
2348
+ */
2349
+ push(msg) {
2350
+ const prn = getBitU(msg, 0, 6);
2351
+ const type = getBitU(msg, 6, 6);
2352
+ const sow = getBitU(msg, 12, 18) * 3;
2353
+ if (prn < 1) return null;
2354
+ let sat = this.sats.get(prn);
2355
+ if (!sat) this.sats.set(prn, sat = { status: emptyStatus() });
2356
+ const s = sat.status;
2357
+ if (type === 10) {
2358
+ sat.t10 = {
2359
+ wn: getBitU(msg, 30, 13),
2360
+ iode: getBitU(msg, 53, 8),
2361
+ e1: ephI(msg, 61),
2362
+ sow
2363
+ };
2364
+ s.integrityFlags = getBitU(msg, 43, 3) << 3 | getBitU(msg, 50, 3);
2365
+ s.sismai = getBitU(msg, 46, 4);
2366
+ if (sat.t11 && sat.t11.sow < sow) sat.t11 = void 0;
2367
+ } else if (type === 11 || type >= 30 && type <= 34 || type === 40) {
2368
+ s.health = getBitU(msg, 30, 2);
2369
+ s.integrityFlags = getBitU(msg, 32, 3) << 3 | getBitU(msg, 39, 3);
2370
+ s.sismai = getBitU(msg, 35, 4);
2371
+ if (type === 11) {
2372
+ if (!sat.t10 || sow <= sat.t10.sow) return null;
2373
+ sat.t11 = { e2: ephII(msg, 42), sow };
2374
+ } else if (type === 34) {
2375
+ applyOc(s, sisaiOc(msg, 42));
2376
+ sat.clock = { c: clock(msg, 64), iodc: getBitU(msg, 133, 10) };
2377
+ } else if (type === 40) {
2378
+ s.sisaiOe = getBitU(msg, 42, 5);
2379
+ applyOc(s, sisaiOc(msg, 47));
2380
+ return null;
2381
+ } else {
2382
+ sat.clock = { c: clock(msg, 42), iodc: getBitU(msg, 111, 10) };
2383
+ if (type === 30)
2384
+ sat.delays = {
2385
+ tgdB2ap: delay(msg, 121),
2386
+ iscB2ad: delay(msg, 133),
2387
+ tgdB1Cp: delay(msg, 219)
2388
+ };
2389
+ }
2390
+ } else return null;
2391
+ const { t10, t11, clock: ck } = sat;
2392
+ if (!t10 || !t11 || !ck || (ck.iodc & 255) !== t10.iode) return null;
2393
+ const key = `${t10.wn}:${ck.iodc}:${t10.iode}:${t10.e1.toe}:${ck.c.toc}`;
2394
+ if (sat.lastKey === key) return null;
2395
+ sat.lastKey = key;
2396
+ return build(
2397
+ "CNV2",
2398
+ prnLabel(prn),
2399
+ t10.wn,
2400
+ t10.sow,
2401
+ t10.e1,
2402
+ t11.e2,
2403
+ ck.c,
2404
+ {
2405
+ iode: t10.iode,
2406
+ iodc: ck.iodc,
2407
+ tgdB1Cp: sat.delays?.tgdB1Cp ?? null,
2408
+ tgdB2ap: sat.delays?.tgdB2ap ?? null,
2409
+ iscB1Cd: null,
2410
+ iscB2ad: sat.delays?.iscB2ad ?? null,
2411
+ tgdB2bI: null
2412
+ },
2413
+ { ...s }
2414
+ );
2415
+ }
2416
+ };
2417
+ var BdsCnav3Assembler = class {
2418
+ sats = /* @__PURE__ */ new Map();
2419
+ /**
2420
+ * Push one CRC-valid 486-bit message (bit 0 = first MesType bit) from
2421
+ * satellite `prn`. Returns the newly completed ephemeris, or null.
2422
+ */
2423
+ push(prn, msg) {
2424
+ const type = getBitU(msg, 0, 6);
2425
+ const sow = getBitU(msg, 6, 20);
2426
+ let sat = this.sats.get(prn);
2427
+ if (!sat) this.sats.set(prn, sat = { status: emptyStatus() });
2428
+ const s = sat.status;
2429
+ if (type === 10) {
2430
+ sat.t10 = { e1: ephI(msg, 30), e2: ephII(msg, 233), sow };
2431
+ s.integrityFlags = getBitU(msg, 455, 3);
2432
+ s.sismai = getBitU(msg, 458, 4);
2433
+ } else if (type === 30) {
2434
+ sat.t30 = {
2435
+ wn: getBitU(msg, 26, 13),
2436
+ c: clock(msg, 43),
2437
+ tgd: delay(msg, 112)
2438
+ };
2439
+ applyOc(s, sisaiOc(msg, 433));
2440
+ s.sisaiOe = getBitU(msg, 455, 5);
2441
+ s.health = getBitU(msg, 460, 2);
2442
+ } else return null;
2443
+ const { t10, t30 } = sat;
2444
+ if (!t10 || !t30 || t10.e1.toe !== t30.c.toc) return null;
2445
+ const key = `${t30.wn}:${t10.e1.toe}:${t30.c.af0}:${t10.e1.m0}`;
2446
+ if (sat.lastKey === key) return null;
2447
+ sat.lastKey = key;
2448
+ return build(
2449
+ "CNV3",
2450
+ prnLabel(prn),
2451
+ t30.wn,
2452
+ t10.sow,
2453
+ t10.e1,
2454
+ t10.e2,
2455
+ t30.c,
2456
+ {
2457
+ iode: null,
2458
+ iodc: null,
2459
+ tgdB1Cp: null,
2460
+ tgdB2ap: null,
2461
+ iscB1Cd: null,
2462
+ iscB2ad: null,
2463
+ tgdB2bI: t30.tgd
2464
+ },
2465
+ { ...s }
2466
+ );
2467
+ }
2468
+ };
2469
+
2470
+ // src/sbf/rawnav-bds-cnav.ts
2471
+ var GPS_BDT_OFFSET = 14;
2472
+ var B1C_FRAME_S = 18;
2473
+ var TOW_DNU2 = 4294967295;
2474
+ function newBdsCnavAssemblers() {
2475
+ return {
2476
+ b1c: new BdsCnav1Assembler(),
2477
+ b2a: new BdsCnav2Assembler(),
2478
+ b2b: new BdsCnav3Assembler()
2479
+ };
2480
+ }
2481
+ function navBits(view, wordsAt, start, nBits) {
2482
+ const out = new Uint8Array(Math.ceil(nBits / 8));
2483
+ for (let i = 0; i < nBits; i++) {
2484
+ const p = start + i;
2485
+ const w = view.getUint32(wordsAt + 4 * (p >>> 5), true);
2486
+ if (w >>> 31 - (p & 31) & 1) out[i >> 3] |= 128 >> (i & 7);
2487
+ }
2488
+ return out;
2489
+ }
2490
+ var MIN_LEN = { 4218: 248, 4219: 92, 4242: 144 };
2491
+ function feedBdsCnavBlock(view, b, id, len, asm) {
2492
+ if (len < (MIN_LEN[id] ?? Infinity)) return {};
2493
+ const prnStr = svidToPrn(view.getUint8(b + 14));
2494
+ if (!prnStr || prnStr[0] !== "C") return {};
2495
+ const prn = Number(prnStr.slice(1));
2496
+ const words = b + 20;
2497
+ if (id === 4218) {
2498
+ const towMs = view.getUint32(b + 8, true);
2499
+ if (towMs === TOW_DNU2) return {};
2500
+ const sf2 = navBits(view, words, 72, 600);
2501
+ const sf3 = navBits(view, words, 1272, 264);
2502
+ const sf2Ok = bdsCnav1Sf2CrcOk(sf2);
2503
+ const bdt = (towMs / 1e3 - GPS_BDT_OFFSET + 604800) % 604800;
2504
+ const tTm = (Math.floor(bdt) - B1C_FRAME_S + 604800) % 604800;
2505
+ const eph = asm.b1c.push(
2506
+ prn,
2507
+ sf2Ok ? sf2 : null,
2508
+ bdsCnav1Sf3CrcOk(sf3) ? sf3 : null,
2509
+ tTm
2510
+ );
2511
+ if (!sf2Ok) return { badCrc: true };
2512
+ return eph ? { eph } : {};
2513
+ }
2514
+ if (id === 4219) {
2515
+ const msg = navBits(view, words, 0, 288);
2516
+ if (!bdsCnav2CrcOk(msg)) return { badCrc: true };
2517
+ const eph = asm.b2a.push(msg);
2518
+ return eph ? { eph } : {};
2519
+ }
2520
+ if (id === 4242) {
2521
+ const msg = navBits(view, words, 12, 486);
2522
+ if (!bdsCnav3CrcOk(msg)) return { badCrc: true };
2523
+ const eph = asm.b2b.push(prn, msg);
2524
+ return eph ? { eph } : {};
2525
+ }
2526
+ return {};
2527
+ }
2528
+ function parseSbfBdsCnav(data) {
2529
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
2530
+ const asm = newBdsCnavAssemblers();
2531
+ const ephemerides = [];
2532
+ let badCrc = 0;
2533
+ let messages = 0;
2534
+ scanSbfFrames(data, view, (id, b, len) => {
2535
+ if (id !== 4218 && id !== 4219 && id !== 4242) return;
2536
+ messages++;
2537
+ const r = feedBdsCnavBlock(view, b, id, len, asm);
2538
+ if (r.eph) ephemerides.push(r.eph);
2539
+ else if (r.badCrc) badCrc++;
2540
+ });
2541
+ return { ephemerides, badCrc, messages };
2542
+ }
2543
+
2171
2544
  // src/navbits/sbas.ts
2172
2545
  var GPS_EPOCH_MS9 = Date.UTC(1980, 0, 6);
2173
2546
  var MS_PER_WEEK4 = 7 * 86400 * 1e3;
@@ -2353,6 +2726,7 @@ function decodeSbfNavigation(data, opts = {}) {
2353
2726
  const ephemerides = [];
2354
2727
  const seen = /* @__PURE__ */ new Set();
2355
2728
  const cnav = [];
2729
+ const bdsCnav = [];
2356
2730
  const ionoCorrections = {};
2357
2731
  let leapSeconds = null;
2358
2732
  const counts = {
@@ -2362,6 +2736,7 @@ function decodeSbfNavigation(data, opts = {}) {
2362
2736
  galRaw: 0,
2363
2737
  gloRaw: 0,
2364
2738
  bdsRaw: 0,
2739
+ bdsCnavRaw: 0,
2365
2740
  sbasRaw: 0,
2366
2741
  sbasL5Raw: 0,
2367
2742
  navicRaw: 0,
@@ -2373,6 +2748,7 @@ function decodeSbfNavigation(data, opts = {}) {
2373
2748
  const galAsm = newGalAssemblers();
2374
2749
  const gloAsm = new GloStringAssembler();
2375
2750
  const bdsAsm = new BdsAssembler();
2751
+ const bdsCnavAsm = newBdsCnavAssemblers();
2376
2752
  const lnavAsm = new GpsLnavAssembler();
2377
2753
  const navicAsm = new NavicAssembler();
2378
2754
  const addEph = (e) => {
@@ -2479,6 +2855,17 @@ function decodeSbfNavigation(data, opts = {}) {
2479
2855
  else if (r.badCrc) counts.badFrames++;
2480
2856
  return;
2481
2857
  }
2858
+ case 4218:
2859
+ // BDSRawB1C
2860
+ case 4219:
2861
+ // BDSRawB2a
2862
+ case 4242: {
2863
+ counts.bdsCnavRaw++;
2864
+ const r = feedBdsCnavBlock(view, b, id, len, bdsCnavAsm);
2865
+ if (r.eph) bdsCnav.push(r.eph);
2866
+ else if (r.badCrc) counts.badFrames++;
2867
+ return;
2868
+ }
2482
2869
  case 4020: {
2483
2870
  if (len < 52) return;
2484
2871
  counts.sbasRaw++;
@@ -2535,7 +2922,15 @@ function decodeSbfNavigation(data, opts = {}) {
2535
2922
  prns: [...dfmcPrns].sort(),
2536
2923
  messages: Object.values(dfmcByType).reduce((a, v) => a + v, 0)
2537
2924
  };
2538
- return { ephemerides, cnav, ionoCorrections, leapSeconds, dfmc, counts };
2925
+ return {
2926
+ ephemerides,
2927
+ cnav,
2928
+ bdsCnav,
2929
+ ionoCorrections,
2930
+ leapSeconds,
2931
+ dfmc,
2932
+ counts
2933
+ };
2539
2934
  }
2540
2935
 
2541
2936
  // src/navbits/rs255.ts
@@ -3740,6 +4135,7 @@ function parseSbfMeas(data) {
3740
4135
  isSbasL1Preamble,
3741
4136
  isSbasL5Correction,
3742
4137
  parseSbfAlmanac,
4138
+ parseSbfBdsCnav,
3743
4139
  parseSbfBdsNav,
3744
4140
  parseSbfCnav,
3745
4141
  parseSbfGalNav,
package/dist/sbf.d.cts CHANGED
@@ -1,6 +1,6 @@
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';
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-CvZXmumD.cjs';
2
2
  import { R as ReceiverPvt } from './receiver-pvt-CVFvi4kT.cjs';
3
- import { K as KeplerEphemeris, C as CnavEphemeris, G as GlonassEphemeris, E as Ephemeris } from './nav-DImXUdbp.cjs';
3
+ import { K as KeplerEphemeris, C as CnavEphemeris, B as BdsCnavEphemeris, G as GlonassEphemeris, E as Ephemeris } from './nav-COp0Vmlw.cjs';
4
4
  import { H as HasMessage } from './has-BaXnQarR.cjs';
5
5
 
6
6
  /**
@@ -273,6 +273,43 @@ interface SbfCnavResult {
273
273
  */
274
274
  declare function parseSbfCnav(data: Uint8Array): SbfCnavResult;
275
275
 
276
+ /**
277
+ * Septentrio SBF raw BeiDou-3 navigation blocks — BDSRawB1C (4218),
278
+ * BDSRawB2a (4219) and BDSRawB2b (4242) — into B-CNAV1/2/3 ephemerides.
279
+ *
280
+ * Block layout: after the 8-byte SBF header, TOW u4 + WNc u2, SVID u1,
281
+ * then CRCPassed u1 (B1C: CRCSF2 u1 + CRCSF3 u1), Source/Reserved
282
+ * bytes, RxChannel u1, and NAVBits as u4 words at +20 — the first bit
283
+ * is the MSB of NAVBits[0], each u4 little-endian in the stream. The
284
+ * receiver has already run the LDPC decoding; the positions inside
285
+ * NAVBits were established on TU Delft DLF500 captures (every message
286
+ * passes CRC-24Q at these offsets) and the decoded fields match DLR's
287
+ * BRD400DLR RINEX 4 records:
288
+ *
289
+ * - B1C (u4[57]): subframe 1 as its 72 raw BCH symbols, then
290
+ * subframe 2's 600 decoded bits at bit 72 and subframe 3's 264 at
291
+ * bit 1272 — each at the start of its 1200/528-symbol slot.
292
+ * - B2a (u4[18]): the 288-bit message from the PRN (no preamble).
293
+ * - B2b (u4[31]): PRN (6) + reserved (6), then the 486-bit message.
294
+ *
295
+ * The receiver's CRC flags are ignored in favor of re-checking CRC-24Q,
296
+ * so `badCrc` counts exactly what this library rejected.
297
+ */
298
+
299
+ interface SbfBdsCnavResult {
300
+ /** Assembled B-CNAV1/2/3 ephemerides in stream order, repeats suppressed. */
301
+ ephemerides: BdsCnavEphemeris[];
302
+ /** Messages whose CRC-24Q check failed (dropped). */
303
+ badCrc: number;
304
+ /** Total BDSRawB1C/B2a/B2b blocks seen (with valid SBF framing). */
305
+ messages: number;
306
+ }
307
+ /**
308
+ * Decode every BDSRawB1C/B2a/B2b block in an SBF byte stream into
309
+ * BeiDou-3 B-CNAV ephemerides (RINEX 4 CNV1/CNV2/CNV3).
310
+ */
311
+ declare function parseSbfBdsCnav(data: Uint8Array): SbfBdsCnavResult;
312
+
276
313
  /** Callback fed every CRC-valid SBAS message (any type), as MSB-first bits. */
277
314
  type SbasMessageCb = (msg: Uint8Array, prn: number, week: number, tow: number) => void;
278
315
  /** Callback fed every CRC-valid native-DFMC (L5) message, with its type. */
@@ -364,7 +401,7 @@ declare function parseSbfGeoL5(data: Uint8Array, opts?: {
364
401
  * A Septentrio broadcasts navigation data as a mix of *decoded* blocks
365
402
  * (GPSNav/GALNav/GLONav/BDSNav/QZSNav — already-parsed ephemeris) and
366
403
  * *raw* navigation-frame blocks (GPSRawCA, GALRawINAV/FNAV, GLORawCA,
367
- * BDSRaw, GPSRawL2C/L5, GEORawL1) whose bits must be assembled — and which class a
404
+ * BDSRaw, BDSRawB1C/B2a/B2b, GPSRawL2C/L5, GEORawL1) whose bits must be assembled — and which class a
368
405
  * given receiver emits depends on its configuration. The granular
369
406
  * `parseSbf*` functions each re-scan the whole stream for one class;
370
407
  * this decoder walks the byte stream **once**, routing every navigation
@@ -394,6 +431,8 @@ interface SbfNavCounts {
394
431
  gloRaw: number;
395
432
  /** Raw BeiDou D1/D2 subframe blocks (BDSRaw). */
396
433
  bdsRaw: number;
434
+ /** Raw BeiDou-3 B-CNAV blocks (BDSRawB1C/B2a/B2b). */
435
+ bdsCnavRaw: number;
397
436
  /** Raw SBAS L1 GEO message blocks (GEORawL1). */
398
437
  sbasRaw: number;
399
438
  /** Raw SBAS L5 GEO message blocks (GEORawL5) — DO-229-on-L5 + native DFMC. */
@@ -412,6 +451,8 @@ interface SbfNavigation {
412
451
  ephemerides: Ephemeris[];
413
452
  /** GPS L2C/L5 CNAV ephemerides (RINEX-4 nav records). */
414
453
  cnav: SbfCnavEphemeris[];
454
+ /** BeiDou-3 B-CNAV1/2/3 ephemerides (RINEX-4 CNV1/CNV2/CNV3 records). */
455
+ bdsCnav: BdsCnavEphemeris[];
415
456
  /**
416
457
  * Iono coefficient sets keyed like `NavHeader.ionoCorrections`
417
458
  * (GPSA/GPSB, GAL, BDSA/BDSB); the last valid block of each type wins.
@@ -426,7 +467,7 @@ interface SbfNavigation {
426
467
  }
427
468
  /**
428
469
  * Decode every navigation block in an SBF byte stream in a single pass:
429
- * decoded ephemeris blocks, raw GPS/QZSS LNAV, GPS CNAV, Galileo I/NAV +
470
+ * decoded ephemeris blocks, raw GPS/QZSS LNAV, GPS CNAV, BeiDou-3 B-CNAV, Galileo I/NAV +
430
471
  * F/NAV, GLONASS strings, BeiDou D1/D2, and the Klobuchar/NeQuick iono +
431
472
  * GPS-UTC leap-second blocks. See the module header for merge semantics.
432
473
  */
@@ -671,4 +712,4 @@ interface SbfParseResult {
671
712
  */
672
713
  declare function parseSbfMeas(data: Uint8Array): SbfParseResult;
673
714
 
674
- export { CnavEphemeris, type DfmcCensus, type DfmcMessageCb, type GeoL5Result, HasMessage, ReceiverPvt, SBAS_L5_MT_NAMES, SBAS_L5_PREAMBLE_UW, type SbasMessageCb, type SbfBdsNavResult, type SbfCnavEphemeris, type SbfCnavResult, type SbfGalEphemeris, type SbfGalNavResult, type SbfGeoL5Result, type SbfGeoNavResult, type SbfGloNavResult, type SbfGpsNavResult, type SbfHasMessage, type SbfHasResult, type SbfIonoUtcResult, type SbfMeasEpoch, type SbfMeasurement, type SbfNavCounts, type SbfNavicResult, type SbfNavigation, type SbfParseResult, type SbfPvt, type SbfPvtResult, type SbfReceiverSetup, decodeSbfNavigation, extractSbfNavicSubframe, feedGeoBlock, feedGeoL5Block, feedNavicBlock, isSbasL1Preamble, isSbasL5Correction, parseSbfBdsNav, parseSbfCnav, parseSbfGalNav, parseSbfGeoL5, parseSbfGeoNav, parseSbfGloNav, parseSbfGpsNav, parseSbfHas, parseSbfIonoUtc, parseSbfMeas, parseSbfNavic, parseSbfPvt, parseSbfReceiverSetup, sbasL5MessageName, sbasL5MessageType, crc16 as sbfCrc16, scanSbfFrames };
715
+ export { BdsCnavEphemeris, CnavEphemeris, type DfmcCensus, type DfmcMessageCb, type GeoL5Result, HasMessage, ReceiverPvt, SBAS_L5_MT_NAMES, SBAS_L5_PREAMBLE_UW, type SbasMessageCb, type SbfBdsCnavResult, type SbfBdsNavResult, type SbfCnavEphemeris, type SbfCnavResult, type SbfGalEphemeris, type SbfGalNavResult, type SbfGeoL5Result, type SbfGeoNavResult, type SbfGloNavResult, type SbfGpsNavResult, type SbfHasMessage, type SbfHasResult, type SbfIonoUtcResult, type SbfMeasEpoch, type SbfMeasurement, type SbfNavCounts, type SbfNavicResult, type SbfNavigation, type SbfParseResult, type SbfPvt, type SbfPvtResult, type SbfReceiverSetup, decodeSbfNavigation, extractSbfNavicSubframe, feedGeoBlock, feedGeoL5Block, feedNavicBlock, isSbasL1Preamble, isSbasL5Correction, parseSbfBdsCnav, parseSbfBdsNav, parseSbfCnav, parseSbfGalNav, parseSbfGeoL5, parseSbfGeoNav, parseSbfGloNav, parseSbfGpsNav, parseSbfHas, parseSbfIonoUtc, parseSbfMeas, parseSbfNavic, parseSbfPvt, parseSbfReceiverSetup, sbasL5MessageName, sbasL5MessageType, crc16 as sbfCrc16, scanSbfFrames };