1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.files.rinex.navigation;
18
19 import java.io.BufferedReader;
20 import java.io.IOException;
21 import java.io.Reader;
22 import java.util.Arrays;
23 import java.util.Collections;
24 import java.util.InputMismatchException;
25 import java.util.function.Function;
26 import java.util.function.Predicate;
27
28 import org.hipparchus.util.FastMath;
29 import org.orekit.annotation.DefaultDataContext;
30 import org.orekit.data.DataContext;
31 import org.orekit.data.DataSource;
32 import org.orekit.errors.OrekitException;
33 import org.orekit.errors.OrekitInternalError;
34 import org.orekit.errors.OrekitMessages;
35 import org.orekit.files.rinex.utils.parsing.RinexUtils;
36 import org.orekit.gnss.Frequency;
37 import org.orekit.gnss.SatelliteSystem;
38 import org.orekit.gnss.TimeSystem;
39 import org.orekit.propagation.analytical.gnss.data.AbstractNavigationMessage;
40 import org.orekit.propagation.analytical.gnss.data.BeidouCivilianNavigationMessage;
41 import org.orekit.propagation.analytical.gnss.data.BeidouLegacyNavigationMessage;
42 import org.orekit.propagation.analytical.gnss.data.BeidouSatelliteType;
43 import org.orekit.propagation.analytical.gnss.data.CivilianNavigationMessage;
44 import org.orekit.propagation.analytical.gnss.data.GLONASSNavigationMessage;
45 import org.orekit.propagation.analytical.gnss.data.GPSCivilianNavigationMessage;
46 import org.orekit.propagation.analytical.gnss.data.GPSLegacyNavigationMessage;
47 import org.orekit.propagation.analytical.gnss.data.GalileoNavigationMessage;
48 import org.orekit.propagation.analytical.gnss.data.IRNSSNavigationMessage;
49 import org.orekit.propagation.analytical.gnss.data.LegacyNavigationMessage;
50 import org.orekit.propagation.analytical.gnss.data.QZSSCivilianNavigationMessage;
51 import org.orekit.propagation.analytical.gnss.data.QZSSLegacyNavigationMessage;
52 import org.orekit.propagation.analytical.gnss.data.SBASNavigationMessage;
53 import org.orekit.time.AbsoluteDate;
54 import org.orekit.time.GNSSDate;
55 import org.orekit.time.TimeScale;
56 import org.orekit.time.TimeScales;
57 import org.orekit.utils.Constants;
58 import org.orekit.utils.units.Unit;
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79 public class RinexNavigationParser {
80
81
82 private static final Unit KM = Unit.KILOMETRE;
83
84
85 private static final Unit KM_PER_S = Unit.parse("km/s");
86
87
88 private static final Unit KM_PER_S2 = Unit.parse("km/s²");;
89
90
91 private static final Unit M_PER_S = Unit.parse("m/s");
92
93
94 private static final Unit S_PER_S = Unit.parse("s/s");
95
96
97 private static final Unit S_PER_S2 = Unit.parse("s/s²");
98
99
100 private static final Unit S_PER_DAY = Unit.parse("s/d");
101
102
103 private static final Unit S_PER_DAY2 = Unit.parse("s/d²");
104
105
106 private static final Unit SQRT_M = Unit.parse("√m");
107
108
109 private static final Unit RAD_PER_S = Unit.parse("rad/s");;
110
111
112 private static final Unit RAD_PER_S2 = Unit.parse("rad/s²");;
113
114
115 private static final Unit AS_PER_DAY = Unit.parse("as/d");;
116
117
118 private static final Unit AS_PER_DAY2 = Unit.parse("as/d²");;
119
120
121 private static final String INITIALS = "GRECIJS";
122
123
124 private final TimeScales timeScales;
125
126
127
128
129
130
131
132 @DefaultDataContext
133 public RinexNavigationParser() {
134 this(DataContext.getDefault().getTimeScales());
135 }
136
137
138
139
140
141 public RinexNavigationParser(final TimeScales timeScales) {
142 this.timeScales = timeScales;
143 }
144
145
146
147
148
149
150
151 public RinexNavigation parse(final DataSource source) throws IOException {
152
153
154 final ParseInfo pi = new ParseInfo(source.getName());
155
156 Iterable<LineParser> candidateParsers = Collections.singleton(LineParser.HEADER_VERSION);
157 try (Reader reader = source.getOpener().openReaderOnce();
158 BufferedReader br = new BufferedReader(reader)) {
159 nextLine:
160 for (String line = br.readLine(); line != null; line = br.readLine()) {
161 ++pi.lineNumber;
162 for (final LineParser candidate : candidateParsers) {
163 if (candidate.canHandle.test(line)) {
164 try {
165 candidate.parsingMethod.parse(line, pi);
166 candidateParsers = candidate.allowedNextProvider.apply(pi);
167 continue nextLine;
168 } catch (StringIndexOutOfBoundsException | NumberFormatException | InputMismatchException e) {
169 throw new OrekitException(e,
170 OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
171 pi.lineNumber, source.getName(), line);
172 }
173 }
174 }
175 throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
176 pi.lineNumber, source.getName(), line);
177 }
178 }
179
180 if (!pi.headerParsed) {
181 throw new OrekitException(OrekitMessages.UNEXPECTED_END_OF_FILE, source.getName());
182 }
183
184 pi.closePendingMessage();
185
186 return pi.file;
187
188 }
189
190
191 private class ParseInfo {
192
193
194 private final String name;
195
196
197 private final TimeScales timeScales;
198
199
200 private RinexNavigation file;
201
202
203 private int initialSpaces;
204
205
206 private boolean headerParsed;
207
208
209 private boolean isIonosphereAlphaInitialized;
210
211
212 private SatelliteSystemLineParser systemLineParser;
213
214
215 private int lineNumber;
216
217
218 private int messageLineNumber;
219
220
221 private GPSLegacyNavigationMessage gpsLNav;
222
223
224 private GPSCivilianNavigationMessage gpsCNav;
225
226
227 private GalileoNavigationMessage galileoNav;
228
229
230 private BeidouLegacyNavigationMessage beidouLNav;
231
232
233 private BeidouCivilianNavigationMessage beidouCNav;
234
235
236 private QZSSLegacyNavigationMessage qzssLNav;
237
238
239 private QZSSCivilianNavigationMessage qzssCNav;
240
241
242 private IRNSSNavigationMessage irnssNav;
243
244
245 private GLONASSNavigationMessage glonassNav;
246
247
248 private SBASNavigationMessage sbasNav;
249
250
251 private SystemTimeOffsetMessage sto;
252
253
254 private EarthOrientationParameterMessage eop;
255
256
257 private IonosphereKlobucharMessage klobuchar;
258
259
260 private IonosphereNequickGMessage nequickG;
261
262
263 private IonosphereBDGIMMessage bdgim;
264
265
266
267
268 ParseInfo(final String name) {
269
270 this.name = name;
271 this.timeScales = RinexNavigationParser.this.timeScales;
272 this.isIonosphereAlphaInitialized = false;
273 this.file = new RinexNavigation();
274
275 }
276
277
278
279 void closePendingMessage() {
280 if (systemLineParser != null) {
281 systemLineParser.closeMessage(this);
282 systemLineParser = null;
283 }
284
285 }
286
287 }
288
289
290 private enum LineParser {
291
292
293 HEADER_VERSION(line -> RinexUtils.matchesLabel(line, "RINEX VERSION / TYPE"),
294 (line, pi) -> {
295 RinexUtils.parseVersionFileTypeSatelliteSystem(line, pi.name, pi.file.getHeader(),
296 2.0, 2.01, 2.10, 2.11,
297 3.01, 3.02, 3.03, 3.04, 3.05,
298 4.00);
299 pi.initialSpaces = pi.file.getHeader().getFormatVersion() < 3.0 ? 3 : 4;
300 },
301 LineParser::headerNext),
302
303
304 HEADER_PROGRAM(line -> RinexUtils.matchesLabel(line, "PGM / RUN BY / DATE"),
305 (line, pi) -> RinexUtils.parseProgramRunByDate(line, pi.lineNumber, pi.name, pi.timeScales, pi.file.getHeader()),
306 LineParser::headerNext),
307
308
309 HEADER_COMMENT(line -> RinexUtils.matchesLabel(line, "COMMENT"),
310 (line, pi) -> RinexUtils.parseComment(pi.lineNumber, line, pi.file),
311 LineParser::headerNext),
312
313
314 HEADER_ION_ALPHA(line -> RinexUtils.matchesLabel(line, "ION ALPHA"),
315 (line, pi) -> {
316
317 pi.file.getHeader().setIonosphericCorrectionType(IonosphericCorrectionType.GPS);
318
319
320 final double[] parameters = new double[4];
321 parameters[0] = RinexUtils.parseDouble(line, 2, 12);
322 parameters[1] = RinexUtils.parseDouble(line, 14, 12);
323 parameters[2] = RinexUtils.parseDouble(line, 26, 12);
324 parameters[3] = RinexUtils.parseDouble(line, 38, 12);
325 pi.file.setKlobucharAlpha(parameters);
326 pi.isIonosphereAlphaInitialized = true;
327
328 },
329 LineParser::headerNext),
330
331
332 HEADER_ION_BETA(line -> RinexUtils.matchesLabel(line, "ION BETA"),
333 (line, pi) -> {
334
335 pi.file.getHeader().setIonosphericCorrectionType(IonosphericCorrectionType.GPS);
336
337
338 final double[] parameters = new double[4];
339 parameters[0] = RinexUtils.parseDouble(line, 2, 12);
340 parameters[1] = RinexUtils.parseDouble(line, 14, 12);
341 parameters[2] = RinexUtils.parseDouble(line, 26, 12);
342 parameters[3] = RinexUtils.parseDouble(line, 38, 12);
343 pi.file.setKlobucharBeta(parameters);
344
345 },
346 LineParser::headerNext),
347
348
349 HEADER_IONOSPHERIC(line -> RinexUtils.matchesLabel(line, "IONOSPHERIC CORR"),
350 (line, pi) -> {
351
352
353 final IonosphericCorrectionType ionoType =
354 IonosphericCorrectionType.valueOf(RinexUtils.parseString(line, 0, 3));
355 pi.file.getHeader().setIonosphericCorrectionType(ionoType);
356
357
358 final double[] parameters = new double[4];
359 parameters[0] = RinexUtils.parseDouble(line, 5, 12);
360 parameters[1] = RinexUtils.parseDouble(line, 17, 12);
361 parameters[2] = RinexUtils.parseDouble(line, 29, 12);
362 parameters[3] = RinexUtils.parseDouble(line, 41, 12);
363
364
365 if (ionoType == IonosphericCorrectionType.GAL) {
366
367
368 pi.file.setNeQuickAlpha(parameters);
369
370 } else {
371
372
373
374 if (pi.isIonosphereAlphaInitialized) {
375
376
377 pi.file.setKlobucharBeta(parameters);
378
379 } else {
380
381
382 pi.file.setKlobucharAlpha(parameters);
383
384
385 pi.isIonosphereAlphaInitialized = true;
386
387 }
388
389 }
390
391 },
392 LineParser::headerNext),
393
394
395 HEADER_DELTA_UTC(line -> RinexUtils.matchesLabel(line, "DELTA-UTC: A0,A1,T,W"),
396 (line, pi) -> {
397
398 final double a0 = RinexUtils.parseDouble(line, 3, 19);
399 final double a1 = RinexUtils.parseDouble(line, 22, 19);
400 final int refTime = RinexUtils.parseInt(line, 41, 9);
401 final int refWeek = RinexUtils.parseInt(line, 50, 9);
402
403
404 final SatelliteSystem satSystem = pi.file.getHeader().getSatelliteSystem();
405 final AbsoluteDate date = new GNSSDate(refWeek, refTime, satSystem, pi.timeScales).getDate();
406
407
408 final TimeSystemCorrection tsc = new TimeSystemCorrection("GPUT", date, a0, a1);
409 pi.file.getHeader().addTimeSystemCorrections(tsc);
410 },
411 LineParser::headerNext),
412
413
414 HEADER_CORR_SYSTEM_TIME(line -> RinexUtils.matchesLabel(line, "CORR TO SYSTEM TIME"),
415 (line, pi) -> {
416
417 final int year = RinexUtils.parseInt(line, 0, 6);
418 final int month = RinexUtils.parseInt(line, 6, 6);
419 final int day = RinexUtils.parseInt(line, 12, 6);
420 final double minusTau = RinexUtils.parseDouble(line, 21, 19);
421
422
423 final SatelliteSystem satSystem = pi.file.getHeader().getSatelliteSystem();
424 final TimeScale timeScale = satSystem.getObservationTimeScale().getTimeScale(pi.timeScales);
425 final AbsoluteDate date = new AbsoluteDate(year, month, day, timeScale);
426
427
428 final TimeSystemCorrection tsc = new TimeSystemCorrection("GLUT", date, minusTau, 0.0);
429 pi.file.getHeader().addTimeSystemCorrections(tsc);
430
431 },
432 LineParser::headerNext),
433
434
435 HEADER_TIME(line -> RinexUtils.matchesLabel(line, "TIME SYSTEM CORR"),
436 (line, pi) -> {
437
438
439 final String type = RinexUtils.parseString(line, 0, 4);
440 final double a0 = RinexUtils.parseDouble(line, 5, 17);
441 final double a1 = RinexUtils.parseDouble(line, 22, 16);
442 final int refTime = RinexUtils.parseInt(line, 38, 7);
443 final int refWeek = RinexUtils.parseInt(line, 46, 5);
444
445
446 final SatelliteSystem satSystem = pi.file.getHeader().getSatelliteSystem();
447 final AbsoluteDate date;
448 if (satSystem == SatelliteSystem.GLONASS) {
449 date = null;
450 } else if (satSystem == SatelliteSystem.BEIDOU) {
451 date = new GNSSDate(refWeek, refTime, satSystem, pi.timeScales).getDate();
452 } else {
453
454 date = new GNSSDate(refWeek, refTime, SatelliteSystem.GPS, pi.timeScales).getDate();
455 }
456
457
458 final TimeSystemCorrection tsc = new TimeSystemCorrection(type, date, a0, a1);
459 pi.file.getHeader().addTimeSystemCorrections(tsc);
460
461 },
462 LineParser::headerNext),
463
464
465 HEADER_LEAP_SECONDS(line -> RinexUtils.matchesLabel(line, "LEAP SECONDS"),
466 (line, pi) -> pi.file.getHeader().setNumberOfLeapSeconds(RinexUtils.parseInt(line, 0, 6)),
467 LineParser::headerNext),
468
469
470
471
472 HEADER_DOI(line -> RinexUtils.matchesLabel(line, "DOI"),
473 (line, pi) -> pi.file.getHeader().setDoi(RinexUtils.parseString(line, 0, RinexUtils.LABEL_INDEX)),
474 LineParser::headerNext),
475
476
477
478
479 HEADER_LICENSE(line -> RinexUtils.matchesLabel(line, "LICENSE OF USE"),
480 (line, pi) -> pi.file.getHeader().setLicense(RinexUtils.parseString(line, 0, RinexUtils.LABEL_INDEX)),
481 LineParser::headerNext),
482
483
484
485
486 HEADER_STATION_INFORMATION(line -> RinexUtils.matchesLabel(line, "STATION INFORMATION"),
487 (line, pi) -> pi.file.getHeader().setStationInformation(RinexUtils.parseString(line, 0, RinexUtils.LABEL_INDEX)),
488 LineParser::headerNext),
489
490
491
492
493 HEADER_MERGED_FILE(line -> RinexUtils.matchesLabel(line, "MERGED FILE"),
494 (line, pi) -> pi.file.getHeader().setMergedFiles(RinexUtils.parseInt(line, 0, 9)),
495 LineParser::headerNext),
496
497
498 HEADER_END(line -> RinexUtils.matchesLabel(line, "END OF HEADER"),
499 (line, pi) -> {
500
501 final RinexNavigationHeader header = pi.file.getHeader();
502 final double version = header.getFormatVersion();
503
504
505 if (header.getRunByName() == null ||
506 version >= 4 && header.getNumberOfLeapSeconds() < 0) {
507 throw new OrekitException(OrekitMessages.INCOMPLETE_HEADER, pi.name);
508 }
509
510 pi.headerParsed = true;
511
512 },
513 LineParser::navigationNext),
514
515
516 NAVIGATION_SV_EPOCH_CLOCK_RINEX_2(line -> true,
517 (line, pi) -> {
518
519
520 pi.messageLineNumber = 0;
521
522
523 pi.closePendingMessage();
524 pi.systemLineParser = SatelliteSystemLineParser.getParser(pi.file.getHeader().getSatelliteSystem(),
525 null, pi, line);
526
527 pi.systemLineParser.parseSvEpochSvClockLine(line, pi);
528
529 },
530 LineParser::navigationNext),
531
532
533 NAVIGATION_SV_EPOCH_CLOCK(line -> INITIALS.indexOf(line.charAt(0)) >= 0,
534 (line, pi) -> {
535
536
537 pi.messageLineNumber = 0;
538
539 if (pi.file.getHeader().getFormatVersion() < 4) {
540
541 final SatelliteSystem system = SatelliteSystem.parseSatelliteSystem(RinexUtils.parseString(line, 0, 1));
542
543
544 pi.closePendingMessage();
545 pi.systemLineParser = SatelliteSystemLineParser.getParser(system, null, pi, line);
546 }
547
548
549 pi.systemLineParser.parseSvEpochSvClockLine(line, pi);
550
551 },
552 LineParser::navigationNext),
553
554
555 EPH_TYPE(line -> line.startsWith("> EPH"),
556 (line, pi) -> {
557 final SatelliteSystem system = SatelliteSystem.parseSatelliteSystem(RinexUtils.parseString(line, 6, 1));
558 final String type = RinexUtils.parseString(line, 10, 4);
559 pi.closePendingMessage();
560 pi.systemLineParser = SatelliteSystemLineParser.getParser(system, type, pi, line);
561 },
562 pi -> Collections.singleton(NAVIGATION_SV_EPOCH_CLOCK)),
563
564
565 BROADCAST_ORBIT(line -> line.startsWith(" "),
566 (line, pi) -> {
567 switch (++pi.messageLineNumber) {
568 case 1: pi.systemLineParser.parseFirstBroadcastOrbit(line, pi);
569 break;
570 case 2: pi.systemLineParser.parseSecondBroadcastOrbit(line, pi);
571 break;
572 case 3: pi.systemLineParser.parseThirdBroadcastOrbit(line, pi);
573 break;
574 case 4: pi.systemLineParser.parseFourthBroadcastOrbit(line, pi);
575 break;
576 case 5: pi.systemLineParser.parseFifthBroadcastOrbit(line, pi);
577 break;
578 case 6: pi.systemLineParser.parseSixthBroadcastOrbit(line, pi);
579 break;
580 case 7: pi.systemLineParser.parseSeventhBroadcastOrbit(line, pi);
581 break;
582 case 8: pi.systemLineParser.parseEighthBroadcastOrbit(line, pi);
583 break;
584 case 9: pi.systemLineParser.parseNinthBroadcastOrbit(line, pi);
585 break;
586 default:
587
588 throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
589 pi.lineNumber, pi.name, line);
590 }
591
592 },
593 LineParser::navigationNext),
594
595
596 STO_LINE_1(line -> true,
597 (line, pi) -> {
598 pi.sto.setTransmissionTime(Unit.SECOND.toSI(RinexUtils.parseDouble(line, 4, 19)));
599 pi.sto.setA0(Unit.SECOND.toSI(RinexUtils.parseDouble(line, 23, 19)));
600 pi.sto.setA1(S_PER_S.toSI(RinexUtils.parseDouble(line, 42, 19)));
601 pi.sto.setA2(S_PER_S2.toSI(RinexUtils.parseDouble(line, 61, 19)));
602 pi.file.addSystemTimeOffset(pi.sto);
603 pi.sto = null;
604 },
605 LineParser::navigationNext),
606
607
608 STO_SV_EPOCH_CLOCK(line -> true,
609 (line, pi) -> {
610
611 pi.sto.setDefinedTimeSystem(TimeSystem.parseTwoLettersCode(RinexUtils.parseString(line, 24, 2)));
612 pi.sto.setReferenceTimeSystem(TimeSystem.parseTwoLettersCode(RinexUtils.parseString(line, 26, 2)));
613 final String sbas = RinexUtils.parseString(line, 43, 18);
614 pi.sto.setSbasId(sbas.length() > 0 ? SbasId.valueOf(sbas) : null);
615 final String utc = RinexUtils.parseString(line, 62, 18);
616 pi.sto.setUtcId(utc.length() > 0 ? UtcId.parseUtcId(utc) : null);
617
618
619 final int year = RinexUtils.parseInt(line, 4, 4);
620 final int month = RinexUtils.parseInt(line, 9, 2);
621 final int day = RinexUtils.parseInt(line, 12, 2);
622 final int hours = RinexUtils.parseInt(line, 15, 2);
623 final int min = RinexUtils.parseInt(line, 18, 2);
624 final int sec = RinexUtils.parseInt(line, 21, 2);
625 pi.sto.setReferenceEpoch(new AbsoluteDate(year, month, day, hours, min, sec,
626 pi.sto.getDefinedTimeSystem().getTimeScale(pi.timeScales)));
627
628 },
629 pi -> Collections.singleton(STO_LINE_1)),
630
631
632 STO_TYPE(line -> line.startsWith("> STO"),
633 (line, pi) -> {
634 pi.closePendingMessage();
635 pi.sto = new SystemTimeOffsetMessage(SatelliteSystem.parseSatelliteSystem(RinexUtils.parseString(line, 6, 1)),
636 RinexUtils.parseInt(line, 7, 2),
637 RinexUtils.parseString(line, 10, 4));
638 },
639 pi -> Collections.singleton(STO_SV_EPOCH_CLOCK)),
640
641
642 EOP_LINE_2(line -> true,
643 (line, pi) -> {
644 pi.eop.setTransmissionTime(Unit.SECOND.toSI(RinexUtils.parseDouble(line, 4, 19)));
645 pi.eop.setDut1(Unit.SECOND.toSI(RinexUtils.parseDouble(line, 23, 19)));
646 pi.eop.setDut1Dot(S_PER_DAY.toSI(RinexUtils.parseDouble(line, 42, 19)));
647 pi.eop.setDut1DotDot(S_PER_DAY2.toSI(RinexUtils.parseDouble(line, 61, 19)));
648 pi.file.addEarthOrientationParameter(pi.eop);
649 pi.eop = null;
650 },
651 LineParser::navigationNext),
652
653
654 EOP_LINE_1(line -> true,
655 (line, pi) -> {
656 pi.eop.setYp(Unit.ARC_SECOND.toSI(RinexUtils.parseDouble(line, 23, 19)));
657 pi.eop.setYpDot(AS_PER_DAY.toSI(RinexUtils.parseDouble(line, 42, 19)));
658 pi.eop.setYpDotDot(AS_PER_DAY2.toSI(RinexUtils.parseDouble(line, 61, 19)));
659 },
660 pi -> Collections.singleton(EOP_LINE_2)),
661
662
663 EOP_SV_EPOCH_CLOCK(line -> true,
664 (line, pi) -> {
665 final int year = RinexUtils.parseInt(line, 4, 4);
666 final int month = RinexUtils.parseInt(line, 9, 2);
667 final int day = RinexUtils.parseInt(line, 12, 2);
668 final int hours = RinexUtils.parseInt(line, 15, 2);
669 final int min = RinexUtils.parseInt(line, 18, 2);
670 final int sec = RinexUtils.parseInt(line, 21, 2);
671 pi.eop.setReferenceEpoch(new AbsoluteDate(year, month, day, hours, min, sec,
672 pi.eop.getSystem().getObservationTimeScale().getTimeScale(pi.timeScales)));
673 pi.eop.setXp(Unit.ARC_SECOND.toSI(RinexUtils.parseDouble(line, 23, 19)));
674 pi.eop.setXpDot(AS_PER_DAY.toSI(RinexUtils.parseDouble(line, 42, 19)));
675 pi.eop.setXpDotDot(AS_PER_DAY2.toSI(RinexUtils.parseDouble(line, 61, 19)));
676 },
677 pi -> Collections.singleton(EOP_LINE_1)),
678
679
680 EOP_TYPE(line -> line.startsWith("> EOP"),
681 (line, pi) -> {
682 pi.closePendingMessage();
683 pi.eop = new EarthOrientationParameterMessage(SatelliteSystem.parseSatelliteSystem(RinexUtils.parseString(line, 6, 1)),
684 RinexUtils.parseInt(line, 7, 2),
685 RinexUtils.parseString(line, 10, 4));
686 },
687 pi -> Collections.singleton(EOP_SV_EPOCH_CLOCK)),
688
689
690 KLOBUCHAR_LINE_2(line -> true,
691 (line, pi) -> {
692 pi.klobuchar.setBetaI(3, IonosphereKlobucharMessage.S_PER_SC_N[3].toSI(RinexUtils.parseDouble(line, 4, 19)));
693 pi.klobuchar.setRegionCode(RinexUtils.parseDouble(line, 23, 19) < 0.5 ?
694 RegionCode.WIDE_AREA : RegionCode.JAPAN);
695 pi.file.addKlobucharMessage(pi.klobuchar);
696 pi.klobuchar = null;
697 },
698 LineParser::navigationNext),
699
700
701 KLOBUCHAR_LINE_1(line -> true,
702 (line, pi) -> {
703 pi.klobuchar.setAlphaI(3, IonosphereKlobucharMessage.S_PER_SC_N[3].toSI(RinexUtils.parseDouble(line, 4, 19)));
704 pi.klobuchar.setBetaI(0, IonosphereKlobucharMessage.S_PER_SC_N[0].toSI(RinexUtils.parseDouble(line, 23, 19)));
705 pi.klobuchar.setBetaI(1, IonosphereKlobucharMessage.S_PER_SC_N[1].toSI(RinexUtils.parseDouble(line, 42, 19)));
706 pi.klobuchar.setBetaI(2, IonosphereKlobucharMessage.S_PER_SC_N[2].toSI(RinexUtils.parseDouble(line, 61, 19)));
707 },
708 pi -> Collections.singleton(KLOBUCHAR_LINE_2)),
709
710
711 KLOBUCHAR_LINE_0(line -> true,
712 (line, pi) -> {
713 final int year = RinexUtils.parseInt(line, 4, 4);
714 final int month = RinexUtils.parseInt(line, 9, 2);
715 final int day = RinexUtils.parseInt(line, 12, 2);
716 final int hours = RinexUtils.parseInt(line, 15, 2);
717 final int min = RinexUtils.parseInt(line, 18, 2);
718 final int sec = RinexUtils.parseInt(line, 21, 2);
719 pi.klobuchar.setTransmitTime(new AbsoluteDate(year, month, day, hours, min, sec,
720 pi.klobuchar.getSystem().getObservationTimeScale().getTimeScale(pi.timeScales)));
721 pi.klobuchar.setAlphaI(0, IonosphereKlobucharMessage.S_PER_SC_N[0].toSI(RinexUtils.parseDouble(line, 23, 19)));
722 pi.klobuchar.setAlphaI(1, IonosphereKlobucharMessage.S_PER_SC_N[1].toSI(RinexUtils.parseDouble(line, 42, 19)));
723 pi.klobuchar.setAlphaI(2, IonosphereKlobucharMessage.S_PER_SC_N[2].toSI(RinexUtils.parseDouble(line, 61, 19)));
724 },
725 pi -> Collections.singleton(KLOBUCHAR_LINE_1)),
726
727
728 NEQUICK_LINE_1(line -> true,
729 (line, pi) -> {
730 pi.nequickG.setFlags((int) FastMath.rint(RinexUtils.parseDouble(line, 4, 19)));
731 pi.file.addNequickGMessage(pi.nequickG);
732 pi.nequickG = null;
733 },
734 LineParser::navigationNext),
735
736
737 NEQUICK_LINE_0(line -> true,
738 (line, pi) -> {
739 final int year = RinexUtils.parseInt(line, 4, 4);
740 final int month = RinexUtils.parseInt(line, 9, 2);
741 final int day = RinexUtils.parseInt(line, 12, 2);
742 final int hours = RinexUtils.parseInt(line, 15, 2);
743 final int min = RinexUtils.parseInt(line, 18, 2);
744 final int sec = RinexUtils.parseInt(line, 21, 2);
745 pi.nequickG.setTransmitTime(new AbsoluteDate(year, month, day, hours, min, sec,
746 pi.nequickG.getSystem().getObservationTimeScale().getTimeScale(pi.timeScales)));
747 pi.nequickG.setAi0(IonosphereNequickGMessage.SFU.toSI(RinexUtils.parseDouble(line, 23, 19)));
748 pi.nequickG.setAi1(IonosphereNequickGMessage.SFU_PER_DEG.toSI(RinexUtils.parseDouble(line, 42, 19)));
749 pi.nequickG.setAi2(IonosphereNequickGMessage.SFU_PER_DEG2.toSI(RinexUtils.parseDouble(line, 61, 19)));
750 },
751 pi -> Collections.singleton(NEQUICK_LINE_1)),
752
753
754 BDGIM_LINE_2(line -> true,
755 (line, pi) -> {
756 pi.bdgim.setAlphaI(7, Unit.TOTAL_ELECTRON_CONTENT_UNIT.toSI(RinexUtils.parseDouble(line, 4, 19)));
757 pi.bdgim.setAlphaI(8, Unit.TOTAL_ELECTRON_CONTENT_UNIT.toSI(RinexUtils.parseDouble(line, 23, 19)));
758 pi.file.addBDGIMMessage(pi.bdgim);
759 pi.bdgim = null;
760 },
761 LineParser::navigationNext),
762
763
764 BDGIM_LINE_1(line -> true,
765 (line, pi) -> {
766 pi.bdgim.setAlphaI(3, Unit.TOTAL_ELECTRON_CONTENT_UNIT.toSI(RinexUtils.parseDouble(line, 4, 19)));
767 pi.bdgim.setAlphaI(4, Unit.TOTAL_ELECTRON_CONTENT_UNIT.toSI(RinexUtils.parseDouble(line, 23, 19)));
768 pi.bdgim.setAlphaI(5, Unit.TOTAL_ELECTRON_CONTENT_UNIT.toSI(RinexUtils.parseDouble(line, 42, 19)));
769 pi.bdgim.setAlphaI(6, Unit.TOTAL_ELECTRON_CONTENT_UNIT.toSI(RinexUtils.parseDouble(line, 61, 19)));
770 },
771 pi -> Collections.singleton(BDGIM_LINE_2)),
772
773
774 BDGIM_LINE_0(line -> true,
775 (line, pi) -> {
776 final int year = RinexUtils.parseInt(line, 4, 4);
777 final int month = RinexUtils.parseInt(line, 9, 2);
778 final int day = RinexUtils.parseInt(line, 12, 2);
779 final int hours = RinexUtils.parseInt(line, 15, 2);
780 final int min = RinexUtils.parseInt(line, 18, 2);
781 final int sec = RinexUtils.parseInt(line, 21, 2);
782 pi.bdgim.setTransmitTime(new AbsoluteDate(year, month, day, hours, min, sec,
783 pi.bdgim.getSystem().getObservationTimeScale().getTimeScale(pi.timeScales)));
784 pi.bdgim.setAlphaI(0, Unit.TOTAL_ELECTRON_CONTENT_UNIT.toSI(RinexUtils.parseDouble(line, 23, 19)));
785 pi.bdgim.setAlphaI(1, Unit.TOTAL_ELECTRON_CONTENT_UNIT.toSI(RinexUtils.parseDouble(line, 42, 19)));
786 pi.bdgim.setAlphaI(2, Unit.TOTAL_ELECTRON_CONTENT_UNIT.toSI(RinexUtils.parseDouble(line, 61, 19)));
787 },
788 pi -> Collections.singleton(BDGIM_LINE_1)),
789
790
791 IONO_TYPE(line -> line.startsWith("> ION"),
792 (line, pi) -> {
793 pi.closePendingMessage();
794 final SatelliteSystem system = SatelliteSystem.parseSatelliteSystem(RinexUtils.parseString(line, 6, 1));
795 final int prn = RinexUtils.parseInt(line, 7, 2);
796 final String type = RinexUtils.parseString(line, 10, 4);
797 if (system == SatelliteSystem.GALILEO) {
798 pi.nequickG = new IonosphereNequickGMessage(system, prn, type);
799 } else {
800
801
802 if (system == SatelliteSystem.BEIDOU && "CNVX".equals(type)) {
803 pi.bdgim = new IonosphereBDGIMMessage(system, prn, type);
804 } else {
805 pi.klobuchar = new IonosphereKlobucharMessage(system, prn, type);
806 }
807 }
808 },
809 pi -> Collections.singleton(pi.nequickG != null ? NEQUICK_LINE_0 : (pi.bdgim != null ? BDGIM_LINE_0 : KLOBUCHAR_LINE_0)));
810
811
812 private final Predicate<String> canHandle;
813
814
815 private final ParsingMethod parsingMethod;
816
817
818 private final Function<ParseInfo, Iterable<LineParser>> allowedNextProvider;
819
820
821
822
823
824
825 LineParser(final Predicate<String> canHandle, final ParsingMethod parsingMethod,
826 final Function<ParseInfo, Iterable<LineParser>> allowedNextProvider) {
827 this.canHandle = canHandle;
828 this.parsingMethod = parsingMethod;
829 this.allowedNextProvider = allowedNextProvider;
830 }
831
832
833
834
835
836 private static Iterable<LineParser> headerNext(final ParseInfo parseInfo) {
837 if (parseInfo.file.getHeader().getFormatVersion() < 3) {
838
839 return Arrays.asList(HEADER_COMMENT, HEADER_PROGRAM,
840 HEADER_ION_ALPHA, HEADER_ION_BETA,
841 HEADER_DELTA_UTC, HEADER_CORR_SYSTEM_TIME,
842 HEADER_LEAP_SECONDS, HEADER_END);
843 } else if (parseInfo.file.getHeader().getFormatVersion() < 4) {
844
845 return Arrays.asList(HEADER_COMMENT, HEADER_PROGRAM,
846 HEADER_IONOSPHERIC, HEADER_TIME,
847 HEADER_LEAP_SECONDS, HEADER_END);
848 } else {
849
850 return Arrays.asList(HEADER_COMMENT, HEADER_PROGRAM,
851 HEADER_DOI, HEADER_LICENSE, HEADER_STATION_INFORMATION, HEADER_MERGED_FILE,
852 HEADER_LEAP_SECONDS, HEADER_END);
853 }
854 }
855
856
857
858
859
860 private static Iterable<LineParser> navigationNext(final ParseInfo parseInfo) {
861 if (parseInfo.gpsLNav != null || parseInfo.gpsCNav != null || parseInfo.galileoNav != null ||
862 parseInfo.beidouLNav != null || parseInfo.beidouCNav != null || parseInfo.qzssLNav != null ||
863 parseInfo.qzssCNav != null || parseInfo.irnssNav != null || parseInfo.sbasNav != null) {
864 return Collections.singleton(BROADCAST_ORBIT);
865 } else if (parseInfo.glonassNav != null) {
866 if (parseInfo.messageLineNumber < 3) {
867 return Collections.singleton(BROADCAST_ORBIT);
868 } else {
869
870
871
872
873
874
875 if (parseInfo.file.getHeader().getFormatVersion() < 4) {
876 return Arrays.asList(BROADCAST_ORBIT, NAVIGATION_SV_EPOCH_CLOCK);
877 } else {
878 return Arrays.asList(BROADCAST_ORBIT, EPH_TYPE, STO_TYPE, EOP_TYPE, IONO_TYPE);
879 }
880 }
881 } else if (parseInfo.file.getHeader().getFormatVersion() < 3) {
882 return Collections.singleton(NAVIGATION_SV_EPOCH_CLOCK_RINEX_2);
883 } else if (parseInfo.file.getHeader().getFormatVersion() < 4) {
884 return Collections.singleton(NAVIGATION_SV_EPOCH_CLOCK);
885 } else {
886 return Arrays.asList(EPH_TYPE, STO_TYPE, EOP_TYPE, IONO_TYPE);
887 }
888 }
889
890 }
891
892
893 private enum SatelliteSystemLineParser {
894
895
896 GPS_LNAV() {
897
898
899 @Override
900 public void parseSvEpochSvClockLine(final String line, final ParseInfo pi) {
901 if (pi.file.getHeader().getFormatVersion() < 3.0) {
902 parseSvEpochSvClockLineRinex2(line, pi.timeScales.getGPS(), pi.gpsLNav);
903 } else {
904 parseSvEpochSvClockLine(line, pi.timeScales.getGPS(), pi.gpsLNav);
905 }
906 }
907
908
909 @Override
910 public void parseFirstBroadcastOrbit(final String line, final ParseInfo pi) {
911 pi.gpsLNav.setIODE(parseBroadcastDouble1(line, pi.initialSpaces, Unit.SECOND));
912 pi.gpsLNav.setCrs(parseBroadcastDouble2(line, pi.initialSpaces, Unit.METRE));
913 pi.gpsLNav.setDeltaN(parseBroadcastDouble3(line, pi.initialSpaces, RAD_PER_S));
914 pi.gpsLNav.setM0(parseBroadcastDouble4(line, pi.initialSpaces, Unit.RADIAN));
915 }
916
917
918 @Override
919 public void parseSecondBroadcastOrbit(final String line, final ParseInfo pi) {
920 pi.gpsLNav.setCuc(parseBroadcastDouble1(line, pi.initialSpaces, Unit.RADIAN));
921 pi.gpsLNav.setE(parseBroadcastDouble2(line, pi.initialSpaces, Unit.NONE));
922 pi.gpsLNav.setCus(parseBroadcastDouble3(line, pi.initialSpaces, Unit.RADIAN));
923 pi.gpsLNav.setSqrtA(parseBroadcastDouble4(line, pi.initialSpaces, SQRT_M));
924 }
925
926
927 @Override
928 public void parseThirdBroadcastOrbit(final String line, final ParseInfo pi) {
929 pi.gpsLNav.setTime(parseBroadcastDouble1(line, pi.initialSpaces, Unit.SECOND));
930 pi.gpsLNav.setCic(parseBroadcastDouble2(line, pi.initialSpaces, Unit.RADIAN));
931 pi.gpsLNav.setOmega0(parseBroadcastDouble3(line, pi.initialSpaces, Unit.RADIAN));
932 pi.gpsLNav.setCis(parseBroadcastDouble4(line, pi.initialSpaces, Unit.RADIAN));
933 }
934
935
936 @Override
937 public void parseFourthBroadcastOrbit(final String line, final ParseInfo pi) {
938 pi.gpsLNav.setI0(parseBroadcastDouble1(line, pi.initialSpaces, Unit.RADIAN));
939 pi.gpsLNav.setCrc(parseBroadcastDouble2(line, pi.initialSpaces, Unit.METRE));
940 pi.gpsLNav.setPa(parseBroadcastDouble3(line, pi.initialSpaces, Unit.RADIAN));
941 pi.gpsLNav.setOmegaDot(parseBroadcastDouble4(line, pi.initialSpaces, RAD_PER_S));
942 }
943
944
945 @Override
946 public void parseFifthBroadcastOrbit(final String line, final ParseInfo pi) {
947
948 pi.gpsLNav.setIDot(parseBroadcastDouble1(line, pi.initialSpaces, RAD_PER_S));
949
950
951
952 pi.gpsLNav.setWeek((int) RinexUtils.parseDouble(line, 42, 19));
953 pi.gpsLNav.setDate(new GNSSDate(pi.gpsLNav.getWeek(),
954 pi.gpsLNav.getTime(),
955 SatelliteSystem.GPS,
956 pi.timeScales).getDate());
957 }
958
959
960 @Override
961 public void parseSixthBroadcastOrbit(final String line, final ParseInfo pi) {
962 pi.gpsLNav.setSvAccuracy(parseBroadcastDouble1(line, pi.initialSpaces, Unit.METRE));
963 pi.gpsLNav.setSvHealth(parseBroadcastInt2(line, pi.initialSpaces));
964 pi.gpsLNav.setTGD(parseBroadcastDouble3(line, pi.initialSpaces, Unit.SECOND));
965 pi.gpsLNav.setIODC(parseBroadcastInt4(line, pi.initialSpaces));
966 }
967
968
969 @Override
970 public void parseSeventhBroadcastOrbit(final String line, final ParseInfo pi) {
971 pi.gpsLNav.setTransmissionTime(parseBroadcastDouble1(line, pi.initialSpaces, Unit.SECOND));
972 pi.gpsLNav.setFitInterval(parseBroadcastInt2(line, pi.initialSpaces));
973 pi.closePendingMessage();
974 }
975
976
977 @Override
978 public void closeMessage(final ParseInfo pi) {
979 pi.file.addGPSLegacyNavigationMessage(pi.gpsLNav);
980 pi.gpsLNav = null;
981 }
982
983 },
984
985
986
987
988 GPS_CNAV() {
989
990
991 @Override
992 public void parseSvEpochSvClockLine(final String line, final ParseInfo pi) {
993 parseSvEpochSvClockLine(line, pi.timeScales.getGPS(), pi.gpsCNav);
994 }
995
996
997 @Override
998 public void parseFirstBroadcastOrbit(final String line, final ParseInfo pi) {
999 pi.gpsCNav.setADot(parseBroadcastDouble1(line, pi.initialSpaces, M_PER_S));
1000 pi.gpsCNav.setCrs(parseBroadcastDouble2(line, pi.initialSpaces, Unit.METRE));
1001 pi.gpsCNav.setDeltaN(parseBroadcastDouble3(line, pi.initialSpaces, RAD_PER_S));
1002 pi.gpsCNav.setM0(parseBroadcastDouble4(line, pi.initialSpaces, Unit.RADIAN));
1003 }
1004
1005
1006 @Override
1007 public void parseSecondBroadcastOrbit(final String line, final ParseInfo pi) {
1008 pi.gpsCNav.setCuc(parseBroadcastDouble1(line, pi.initialSpaces, Unit.RADIAN));
1009 pi.gpsCNav.setE(parseBroadcastDouble2(line, pi.initialSpaces, Unit.NONE));
1010 pi.gpsCNav.setCus(parseBroadcastDouble3(line, pi.initialSpaces, Unit.RADIAN));
1011 pi.gpsCNav.setSqrtA(parseBroadcastDouble4(line, pi.initialSpaces, SQRT_M));
1012 }
1013
1014
1015 @Override
1016 public void parseThirdBroadcastOrbit(final String line, final ParseInfo pi) {
1017 pi.gpsCNav.setTime(parseBroadcastDouble1(line, pi.initialSpaces, Unit.SECOND));
1018 pi.gpsCNav.setCic(parseBroadcastDouble2(line, pi.initialSpaces, Unit.RADIAN));
1019 pi.gpsCNav.setOmega0(parseBroadcastDouble3(line, pi.initialSpaces, Unit.RADIAN));
1020 pi.gpsCNav.setCis(parseBroadcastDouble4(line, pi.initialSpaces, Unit.RADIAN));
1021 }
1022
1023
1024 @Override
1025 public void parseFourthBroadcastOrbit(final String line, final ParseInfo pi) {
1026 pi.gpsCNav.setI0(parseBroadcastDouble1(line, pi.initialSpaces, Unit.RADIAN));
1027 pi.gpsCNav.setCrc(parseBroadcastDouble2(line, pi.initialSpaces, Unit.METRE));
1028 pi.gpsCNav.setPa(parseBroadcastDouble3(line, pi.initialSpaces, Unit.RADIAN));
1029 pi.gpsCNav.setOmegaDot(parseBroadcastDouble4(line, pi.initialSpaces, RAD_PER_S));
1030 }
1031
1032
1033 @Override
1034 public void parseFifthBroadcastOrbit(final String line, final ParseInfo pi) {
1035 pi.gpsCNav.setIDot(parseBroadcastDouble1(line, pi.initialSpaces, RAD_PER_S));
1036 pi.gpsCNav.setDeltaN0Dot(parseBroadcastDouble2(line, pi.initialSpaces, RAD_PER_S2));
1037 pi.gpsCNav.setUraiNed0(parseBroadcastInt3(line, pi.initialSpaces));
1038 pi.gpsCNav.setUraiNed1(parseBroadcastInt4(line, pi.initialSpaces));
1039 }
1040
1041
1042 @Override
1043 public void parseSixthBroadcastOrbit(final String line, final ParseInfo pi) {
1044 pi.gpsCNav.setUraiEd(parseBroadcastInt1(line, pi.initialSpaces));
1045 pi.gpsCNav.setSvHealth(parseBroadcastInt2(line, pi.initialSpaces));
1046 pi.gpsCNav.setTGD(parseBroadcastDouble3(line, pi.initialSpaces, Unit.SECOND));
1047 pi.gpsCNav.setUraiNed2(parseBroadcastInt4(line, pi.initialSpaces));
1048 }
1049
1050
1051 @Override
1052 public void parseSeventhBroadcastOrbit(final String line, final ParseInfo pi) {
1053 pi.gpsCNav.setIscL1CA(parseBroadcastDouble1(line, pi.initialSpaces, Unit.SECOND));
1054 pi.gpsCNav.setIscL2C(parseBroadcastDouble2(line, pi.initialSpaces, Unit.SECOND));
1055 pi.gpsCNav.setIscL5I5(parseBroadcastDouble3(line, pi.initialSpaces, Unit.SECOND));
1056 pi.gpsCNav.setIscL5Q5(parseBroadcastDouble4(line, pi.initialSpaces, Unit.SECOND));
1057 }
1058
1059
1060 @Override
1061 public void parseEighthBroadcastOrbit(final String line, final ParseInfo pi) {
1062 if (pi.gpsCNav.isCnv2()) {
1063
1064 pi.gpsCNav.setIscL1CD(parseBroadcastDouble1(line, pi.initialSpaces, Unit.SECOND));
1065 pi.gpsCNav.setIscL1CP(parseBroadcastDouble2(line, pi.initialSpaces, Unit.SECOND));
1066 } else {
1067 parseTransmissionTimeLine(line, pi);
1068 }
1069 }
1070
1071
1072 @Override
1073 public void parseNinthBroadcastOrbit(final String line, final ParseInfo pi) {
1074 parseTransmissionTimeLine(line, pi);
1075 }
1076
1077
1078
1079
1080
1081 private void parseTransmissionTimeLine(final String line, final ParseInfo pi) {
1082 pi.gpsCNav.setTransmissionTime(parseBroadcastDouble1(line, pi.initialSpaces, Unit.SECOND));
1083 pi.closePendingMessage();
1084 }
1085
1086
1087 @Override
1088 public void closeMessage(final ParseInfo pi) {
1089 pi.file.addGPSLegacyNavigationMessage(pi.gpsCNav);
1090 pi.gpsCNav = null;
1091 }
1092
1093 },
1094
1095
1096 GALILEO() {
1097
1098
1099 @Override
1100 public void parseSvEpochSvClockLine(final String line, final ParseInfo pi) {
1101 parseSvEpochSvClockLine(line, pi.timeScales.getGPS(), pi.galileoNav);
1102 }
1103
1104
1105 @Override
1106 public void parseFirstBroadcastOrbit(final String line, final ParseInfo pi) {
1107 pi.galileoNav.setIODNav(parseBroadcastInt1(line, pi.initialSpaces));
1108 pi.galileoNav.setCrs(parseBroadcastDouble2(line, pi.initialSpaces, Unit.METRE));
1109 pi.galileoNav.setDeltaN(parseBroadcastDouble3(line, pi.initialSpaces, RAD_PER_S));
1110 pi.galileoNav.setM0(parseBroadcastDouble4(line, pi.initialSpaces, Unit.RADIAN));
1111 }
1112
1113
1114 @Override
1115 public void parseSecondBroadcastOrbit(final String line, final ParseInfo pi) {
1116 pi.galileoNav.setCuc(parseBroadcastDouble1(line, pi.initialSpaces, Unit.RADIAN));
1117 pi.galileoNav.setE(parseBroadcastDouble2(line, pi.initialSpaces, Unit.NONE));
1118 pi.galileoNav.setCus(parseBroadcastDouble3(line, pi.initialSpaces, Unit.RADIAN));
1119 pi.galileoNav.setSqrtA(parseBroadcastDouble4(line, pi.initialSpaces, SQRT_M));
1120 }
1121
1122
1123 @Override
1124 public void parseThirdBroadcastOrbit(final String line, final ParseInfo pi) {
1125 pi.galileoNav.setTime(parseBroadcastDouble1(line, pi.initialSpaces, Unit.SECOND));
1126 pi.galileoNav.setCic(parseBroadcastDouble2(line, pi.initialSpaces, Unit.RADIAN));
1127 pi.galileoNav.setOmega0(parseBroadcastDouble3(line, pi.initialSpaces, Unit.RADIAN));
1128 pi.galileoNav.setCis(parseBroadcastDouble4(line, pi.initialSpaces, Unit.RADIAN));
1129 }
1130
1131
1132 @Override
1133 public void parseFourthBroadcastOrbit(final String line, final ParseInfo pi) {
1134 pi.galileoNav.setI0(parseBroadcastDouble1(line, pi.initialSpaces, Unit.RADIAN));
1135 pi.galileoNav.setCrc(parseBroadcastDouble2(line, pi.initialSpaces, Unit.METRE));
1136 pi.galileoNav.setPa(parseBroadcastDouble3(line, pi.initialSpaces, Unit.RADIAN));
1137 pi.galileoNav.setOmegaDot(parseBroadcastDouble4(line, pi.initialSpaces, RAD_PER_S));
1138 }
1139
1140
1141 @Override
1142 public void parseFifthBroadcastOrbit(final String line, final ParseInfo pi) {
1143
1144 pi.galileoNav.setIDot(parseBroadcastDouble1(line, pi.initialSpaces, RAD_PER_S));
1145 pi.galileoNav.setDataSource(parseBroadcastInt2(line, pi.initialSpaces));
1146
1147 pi.galileoNav.setWeek(parseBroadcastInt3(line, pi.initialSpaces));
1148 pi.galileoNav.setDate(new GNSSDate(pi.galileoNav.getWeek(),
1149 pi.galileoNav.getTime(),
1150 SatelliteSystem.GPS,
1151 pi.timeScales).getDate());
1152 }
1153
1154
1155 @Override
1156 public void parseSixthBroadcastOrbit(final String line, final ParseInfo pi) {
1157 pi.galileoNav.setSisa(parseBroadcastDouble1(line, pi.initialSpaces, Unit.METRE));
1158 pi.galileoNav.setSvHealth(parseBroadcastDouble2(line, pi.initialSpaces, Unit.NONE));
1159 pi.galileoNav.setBGDE1E5a(parseBroadcastDouble3(line, pi.initialSpaces, Unit.SECOND));
1160 pi.galileoNav.setBGDE5bE1(parseBroadcastDouble4(line, pi.initialSpaces, Unit.SECOND));
1161 }
1162
1163
1164 @Override
1165 public void parseSeventhBroadcastOrbit(final String line, final ParseInfo pi) {
1166 pi.galileoNav.setTransmissionTime(parseBroadcastDouble1(line, pi.initialSpaces, Unit.SECOND));
1167 pi.closePendingMessage();
1168 }
1169
1170
1171 @Override
1172 public void closeMessage(final ParseInfo pi) {
1173 pi.file.addGalileoNavigationMessage(pi.galileoNav);
1174 pi.galileoNav = null;
1175 }
1176
1177 },
1178
1179
1180 GLONASS() {
1181
1182
1183 @Override
1184 public void parseSvEpochSvClockLine(final String line, final ParseInfo pi) {
1185
1186 if (pi.file.getHeader().getFormatVersion() < 3.0) {
1187
1188 pi.glonassNav.setPRN(RinexUtils.parseInt(line, 0, 2));
1189
1190
1191 final int year = RinexUtils.convert2DigitsYear(RinexUtils.parseInt(line, 3, 2));
1192 final int month = RinexUtils.parseInt(line, 6, 2);
1193 final int day = RinexUtils.parseInt(line, 9, 2);
1194 final int hours = RinexUtils.parseInt(line, 12, 2);
1195 final int min = RinexUtils.parseInt(line, 15, 2);
1196 final double sec = RinexUtils.parseDouble(line, 17, 5);
1197 pi.glonassNav.setEpochToc(new AbsoluteDate(year, month, day, hours, min, sec,
1198 pi.timeScales.getUTC()));
1199
1200
1201 pi.glonassNav.setTauN(-RinexUtils.parseDouble(line, 22, 19));
1202 pi.glonassNav.setGammaN(RinexUtils.parseDouble(line, 41, 19));
1203 pi.glonassNav.setTime(fmod(RinexUtils.parseDouble(line, 60, 19), Constants.JULIAN_DAY));
1204
1205
1206 pi.glonassNav.setDate(pi.glonassNav.getEpochToc());
1207
1208 } else {
1209 pi.glonassNav.setPRN(RinexUtils.parseInt(line, 1, 2));
1210
1211
1212 pi.glonassNav.setEpochToc(parsePrnSvEpochClock(line, pi.timeScales.getUTC()));
1213
1214
1215 pi.glonassNav.setTauN(-RinexUtils.parseDouble(line, 23, 19));
1216 pi.glonassNav.setGammaN(RinexUtils.parseDouble(line, 42, 19));
1217 pi.glonassNav.setTime(fmod(RinexUtils.parseDouble(line, 61, 19), Constants.JULIAN_DAY));
1218
1219
1220 pi.glonassNav.setDate(pi.glonassNav.getEpochToc());
1221 }
1222
1223 }
1224
1225
1226 @Override
1227 public void parseFirstBroadcastOrbit(final String line, final ParseInfo pi) {
1228 pi.glonassNav.setX(parseBroadcastDouble1(line, pi.initialSpaces, KM));
1229 pi.glonassNav.setXDot(parseBroadcastDouble2(line, pi.initialSpaces, KM_PER_S));
1230 pi.glonassNav.setXDotDot(parseBroadcastDouble3(line, pi.initialSpaces, KM_PER_S2));
1231 pi.glonassNav.setHealth(parseBroadcastDouble4(line, pi.initialSpaces, Unit.NONE));
1232 }
1233
1234
1235 @Override
1236 public void parseSecondBroadcastOrbit(final String line, final ParseInfo pi) {
1237 pi.glonassNav.setY(parseBroadcastDouble1(line, pi.initialSpaces, KM));
1238 pi.glonassNav.setYDot(parseBroadcastDouble2(line, pi.initialSpaces, KM_PER_S));
1239 pi.glonassNav.setYDotDot(parseBroadcastDouble3(line, pi.initialSpaces, KM_PER_S2));
1240 pi.glonassNav.setFrequencyNumber(parseBroadcastDouble4(line, pi.initialSpaces, Unit.NONE));
1241 }
1242
1243
1244 @Override
1245 public void parseThirdBroadcastOrbit(final String line, final ParseInfo pi) {
1246 pi.glonassNav.setZ(parseBroadcastDouble1(line, pi.initialSpaces, KM));
1247 pi.glonassNav.setZDot(parseBroadcastDouble2(line, pi.initialSpaces, KM_PER_S));
1248 pi.glonassNav.setZDotDot(parseBroadcastDouble3(line, pi.initialSpaces, KM_PER_S2));
1249 if (pi.file.getHeader().getFormatVersion() < 3.045) {
1250 pi.closePendingMessage();
1251 }
1252 }
1253
1254
1255 @Override
1256 public void parseFourthBroadcastOrbit(final String line, final ParseInfo pi) {
1257 pi.glonassNav.setStatusFlags(parseBroadcastDouble1(line, pi.initialSpaces, Unit.NONE));
1258 pi.glonassNav.setGroupDelayDifference(parseBroadcastDouble2(line, pi.initialSpaces, Unit.NONE));
1259 pi.glonassNav.setURA(parseBroadcastDouble3(line, pi.initialSpaces, Unit.NONE));
1260 pi.glonassNav.setHealthFlags(parseBroadcastDouble4(line, pi.initialSpaces, Unit.NONE));
1261 pi.closePendingMessage();
1262 }
1263
1264
1265 @Override
1266 public void closeMessage(final ParseInfo pi) {
1267 pi.file.addGlonassNavigationMessage(pi.glonassNav);
1268 pi.glonassNav = null;
1269 }
1270
1271 },
1272
1273
1274 QZSS_LNAV() {
1275
1276
1277 @Override
1278 public void parseSvEpochSvClockLine(final String line, final ParseInfo pi) {
1279 parseSvEpochSvClockLine(line, pi.timeScales.getGPS(), pi.qzssLNav);
1280 }
1281
1282
1283 @Override
1284 public void parseFirstBroadcastOrbit(final String line, final ParseInfo pi) {
1285 pi.qzssLNav.setIODE(parseBroadcastDouble1(line, pi.initialSpaces, Unit.SECOND));
1286 pi.qzssLNav.setCrs(parseBroadcastDouble2(line, pi.initialSpaces, Unit.METRE));
1287 pi.qzssLNav.setDeltaN(parseBroadcastDouble3(line, pi.initialSpaces, RAD_PER_S));
1288 pi.qzssLNav.setM0(parseBroadcastDouble4(line, pi.initialSpaces, Unit.RADIAN));
1289 }
1290
1291
1292 @Override
1293 public void parseSecondBroadcastOrbit(final String line, final ParseInfo pi) {
1294 pi.qzssLNav.setCuc(parseBroadcastDouble1(line, pi.initialSpaces, Unit.RADIAN));
1295 pi.qzssLNav.setE(parseBroadcastDouble2(line, pi.initialSpaces, Unit.NONE));
1296 pi.qzssLNav.setCus(parseBroadcastDouble3(line, pi.initialSpaces, Unit.RADIAN));
1297 pi.qzssLNav.setSqrtA(parseBroadcastDouble4(line, pi.initialSpaces, SQRT_M));
1298 }
1299
1300
1301 @Override
1302 public void parseThirdBroadcastOrbit(final String line, final ParseInfo pi) {
1303 pi.qzssLNav.setTime(parseBroadcastDouble1(line, pi.initialSpaces, Unit.SECOND));
1304 pi.qzssLNav.setCic(parseBroadcastDouble2(line, pi.initialSpaces, Unit.RADIAN));
1305 pi.qzssLNav.setOmega0(parseBroadcastDouble3(line, pi.initialSpaces, Unit.RADIAN));
1306 pi.qzssLNav.setCis(parseBroadcastDouble4(line, pi.initialSpaces, Unit.RADIAN));
1307 }
1308
1309
1310 @Override
1311 public void parseFourthBroadcastOrbit(final String line, final ParseInfo pi) {
1312 pi.qzssLNav.setI0(parseBroadcastDouble1(line, pi.initialSpaces, Unit.RADIAN));
1313 pi.qzssLNav.setCrc(parseBroadcastDouble2(line, pi.initialSpaces, Unit.METRE));
1314 pi.qzssLNav.setPa(parseBroadcastDouble3(line, pi.initialSpaces, Unit.RADIAN));
1315 pi.qzssLNav.setOmegaDot(parseBroadcastDouble4(line, pi.initialSpaces, RAD_PER_S));
1316 }
1317
1318
1319 @Override
1320 public void parseFifthBroadcastOrbit(final String line, final ParseInfo pi) {
1321
1322 pi.qzssLNav.setIDot(parseBroadcastDouble1(line, pi.initialSpaces, RAD_PER_S));
1323
1324
1325
1326 pi.qzssLNav.setWeek(parseBroadcastInt3(line, pi.initialSpaces));
1327 pi.qzssLNav.setDate(new GNSSDate(pi.qzssLNav.getWeek(),
1328 pi.qzssLNav.getTime(),
1329 SatelliteSystem.GPS,
1330 pi.timeScales).getDate());
1331 }
1332
1333
1334 @Override
1335 public void parseSixthBroadcastOrbit(final String line, final ParseInfo pi) {
1336 pi.qzssLNav.setSvAccuracy(parseBroadcastDouble1(line, pi.initialSpaces, Unit.METRE));
1337 pi.qzssLNav.setSvHealth(parseBroadcastInt2(line, pi.initialSpaces));
1338 pi.qzssLNav.setTGD(parseBroadcastDouble3(line, pi.initialSpaces, Unit.SECOND));
1339 pi.qzssLNav.setIODC(parseBroadcastInt4(line, pi.initialSpaces));
1340 }
1341
1342
1343 @Override
1344 public void parseSeventhBroadcastOrbit(final String line, final ParseInfo pi) {
1345 pi.qzssLNav.setTransmissionTime(parseBroadcastDouble1(line, pi.initialSpaces, Unit.SECOND));
1346 pi.qzssLNav.setFitInterval(parseBroadcastInt2(line, pi.initialSpaces));
1347 pi.closePendingMessage();
1348 }
1349
1350
1351 @Override
1352 public void closeMessage(final ParseInfo pi) {
1353 pi.file.addQZSSLegacyNavigationMessage(pi.qzssLNav);
1354 pi.qzssLNav = null;
1355 }
1356
1357 },
1358
1359
1360
1361
1362 QZSS_CNAV() {
1363
1364
1365 @Override
1366 public void parseSvEpochSvClockLine(final String line, final ParseInfo pi) {
1367 parseSvEpochSvClockLine(line, pi.timeScales.getGPS(), pi.qzssCNav);
1368 }
1369
1370
1371 @Override
1372 public void parseFirstBroadcastOrbit(final String line, final ParseInfo pi) {
1373 pi.qzssCNav.setADot(parseBroadcastDouble1(line, pi.initialSpaces, M_PER_S));
1374 pi.qzssCNav.setCrs(parseBroadcastDouble2(line, pi.initialSpaces, Unit.METRE));
1375 pi.qzssCNav.setDeltaN(parseBroadcastDouble3(line, pi.initialSpaces, RAD_PER_S));
1376 pi.qzssCNav.setM0(parseBroadcastDouble4(line, pi.initialSpaces, Unit.RADIAN));
1377 }
1378
1379
1380 @Override
1381 public void parseSecondBroadcastOrbit(final String line, final ParseInfo pi) {
1382 pi.qzssCNav.setCuc(parseBroadcastDouble1(line, pi.initialSpaces, Unit.RADIAN));
1383 pi.qzssCNav.setE(parseBroadcastDouble2(line, pi.initialSpaces, Unit.NONE));
1384 pi.qzssCNav.setCus(parseBroadcastDouble3(line, pi.initialSpaces, Unit.RADIAN));
1385 pi.qzssCNav.setSqrtA(parseBroadcastDouble4(line, pi.initialSpaces, SQRT_M));
1386 }
1387
1388
1389 @Override
1390 public void parseThirdBroadcastOrbit(final String line, final ParseInfo pi) {
1391 pi.qzssCNav.setTime(parseBroadcastDouble1(line, pi.initialSpaces, Unit.SECOND));
1392 pi.qzssCNav.setCic(parseBroadcastDouble2(line, pi.initialSpaces, Unit.RADIAN));
1393 pi.qzssCNav.setOmega0(parseBroadcastDouble3(line, pi.initialSpaces, Unit.RADIAN));
1394 pi.qzssCNav.setCis(parseBroadcastDouble4(line, pi.initialSpaces, Unit.RADIAN));
1395 }
1396
1397
1398 @Override
1399 public void parseFourthBroadcastOrbit(final String line, final ParseInfo pi) {
1400 pi.qzssCNav.setI0(parseBroadcastDouble1(line, pi.initialSpaces, Unit.RADIAN));
1401 pi.qzssCNav.setCrc(parseBroadcastDouble2(line, pi.initialSpaces, Unit.METRE));
1402 pi.qzssCNav.setPa(parseBroadcastDouble3(line, pi.initialSpaces, Unit.RADIAN));
1403 pi.qzssCNav.setOmegaDot(parseBroadcastDouble4(line, pi.initialSpaces, RAD_PER_S));
1404 }
1405
1406
1407 @Override
1408 public void parseFifthBroadcastOrbit(final String line, final ParseInfo pi) {
1409 pi.qzssCNav.setIDot(parseBroadcastDouble1(line, pi.initialSpaces, RAD_PER_S));
1410 pi.qzssCNav.setDeltaN0Dot(parseBroadcastDouble2(line, pi.initialSpaces, RAD_PER_S2));
1411 pi.qzssCNav.setUraiNed0(parseBroadcastInt3(line, pi.initialSpaces));
1412 pi.qzssCNav.setUraiNed1(parseBroadcastInt4(line, pi.initialSpaces));
1413 }
1414
1415
1416 @Override
1417 public void parseSixthBroadcastOrbit(final String line, final ParseInfo pi) {
1418 pi.qzssCNav.setUraiEd(parseBroadcastInt1(line, pi.initialSpaces));
1419 pi.qzssCNav.setSvHealth(parseBroadcastInt2(line, pi.initialSpaces));
1420 pi.qzssCNav.setTGD(parseBroadcastDouble3(line, pi.initialSpaces, Unit.SECOND));
1421 pi.qzssCNav.setUraiNed2(parseBroadcastInt4(line, pi.initialSpaces));
1422 }
1423
1424
1425 @Override
1426 public void parseSeventhBroadcastOrbit(final String line, final ParseInfo pi) {
1427 pi.qzssCNav.setIscL1CA(parseBroadcastDouble1(line, pi.initialSpaces, Unit.SECOND));
1428 pi.qzssCNav.setIscL2C(parseBroadcastDouble2(line, pi.initialSpaces, Unit.SECOND));
1429 pi.qzssCNav.setIscL5I5(parseBroadcastDouble3(line, pi.initialSpaces, Unit.SECOND));
1430 pi.qzssCNav.setIscL5Q5(parseBroadcastDouble4(line, pi.initialSpaces, Unit.SECOND));
1431 }
1432
1433
1434 @Override
1435 public void parseEighthBroadcastOrbit(final String line, final ParseInfo pi) {
1436 if (pi.qzssCNav.isCnv2()) {
1437
1438 pi.qzssCNav.setIscL1CD(parseBroadcastDouble1(line, pi.initialSpaces, Unit.SECOND));
1439 pi.qzssCNav.setIscL1CP(parseBroadcastDouble2(line, pi.initialSpaces, Unit.SECOND));
1440 } else {
1441 parseTransmissionTimeLine(line, pi);
1442 }
1443 }
1444
1445
1446 @Override
1447 public void parseNinthBroadcastOrbit(final String line, final ParseInfo pi) {
1448 parseTransmissionTimeLine(line, pi);
1449 }
1450
1451
1452
1453
1454
1455 private void parseTransmissionTimeLine(final String line, final ParseInfo pi) {
1456 pi.qzssCNav.setTransmissionTime(parseBroadcastDouble1(line, pi.initialSpaces, Unit.SECOND));
1457 pi.closePendingMessage();
1458 }
1459
1460
1461 @Override
1462 public void closeMessage(final ParseInfo pi) {
1463 pi.file.addQZSSCivilianNavigationMessage(pi.qzssCNav);
1464 pi.qzssCNav = null;
1465 }
1466
1467 },
1468
1469
1470 BEIDOU_D1_D2() {
1471
1472
1473 @Override
1474 public void parseSvEpochSvClockLine(final String line, final ParseInfo pi) {
1475 parseSvEpochSvClockLine(line, pi.timeScales.getBDT(), pi.beidouLNav);
1476 }
1477
1478
1479 @Override
1480 public void parseFirstBroadcastOrbit(final String line, final ParseInfo pi) {
1481 pi.beidouLNav.setAODE(parseBroadcastDouble1(line, pi.initialSpaces, Unit.SECOND));
1482 pi.beidouLNav.setCrs(parseBroadcastDouble2(line, pi.initialSpaces, Unit.METRE));
1483 pi.beidouLNav.setDeltaN(parseBroadcastDouble3(line, pi.initialSpaces, RAD_PER_S));
1484 pi.beidouLNav.setM0(parseBroadcastDouble4(line, pi.initialSpaces, Unit.RADIAN));
1485 }
1486
1487
1488 @Override
1489 public void parseSecondBroadcastOrbit(final String line, final ParseInfo pi) {
1490 pi.beidouLNav.setCuc(parseBroadcastDouble1(line, pi.initialSpaces, Unit.RADIAN));
1491 pi.beidouLNav.setE(parseBroadcastDouble2(line, pi.initialSpaces, Unit.NONE));
1492 pi.beidouLNav.setCus(parseBroadcastDouble3(line, pi.initialSpaces, Unit.RADIAN));
1493 pi.beidouLNav.setSqrtA(parseBroadcastDouble4(line, pi.initialSpaces, SQRT_M));
1494 }
1495
1496
1497 @Override
1498 public void parseThirdBroadcastOrbit(final String line, final ParseInfo pi) {
1499 pi.beidouLNav.setTime(parseBroadcastDouble1(line, pi.initialSpaces, Unit.SECOND));
1500 pi.beidouLNav.setCic(parseBroadcastDouble2(line, pi.initialSpaces, Unit.RADIAN));
1501 pi.beidouLNav.setOmega0(parseBroadcastDouble3(line, pi.initialSpaces, Unit.RADIAN));
1502 pi.beidouLNav.setCis(parseBroadcastDouble4(line, pi.initialSpaces, Unit.RADIAN));
1503 }
1504
1505
1506 @Override
1507 public void parseFourthBroadcastOrbit(final String line, final ParseInfo pi) {
1508 pi.beidouLNav.setI0(parseBroadcastDouble1(line, pi.initialSpaces, Unit.RADIAN));
1509 pi.beidouLNav.setCrc(parseBroadcastDouble2(line, pi.initialSpaces, Unit.METRE));
1510 pi.beidouLNav.setPa(parseBroadcastDouble3(line, pi.initialSpaces, Unit.RADIAN));
1511 pi.beidouLNav.setOmegaDot(parseBroadcastDouble4(line, pi.initialSpaces, RAD_PER_S));
1512 }
1513
1514
1515 @Override
1516 public void parseFifthBroadcastOrbit(final String line, final ParseInfo pi) {
1517
1518 pi.beidouLNav.setIDot(parseBroadcastDouble1(line, pi.initialSpaces, RAD_PER_S));
1519
1520 pi.beidouLNav.setWeek(parseBroadcastInt3(line, pi.initialSpaces));
1521 pi.beidouLNav.setDate(new GNSSDate(pi.beidouLNav.getWeek(),
1522 pi.beidouLNav.getTime(),
1523 SatelliteSystem.BEIDOU,
1524 pi.timeScales).getDate());
1525 }
1526
1527
1528 @Override
1529 public void parseSixthBroadcastOrbit(final String line, final ParseInfo pi) {
1530 pi.beidouLNav.setSvAccuracy(parseBroadcastDouble1(line, pi.initialSpaces, Unit.METRE));
1531
1532 pi.beidouLNav.setTGD1(parseBroadcastDouble3(line, pi.initialSpaces, Unit.SECOND));
1533 pi.beidouLNav.setTGD2(parseBroadcastDouble4(line, pi.initialSpaces, Unit.SECOND));
1534 }
1535
1536
1537 @Override
1538 public void parseSeventhBroadcastOrbit(final String line, final ParseInfo pi) {
1539 pi.beidouLNav.setTransmissionTime(parseBroadcastDouble1(line, pi.initialSpaces, Unit.SECOND));
1540 pi.beidouLNav.setAODC(parseBroadcastDouble2(line, pi.initialSpaces, Unit.SECOND));
1541 pi.closePendingMessage();
1542 }
1543
1544
1545 @Override
1546 public void closeMessage(final ParseInfo pi) {
1547 pi.file.addBeidouLegacyNavigationMessage(pi.beidouLNav);
1548 pi.beidouLNav = null;
1549 }
1550
1551 },
1552
1553
1554 BEIDOU_CNV_123() {
1555
1556
1557 @Override
1558 public void parseSvEpochSvClockLine(final String line, final ParseInfo pi) {
1559 parseSvEpochSvClockLine(line, pi.timeScales.getBDT(), pi.beidouCNav);
1560 }
1561
1562
1563 @Override
1564 public void parseFirstBroadcastOrbit(final String line, final ParseInfo pi) {
1565 pi.beidouCNav.setADot(parseBroadcastDouble1(line, pi.initialSpaces, M_PER_S));
1566 pi.beidouCNav.setCrs(parseBroadcastDouble2(line, pi.initialSpaces, Unit.METRE));
1567 pi.beidouCNav.setDeltaN(parseBroadcastDouble3(line, pi.initialSpaces, RAD_PER_S));
1568 pi.beidouCNav.setM0(parseBroadcastDouble4(line, pi.initialSpaces, Unit.RADIAN));
1569 }
1570
1571
1572 @Override
1573 public void parseSecondBroadcastOrbit(final String line, final ParseInfo pi) {
1574 pi.beidouCNav.setCuc(parseBroadcastDouble1(line, pi.initialSpaces, Unit.RADIAN));
1575 pi.beidouCNav.setE(parseBroadcastDouble2(line, pi.initialSpaces, Unit.NONE));
1576 pi.beidouCNav.setCus(parseBroadcastDouble3(line, pi.initialSpaces, Unit.RADIAN));
1577 pi.beidouCNav.setSqrtA(parseBroadcastDouble4(line, pi.initialSpaces, SQRT_M));
1578 }
1579
1580
1581 @Override
1582 public void parseThirdBroadcastOrbit(final String line, final ParseInfo pi) {
1583 pi.beidouCNav.setTime(parseBroadcastDouble1(line, pi.initialSpaces, Unit.SECOND));
1584 pi.beidouCNav.setCic(parseBroadcastDouble2(line, pi.initialSpaces, Unit.RADIAN));
1585 pi.beidouCNav.setOmega0(parseBroadcastDouble3(line, pi.initialSpaces, Unit.RADIAN));
1586 pi.beidouCNav.setCis(parseBroadcastDouble4(line, pi.initialSpaces, Unit.RADIAN));
1587 }
1588
1589
1590 @Override
1591 public void parseFourthBroadcastOrbit(final String line, final ParseInfo pi) {
1592 pi.beidouCNav.setI0(parseBroadcastDouble1(line, pi.initialSpaces, Unit.RADIAN));
1593 pi.beidouCNav.setCrc(parseBroadcastDouble2(line, pi.initialSpaces, Unit.METRE));
1594 pi.beidouCNav.setPa(parseBroadcastDouble3(line, pi.initialSpaces, Unit.RADIAN));
1595 pi.beidouCNav.setOmegaDot(parseBroadcastDouble4(line, pi.initialSpaces, RAD_PER_S));
1596 }
1597
1598
1599 @Override
1600 public void parseFifthBroadcastOrbit(final String line, final ParseInfo pi) {
1601 pi.beidouCNav.setIDot(parseBroadcastDouble1(line, pi.initialSpaces, RAD_PER_S));
1602 pi.beidouCNav.setDeltaN0Dot(parseBroadcastDouble2(line, pi.initialSpaces, RAD_PER_S2));
1603 switch (parseBroadcastInt3(line, pi.initialSpaces)) {
1604 case 0 :
1605 pi.beidouCNav.setSatelliteType(BeidouSatelliteType.RESERVED);
1606 break;
1607 case 1 :
1608 pi.beidouCNav.setSatelliteType(BeidouSatelliteType.GEO);
1609 break;
1610 case 2 :
1611 pi.beidouCNav.setSatelliteType(BeidouSatelliteType.IGSO);
1612 break;
1613 case 3 :
1614 pi.beidouCNav.setSatelliteType(BeidouSatelliteType.MEO);
1615 break;
1616 default:
1617 throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
1618 pi.lineNumber, pi.name, line);
1619 }
1620 pi.beidouCNav.setTime(parseBroadcastDouble4(line, pi.initialSpaces, Unit.SECOND));
1621 }
1622
1623
1624 @Override
1625 public void parseSixthBroadcastOrbit(final String line, final ParseInfo pi) {
1626 pi.beidouCNav.setSisaiOe(parseBroadcastInt1(line, pi.initialSpaces));
1627 pi.beidouCNav.setSisaiOcb(parseBroadcastInt2(line, pi.initialSpaces));
1628 pi.beidouCNav.setSisaiOc1(parseBroadcastInt3(line, pi.initialSpaces));
1629 pi.beidouCNav.setSisaiOc2(parseBroadcastInt4(line, pi.initialSpaces));
1630 }
1631
1632
1633 @Override
1634 public void parseSeventhBroadcastOrbit(final String line, final ParseInfo pi) {
1635 if (pi.beidouCNav.getSignal() == Frequency.B1C) {
1636 pi.beidouCNav.setIscB1CD(parseBroadcastDouble1(line, pi.initialSpaces, Unit.SECOND));
1637
1638 pi.beidouCNav.setTgdB1Cp(parseBroadcastDouble3(line, pi.initialSpaces, Unit.SECOND));
1639 pi.beidouCNav.setTgdB2ap(parseBroadcastDouble4(line, pi.initialSpaces, Unit.SECOND));
1640 } else if (pi.beidouCNav.getSignal() == Frequency.B2A) {
1641
1642 pi.beidouCNav.setIscB2AD(parseBroadcastDouble2(line, pi.initialSpaces, Unit.SECOND));
1643 pi.beidouCNav.setTgdB1Cp(parseBroadcastDouble3(line, pi.initialSpaces, Unit.SECOND));
1644 pi.beidouCNav.setTgdB2ap(parseBroadcastDouble4(line, pi.initialSpaces, Unit.SECOND));
1645 } else {
1646 parseSismaiHealthIntegrity(line, pi);
1647 }
1648 }
1649
1650
1651 @Override
1652 public void parseEighthBroadcastOrbit(final String line, final ParseInfo pi) {
1653 if (pi.beidouCNav.getSignal() == Frequency.B2B) {
1654 pi.beidouCNav.setTransmissionTime(parseBroadcastDouble1(line, pi.initialSpaces, Unit.SECOND));
1655 pi.closePendingMessage();
1656 } else {
1657 parseSismaiHealthIntegrity(line, pi);
1658 }
1659 }
1660
1661
1662 @Override
1663 public void parseNinthBroadcastOrbit(final String line, final ParseInfo pi) {
1664 pi.beidouCNav.setTransmissionTime(parseBroadcastDouble1(line, pi.initialSpaces, Unit.SECOND));
1665
1666
1667 pi.beidouCNav.setIODE(parseBroadcastInt4(line, pi.initialSpaces));
1668 pi.closePendingMessage();
1669 }
1670
1671
1672 @Override
1673 public void closeMessage(final ParseInfo pi) {
1674 pi.file.addBeidouCivilianNavigationMessage(pi.beidouCNav);
1675 pi.beidouCNav = null;
1676 }
1677
1678
1679
1680
1681
1682
1683 private void parseSismaiHealthIntegrity(final String line, final ParseInfo pi) {
1684 pi.beidouCNav.setSismai(parseBroadcastInt1(line, pi.initialSpaces));
1685 pi.beidouCNav.setHealth(parseBroadcastInt2(line, pi.initialSpaces));
1686 pi.beidouCNav.setIntegrityFlags(parseBroadcastInt3(line, pi.initialSpaces));
1687 pi.beidouCNav.setIODC(parseBroadcastInt4(line, pi.initialSpaces));
1688 }
1689
1690 },
1691
1692
1693 SBAS() {
1694
1695
1696 @Override
1697 public void parseSvEpochSvClockLine(final String line, final ParseInfo pi) {
1698
1699
1700 pi.sbasNav.setPRN(RinexUtils.parseInt(line, 1, 2));
1701
1702
1703 final int version100 = (int) FastMath.rint(pi.file.getHeader().getFormatVersion() * 100);
1704 final TimeScale timeScale = (version100 == 301) ? pi.timeScales.getUTC() : pi.timeScales.getGPS();
1705
1706 pi.sbasNav.setEpochToc(parsePrnSvEpochClock(line, timeScale));
1707 pi.sbasNav.setAGf0(parseBroadcastDouble2(line, pi.initialSpaces, Unit.SECOND));
1708 pi.sbasNav.setAGf1(parseBroadcastDouble3(line, pi.initialSpaces, S_PER_S));
1709 pi.sbasNav.setTime(parseBroadcastDouble4(line, pi.initialSpaces, Unit.SECOND));
1710
1711
1712 pi.sbasNav.setDate(pi.sbasNav.getEpochToc());
1713
1714 }
1715
1716
1717 @Override
1718 public void parseFirstBroadcastOrbit(final String line, final ParseInfo pi) {
1719 pi.sbasNav.setX(parseBroadcastDouble1(line, pi.initialSpaces, KM));
1720 pi.sbasNav.setXDot(parseBroadcastDouble2(line, pi.initialSpaces, KM_PER_S));
1721 pi.sbasNav.setXDotDot(parseBroadcastDouble3(line, pi.initialSpaces, KM_PER_S2));
1722 pi.sbasNav.setHealth(parseBroadcastDouble4(line, pi.initialSpaces, Unit.NONE));
1723 }
1724
1725
1726 @Override
1727 public void parseSecondBroadcastOrbit(final String line, final ParseInfo pi) {
1728 pi.sbasNav.setY(parseBroadcastDouble1(line, pi.initialSpaces, KM));
1729 pi.sbasNav.setYDot(parseBroadcastDouble2(line, pi.initialSpaces, KM_PER_S));
1730 pi.sbasNav.setYDotDot(parseBroadcastDouble3(line, pi.initialSpaces, KM_PER_S2));
1731 pi.sbasNav.setURA(parseBroadcastDouble4(line, pi.initialSpaces, Unit.NONE));
1732 }
1733
1734
1735 @Override
1736 public void parseThirdBroadcastOrbit(final String line, final ParseInfo pi) {
1737 pi.sbasNav.setZ(parseBroadcastDouble1(line, pi.initialSpaces, KM));
1738 pi.sbasNav.setZDot(parseBroadcastDouble2(line, pi.initialSpaces, KM_PER_S));
1739 pi.sbasNav.setZDotDot(parseBroadcastDouble3(line, pi.initialSpaces, KM_PER_S2));
1740 pi.sbasNav.setIODN(parseBroadcastDouble4(line, pi.initialSpaces, Unit.NONE));
1741 pi.closePendingMessage();
1742 }
1743
1744
1745 @Override
1746 public void closeMessage(final ParseInfo pi) {
1747 pi.file.addSBASNavigationMessage(pi.sbasNav);
1748 pi.sbasNav = null;
1749 }
1750
1751 },
1752
1753
1754 IRNSS() {
1755
1756
1757 @Override
1758 public void parseSvEpochSvClockLine(final String line, final ParseInfo pi) {
1759 parseSvEpochSvClockLine(line, pi.timeScales.getIRNSS(), pi.irnssNav);
1760 }
1761
1762
1763 @Override
1764 public void parseFirstBroadcastOrbit(final String line, final ParseInfo pi) {
1765 pi.irnssNav.setIODEC(parseBroadcastDouble1(line, pi.initialSpaces, Unit.SECOND));
1766 pi.irnssNav.setCrs(parseBroadcastDouble2(line, pi.initialSpaces, Unit.METRE));
1767 pi.irnssNav.setDeltaN(parseBroadcastDouble3(line, pi.initialSpaces, RAD_PER_S));
1768 pi.irnssNav.setM0(parseBroadcastDouble4(line, pi.initialSpaces, Unit.RADIAN));
1769 }
1770
1771
1772 @Override
1773 public void parseSecondBroadcastOrbit(final String line, final ParseInfo pi) {
1774 pi.irnssNav.setCuc(parseBroadcastDouble1(line, pi.initialSpaces, Unit.RADIAN));
1775 pi.irnssNav.setE(parseBroadcastDouble2(line, pi.initialSpaces, Unit.NONE));
1776 pi.irnssNav.setCus(parseBroadcastDouble3(line, pi.initialSpaces, Unit.RADIAN));
1777 pi.irnssNav.setSqrtA(parseBroadcastDouble4(line, pi.initialSpaces, SQRT_M));
1778 }
1779
1780
1781 @Override
1782 public void parseThirdBroadcastOrbit(final String line, final ParseInfo pi) {
1783 pi.irnssNav.setTime(parseBroadcastDouble1(line, pi.initialSpaces, Unit.SECOND));
1784 pi.irnssNav.setCic(parseBroadcastDouble2(line, pi.initialSpaces, Unit.RADIAN));
1785 pi.irnssNav.setOmega0(parseBroadcastDouble3(line, pi.initialSpaces, Unit.RADIAN));
1786 pi.irnssNav.setCis(parseBroadcastDouble4(line, pi.initialSpaces, Unit.RADIAN));
1787 }
1788
1789
1790 @Override
1791 public void parseFourthBroadcastOrbit(final String line, final ParseInfo pi) {
1792 pi.irnssNav.setI0(parseBroadcastDouble1(line, pi.initialSpaces, Unit.RADIAN));
1793 pi.irnssNav.setCrc(parseBroadcastDouble2(line, pi.initialSpaces, Unit.METRE));
1794 pi.irnssNav.setPa(parseBroadcastDouble3(line, pi.initialSpaces, Unit.RADIAN));
1795 pi.irnssNav.setOmegaDot(parseBroadcastDouble4(line, pi.initialSpaces, RAD_PER_S));
1796 }
1797
1798
1799 @Override
1800 public void parseFifthBroadcastOrbit(final String line, final ParseInfo pi) {
1801
1802 pi.irnssNav.setIDot(parseBroadcastDouble1(line, pi.initialSpaces, RAD_PER_S));
1803
1804 pi.irnssNav.setWeek(parseBroadcastInt3(line, pi.initialSpaces));
1805 pi.irnssNav.setDate(new GNSSDate(pi.irnssNav.getWeek(),
1806 pi.irnssNav.getTime(),
1807 SatelliteSystem.GPS,
1808 pi.timeScales).getDate());
1809 }
1810
1811
1812 @Override
1813 public void parseSixthBroadcastOrbit(final String line, final ParseInfo pi) {
1814 pi.irnssNav.setURA(parseBroadcastDouble1(line, pi.initialSpaces, Unit.METRE));
1815 pi.irnssNav.setSvHealth(parseBroadcastDouble2(line, pi.initialSpaces, Unit.NONE));
1816 pi.irnssNav.setTGD(parseBroadcastDouble3(line, pi.initialSpaces, Unit.SECOND));
1817 }
1818
1819
1820 @Override
1821 public void parseSeventhBroadcastOrbit(final String line, final ParseInfo pi) {
1822 pi.irnssNav.setTransmissionTime(parseBroadcastDouble1(line, pi.initialSpaces, Unit.SECOND));
1823 pi.closePendingMessage();
1824 }
1825
1826
1827 @Override
1828 public void closeMessage(final ParseInfo pi) {
1829 pi.file.addIRNSSNavigationMessage(pi.irnssNav);
1830 pi.irnssNav = null;
1831 }
1832
1833 };
1834
1835
1836
1837
1838
1839
1840
1841
1842 private static SatelliteSystemLineParser getParser(final SatelliteSystem system, final String type,
1843 final ParseInfo parseInfo, final String line) {
1844 switch (system) {
1845 case GPS :
1846 if (type == null || type.equals(LegacyNavigationMessage.LNAV)) {
1847 parseInfo.gpsLNav = new GPSLegacyNavigationMessage();
1848 return GPS_LNAV;
1849 } else if (type.equals(CivilianNavigationMessage.CNAV)) {
1850 parseInfo.gpsCNav = new GPSCivilianNavigationMessage(false);
1851 return GPS_CNAV;
1852 } else if (type.equals(CivilianNavigationMessage.CNV2)) {
1853 parseInfo.gpsCNav = new GPSCivilianNavigationMessage(true);
1854 return GPS_CNAV;
1855 }
1856 break;
1857 case GALILEO :
1858 if (type == null || type.equals("INAV") || type.equals("FNAV")) {
1859 parseInfo.galileoNav = new GalileoNavigationMessage();
1860 return GALILEO;
1861 }
1862 break;
1863 case GLONASS :
1864 if (type == null || type.equals("FDMA")) {
1865 parseInfo.glonassNav = new GLONASSNavigationMessage();
1866 return GLONASS;
1867 }
1868 break;
1869 case QZSS :
1870 if (type == null || type.equals(LegacyNavigationMessage.LNAV)) {
1871 parseInfo.qzssLNav = new QZSSLegacyNavigationMessage();
1872 return QZSS_LNAV;
1873 } else if (type.equals(CivilianNavigationMessage.CNAV)) {
1874 parseInfo.qzssCNav = new QZSSCivilianNavigationMessage(false);
1875 return QZSS_CNAV;
1876 } else if (type.equals(CivilianNavigationMessage.CNV2)) {
1877 parseInfo.qzssCNav = new QZSSCivilianNavigationMessage(true);
1878 return QZSS_CNAV;
1879 }
1880 break;
1881 case BEIDOU :
1882 if (type == null ||
1883 type.equals(BeidouLegacyNavigationMessage.D1) ||
1884 type.equals(BeidouLegacyNavigationMessage.D2)) {
1885 parseInfo.beidouLNav = new BeidouLegacyNavigationMessage();
1886 return BEIDOU_D1_D2;
1887 } else if (type.equals(BeidouCivilianNavigationMessage.CNV1)) {
1888 parseInfo.beidouCNav = new BeidouCivilianNavigationMessage(Frequency.B1C);
1889 return BEIDOU_CNV_123;
1890 } else if (type.equals(BeidouCivilianNavigationMessage.CNV2)) {
1891 parseInfo.beidouCNav = new BeidouCivilianNavigationMessage(Frequency.B2A);
1892 return BEIDOU_CNV_123;
1893 } else if (type.equals(BeidouCivilianNavigationMessage.CNV3)) {
1894 parseInfo.beidouCNav = new BeidouCivilianNavigationMessage(Frequency.B2B);
1895 return BEIDOU_CNV_123;
1896 }
1897 break;
1898 case IRNSS :
1899 if (type == null || type.equals("LNAV")) {
1900 parseInfo.irnssNav = new IRNSSNavigationMessage();
1901 return IRNSS;
1902 }
1903 break;
1904 case SBAS :
1905 if (type == null || type.equals("SBAS")) {
1906 parseInfo.sbasNav = new SBASNavigationMessage();
1907 return SBAS;
1908 }
1909 break;
1910 default:
1911
1912 }
1913 throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
1914 parseInfo.lineNumber, parseInfo.name, line);
1915 }
1916
1917
1918
1919
1920
1921
1922
1923 protected void parseSvEpochSvClockLineRinex2(final String line, final TimeScale timeScale,
1924 final AbstractNavigationMessage message) {
1925
1926 message.setPRN(RinexUtils.parseInt(line, 0, 2));
1927
1928
1929 final int year = RinexUtils.convert2DigitsYear(RinexUtils.parseInt(line, 2, 3));
1930 final int month = RinexUtils.parseInt(line, 5, 3);
1931 final int day = RinexUtils.parseInt(line, 8, 3);
1932 final int hours = RinexUtils.parseInt(line, 11, 3);
1933 final int min = RinexUtils.parseInt(line, 14, 3);
1934 final double sec = RinexUtils.parseDouble(line, 17, 5);
1935 message.setEpochToc(new AbsoluteDate( year, month, day, hours, min, sec, timeScale));
1936
1937
1938 message.setAf0(RinexUtils.parseDouble(line, 22, 19));
1939 message.setAf1(RinexUtils.parseDouble(line, 41, 19));
1940 message.setAf2(RinexUtils.parseDouble(line, 60, 19));
1941
1942 }
1943
1944
1945
1946
1947
1948
1949
1950 protected void parseSvEpochSvClockLine(final String line, final TimeScale timeScale,
1951 final AbstractNavigationMessage message) {
1952
1953 message.setPRN(RinexUtils.parseInt(line, 1, 2));
1954
1955
1956 message.setEpochToc(parsePrnSvEpochClock(line, timeScale));
1957
1958
1959 message.setAf0(RinexUtils.parseDouble(line, 23, 19));
1960 message.setAf1(RinexUtils.parseDouble(line, 42, 19));
1961 message.setAf2(RinexUtils.parseDouble(line, 61, 19));
1962
1963 }
1964
1965
1966
1967
1968
1969
1970 protected AbsoluteDate parsePrnSvEpochClock(final String line, final TimeScale timeScale) {
1971 final int year = RinexUtils.parseInt(line, 4, 4);
1972 final int month = RinexUtils.parseInt(line, 9, 2);
1973 final int day = RinexUtils.parseInt(line, 12, 2);
1974 final int hours = RinexUtils.parseInt(line, 15, 2);
1975 final int min = RinexUtils.parseInt(line, 18, 2);
1976 final int sec = RinexUtils.parseInt(line, 21, 2);
1977 return new AbsoluteDate(year, month, day, hours, min, sec, timeScale);
1978 }
1979
1980
1981
1982
1983
1984
1985
1986 protected double parseBroadcastDouble1(final String line, final int initialSpaces, final Unit unit) {
1987 return unit.toSI(RinexUtils.parseDouble(line, initialSpaces, 19));
1988 }
1989
1990
1991
1992
1993
1994
1995 protected int parseBroadcastInt1(final String line, final int initialSpaces) {
1996 return (int) FastMath.rint(RinexUtils.parseDouble(line, initialSpaces, 19));
1997 }
1998
1999
2000
2001
2002
2003
2004
2005 protected double parseBroadcastDouble2(final String line, final int initialSpaces, final Unit unit) {
2006 return unit.toSI(RinexUtils.parseDouble(line, initialSpaces + 19, 19));
2007 }
2008
2009
2010
2011
2012
2013
2014 protected int parseBroadcastInt2(final String line, final int initialSpaces) {
2015 return (int) FastMath.rint(RinexUtils.parseDouble(line, initialSpaces + 19, 19));
2016 }
2017
2018
2019
2020
2021
2022
2023
2024 protected double parseBroadcastDouble3(final String line, final int initialSpaces, final Unit unit) {
2025 return unit.toSI(RinexUtils.parseDouble(line, initialSpaces + 38, 19));
2026 }
2027
2028
2029
2030
2031
2032
2033 protected int parseBroadcastInt3(final String line, final int initialSpaces) {
2034 return (int) FastMath.rint(RinexUtils.parseDouble(line, initialSpaces + 38, 19));
2035 }
2036
2037
2038
2039
2040
2041
2042
2043 protected double parseBroadcastDouble4(final String line, final int initialSpaces, final Unit unit) {
2044 return unit.toSI(RinexUtils.parseDouble(line, initialSpaces + 57, 19));
2045 }
2046
2047
2048
2049
2050
2051
2052 protected int parseBroadcastInt4(final String line, final int initialSpaces) {
2053 return (int) FastMath.rint(RinexUtils.parseDouble(line, initialSpaces + 57, 19));
2054 }
2055
2056
2057
2058
2059
2060
2061 public abstract void parseSvEpochSvClockLine(String line, ParseInfo pi);
2062
2063
2064
2065
2066
2067
2068 public abstract void parseFirstBroadcastOrbit(String line, ParseInfo pi);
2069
2070
2071
2072
2073
2074
2075 public abstract void parseSecondBroadcastOrbit(String line, ParseInfo pi);
2076
2077
2078
2079
2080
2081
2082 public abstract void parseThirdBroadcastOrbit(String line, ParseInfo pi);
2083
2084
2085
2086
2087
2088
2089 public void parseFourthBroadcastOrbit(final String line, final ParseInfo pi) {
2090
2091 throw new OrekitInternalError(null);
2092 }
2093
2094
2095
2096
2097
2098
2099 public void parseFifthBroadcastOrbit(final String line, final ParseInfo pi) {
2100
2101 throw new OrekitInternalError(null);
2102 }
2103
2104
2105
2106
2107
2108
2109 public void parseSixthBroadcastOrbit(final String line, final ParseInfo pi) {
2110
2111 throw new OrekitInternalError(null);
2112 }
2113
2114
2115
2116
2117
2118
2119 public void parseSeventhBroadcastOrbit(final String line, final ParseInfo pi) {
2120
2121 throw new OrekitInternalError(null);
2122 }
2123
2124
2125
2126
2127
2128
2129 public void parseEighthBroadcastOrbit(final String line, final ParseInfo pi) {
2130
2131 throw new OrekitInternalError(null);
2132 }
2133
2134
2135
2136
2137
2138
2139 public void parseNinthBroadcastOrbit(final String line, final ParseInfo pi) {
2140
2141 throw new OrekitInternalError(null);
2142 }
2143
2144
2145
2146
2147
2148 public abstract void closeMessage(ParseInfo pi);
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160 private static double fmod(final double a, final double b) {
2161 final double x = (int) (a / b);
2162 return a - x * b;
2163 }
2164
2165 }
2166
2167
2168 @FunctionalInterface
2169 private interface ParsingMethod {
2170
2171
2172
2173
2174 void parse(String line, ParseInfo parseInfo);
2175 }
2176
2177 }