gnss-js 1.14.1 → 1.16.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/novatel.js CHANGED
@@ -1,6 +1,17 @@
1
1
  import {
2
+ OEM4_HLEN,
3
+ crc32,
4
+ oem4Frames,
5
+ parseNovatelNav,
2
6
  parseNovatelRange
3
- } from "./chunk-SWKWJEGY.js";
7
+ } from "./chunk-R33A2VA7.js";
8
+ import "./chunk-4LVD4DYL.js";
9
+ import "./chunk-HVXYFUCB.js";
10
+ import "./chunk-LEEU5OIO.js";
4
11
  export {
12
+ OEM4_HLEN,
13
+ crc32,
14
+ oem4Frames,
15
+ parseNovatelNav,
5
16
  parseNovatelRange
6
17
  };
package/dist/sbf.cjs CHANGED
@@ -20,12 +20,15 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/sbf/index.ts
21
21
  var sbf_exports = {};
22
22
  __export(sbf_exports, {
23
- parseSbfMeas: () => parseSbfMeas
23
+ parseSbfAlmanac: () => parseSbfAlmanac,
24
+ parseSbfMeas: () => parseSbfMeas,
25
+ parseSbfNav: () => parseSbfNav,
26
+ sbfCrc16: () => crc16,
27
+ scanSbfFrames: () => scanSbfFrames
24
28
  });
25
29
  module.exports = __toCommonJS(sbf_exports);
