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