1   /* Copyright 2002-2024 CS GROUP
2    * Licensed to CS GROUP (CS) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * CS licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.orekit.time;
18  
19  import org.orekit.errors.OrekitException;
20  import org.orekit.errors.OrekitMessages;
21  
22  /** This class represents a CCSDS unsegmented time code.
23   * @param <T> type of the date
24   * @author Luc Maisonobe
25   * @since 12.1
26   * @see AbsoluteDate
27   * @see FieldAbsoluteDate
28   */
29  class CcsdsUnsegmentedTimeCode<T> extends AbstractCcsdsTimeCode {
30  
31      /** Epoch part. */
32      private final T epoch;
33  
34      /** Seconds part. */
35      private final long seconds;
36  
37      /** Sub-second part. */
38      private final double subSecond;
39  
40      /** Create an instance CCSDS Day Unegmented Time Code (CDS).
41       * <p>
42       * CCSDS Unsegmented Time Code is defined in the blue book: CCSDS Time Code Format
43       * (CCSDS 301.0-B-4) published in November 2010
44       * </p>
45       * <p>
46       * If the date to be parsed is formatted using version 3 of the standard (CCSDS
47       * 301.0-B-3 published in 2002) or if the extension of the preamble field introduced
48       * in version 4 of the standard is not used, then the {@code preambleField2} parameter
49       * can be set to 0.
50       * </p>
51       * @param preambleField1     first byte of the field specifying the format, often not
52       *                           transmitted in data interfaces, as it is constant for a
53       *                           given data interface
54       * @param preambleField2     second byte of the field specifying the format (added in
55       *                           revision 4 of the CCSDS standard in 2010), often not
56       *                           transmitted in data interfaces, as it is constant for a
57       *                           given data interface (value ignored if presence not
58       *                           signaled in {@code preambleField1})
59       * @param timeField          byte array containing the time code
60       * @param agencyDefinedEpoch reference epoch, ignored if the preamble field specifies
61       *                           the {@link DateComponents#CCSDS_EPOCH CCSDS reference epoch} is used
62       *                           (and hence may be null in this case)
63       * @param ccsdsEpoch         reference epoch, ignored if the preamble field specifies
64       *                           the agency epoch is used.
65       */
66      CcsdsUnsegmentedTimeCode(final byte preambleField1,
67                               final byte preambleField2,
68                               final byte[] timeField,
69                               final T agencyDefinedEpoch,
70                               final T ccsdsEpoch) {
71  
72          // time code identification and reference epoch
73          switch (preambleField1 & 0x70) {
74              case 0x10:
75                  // the reference epoch is CCSDS epoch 1958-01-01T00:00:00 TAI
76                  epoch = ccsdsEpoch;
77                  break;
78              case 0x20:
79                  // the reference epoch is agency defined
80                  if (agencyDefinedEpoch == null) {
81                      throw new OrekitException(OrekitMessages.CCSDS_DATE_MISSING_AGENCY_EPOCH);
82                  }
83                  epoch = agencyDefinedEpoch;
84                  break;
85              default :
86                  throw new OrekitException(OrekitMessages.CCSDS_DATE_INVALID_PREAMBLE_FIELD,
87                                            formatByte(preambleField1));
88          }
89  
90          // time field lengths
91          int coarseTimeLength = 1 + ((preambleField1 & 0x0C) >>> 2);
92          int fineTimeLength   = preambleField1 & 0x03;
93  
94          if ((preambleField1 & 0x80) != 0x0) {
95              // there is an additional octet in preamble field
96              coarseTimeLength += (preambleField2 & 0x60) >>> 5;
97              fineTimeLength   += (preambleField2 & 0x1C) >>> 2;
98          }
99  
100         if (timeField.length != coarseTimeLength + fineTimeLength) {
101             throw new OrekitException(OrekitMessages.CCSDS_DATE_INVALID_LENGTH_TIME_FIELD,
102                                       timeField.length, coarseTimeLength + fineTimeLength);
103         }
104 
105         long s = 0L;
106         for (int i = 0; i < coarseTimeLength; ++i) {
107             s = s * 256 + toUnsigned(timeField[i]);
108         }
109         seconds = s;
110 
111         double sub = 0;
112         for (int i = timeField.length - 1; i >= coarseTimeLength; --i) {
113             sub = (sub + toUnsigned(timeField[i])) / 256;
114         }
115         subSecond = sub;
116 
117     }
118 
119     /** Get the epoch part.
120      * @return epoch part
121      */
122     public T getEpoch() {
123         return epoch;
124     }
125 
126     /** Get the seconds part.
127      * @return seconds part
128      */
129     public long getSeconds() {
130         return seconds;
131     }
132 
133     /** Get the sub-second part.
134      * @return sub-second part
135      */
136     public double getSubSecond() {
137         return subSecond;
138     }
139 
140 }