gnss-js 1.14.0 → 1.15.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/index.d.cts CHANGED
@@ -10,8 +10,8 @@ export { E as Ephemeris, G as GlonassEphemeris, K as KeplerEphemeris, N as NavHe
10
10
  export { B as BitReader, E as EphemerisInfo, R as Rtcm3DebugHandler, a as Rtcm3Decoder, b as Rtcm3Frame, d as decodeEphemeris, r as readString, c as reportDecodeError, s as setRtcm3DebugHandler } from './ephemeris-Ohl6NAfw.cjs';
11
11
  export { MessageTypeStats, MsmEpoch, MsmSatObs, MsmSignal, RTCM3_MESSAGE_NAMES, SatCn0, SignalCn0, StationMeta, StreamStats, createStationMeta, createStreamStats, decodeMsmFull, msmEpochToDate, resetGloFreqCache, rtcm3Constellation, setGloFreqNumber, updateStationMeta, updateStreamStats } from './rtcm3.cjs';
12
12
  export { UbxMeasurement, UbxParseResult, UbxRawxEpoch, parseUbxRawx } from './ubx.cjs';
13
- export { SbfMeasEpoch, SbfMeasurement, SbfParseResult, parseSbfMeas } from './sbf.cjs';
14
- export { NovatelEpoch, NovatelMeasurement, NovatelParseResult, parseNovatelRange } from './novatel.cjs';
13
+ export { SbfAlmanac, SbfAlmanacResult, SbfGlonassAlmanac, SbfKeplerAlmanac, SbfMeasEpoch, SbfMeasurement, SbfNavResult, SbfParseResult, parseSbfAlmanac, parseSbfMeas, parseSbfNav } from './sbf.cjs';
14
+ export { NovatelEpoch, NovatelMeasurement, NovatelNavResult, NovatelParseResult, OEM4_HLEN, Oem4Frame, crc32, oem4Frames, parseNovatelNav, parseNovatelRange } from './novatel.cjs';
15
15
  export { AllPositionsData, DopValues, EpochSkyData, SatAzEl, SatPoint, SatPosition, VisibilityPass, VisibilityResult, computeAllPositions, computeDop, computeLiveSkyPositions, computeSatPosition, computeVisibility, computeVisibilityFromPositions, dopplerHz, ecefToAzEl, ephInfoToEphemeris, glonassPosition, keplerPosition, maskRadForAzimuth, navTimesFromEph, rangeRate, selectEphemeris } from './orbit.cjs';
16
16
  export { Helmert14, REFERENCE_FRAMES, ReferenceFrame, applyHelmert, dateToEpoch, transformFrame } from './frames.cjs';
17
17
  export { KlobucharCoeffs, SppOptions, SppSolution, ionoFree, klobucharDelay, satClockCorrection, solveSpp } from './positioning.cjs';
package/dist/index.d.ts CHANGED
@@ -10,8 +10,8 @@ export { E as Ephemeris, G as GlonassEphemeris, K as KeplerEphemeris, N as NavHe
10
10
  export { B as BitReader, E as EphemerisInfo, R as Rtcm3DebugHandler, a as Rtcm3Decoder, b as Rtcm3Frame, d as decodeEphemeris, r as readString, c as reportDecodeError, s as setRtcm3DebugHandler } from './ephemeris-Ohl6NAfw.js';
11
11
  export { MessageTypeStats, MsmEpoch, MsmSatObs, MsmSignal, RTCM3_MESSAGE_NAMES, SatCn0, SignalCn0, StationMeta, StreamStats, createStationMeta, createStreamStats, decodeMsmFull, msmEpochToDate, resetGloFreqCache, rtcm3Constellation, setGloFreqNumber, updateStationMeta, updateStreamStats } from './rtcm3.js';
12
12
  export { UbxMeasurement, UbxParseResult, UbxRawxEpoch, parseUbxRawx } from './ubx.js';
13
- export { SbfMeasEpoch, SbfMeasurement, SbfParseResult, parseSbfMeas } from './sbf.js';
14
- export { NovatelEpoch, NovatelMeasurement, NovatelParseResult, parseNovatelRange } from './novatel.js';
13
+ export { SbfAlmanac, SbfAlmanacResult, SbfGlonassAlmanac, SbfKeplerAlmanac, SbfMeasEpoch, SbfMeasurement, SbfNavResult, SbfParseResult, parseSbfAlmanac, parseSbfMeas, parseSbfNav } from './sbf.js';
14
+ export { NovatelEpoch, NovatelMeasurement, NovatelNavResult, NovatelParseResult, OEM4_HLEN, Oem4Frame, crc32, oem4Frames, parseNovatelNav, parseNovatelRange } from './novatel.js';
15
15
  export { AllPositionsData, DopValues, EpochSkyData, SatAzEl, SatPoint, SatPosition, VisibilityPass, VisibilityResult, computeAllPositions, computeDop, computeLiveSkyPositions, computeSatPosition, computeVisibility, computeVisibilityFromPositions, dopplerHz, ecefToAzEl, ephInfoToEphemeris, glonassPosition, keplerPosition, maskRadForAzimuth, navTimesFromEph, rangeRate, selectEphemeris } from './orbit.js';
16
16
  export { Helmert14, REFERENCE_FRAMES, ReferenceFrame, applyHelmert, dateToEpoch, transformFrame } from './frames.js';
17
17
  export { KlobucharCoeffs, SppOptions, SppSolution, ionoFree, klobucharDelay, satClockCorrection, solveSpp } from './positioning.js';
package/dist/index.js CHANGED
@@ -37,11 +37,17 @@ import {
37
37
  parseUbxRawx
38
38
  } from "./chunk-5IXK25MX.js";
39
39
  import {
40
- parseSbfMeas
41
- } from "./chunk-YIHO74OS.js";
40
+ parseSbfAlmanac,
41
+ parseSbfMeas,
42
+ parseSbfNav
43
+ } from "./chunk-BEQSEJMU.js";
42
44
  import {
45
+ OEM4_HLEN,
46
+ crc32,
47
+ oem4Frames,
48
+ parseNovatelNav,
43
49
  parseNovatelRange
44
- } from "./chunk-SWKWJEGY.js";
50
+ } from "./chunk-I4UV45NT.js";
45
51
  import {
46
52
  connectToMountpoint,
47
53
  fetchSourcetable,
@@ -112,7 +118,7 @@ import {
112
118
  klobucharDelay,
113
119
  satClockCorrection,
114
120
  solveSpp
115
- } from "./chunk-E5CP37P2.js";
121
+ } from "./chunk-QXZZNXE3.js";
116
122
  import {
117
123
  computeAllPositions,
118
124
  computeDop,
@@ -129,42 +135,7 @@ import {
129
135
  navTimesFromEph,
130
136
  rangeRate,
131
137
  selectEphemeris
132
- } from "./chunk-VAHMHYID.js";
133
- import {
134
- getBdsTime,
135
- getDateFromBdsTime,
136
- getDateFromGalTime,
137
- getDateFromGloN,
138
- getDateFromGpsData,
139
- getDateFromGpsTime,
140
- getDateFromTai,
141
- getDateFromTt,
142
- getDateFromUnixTime,
143
- getDateFromUtc,
144
- getGalTime,
145
- getGloN4,
146
- getGloNA,
147
- getGpsLeap,
148
- getGpsTime,
149
- getHoursFromTimeDifference,
150
- getLeap,
151
- getMinutesFromTimeDifference,
152
- getNtpTime,
153
- getSecondsFromTimeDifference,
154
- getTaiDate,
155
- getTimeDifference,
156
- getTimeDifferenceFromDays,
157
- getTimeDifferenceFromHours,
158
- getTimeDifferenceFromMinutes,
159
- getTimeDifferenceFromObject,
160
- getTimeDifferenceFromSeconds,
161
- getTimeOfWeek,
162
- getTotalDaysFromTimeDifference,
163
- getTtDate,
164
- getUnixTime,
165
- getUtcDate,
166
- getWeekNumber
167
- } from "./chunk-HVXYFUCB.js";
138
+ } from "./chunk-OMVL3X7V.js";
168
139
  import {
169
140
  clampUnit,
170
141
  ecefToGeodetic,
@@ -224,7 +195,42 @@ import {
224
195
  setRtcm3DebugHandler,
225
196
  updateStationMeta,
226
197
  updateStreamStats
227
- } from "./chunk-FGRC3PB3.js";
198
+ } from "./chunk-BRT6XZ7B.js";
199
+ import {
200
+ getBdsTime,
201
+ getDateFromBdsTime,
202
+ getDateFromGalTime,
203
+ getDateFromGloN,
204
+ getDateFromGpsData,
205
+ getDateFromGpsTime,
206
+ getDateFromTai,
207
+ getDateFromTt,
208
+ getDateFromUnixTime,
209
+ getDateFromUtc,
210
+ getGalTime,
211
+ getGloN4,
212
+ getGloNA,
213
+ getGpsLeap,
214
+ getGpsTime,
215
+ getHoursFromTimeDifference,
216
+ getLeap,
217
+ getMinutesFromTimeDifference,
218
+ getNtpTime,
219
+ getSecondsFromTimeDifference,
220
+ getTaiDate,
221
+ getTimeDifference,
222
+ getTimeDifferenceFromDays,
223
+ getTimeDifferenceFromHours,
224
+ getTimeDifferenceFromMinutes,
225
+ getTimeDifferenceFromObject,
226
+ getTimeDifferenceFromSeconds,
227
+ getTimeOfWeek,
228
+ getTotalDaysFromTimeDifference,
229
+ getTtDate,
230
+ getUnixTime,
231
+ getUtcDate,
232
+ getWeekNumber
233
+ } from "./chunk-HVXYFUCB.js";
228
234
  import {
229
235
  DAYS_MJD2000_MJD,
230
236
  DAYS_MJD_JULIAN,
@@ -330,6 +336,7 @@ export {
330
336
  MILLISECONDS_IN_WEEK,
331
337
  MILLISECONDS_TT_TAI,
332
338
  MultipathAccumulator,
339
+ OEM4_HLEN,
333
340
  OMEGA_E,
334
341
  REFERENCE_FRAMES,
335
342
  RINEX_CODES,
@@ -373,6 +380,7 @@ export {
373
380
  computeVisibility,
374
381
  computeVisibilityFromPositions,
375
382
  connectToMountpoint,
383
+ crc32,
376
384
  createGzipLineSink,
377
385
  createStationMeta,
378
386
  createStreamStats,
@@ -462,6 +470,7 @@ export {
462
470
  msmEpochToDate,
463
471
  navTimesFromEph,
464
472
  nmeaCoordToDecimal,
473
+ oem4Frames,
465
474
  padL,
466
475
  padR,
467
476
  parseAntex,
@@ -469,9 +478,12 @@ export {
469
478
  parseIonex,
470
479
  parseNavFile,
471
480
  parseNmeaFile,
481
+ parseNovatelNav,
472
482
  parseNovatelRange,
473
483
  parseRinexStream,
484
+ parseSbfAlmanac,
474
485
  parseSbfMeas,
486
+ parseSbfNav,
475
487
  parseSinexBiasDcb,
476
488
  parseSourcetable,
477
489
  parseSp3,
package/dist/novatel.cjs CHANGED
@@ -20,15 +20,364 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/novatel/index.ts
21
21
  var novatel_exports = {};
22
22
  __export(novatel_exports, {
23
+ OEM4_HLEN: () => OEM4_HLEN,
24
+ crc32: () => crc32,
25
+ oem4Frames: () => oem4Frames,
26
+ parseNovatelNav: () => parseNovatelNav,
23
27
  parseNovatelRange: () => parseNovatelRange
24
28
  });
25
29
  module.exports = __toCommonJS(novatel_exports);
30
+
31
+ // src/novatel/frame.ts
32
+ var OEM4_HLEN = 28;
33
+ function crc32(data, start, len) {
34
+ let crc = 0;
35
+ for (let i = start; i < start + len; i++) {
36
+ crc ^= data[i];
37
+ for (let j = 0; j < 8; j++) {
38
+ crc = crc & 1 ? crc >>> 1 ^ 3988292384 : crc >>> 1;
39
+ }
40
+ }
41
+ return crc >>> 0;
42
+ }
43
+ function* oem4Frames(data, view, stats) {
44
+ let i = 0;
45
+ while (i + OEM4_HLEN + 4 <= data.length) {
46
+ if (data[i] !== 170 || data[i + 1] !== 68 || data[i + 2] !== 18) {
47
+ i++;
48
+ continue;
49
+ }
50
+ const hlen = data[i + 3];
51
+ const msgLen = view.getUint16(i + 8, true);
52
+ const total = hlen + msgLen + 4;
53
+ if (hlen < OEM4_HLEN || i + total > data.length) {
54
+ i++;
55
+ continue;
56
+ }
57
+ if (crc32(data, i, hlen + msgLen) !== view.getUint32(i + hlen + msgLen, true)) {
58
+ stats.badCrc++;
59
+ i++;
60
+ continue;
61
+ }
62
+ yield {
63
+ id: view.getUint16(i + 4, true),
64
+ start: i,
65
+ payload: i + hlen,
66
+ msgLen,
67
+ binary: (data[i + 6] >> 4 & 3) === 0,
68
+ week: view.getUint16(i + 14, true),
69
+ towMs: view.getUint32(i + 16, true)
70
+ };
71
+ i += total;
72
+ }
73
+ }
74
+
75
+ // src/navbits/index.ts
76
+ var GPS_PI = 3.1415926535898;
26
77
  var GPS_EPOCH_MS = Date.UTC(1980, 0, 6);
78
+ var SEC_PER_WEEK = 7 * 86400;
79
+ function getBitU(buff, pos, len) {
80
+ let bits = 0;
81
+ for (let i = pos; i < pos + len; i++) {
82
+ bits = bits * 2 + (buff[i >> 3] >> 7 - (i & 7) & 1);
83
+ }
84
+ return bits;
85
+ }
86
+ function getBitS(buff, pos, len) {
87
+ const bits = getBitU(buff, pos, len);
88
+ if (len <= 0 || bits < 2 ** (len - 1)) return bits;
89
+ return bits - 2 ** len;
90
+ }
91
+ function decodeGpsLnavFrame(subframes, opts = {}) {
92
+ if (subframes.length < 90) return null;
93
+ const b = subframes;
94
+ let i = 24;
95
+ const tow1 = getBitU(b, i, 17) * 6;
96
+ i += 17 + 2;
97
+ const id1 = getBitU(b, i, 3);
98
+ i += 3 + 2;
99
+ const week10 = getBitU(b, i, 10);
100
+ i += 10;
101
+ i += 2;
102
+ i += 4;
103
+ const svHealth = getBitU(b, i, 6);
104
+ i += 6;
105
+ const iodc0 = getBitU(b, i, 2);
106
+ i += 2;
107
+ i += 1 + 87;
108
+ const tgdRaw = getBitS(b, i, 8);
109
+ i += 8;
110
+ const iodc1 = getBitU(b, i, 8);
111
+ i += 8;
112
+ const tocSec = getBitU(b, i, 16) * 16;
113
+ i += 16;
114
+ const af2 = getBitS(b, i, 8) * 2 ** -55;
115
+ i += 8;
116
+ const af1 = getBitS(b, i, 16) * 2 ** -43;
117
+ i += 16;
118
+ const af0 = getBitS(b, i, 22) * 2 ** -31;
119
+ i = 240 + 24;
120
+ i += 17 + 2;
121
+ const id2 = getBitU(b, i, 3);
122
+ i += 3 + 2;
123
+ const iode = getBitU(b, i, 8);
124
+ i += 8;
125
+ const crs = getBitS(b, i, 16) * 2 ** -5;
126
+ i += 16;
127
+ const deltaN = getBitS(b, i, 16) * 2 ** -43 * GPS_PI;
128
+ i += 16;
129
+ const m0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
130
+ i += 32;
131
+ const cuc = getBitS(b, i, 16) * 2 ** -29;
132
+ i += 16;
133
+ const e = getBitU(b, i, 32) * 2 ** -33;
134
+ i += 32;
135
+ const cus = getBitS(b, i, 16) * 2 ** -29;
136
+ i += 16;
137
+ const sqrtA = getBitU(b, i, 32) * 2 ** -19;
138
+ i += 32;
139
+ const toes = getBitU(b, i, 16) * 16;
140
+ i = 480 + 24;
141
+ i += 17 + 2;
142
+ const id3 = getBitU(b, i, 3);
143
+ i += 3 + 2;
144
+ const cic = getBitS(b, i, 16) * 2 ** -29;
145
+ i += 16;
146
+ const omega0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
147
+ i += 32;
148
+ const cis = getBitS(b, i, 16) * 2 ** -29;
149
+ i += 16;
150
+ const i0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
151
+ i += 32;
152
+ const crc = getBitS(b, i, 16) * 2 ** -5;
153
+ i += 16;
154
+ const omega = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
155
+ i += 32;
156
+ const omegaDot = getBitS(b, i, 24) * 2 ** -43 * GPS_PI;
157
+ i += 24;
158
+ const iode3 = getBitU(b, i, 8);
159
+ i += 8;
160
+ const idot = getBitS(b, i, 14) * 2 ** -43 * GPS_PI;
161
+ const iodc = iodc0 * 256 + iodc1;
162
+ if (id1 !== 1 || id2 !== 2 || id3 !== 3) return null;
163
+ if (iode3 !== iode || iode !== (iodc & 255)) return null;
164
+ const ref = opts.refWeek ?? Math.floor((Date.now() - GPS_EPOCH_MS) / 1e3 / SEC_PER_WEEK);
165
+ let week = week10 + 1024 * Math.round((ref - week10) / 1024);
166
+ if (toes < tow1 - 302400) week++;
167
+ else if (toes > tow1 + 302400) week--;
168
+ const prn = opts.prn ?? "G00";
169
+ const tocDate = new Date(
170
+ GPS_EPOCH_MS + (week * SEC_PER_WEEK + tocSec) * 1e3
171
+ );
172
+ return {
173
+ system: prn[0] === "J" ? "J" : "G",
174
+ prn,
175
+ tocDate,
176
+ // Same seconds-of-week convention as parseNavFile (rinex/nav.ts).
177
+ toc: tocDate.getTime() / 1e3 % SEC_PER_WEEK,
178
+ af0,
179
+ af1,
180
+ af2,
181
+ iode,
182
+ crs,
183
+ deltaN,
184
+ m0,
185
+ cuc,
186
+ e,
187
+ cus,
188
+ sqrtA,
189
+ toe: toes,
190
+ cic,
191
+ omega0,
192
+ cis,
193
+ i0,
194
+ crc,
195
+ omega,
196
+ omegaDot,
197
+ idot,
198
+ week,
199
+ svHealth,
200
+ tgd: tgdRaw === -128 ? 0 : tgdRaw * 2 ** -31
201
+ // IS-GPS-200: -128 reserved
202
+ };
203
+ }
204
+
205
+ // src/constants/time.ts
206
+ var MILLISECONDS_IN_SECOND = 1e3;
207
+ var MILLISECONDS_GPS_TAI = 19e3;
208
+ var START_NTP_TIME = /* @__PURE__ */ new Date("1900-01-01T00:00:00Z");
209
+
210
+ // src/time/gnss.ts
211
+ function getTaiDate(date) {
212
+ return new Date(date.getTime() + MILLISECONDS_GPS_TAI);
213
+ }
214
+ function getNtpTime(date) {
215
+ return getTaiDate(date).getTime() - START_NTP_TIME.getTime();
216
+ }
217
+
218
+ // src/time/utc.ts
219
+ var LEAP_SECONDS_TABLE = [
220
+ [3692217600, 37],
221
+ // 1 Jan 2017
222
+ [3644697600, 36],
223
+ // 1 Jul 2015
224
+ [3550089600, 35],
225
+ // 1 Jul 2012
226
+ [3439756800, 34],
227
+ // 1 Jan 2009
228
+ [3345062400, 33],
229
+ // 1 Jan 2006
230
+ [3124137600, 32],
231
+ // 1 Jan 1999
232
+ [3076704e3, 31],
233
+ // 1 Jul 1997
234
+ [3029443200, 30],
235
+ // 1 Jan 1996
236
+ [2982009600, 29],
237
+ // 1 Jul 1994
238
+ [2950473600, 28],
239
+ // 1 Jul 1993
240
+ [2918937600, 27],
241
+ // 1 Jul 1992
242
+ [2871676800, 26],
243
+ // 1 Jan 1991
244
+ [2840140800, 25],
245
+ // 1 Jan 1990
246
+ [2776982400, 24],
247
+ // 1 Jan 1988
248
+ [2698012800, 23],
249
+ // 1 Jul 1985
250
+ [2634854400, 22],
251
+ // 1 Jul 1983
252
+ [2603318400, 21],
253
+ // 1 Jul 1982
254
+ [2571782400, 20],
255
+ // 1 Jul 1981
256
+ [2524521600, 19],
257
+ // 1 Jan 1980
258
+ [2492985600, 18],
259
+ // 1 Jan 1979
260
+ [2461449600, 17],
261
+ // 1 Jan 1978
262
+ [2429913600, 16],
263
+ // 1 Jan 1977
264
+ [2398291200, 15],
265
+ // 1 Jan 1976
266
+ [2366755200, 14],
267
+ // 1 Jan 1975
268
+ [2335219200, 13],
269
+ // 1 Jan 1974
270
+ [2303683200, 12],
271
+ // 1 Jan 1973
272
+ [2287785600, 11],
273
+ // 1 Jul 1972
274
+ [2272060800, 10]
275
+ // 1 Jan 1972
276
+ ];
277
+ function getLeap(date) {
278
+ const ntp_time = getNtpTime(date);
279
+ for (const [timestamp, leapSeconds] of LEAP_SECONDS_TABLE) {
280
+ if (ntp_time / MILLISECONDS_IN_SECOND - leapSeconds >= timestamp) {
281
+ return leapSeconds;
282
+ }
283
+ }
284
+ return 8;
285
+ }
286
+ function getUtcDate(date) {
287
+ const tai_date = getTaiDate(date);
288
+ const leap_seconds = getLeap(date);
289
+ return new Date(tai_date.getTime() - leap_seconds * MILLISECONDS_IN_SECOND);
290
+ }
291
+
292
+ // src/novatel/nav.ts
293
+ var ID_RAWEPHEM = 41;
294
+ var ID_GLOEPHEMERIS = 723;
295
+ var GPS_EPOCH_MS2 = Date.UTC(1980, 0, 6);
296
+ var SEC_PER_WEEK2 = 7 * 86400;
297
+ var SEC_PER_DAY = 86400;
298
+ function decodeRawEphem(data, view, p) {
299
+ const prn = view.getUint32(p, true);
300
+ if (prn < 1 || prn > 32) return null;
301
+ const refWeek = view.getUint32(p + 4, true);
302
+ return decodeGpsLnavFrame(data.subarray(p + 12, p + 102), {
303
+ prn: `G${String(prn).padStart(2, "0")}`,
304
+ refWeek
305
+ });
306
+ }
307
+ function decodeGloEphemeris(view, p) {
308
+ const slot = view.getUint16(p, true) - 37;
309
+ if (slot < 1 || slot > 27) return null;
310
+ const freqNum = view.getUint16(p + 2, true) - 7;
311
+ const week = view.getUint16(p + 6, true);
312
+ const tow = Math.floor(view.getUint32(p + 8, true) / 1e3 + 0.5);
313
+ const toff = view.getUint32(p + 12, true);
314
+ const health = view.getUint32(p + 24, true) < 4 ? 0 : 1;
315
+ let tof = view.getUint32(p + 124, true) - toff;
316
+ tof += Math.floor(tow / SEC_PER_DAY) * SEC_PER_DAY;
317
+ if (tof < tow - 43200) tof += SEC_PER_DAY;
318
+ else if (tof > tow + 43200) tof -= SEC_PER_DAY;
319
+ const toeGpsMs = GPS_EPOCH_MS2 + (week * SEC_PER_WEEK2 + tow) * 1e3;
320
+ const tofGpsMs = GPS_EPOCH_MS2 + (week * SEC_PER_WEEK2 + tof) * 1e3;
321
+ const tofUtcSec = (getUtcDate(new Date(tofGpsMs)).getTime() - GPS_EPOCH_MS2) / 1e3;
322
+ return {
323
+ system: "R",
324
+ prn: `R${String(slot).padStart(2, "0")}`,
325
+ tocDate: getUtcDate(new Date(toeGpsMs)),
326
+ tauN: -view.getFloat64(p + 100, true),
327
+ // RINEX stores −τ_n
328
+ gammaN: view.getFloat64(p + 116, true),
329
+ messageFrameTime: (tofUtcSec % SEC_PER_WEEK2 + SEC_PER_WEEK2) % SEC_PER_WEEK2,
330
+ x: view.getFloat64(p + 28, true) / 1e3,
331
+ y: view.getFloat64(p + 36, true) / 1e3,
332
+ z: view.getFloat64(p + 44, true) / 1e3,
333
+ xDot: view.getFloat64(p + 52, true) / 1e3,
334
+ yDot: view.getFloat64(p + 60, true) / 1e3,
335
+ zDot: view.getFloat64(p + 68, true) / 1e3,
336
+ xAcc: view.getFloat64(p + 76, true) / 1e3,
337
+ yAcc: view.getFloat64(p + 84, true) / 1e3,
338
+ zAcc: view.getFloat64(p + 92, true) / 1e3,
339
+ health,
340
+ freqNum
341
+ };
342
+ }
343
+ function parseNovatelNav(data) {
344
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
345
+ const stats = { badCrc: 0 };
346
+ const ephemerides = [];
347
+ const lastGps = /* @__PURE__ */ new Map();
348
+ const lastGlo = /* @__PURE__ */ new Map();
349
+ for (const frame of oem4Frames(data, view, stats)) {
350
+ if (!frame.binary) continue;
351
+ if (frame.id === ID_RAWEPHEM && frame.msgLen >= 102) {
352
+ const eph = decodeRawEphem(data, view, frame.payload);
353
+ if (!eph) continue;
354
+ const prev = lastGps.get(eph.prn);
355
+ if (prev && prev.iode === eph.iode && prev.tocDate.getTime() === eph.tocDate.getTime()) {
356
+ continue;
357
+ }
358
+ lastGps.set(eph.prn, eph);
359
+ ephemerides.push(eph);
360
+ } else if (frame.id === ID_GLOEPHEMERIS && frame.msgLen >= 144) {
361
+ const eph = decodeGloEphemeris(view, frame.payload);
362
+ if (!eph) continue;
363
+ const prev = lastGlo.get(eph.prn);
364
+ if (prev && Math.abs(prev.tocDate.getTime() - eph.tocDate.getTime()) < 1e3 && prev.health === eph.health) {
365
+ continue;
366
+ }
367
+ lastGlo.set(eph.prn, eph);
368
+ ephemerides.push(eph);
369
+ }
370
+ }
371
+ return { ephemerides, badCrc: stats.badCrc };
372
+ }
373
+
374
+ // src/novatel/index.ts
375
+ var GPS_EPOCH_MS3 = Date.UTC(1980, 0, 6);
27
376
  var MS_PER_WEEK = 7 * 864e5;
28
377
  var HDR = 28;
29
378
  var ID_RANGE = 43;
30
379
  var ID_RANGECMP = 140;
31
- var ID_GLOEPHEMERIS = 723;
380
+ var ID_GLOEPHEMERIS2 = 723;
32
381
  var C_LIGHT = 299792458;
33
382
  var ADR_ROLL = 8388608;
34
383
  function carrierFreq(sys, code, gloK) {
@@ -56,16 +405,6 @@ function carrierFreq(sys, code, gloK) {
56
405
  function exsign(v, bits) {
57
406
  return v & 1 << bits - 1 ? v - 2 ** bits : v;
58
407
  }
59
- function crc32(data, start, len) {
60
- let crc = 0;
61
- for (let i = start; i < start + len; i++) {
62
- crc ^= data[i];
63
- for (let j = 0; j < 8; j++) {
64
- crc = crc & 1 ? crc >>> 1 ^ 3988292384 : crc >>> 1;
65
- }
66
- }
67
- return crc >>> 0;
68
- }
69
408
  var SIGNALS = {
70
409
  0: {
71
410
  0: ["G", "1C"],
@@ -119,7 +458,7 @@ function parseNovatelRange(data) {
119
458
  const hl = data[j + 3];
120
459
  const id = view.getUint16(j + 4, true);
121
460
  const ln = view.getUint16(j + 8, true);
122
- if (id !== ID_GLOEPHEMERIS || hl < HDR || j + hl + ln + 4 > data.length)
461
+ if (id !== ID_GLOEPHEMERIS2 || hl < HDR || j + hl + ln + 4 > data.length)
123
462
  continue;
124
463
  if (crc32(data, j, hl + ln) !== view.getUint32(j + hl + ln, true)) continue;
125
464
  const slot = view.getUint16(j + hl, true) - 37;
@@ -203,7 +542,7 @@ function parseNovatelRange(data) {
203
542
  if (!codes.includes(code)) codes.push(code);
204
543
  }
205
544
  epochs.push({
206
- timeMs: GPS_EPOCH_MS + week * MS_PER_WEEK + towMs,
545
+ timeMs: GPS_EPOCH_MS3 + week * MS_PER_WEEK + towMs,
207
546
  meas
208
547
  });
209
548
  }
@@ -255,7 +594,7 @@ function parseNovatelRange(data) {
255
594
  if (!codes.includes(code)) codes.push(code);
256
595
  }
257
596
  epochs.push({
258
- timeMs: GPS_EPOCH_MS + week * MS_PER_WEEK + towMs,
597
+ timeMs: GPS_EPOCH_MS3 + week * MS_PER_WEEK + towMs,
259
598
  meas
260
599
  });
261
600
  }
@@ -266,5 +605,9 @@ function parseNovatelRange(data) {
266
605
  }
267
606
  // Annotate the CommonJS export names for ESM import in node:
268
607
  0 && (module.exports = {
608
+ OEM4_HLEN,
609
+ crc32,
610
+ oem4Frames,
611
+ parseNovatelNav,
269
612
  parseNovatelRange
270
613
  });
@@ -1,3 +1,70 @@
1
+ import { E as Ephemeris } from './nav-BAI1a9vK.cjs';
2
+
3
+ /**
4
+ * NovAtel OEM4/6/7 binary framing shared by the measurement and
5
+ * navigation decoders: sync pattern 0xAA 0x44 0x12, a 28+-byte header,
6
+ * and a reflected CRC-32 (poly 0xEDB88320) over the whole frame.
7
+ */
8
+ /** Minimum (standard) OEM4 binary header length. */
9
+ declare const OEM4_HLEN = 28;
10
+ /** Reflected CRC-32 (poly 0xEDB88320, init 0) — NovAtel "32-bit CRC". */
11
+ declare function crc32(data: Uint8Array, start: number, len: number): number;
12
+ /** One CRC-valid OEM4 frame located in a byte stream. */
13
+ interface Oem4Frame {
14
+ /** Message ID. */
15
+ id: number;
16
+ /** Offset of the frame start (first sync byte). */
17
+ start: number;
18
+ /** Offset of the payload (frame start + header length). */
19
+ payload: number;
20
+ /** Payload length in bytes. */
21
+ msgLen: number;
22
+ /** True when the header's message-type field marks a binary body. */
23
+ binary: boolean;
24
+ /** GPS week from the header. */
25
+ week: number;
26
+ /** GPS time of week from the header (ms). */
27
+ towMs: number;
28
+ }
29
+ /**
30
+ * Iterate every CRC-valid OEM4 frame in `data`. Corrupt or truncated
31
+ * candidates resync at the next byte; CRC failures additionally
32
+ * increment `stats.badCrc`.
33
+ */
34
+ declare function oem4Frames(data: Uint8Array, view: DataView, stats: {
35
+ badCrc: number;
36
+ }): Generator<Oem4Frame>;
37
+
38
+ /**
39
+ * NovAtel navigation-message decoding: RAWEPHEM (message 41, raw GPS
40
+ * LNAV subframes 1–3) and GLOEPHEMERIS (message 723, decoded GLONASS
41
+ * L1 C/A ephemeris).
42
+ *
43
+ * Ported from RTKLIB demo5 (rtklibexplorer fork, src/rcv/novatel.c:
44
+ * decode_rawephemb / decode_gloephemerisb, Copyright (c) 2007-2020
45
+ * T. Takasu, BSD-2-Clause) and cross-checked against the OEM7
46
+ * Commands and Logs Reference Manual. Output records mirror what
47
+ * `parseNavFile` produces for the equivalent RINEX 3 navigation file:
48
+ * GPS `tocDate` is a GPS-scale Date, GLONASS `tocDate` is the UTC
49
+ * epoch, GLONASS state vectors are in km (PZ-90), the RINEX clock bias
50
+ * is −τ_n, and `messageFrameTime` is the frame time as seconds of the
51
+ * UTC week.
52
+ */
53
+
54
+ interface NovatelNavResult {
55
+ /** Broadcast ephemerides in stream order, duplicates suppressed. */
56
+ ephemerides: Ephemeris[];
57
+ /** Frames whose CRC failed (corruption indicator). */
58
+ badCrc: number;
59
+ }
60
+ /**
61
+ * Decode every navigation message (RAWEPHEM, GLOEPHEMERIS) in a
62
+ * NovAtel binary byte stream. Repeated broadcasts of an unchanged
63
+ * ephemeris are suppressed the same way RTKLIB does: GPS by issue of
64
+ * data, GLONASS by reference time and health.
65
+ */
66
+ declare function parseNovatelNav(data: Uint8Array): NovatelNavResult;
67
+
1
68
  /**
2
69
  * NovAtel OEM4/6/7 raw-measurement decoding (RANGE log, message 43).
3
70
  *
@@ -15,6 +82,7 @@
15
82
  * without known parity are dropped, and code/phase are individually
16
83
  * gated by their lock flags.
17
84
  */
85
+
18
86
  interface NovatelMeasurement {
19
87
  /** RINEX PRN, e.g. "G04", "R11", "S23", "J01". */
20
88
  prn: string;
@@ -54,4 +122,4 @@ interface NovatelParseResult {
54
122
  */
55
123
  declare function parseNovatelRange(data: Uint8Array): NovatelParseResult;
56
124
 
57
- export { type NovatelEpoch, type NovatelMeasurement, type NovatelParseResult, parseNovatelRange };
125
+ export { type NovatelEpoch, type NovatelMeasurement, type NovatelNavResult, type NovatelParseResult, OEM4_HLEN, type Oem4Frame, crc32, oem4Frames, parseNovatelNav, parseNovatelRange };