1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.files.ccsds.ndm.adm.acm;
18
19 import java.util.ArrayList;
20 import java.util.Collections;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.function.Function;
24 import java.util.regex.Pattern;
25
26 import org.orekit.data.DataContext;
27 import org.orekit.data.DataSource;
28 import org.orekit.errors.OrekitException;
29 import org.orekit.errors.OrekitIllegalArgumentException;
30 import org.orekit.errors.OrekitMessages;
31 import org.orekit.files.ccsds.definitions.CcsdsFrameMapper;
32 import org.orekit.files.ccsds.ndm.ParsedUnitsBehavior;
33 import org.orekit.files.ccsds.ndm.adm.AdmHeader;
34 import org.orekit.files.ccsds.ndm.adm.AdmMetadataKey;
35 import org.orekit.files.ccsds.ndm.adm.AdmParser;
36 import org.orekit.files.ccsds.ndm.odm.UserDefined;
37 import org.orekit.files.ccsds.ndm.odm.ocm.Ocm;
38 import org.orekit.files.ccsds.section.HeaderProcessingState;
39 import org.orekit.files.ccsds.section.KvnStructureProcessingState;
40 import org.orekit.files.ccsds.section.MetadataKey;
41 import org.orekit.files.ccsds.section.Segment;
42 import org.orekit.files.ccsds.section.XmlStructureProcessingState;
43 import org.orekit.files.ccsds.utils.ContextBinding;
44 import org.orekit.files.ccsds.utils.FileFormat;
45 import org.orekit.files.ccsds.utils.lexical.ParseToken;
46 import org.orekit.files.ccsds.utils.lexical.TokenType;
47 import org.orekit.files.ccsds.utils.lexical.UserDefinedXmlTokenBuilder;
48 import org.orekit.files.ccsds.utils.lexical.XmlTokenBuilder;
49 import org.orekit.files.ccsds.utils.parsing.ProcessingState;
50 import org.orekit.files.general.AttitudeEphemerisFileParser;
51 import org.orekit.frames.Frame;
52 import org.orekit.time.AbsoluteDate;
53 import org.orekit.utils.IERSConventions;
54
55
56
57
58
59 public class AcmParser extends AdmParser<Acm, AcmParser> implements AttitudeEphemerisFileParser<Acm> {
60
61
62 private static final Pattern SPLIT_AT_BLANKS = Pattern.compile("\\s+");
63
64
65 private AdmHeader header;
66
67
68 private AcmMetadata metadata;
69
70
71 private ContextBinding context;
72
73
74 private List<AttitudeStateHistory> attitudeBlocks;
75
76
77 private AttitudeStateHistoryMetadata currentAttitudeStateHistoryMetadata;
78
79
80 private List<AttitudeState> currentAttitudeStateHistory;
81
82
83 private AttitudePhysicalProperties physicBlock;
84
85
86 private List<AttitudeCovarianceHistory> covarianceBlocks;
87
88
89 private AttitudeCovarianceHistoryMetadata currentCovarianceHistoryMetadata;
90
91
92 private List<AttitudeCovariance> currentCovarianceHistory;
93
94
95 private List<AttitudeManeuver> maneuverBlocks;
96
97
98 private AttitudeManeuver currentManeuver;
99
100
101 private AttitudeDetermination attitudeDeterminationBlock;
102
103
104 private AttitudeDeterminationSensor attitudeDeterminationSensorBlock;
105
106
107 private UserDefined userDefinedBlock;
108
109
110 private ProcessingState structureProcessor;
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127 public AcmParser(final IERSConventions conventions, final boolean simpleEOP, final DataContext dataContext,
128 final ParsedUnitsBehavior parsedUnitsBehavior,
129 final Function<ParseToken, List<ParseToken>>[] filters,
130 final CcsdsFrameMapper frameMapper) {
131 super(Acm.ROOT, Acm.FORMAT_VERSION_KEY, conventions, simpleEOP, dataContext, null,
132 parsedUnitsBehavior, filters, frameMapper);
133 }
134
135
136 @Override
137 public Map<String, XmlTokenBuilder> getSpecialXmlElementsBuilders() {
138
139 final Map<String, XmlTokenBuilder> builders = super.getSpecialXmlElementsBuilders();
140
141
142 builders.put(UserDefined.USER_DEFINED_XML_TAG, new UserDefinedXmlTokenBuilder());
143
144 return builders;
145
146 }
147
148
149 @Override
150 public Acm parse(final DataSource source) {
151 return parseMessage(source);
152 }
153
154
155 @Override
156 public AdmHeader getHeader() {
157 return header;
158 }
159
160
161 @Override
162 public void reset(final FileFormat fileFormat) {
163 header = new AdmHeader();
164 metadata = null;
165 context = null;
166 attitudeBlocks = null;
167 physicBlock = null;
168 covarianceBlocks = null;
169 maneuverBlocks = null;
170 attitudeDeterminationBlock = null;
171 userDefinedBlock = null;
172 if (fileFormat == FileFormat.XML) {
173 structureProcessor = new XmlStructureProcessingState(Acm.ROOT, this);
174 reset(fileFormat, structureProcessor);
175 } else {
176 structureProcessor = new KvnStructureProcessingState(this);
177 reset(fileFormat, new HeaderProcessingState(this));
178 }
179 }
180
181
182 @Override
183 public boolean prepareHeader() {
184 anticipateNext(new HeaderProcessingState(this));
185 return true;
186 }
187
188
189 @Override
190 public boolean inHeader() {
191 anticipateNext(structureProcessor);
192 return true;
193 }
194
195
196 @Override
197 public boolean finalizeHeader() {
198 header.validate(header.getFormatVersion());
199 return true;
200 }
201
202
203 @Override
204 public boolean prepareMetadata() {
205 if (metadata != null) {
206 return false;
207 }
208 metadata = new AcmMetadata(getFrameMapper());
209 context = new ContextBinding(this::getConventions, this::isSimpleEOP, this::getDataContext,
210 this::getParsedUnitsBehavior, metadata::getEpochT0, metadata::getTimeSystem,
211 () -> 0.0, () -> 1.0);
212 anticipateNext(this::processMetadataToken);
213 return true;
214 }
215
216
217 @Override
218 public boolean inMetadata() {
219 anticipateNext(structureProcessor);
220 return true;
221 }
222
223
224 @Override
225 public boolean finalizeMetadata() {
226 metadata.validate(header.getFormatVersion());
227 anticipateNext(this::processDataSubStructureToken);
228 return true;
229 }
230
231
232 @Override
233 public boolean prepareData() {
234 anticipateNext(this::processDataSubStructureToken);
235 return true;
236 }
237
238
239 @Override
240 public boolean inData() {
241 return true;
242 }
243
244
245 @Override
246 public boolean finalizeData() {
247 return true;
248 }
249
250
251
252
253
254
255 boolean manageAttitudeStateSection(final boolean starting) {
256 if (starting) {
257 if (attitudeBlocks == null) {
258
259 attitudeBlocks = new ArrayList<>();
260 }
261 currentAttitudeStateHistoryMetadata =
262 new AttitudeStateHistoryMetadata(getFrameMapper());
263 currentAttitudeStateHistory = new ArrayList<>();
264 anticipateNext(this::processAttitudeStateToken);
265 } else {
266 anticipateNext(structureProcessor);
267 attitudeBlocks.add(new AttitudeStateHistory(currentAttitudeStateHistoryMetadata,
268 currentAttitudeStateHistory));
269 }
270 return true;
271 }
272
273
274
275
276
277
278 boolean managePhysicalPropertiesSection(final boolean starting) {
279 if (starting) {
280 physicBlock = new AttitudePhysicalProperties();
281 anticipateNext(this::processPhysicalPropertyToken);
282 } else {
283 anticipateNext(structureProcessor);
284 }
285 return true;
286 }
287
288
289
290
291
292
293 boolean manageCovarianceHistorySection(final boolean starting) {
294 if (starting) {
295 if (covarianceBlocks == null) {
296
297 covarianceBlocks = new ArrayList<>();
298 }
299 currentCovarianceHistoryMetadata = new AttitudeCovarianceHistoryMetadata();
300 currentCovarianceHistory = new ArrayList<>();
301 anticipateNext(this::processCovarianceToken);
302 } else {
303 anticipateNext(structureProcessor);
304 covarianceBlocks.add(new AttitudeCovarianceHistory(currentCovarianceHistoryMetadata,
305 currentCovarianceHistory));
306 currentCovarianceHistoryMetadata = null;
307 currentCovarianceHistory = null;
308 }
309 return true;
310 }
311
312
313
314
315
316
317 boolean manageManeuversSection(final boolean starting) {
318 if (starting) {
319 if (maneuverBlocks == null) {
320
321 maneuverBlocks = new ArrayList<>();
322 }
323 currentManeuver = new AttitudeManeuver();
324 anticipateNext(this::processManeuverToken);
325 } else {
326 anticipateNext(structureProcessor);
327 maneuverBlocks.add(currentManeuver);
328 currentManeuver = null;
329 }
330 return true;
331 }
332
333
334
335
336
337
338 boolean manageAttitudeDeterminationSection(final boolean starting) {
339 if (starting) {
340 attitudeDeterminationBlock =
341 new AttitudeDetermination(getFrameMapper());
342 anticipateNext(this::processAttitudeDeterminationToken);
343 } else {
344 anticipateNext(structureProcessor);
345 }
346 return true;
347 }
348
349
350
351
352
353
354 boolean manageAttitudeDeterminationSensorSection(final boolean starting) {
355 if (starting) {
356 attitudeDeterminationSensorBlock = new AttitudeDeterminationSensor();
357 anticipateNext(this::processAttitudeDeterminationSensorToken);
358 } else {
359 anticipateNext(this::processDataSubStructureToken);
360 }
361 return true;
362 }
363
364
365
366
367
368
369 boolean manageUserDefinedParametersSection(final boolean starting) {
370 if (starting) {
371 userDefinedBlock = new UserDefined();
372 anticipateNext(this::processUserDefinedToken);
373 } else {
374 anticipateNext(structureProcessor);
375 }
376 return true;
377 }
378
379
380 @Override
381 public Acm build() {
382
383 if (userDefinedBlock != null && userDefinedBlock.getParameters().isEmpty()) {
384 userDefinedBlock = null;
385 }
386
387 final AcmData data = new AcmData(attitudeBlocks, physicBlock, covarianceBlocks,
388 maneuverBlocks, attitudeDeterminationBlock, userDefinedBlock);
389 data.validate(header.getFormatVersion());
390
391 return new Acm(header, Collections.singletonList(new Segment<>(metadata, data)),
392 getConventions(), getDataContext());
393
394 }
395
396
397
398
399
400 private boolean processMetadataToken(final ParseToken token) {
401 inMetadata();
402 try {
403 return token.getName() != null &&
404 MetadataKey.valueOf(token.getName()).process(token, context, metadata);
405 } catch (IllegalArgumentException iaeM) {
406 try {
407 return AdmMetadataKey.valueOf(token.getName()).process(token, context, metadata);
408 } catch (IllegalArgumentException iaeD) {
409 try {
410 return AcmMetadataKey.valueOf(token.getName()).process(token, context, metadata);
411 } catch (IllegalArgumentException iaeC) {
412
413 return false;
414 }
415 }
416 }
417 }
418
419
420
421
422
423 private boolean processDataSubStructureToken(final ParseToken token) {
424 try {
425 return token.getName() != null &&
426 AcmDataSubStructureKey.valueOf(token.getName()).process(token, this);
427 } catch (IllegalArgumentException iae) {
428
429 return false;
430 }
431 }
432
433
434
435
436
437 private boolean processAttitudeStateToken(final ParseToken token) {
438 if (token.getName() != null && !token.getName().equals(Acm.ATT_LINE)) {
439
440 try {
441 return AttitudeStateHistoryMetadataKey.valueOf(token.getName()).
442 process(token, context, currentAttitudeStateHistoryMetadata);
443 } catch (IllegalArgumentException iae) {
444
445 return false;
446 }
447 } else {
448
449 if (currentAttitudeStateHistory.isEmpty()) {
450
451 currentAttitudeStateHistoryMetadata.validate(header.getFormatVersion());
452 anticipateNext(this::processDataSubStructureToken);
453 }
454 if (token.getType() == TokenType.START || token.getType() == TokenType.STOP) {
455 return true;
456 }
457 try {
458 final String[] fields = SPLIT_AT_BLANKS.split(token.getRawContent().trim());
459 final AbsoluteDate epoch = context.getTimeSystem().getConverter(context).parse(fields[0]);
460 return currentAttitudeStateHistory.add(new AttitudeState(currentAttitudeStateHistoryMetadata.getAttitudeType(),
461 currentAttitudeStateHistoryMetadata.getRateType(),
462 epoch, fields, 1));
463 } catch (NumberFormatException | OrekitIllegalArgumentException e) {
464 throw new OrekitException(e, OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
465 token.getLineNumber(), token.getFileName(), token.getContentAsNormalizedString());
466 }
467 }
468 }
469
470
471
472
473
474 private boolean processPhysicalPropertyToken(final ParseToken token) {
475 anticipateNext(this::processDataSubStructureToken);
476 try {
477 return token.getName() != null &&
478 AttitudePhysicalPropertiesKey.valueOf(token.getName()).process(token, context, physicBlock);
479 } catch (IllegalArgumentException iae) {
480
481 return false;
482 }
483 }
484
485
486
487
488
489 private boolean processCovarianceToken(final ParseToken token) {
490 if (token.getName() != null && !token.getName().equals(Ocm.COV_LINE)) {
491
492 try {
493 return AttitudeCovarianceHistoryMetadataKey.valueOf(token.getName()).
494 process(token, context, currentCovarianceHistoryMetadata);
495 } catch (IllegalArgumentException iae) {
496
497 return false;
498 }
499 } else {
500
501 if (currentCovarianceHistory.isEmpty()) {
502
503 currentCovarianceHistoryMetadata.validate(header.getFormatVersion());
504 anticipateNext(this::processDataSubStructureToken);
505 }
506 if (token.getType() == TokenType.START || token.getType() == TokenType.STOP) {
507 return true;
508 }
509 try {
510 final String[] fields = SPLIT_AT_BLANKS.split(token.getRawContent().trim());
511 currentCovarianceHistory.add(new AttitudeCovariance(currentCovarianceHistoryMetadata.getCovType(),
512 context.getTimeSystem().getConverter(context).parse(fields[0]),
513 fields, 1));
514 return true;
515 } catch (NumberFormatException nfe) {
516 throw new OrekitException(nfe, OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
517 token.getLineNumber(), token.getFileName(), token.getContentAsNormalizedString());
518 }
519 }
520 }
521
522
523
524
525
526 private boolean processManeuverToken(final ParseToken token) {
527 anticipateNext(this::processDataSubStructureToken);
528 try {
529 return token.getName() != null &&
530 AttitudeManeuverKey.valueOf(token.getName()).process(token, context, currentManeuver);
531 } catch (IllegalArgumentException iae) {
532
533 return false;
534 }
535 }
536
537
538
539
540
541 private boolean processAttitudeDeterminationToken(final ParseToken token) {
542 anticipateNext(attitudeDeterminationSensorBlock != null ?
543 this::processAttitudeDeterminationSensorToken :
544 this::processDataSubStructureToken);
545 if (token.getName() == null) {
546 return false;
547 }
548 try {
549 return AttitudeDeterminationKey.valueOf(token.getName()).process(token, this, context, attitudeDeterminationBlock);
550 } catch (IllegalArgumentException iae1) {
551
552 return false;
553 }
554 }
555
556
557
558
559
560 private boolean processAttitudeDeterminationSensorToken(final ParseToken token) {
561 anticipateNext(this::processAttitudeDeterminationToken);
562 if (token.getName() == null) {
563 return false;
564 }
565 try {
566 return AttitudeDeterminationSensorKey.valueOf(token.getName()).process(token, context, attitudeDeterminationSensorBlock);
567 } catch (IllegalArgumentException iae1) {
568
569 attitudeDeterminationBlock.addSensor(attitudeDeterminationSensorBlock);
570 attitudeDeterminationSensorBlock = null;
571 return false;
572 }
573 }
574
575
576
577
578
579 private boolean processUserDefinedToken(final ParseToken token) {
580 anticipateNext(this::processDataSubStructureToken);
581 if ("COMMENT".equals(token.getName())) {
582 return token.getType() == TokenType.ENTRY ? userDefinedBlock.addComment(token.getContentAsNormalizedString()) : true;
583 } else if (token.getName().startsWith(UserDefined.USER_DEFINED_PREFIX)) {
584 if (token.getType() == TokenType.ENTRY) {
585 userDefinedBlock.addEntry(token.getName().substring(UserDefined.USER_DEFINED_PREFIX.length()),
586 token.getContentAsNormalizedString());
587 }
588 return true;
589 } else {
590
591 return false;
592 }
593 }
594
595 }