26
- var CLIGHT = 299792458;
27
- var GPS_EPOCH_MS = Date.UTC(1980, 0, 6);
28
- var MS_PER_WEEK = 7 * 864e5;
30
+
31
+ // src/sbf/frame.ts
29
32
  var CRC_TABLE = (() => {
30
33
  const t = new Uint16Array(256);
31
34
  for (let n = 0; n < 256; n++) {
@@ -42,6 +45,449 @@ function crc16(data, start, end) {
42
45
  crc = (crc << 8 ^ CRC_TABLE[(crc >> 8 ^ data[i]) & 255]) & 65535;
43
46
  return crc;
44
47
  }
48
+ function scanSbfFrames(data, view, onBlock) {
49
+ let badCrc = 0;
50
+ let i = 0;
51
+ while (i + 8 <= data.length) {
52
+ if (data[i] !== 36 || data[i + 1] !== 64) {
53
+ i++;
54
+ continue;
55
+ }
56
+ const len = view.getUint16(i + 6, true);
57
+ if (len < 8 || len % 4 !== 0) {
58
+ i++;
59
+ continue;
60
+ }
61
+ if (i + len > data.length) break;
62
+ if (crc16(data, i + 4, i + len) !== view.getUint16(i + 2, true)) {
63
+ badCrc++;
64
+ i++;
65
+ continue;
66
+ }
67
+ onBlock(view.getUint16(i + 4, true) & 8191, i, len);
68
+ i += len;
69
+ }
70
+ return badCrc;
71
+ }
72
+ var two = (n) => String(n).padStart(2, "0");
73
+ function svidToPrn(svid) {
74
+ if (svid >= 1 && svid <= 37) return svid <= 32 ? `G${two(svid)}` : null;
75
+ if (svid <= 61) return svid - 37 <= 27 ? `R${two(svid - 37)}` : null;
76
+ if (svid <= 62) return null;
77
+ if (svid <= 68) return svid - 38 <= 27 ? `R${two(svid - 38)}` : null;
78
+ if (svid <= 70) return null;
79
+ if (svid <= 106) return svid - 70 <= 36 ? `E${two(svid - 70)}` : null;
80
+ if (svid <= 119) return null;
81
+ if (svid <= 140) return `S${two(svid - 100)}`;
82
+ if (svid <= 180) return svid - 140 <= 50 ? `C${two(svid - 140)}` : null;
83
+ if (svid <= 190) return `J${two(svid - 180)}`;
84
+ if (svid <= 197) return svid - 190 <= 14 ? `I${two(svid - 190)}` : null;
85
+ if (svid <= 215) return `S${two(svid - 157)}`;
86
+ if (svid <= 222) return svid - 208 <= 14 ? `I${two(svid - 208)}` : null;
87
+ if (svid <= 245) return svid - 182 <= 50 ? `C${two(svid - 182)}` : null;
88
+ return null;
89
+ }
90
+
91
+ // src/constants/time.ts
92
+ var MILLISECONDS_IN_SECOND = 1e3;
93
+ var MILLISECONDS_GPS_TAI = 19e3;
94
+ var START_NTP_TIME = /* @__PURE__ */ new Date("1900-01-01T00:00:00Z");
95
+
96
+ // src/time/gnss.ts
97
+ function getTaiDate(date) {
98
+ return new Date(date.getTime() + MILLISECONDS_GPS_TAI);
99
+ }
100
+ function getNtpTime(date) {
101
+ return getTaiDate(date).getTime() - START_NTP_TIME.getTime();
102
+ }
103
+
104
+ // src/time/utc.ts
105
+ var LEAP_SECONDS_TABLE = [
106
+ [3692217600, 37],
107
+ // 1 Jan 2017
108
+ [3644697600, 36],
109
+ // 1 Jul 2015
110
+ [3550089600, 35],
111
+ // 1 Jul 2012
112
+ [3439756800, 34],
113
+ // 1 Jan 2009
114
+ [3345062400, 33],
115
+ // 1 Jan 2006
116
+ [3124137600, 32],
117
+ // 1 Jan 1999
118
+ [3076704e3, 31],
119
+ // 1 Jul 1997
120
+ [3029443200, 30],
121
+ // 1 Jan 1996
122
+ [2982009600, 29],
123
+ // 1 Jul 1994
124
+ [2950473600, 28],
125
+ // 1 Jul 1993
126
+ [2918937600, 27],
127
+ // 1 Jul 1992
128
+ [2871676800, 26],
129
+ // 1 Jan 1991
130
+ [2840140800, 25],
131
+ // 1 Jan 1990
132
+ [2776982400, 24],
133
+ // 1 Jan 1988
134
+ [2698012800, 23],
135
+ // 1 Jul 1985
136
+ [2634854400, 22],
137
+ // 1 Jul 1983
138
+ [2603318400, 21],
139
+ // 1 Jul 1982
140
+ [2571782400, 20],
141
+ // 1 Jul 1981
142
+ [2524521600, 19],
143
+ // 1 Jan 1980
144
+ [2492985600, 18],
145
+ // 1 Jan 1979
146
+ [2461449600, 17],
147
+ // 1 Jan 1978
148
+ [2429913600, 16],
149
+ // 1 Jan 1977
150
+ [2398291200, 15],
151
+ // 1 Jan 1976
152
+ [2366755200, 14],
153
+ // 1 Jan 1975
154
+ [2335219200, 13],
155
+ // 1 Jan 1974
156
+ [2303683200, 12],
157
+ // 1 Jan 1973
158
+ [2287785600, 11],
159
+ // 1 Jul 1972
160
+ [2272060800, 10]
161
+ // 1 Jan 1972
162
+ ];
163
+ function getLeap(date) {
164
+ const ntp_time = getNtpTime(date);
165
+ for (const [timestamp, leapSeconds] of LEAP_SECONDS_TABLE) {
166
+ if (ntp_time / MILLISECONDS_IN_SECOND - leapSeconds >= timestamp) {
167
+ return leapSeconds;
168
+ }
169
+ }
170
+ return 8;
171
+ }
172
+ function getGpsLeap(date) {
173
+ const leap_seconds = getLeap(date);
174
+ if (leap_seconds < 0) return 0;
175
+ return leap_seconds - 19;
176
+ }
177
+
178
+ // src/sbf/nav.ts
179
+ var PI = Math.PI;
180
+ var GPS_EPOCH_MS = Date.UTC(1980, 0, 6);
181
+ var BDT_EPOCH_MS = Date.UTC(2006, 0, 1);
182
+ var SEC_PER_WEEK = 7 * 86400;
183
+ var MS_PER_WEEK = SEC_PER_WEEK * 1e3;
184
+ var F4_DNU = -2e10;
185
+ var U4_DNU = 4294967295;
186
+ function adjustWeek(refWeek, wn, mod) {
187
+ let offset = refWeek % mod - wn;
188
+ if (offset > mod / 2) offset -= mod;
189
+ if (offset < -(mod / 2 - 1)) offset += mod;
190
+ return refWeek - offset;
191
+ }
192
+ var gpsMs = (week, sec) => GPS_EPOCH_MS + week * MS_PER_WEEK + sec * 1e3;
193
+ var sowOf = (dateMs) => dateMs / 1e3 % SEC_PER_WEEK;
194
+ function decodeGpsQzsNav(view, b, sys) {
195
+ const svid = view.getUint8(b + 14);
196
+ const prn = sys === "G" ? svid : svid - 180;
197
+ const max = sys === "G" ? 32 : 10;
198
+ if (prn < 1 || prn > max) return null;
199
+ const wnc = view.getUint16(b + 12, true);
200
+ const tgdRaw = view.getFloat32(b + 28, true);
201
+ const tocs = view.getUint32(b + 32, true);
202
+ const toes = view.getUint32(b + 88, true);
203
+ const wnToc = adjustWeek(wnc, view.getUint16(b + 136, true), 1024);
204
+ const tocDate = new Date(gpsMs(wnToc, tocs));
205
+ return {
206
+ system: sys,
207
+ prn: `${sys}${String(prn).padStart(2, "0")}`,
208
+ toc: sowOf(tocDate.getTime()),
209
+ tocDate,
210
+ af0: view.getFloat32(b + 44, true),
211
+ af1: view.getFloat32(b + 40, true),
212
+ af2: view.getFloat32(b + 36, true),
213
+ iode: view.getUint8(b + 24),
214
+ crs: view.getFloat32(b + 48, true),
215
+ deltaN: view.getFloat32(b + 52, true) * PI,
216
+ m0: view.getFloat64(b + 56, true) * PI,
217
+ cuc: view.getFloat32(b + 64, true),
218
+ e: view.getFloat64(b + 68, true),
219
+ cus: view.getFloat32(b + 76, true),
220
+ sqrtA: view.getFloat64(b + 80, true),
221
+ toe: toes,
222
+ cic: view.getFloat32(b + 92, true),
223
+ omega0: view.getFloat64(b + 96, true) * PI,
224
+ cis: view.getFloat32(b + 104, true),
225
+ i0: view.getFloat64(b + 108, true) * PI,
226
+ crc: view.getFloat32(b + 116, true),
227
+ omega: view.getFloat64(b + 120, true) * PI,
228
+ omegaDot: view.getFloat32(b + 128, true) * PI,
229
+ idot: view.getFloat32(b + 132, true) * PI,
230
+ // RINEX "GPS week to go with toe": RTKLIB writes WNc for GPS and
231
+ // the week of toc for QZSS — mirrored here so records compare
232
+ // 1:1 against convbin output. wnToe is still used for `toe` above.
233
+ week: sys === "G" ? wnc : wnToc,
234
+ svHealth: view.getUint8(b + 20),
235
+ tgd: tgdRaw !== F4_DNU ? tgdRaw : 0
236
+ };
237
+ }
238
+ function decodeGalNav(view, b) {
239
+ const prn = view.getUint8(b + 14) - 70;
240
+ if (prn < 1 || prn > 36) return null;
241
+ const source = view.getUint8(b + 15);
242
+ if (source !== 2 && source !== 16) return null;
243
+ const wnc = view.getUint16(b + 12, true);
244
+ const toes = view.getUint32(b + 100, true);
245
+ const tocs = view.getUint32(b + 104, true);
246
+ const wnToc = adjustWeek(wnc, view.getUint16(b + 126, true), 4096);
247
+ const tocDate = new Date(gpsMs(wnToc, tocs));
248
+ const health = view.getUint16(b + 130, true);
249
+ let svh = 0;
250
+ if (health & 1) svh |= health >> 1 & 7;
251
+ if (health & 16) svh |= (health >> 5 & 7) << 6;
252
+ if (health & 256) svh |= (health >> 9 & 7) << 3;
253
+ const bgdE5a = view.getFloat32(b + 136, true);
254
+ return {
255
+ system: "E",
256
+ prn: `E${String(prn).padStart(2, "0")}`,
257
+ toc: sowOf(tocDate.getTime()),
258
+ tocDate,
259
+ af0: view.getFloat64(b + 116, true),
260
+ af1: view.getFloat32(b + 112, true),
261
+ af2: view.getFloat32(b + 108, true),
262
+ iode: view.getUint16(b + 128, true),
263
+ // IODnav
264
+ crs: view.getFloat32(b + 88, true),
265
+ deltaN: view.getFloat32(b + 72, true) * PI,
266
+ m0: view.getFloat64(b + 24, true) * PI,
267
+ cuc: view.getFloat32(b + 76, true),
268
+ e: view.getFloat64(b + 32, true),
269
+ cus: view.getFloat32(b + 80, true),
270
+ sqrtA: view.getFloat64(b + 16, true),
271
+ toe: toes,
272
+ cic: view.getFloat32(b + 92, true),
273
+ omega0: view.getFloat64(b + 56, true) * PI,
274
+ cis: view.getFloat32(b + 96, true),
275
+ i0: view.getFloat64(b + 40, true) * PI,
276
+ crc: view.getFloat32(b + 84, true),
277
+ omega: view.getFloat64(b + 48, true) * PI,
278
+ omegaDot: view.getFloat32(b + 64, true) * PI,
279
+ idot: view.getFloat32(b + 68, true) * PI,
280
+ week: wnc,
281
+ // RINEX GAL week is GPS-aligned and continuous
282
+ svHealth: svh,
283
+ tgd: bgdE5a !== F4_DNU ? bgdE5a : 0
284
+ // BGD E5a/E1 (RINEX slot)
285
+ };
286
+ }
287
+ function decodeBdsNav(view, b) {
288
+ const prn = svidToPrn(view.getUint8(b + 14));
289
+ if (!prn || prn[0] !== "C") return null;
290
+ const bdsWeekRef = view.getUint16(b + 12, true) - 1356;
291
+ const tgd1 = view.getFloat32(b + 24, true);
292
+ const tocs = view.getUint32(b + 32, true);
293
+ const toes = view.getUint32(b + 88, true);
294
+ const wnToc = adjustWeek(bdsWeekRef, view.getUint16(b + 136, true), 8192);
295
+ const wnToe = adjustWeek(bdsWeekRef, view.getUint16(b + 138, true), 8192);
296
+ const tocDate = new Date(BDT_EPOCH_MS + wnToc * MS_PER_WEEK + tocs * 1e3);
297
+ return {
298
+ system: "C",
299
+ prn,
300
+ toc: sowOf(tocDate.getTime()),
301
+ tocDate,
302
+ af0: view.getFloat32(b + 44, true),
303
+ af1: view.getFloat32(b + 40, true),
304
+ af2: view.getFloat32(b + 36, true),
305
+ iode: view.getUint8(b + 21),
306
+ // AODE
307
+ crs: view.getFloat32(b + 48, true),
308
+ deltaN: view.getFloat32(b + 52, true) * PI,
309
+ m0: view.getFloat64(b + 56, true) * PI,
310
+ cuc: view.getFloat32(b + 64, true),
311
+ e: view.getFloat64(b + 68, true),
312
+ cus: view.getFloat32(b + 76, true),
313
+ sqrtA: view.getFloat64(b + 80, true),
314
+ toe: toes,
315
+ cic: view.getFloat32(b + 92, true),
316
+ omega0: view.getFloat64(b + 96, true) * PI,
317
+ cis: view.getFloat32(b + 104, true),
318
+ i0: view.getFloat64(b + 108, true) * PI,
319
+ crc: view.getFloat32(b + 116, true),
320
+ omega: view.getFloat64(b + 120, true) * PI,
321
+ omegaDot: view.getFloat32(b + 128, true) * PI,
322
+ idot: view.getFloat32(b + 132, true) * PI,
323
+ week: wnToe,
324
+ // RINEX BDS week field is the BDT week
325
+ svHealth: view.getUint8(b + 19),
326
+ // SatH1
327
+ tgd: tgd1 !== F4_DNU ? tgd1 : 0
328
+ // TGD1 B1/B3 (RINEX slot)
329
+ };
330
+ }
331
+ function decodeGloNav(view, b) {
332
+ const prn = svidToPrn(view.getUint8(b + 14));
333
+ if (!prn || prn[0] !== "R") return null;
334
+ const wnc = view.getUint16(b + 12, true);
335
+ const toes = view.getUint32(b + 76, true);
336
+ const wnToe = adjustWeek(wnc, view.getUint16(b + 80, true), 1024);
337
+ const toeGpsMs = gpsMs(wnToe, toes);
338
+ const leapMs = getGpsLeap(new Date(toeGpsMs)) * 1e3;
339
+ const tocDate = new Date(toeGpsMs - leapMs);
340
+ const tofGpsMs = gpsMs(wnc, 0) + view.getUint32(b + 8, true);
341
+ const tofLeapMs = getGpsLeap(new Date(tofGpsMs)) * 1e3;
342
+ const messageFrameTime = (tofGpsMs - tofLeapMs - GPS_EPOCH_MS) / 1e3 % SEC_PER_WEEK;
343
+ return {
344
+ system: "R",
345
+ prn,
346
+ tocDate,
347
+ // RINEX stores −τn as the clock bias; SBF carries τn (ICD sign)
348
+ tauN: -view.getFloat32(b + 68, true),
349
+ gammaN: view.getFloat32(b + 64, true),
350
+ messageFrameTime,
351
+ x: view.getFloat64(b + 16, true),
352
+ // SBF unit is km, like RINEX
353
+ xDot: view.getFloat32(b + 40, true),
354
+ xAcc: view.getFloat32(b + 52, true),
355
+ y: view.getFloat64(b + 24, true),
356
+ yDot: view.getFloat32(b + 44, true),
357
+ yAcc: view.getFloat32(b + 56, true),
358
+ z: view.getFloat64(b + 32, true),
359
+ zDot: view.getFloat32(b + 48, true),
360
+ zAcc: view.getFloat32(b + 60, true),
361
+ // MSB of the 3-bit Bn word — the unhealthy flag RINEX carries
362
+ health: view.getUint8(b + 85) >> 2,
363
+ freqNum: view.getUint8(b + 15) - 8
364
+ };
365
+ }
366
+ function parseSbfNav(data) {
367
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
368
+ const ephemerides = [];
369
+ const badCrc = scanSbfFrames(data, view, (id, b, len) => {
370
+ let eph = null;
371
+ if (id === 5891 && len >= 140) eph = decodeGpsQzsNav(view, b, "G");
372
+ else if (id === 4095 && len >= 140) eph = decodeGpsQzsNav(view, b, "J");
373
+ else if (id === 4002 && len >= 149) eph = decodeGalNav(view, b);
374
+ else if (id === 4081 && len >= 140) eph = decodeBdsNav(view, b);
375
+ else if (id === 4004 && len >= 96) eph = decodeGloNav(view, b);
376
+ if (eph) ephemerides.push(eph);
377
+ });
378
+ return { ephemerides, badCrc };
379
+ }
380
+ var GAL_SQRT_A_NOMINAL = Math.sqrt(296e5);
381
+ var GAL_I_NOMINAL = 56 / 180 * PI;
382
+ var I_REF_03 = 0.3 * PI;
383
+ function decodeGpsGalAlm(view, b, sys) {
384
+ const wnc = view.getUint16(b + 12, true);
385
+ const toa = view.getUint32(b + 20, true);
386
+ if (toa === U4_DNU) return null;
387
+ let prn;
388
+ let weekAlm;
389
+ let i0;
390
+ let sqrtA = view.getFloat32(b + 32, true);
391
+ let health;
392
+ if (sys === "G") {
393
+ prn = view.getUint8(b + 14);
394
+ if (prn < 1 || prn > 32) return null;
395
+ weekAlm = adjustWeek(wnc, view.getUint8(b + 56), 256);
396
+ i0 = I_REF_03 + view.getFloat32(b + 24, true) * PI;
397
+ health = view.getUint8(b + 58);
398
+ } else {
399
+ prn = view.getUint8(b + 57) - 70;
400
+ if (prn < 1 || prn > 36) return null;
401
+ weekAlm = adjustWeek(wnc, view.getUint8(b + 56), 4);
402
+ i0 = GAL_I_NOMINAL + view.getFloat32(b + 24, true) * PI;
403
+ sqrtA += GAL_SQRT_A_NOMINAL;
404
+ health = view.getUint16(b + 58, true);
405
+ }
406
+ return {
407
+ system: sys,
408
+ prn: `${sys}${String(prn).padStart(2, "0")}`,
409
+ weekAlm,
410
+ toaSec: toa,
411
+ sqrtA,
412
+ e: view.getFloat32(b + 16, true),
413
+ i0OrDeltaI: i0,
414
+ omega0: view.getFloat32(b + 36, true) * PI,
415
+ omega: view.getFloat32(b + 40, true) * PI,
416
+ m0: view.getFloat32(b + 44, true) * PI,
417
+ omegaDot: view.getFloat32(b + 28, true) * PI,
418
+ af0: view.getFloat32(b + 52, true),
419
+ af1: view.getFloat32(b + 48, true),
420
+ health
421
+ };
422
+ }
423
+ function decodeBdsAlm(view, b) {
424
+ const prnStr = svidToPrn(view.getUint8(b + 14));
425
+ if (!prnStr || prnStr[0] !== "C") return null;
426
+ const prn = parseInt(prnStr.slice(1), 10);
427
+ const toa = view.getUint32(b + 16, true);
428
+ if (toa === U4_DNU) return null;
429
+ const bdsWeekRef = view.getUint16(b + 12, true) - 1356;
430
+ const geo = prn <= 5 || prn >= 59;
431
+ return {
432
+ system: "C",
433
+ prn: prnStr,
434
+ weekAlm: adjustWeek(bdsWeekRef, view.getUint8(b + 15), 256),
435
+ toaSec: toa,
436
+ sqrtA: view.getFloat32(b + 20, true),
437
+ e: view.getFloat32(b + 24, true),
438
+ i0OrDeltaI: (geo ? 0 : I_REF_03) + view.getFloat32(b + 44, true) * PI,
439
+ omega0: view.getFloat32(b + 36, true) * PI,
440
+ omega: view.getFloat32(b + 28, true) * PI,
441
+ m0: view.getFloat32(b + 32, true) * PI,
442
+ omegaDot: view.getFloat32(b + 40, true) * PI,
443
+ af0: view.getFloat32(b + 48, true),
444
+ af1: view.getFloat32(b + 52, true),
445
+ health: view.getUint16(b + 56, true)
446
+ };
447
+ }
448
+ function decodeGloAlm(view, b) {
449
+ const prn = svidToPrn(view.getUint8(b + 14));
450
+ if (!prn || prn[0] !== "R") return null;
451
+ const wnc = view.getUint16(b + 12, true);
452
+ const toa = view.getUint32(b + 20, true);
453
+ if (toa === U4_DNU) return null;
454
+ return {
455
+ system: "R",
456
+ prn,
457
+ freqNr: view.getUint8(b + 15) - 8,
458
+ weekAlm: adjustWeek(wnc, view.getUint8(b + 52), 256),
459
+ toaSec: toa,
460
+ epsilon: view.getFloat32(b + 16, true),
461
+ deltaI: view.getFloat32(b + 24, true) * PI,
462
+ lambda: view.getFloat32(b + 28, true) * PI,
463
+ tLambda: view.getFloat32(b + 32, true),
464
+ omega: view.getFloat32(b + 36, true) * PI,
465
+ deltaT: view.getFloat32(b + 40, true),
466
+ deltaTDot: view.getFloat32(b + 44, true),
467
+ tau: view.getFloat32(b + 48, true),
468
+ health: view.getUint8(b + 53),
469
+ nDay: view.getUint16(b + 54, true),
470
+ n4: view.getUint8(b + 57)
471
+ };
472
+ }
473
+ function parseSbfAlmanac(data) {
474
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
475
+ const almanacs = [];
476
+ const badCrc = scanSbfFrames(data, view, (id, b, len) => {
477
+ let alm = null;
478
+ if (id === 5892 && len >= 60) alm = decodeGpsGalAlm(view, b, "G");
479
+ else if (id === 4003 && len >= 61) alm = decodeGpsGalAlm(view, b, "E");
480
+ else if (id === 4119 && len >= 60) alm = decodeBdsAlm(view, b);
481
+ else if (id === 4005 && len >= 60) alm = decodeGloAlm(view, b);
482
+ if (alm) almanacs.push(alm);
483
+ });
484
+ return { almanacs, badCrc };
485
+ }
486
+
487
+ // src/sbf/index.ts
488
+ var CLIGHT = 299792458;
489
+ var GPS_EPOCH_MS2 = Date.UTC(1980, 0, 6);
490
+ var MS_PER_WEEK2 = 7 * 864e5;
45
491
  var M3_SYS = ["G", "R", "E", "C", "S", "J", "I"];
46
492
  var M3_PR_BASE = [19e6, 19e6, 22e6, 2e7, 34e6, 34e6, 34e6];
47
493
  var M3_INTERVALS = [
@@ -140,44 +586,27 @@ var MEAS2_SIG = [
140
586
  ["J", "1E"],
141
587
  ["J", "5P"]
142
588
  ];
143
- var two = (n) => String(n).padStart(2, "0");
589
+ var two2 = (n) => String(n).padStart(2, "0");
144
590
  function m3Prn(navsys, svid) {
145
591
  switch (navsys) {
146
592
  case 0:
147
- return svid < 32 ? `G${two(svid + 1)}` : null;
593
+ return svid < 32 ? `G${two2(svid + 1)}` : null;
148
594
  case 1:
149
- return svid < 27 ? `R${two(svid + 1)}` : null;
595
+ return svid < 27 ? `R${two2(svid + 1)}` : null;
150
596
  case 2:
151
- return svid < 36 ? `E${two(svid + 1)}` : null;
597
+ return svid < 36 ? `E${two2(svid + 1)}` : null;
152
598
  case 3:
153
- return svid < 50 ? `C${two(svid + 1)}` : null;
599
+ return svid < 50 ? `C${two2(svid + 1)}` : null;
154
600
  case 4:
155
- return svid <= 38 ? `S${two(svid + 20)}` : null;
601
+ return svid <= 38 ? `S${two2(svid + 20)}` : null;
156
602
  case 5:
157
- return svid < 10 ? `J${two(svid + 1)}` : null;
603
+ return svid < 10 ? `J${two2(svid + 1)}` : null;
158
604
  case 6:
159
- return svid < 14 ? `I${two(svid + 1)}` : null;
605
+ return svid < 14 ? `I${two2(svid + 1)}` : null;
160
606
  default:
161
607
  return null;
162
608
  }
163
609
  }
164
- function svidToPrn(svid) {
165
- if (svid >= 1 && svid <= 37) return svid <= 32 ? `G${two(svid)}` : null;
166
- if (svid <= 61) return svid - 37 <= 27 ? `R${two(svid - 37)}` : null;
167
- if (svid <= 62) return null;
168
- if (svid <= 68) return svid - 38 <= 27 ? `R${two(svid - 38)}` : null;
169
- if (svid <= 70) return null;
170
- if (svid <= 106) return svid - 70 <= 36 ? `E${two(svid - 70)}` : null;
171
- if (svid <= 119) return null;
172
- if (svid <= 140) return `S${two(svid - 100)}`;
173
- if (svid <= 180) return svid - 140 <= 50 ? `C${two(svid - 140)}` : null;
174
- if (svid <= 190) return `J${two(svid - 180)}`;
175
- if (svid <= 197) return svid - 190 <= 14 ? `I${two(svid - 190)}` : null;
176
- if (svid <= 215) return `S${two(svid - 157)}`;
177
- if (svid <= 222) return svid - 208 <= 14 ? `I${two(svid - 208)}` : null;
178
- if (svid <= 245) return svid - 182 <= 50 ? `C${two(svid - 182)}` : null;
179
- return null;
180
- }
181
610
  function carrierFreq(sys, code, fcn) {
182
611
  const band = code.charCodeAt(0) - 48;
183
612
  switch (sys) {
@@ -240,7 +669,6 @@ function parseSbfMeas(data) {
240
669
  const epochs = [];
241
670
  const messageCounts = {};
242
671
  const obsCodes = {};
243
- let badCrc = 0;
244
672
  let ref = freshRefEpoch(-1);
245
673
  let curTime = NaN;
246
674
  let curMeas = [];
@@ -271,8 +699,8 @@ function parseSbfMeas(data) {
271
699
  curTime = timeMs;
272
700
  }
273
701
  };
274
- const decodeMeas3Ranges = (i2, tow) => {
275
- const o = i2 + 8;
702
+ const decodeMeas3Ranges = (i, tow) => {
703
+ const o = i + 8;
276
704
  const constellations = view.getUint16(o + 8, true) & 127;
277
705
  const misc = data[o + 10];
278
706
  const version = data[o + 11];
@@ -550,8 +978,8 @@ function parseSbfMeas(data) {
550
978
  }
551
979
  }
552
980
  };
553
- const decodeMeas3CN0 = (i2, len) => {
554
- const flags = view.getUint16(i2 + 14, true);
981
+ const decodeMeas3CN0 = (i, len) => {
982
+ const flags = view.getUint16(i + 14, true);
555
983
  if ((flags & 7) !== 0) return;
556
984
  const maxNibbles = (len - 16) * 2;
557
985
  let off = 0;
@@ -561,7 +989,7 @@ function parseSbfMeas(data) {
561
989
  for (let k = 0; k < e.slots.length; k++) {
562
990
  const slot = e.slots[k];
563
991
  if (k > 0 && !slot) break;
564
- const nib = (data[i2 + 16 + (off >> 1)] ?? 0) >> (off & 1) * 4 & 15;
992
+ const nib = (data[i + 16 + (off >> 1)] ?? 0) >> (off & 1) * 4 & 15;
565
993
  if (slot && slot.cn0 !== null) slot.cn0 += nib * 0.0625 - 0.5;
566
994
  off++;
567
995
  }
@@ -588,14 +1016,14 @@ function parseSbfMeas(data) {
588
1016
  if ((v & 1) === 1) value = -value;
589
1017
  return { value, size };
590
1018
  };
591
- const decodeMeas3Doppler = (i2, len) => {
592
- const flags = view.getUint16(i2 + 14, true);
1019
+ const decodeMeas3Doppler = (i, len) => {
1020
+ const flags = view.getUint16(i + 14, true);
593
1021
  if ((flags & 7) !== 0) return;
594
1022
  let off = 0;
595
1023
  for (const e of curSats) {
596
1024
  if (off + 16 >= len) break;
597
1025
  if (!e.prn) continue;
598
- const master = readPrRate(i2 + 16, off);
1026
+ const master = readPrRate(i + 16, off);
599
1027
  off += master.size;
600
1028
  if (master.value === -268435455) continue;
601
1029
  const refPrRate = ref.sats[e.navsys][e.svid]?.prRate ?? 0;
@@ -605,20 +1033,20 @@ function parseSbfMeas(data) {
605
1033
  for (let k = 1; k < e.slots.length; k++) {
606
1034
  const slot = e.slots[k];
607
1035
  if (!slot) break;
608
- const slave = readPrRate(i2 + 16, off);
1036
+ const slave = readPrRate(i + 16, off);
609
1037
  off += slave.size;
610
1038
  if (m)
611
1039
  slot.doppler = (mD * (CLIGHT / m.freq) * 1e3 - slave.value) * 1e-3 / (CLIGHT / slot.freq);
612
1040
  }
613
1041
  }
614
1042
  };
615
- const decodeMeasEpoch = (i2, len) => {
616
- const n1 = data[i2 + 14];
617
- const len1 = data[i2 + 15];
618
- const len2 = data[i2 + 16];
619
- if ((data[i2 + 17] & 128) !== 0) return;
620
- const end = i2 + len;
621
- let p = i2 + 20;
1043
+ const decodeMeasEpoch = (i, len) => {
1044
+ const n1 = data[i + 14];
1045
+ const len1 = data[i + 15];
1046
+ const len2 = data[i + 16];
1047
+ if ((data[i + 17] & 128) !== 0) return;
1048
+ const end = i + len;
1049
+ let p = i + 20;
622
1050
  for (let b1 = 0; b1 < n1 && p + 20 <= end; b1++) {
623
1051
  const ant = data[p + 1] >> 5;
624
1052
  let sig = data[p + 1] & 31;
@@ -705,43 +1133,29 @@ function parseSbfMeas(data) {
705
1133
  }
706
1134
  }
707
1135
  };
708
- let i = 0;
709
- while (i + 8 <= data.length) {
710
- if (data[i] !== 36 || data[i + 1] !== 64) {
711
- i++;
712
- continue;
713
- }
714
- const len = view.getUint16(i + 6, true);
715
- if (len < 8 || len % 4 !== 0) {
716
- i++;
717
- continue;
718
- }
719
- if (i + len > data.length) break;
720
- if (crc16(data, i + 4, i + len) !== view.getUint16(i + 2, true)) {
721
- badCrc++;
722
- i++;
723
- continue;
724
- }
725
- const id = view.getUint16(i + 4, true) & 8191;
1136
+ const badCrc = scanSbfFrames(data, view, (id, i, len) => {
726
1137
  const key = String(id);
727
1138
  messageCounts[key] = (messageCounts[key] ?? 0) + 1;
728
1139
  if ((id === 4027 || id === 4109 || id === 4110 || id === 4111) && len >= 16) {
729
1140
  const tow = view.getUint32(i + 8, true);
730
1141
  const wnc = view.getUint16(i + 12, true);
731
1142
  if (tow !== 4294967295 && wnc !== 65535) {
732
- ensureEpoch(GPS_EPOCH_MS + wnc * MS_PER_WEEK + tow);
1143
+ ensureEpoch(GPS_EPOCH_MS2 + wnc * MS_PER_WEEK2 + tow);
733
1144
  if (id === 4109) decodeMeas3Ranges(i, tow);
734
1145
  else if (id === 4110) decodeMeas3CN0(i, len);
735
1146
  else if (id === 4111) decodeMeas3Doppler(i, len);
736
1147
  else decodeMeasEpoch(i, len);
737
1148
  }
738
1149
  }
739
- i += len;
740
- }
1150
+ });
741
1151
  flush();
742
1152
  return { epochs, messageCounts, obsCodes, badCrc };
743
1153
  }
744
1154
  // Annotate the CommonJS export names for ESM import in node:
745
1155
  0 && (module.exports = {
746
- parseSbfMeas
1156
+ parseSbfAlmanac,
1157
+ parseSbfMeas,
1158
+ parseSbfNav,
1159
+ sbfCrc16,
1160
+ scanSbfFrames
747
1161
  });