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 segmented time code.
23 * @author Luc Maisonobe
24 * @since 12.1
25 * @see AbsoluteDate
26 * @see FieldAbsoluteDate
27 */
28 class CcsdsSegmentedTimeCode extends AbstractCcsdsTimeCode {
29
30 /** Date part. */
31 private final DateComponents date;
32
33 /** Time part (down to second only). */
34 private final TimeComponents time;
35
36 /** Sub-second part. */
37 private final double subSecond;
38
39 /** Create an instance CCSDS Day Segmented Time Code (CDS).
40 * <p>
41 * CCSDS Day Segmented Time Code is defined in the blue book:
42 * CCSDS Time Code Format (CCSDS 301.0-B-4) published in November 2010
43 * </p>
44 * @param preambleField field specifying the format, often not transmitted in
45 * data interfaces, as it is constant for a given data interface
46 * @param timeField byte array containing the time code
47 * @param agencyDefinedEpoch reference epoch, ignored if the preamble field
48 * specifies the {@link DateComponents#CCSDS_EPOCH CCSDS reference epoch} is used
49 * (and hence may be null in this case)
50 */
51 CcsdsSegmentedTimeCode(final byte preambleField, final byte[] timeField,
52 final DateComponents agencyDefinedEpoch) {
53
54 // time code identification
55 if ((preambleField & 0xF0) != 0x40) {
56 throw new OrekitException(OrekitMessages.CCSDS_DATE_INVALID_PREAMBLE_FIELD,
57 formatByte(preambleField));
58 }
59
60 // reference epoch
61 final DateComponents epoch;
62 if ((preambleField & 0x08) == 0x00) {
63 // the reference epoch is CCSDS epoch 1958-01-01T00:00:00 TAI
64 epoch = DateComponents.CCSDS_EPOCH;
65 } else {
66 // the reference epoch is agency defined
67 if (agencyDefinedEpoch == null) {
68 throw new OrekitException(OrekitMessages.CCSDS_DATE_MISSING_AGENCY_EPOCH);
69 }
70 epoch = agencyDefinedEpoch;
71 }
72
73 // time field lengths
74 final int daySegmentLength = ((preambleField & 0x04) == 0x0) ? 2 : 3;
75 final int subMillisecondLength = (preambleField & 0x03) << 1;
76 if (subMillisecondLength == 6) {
77 throw new OrekitException(OrekitMessages.CCSDS_DATE_INVALID_PREAMBLE_FIELD,
78 formatByte(preambleField));
79 }
80 if (timeField.length != daySegmentLength + 4 + subMillisecondLength) {
81 throw new OrekitException(OrekitMessages.CCSDS_DATE_INVALID_LENGTH_TIME_FIELD,
82 timeField.length, daySegmentLength + 4 + subMillisecondLength);
83 }
84
85
86 int i = 0;
87 int day = 0;
88 while (i < daySegmentLength) {
89 day = day * 256 + toUnsigned(timeField[i++]);
90 }
91
92 long milliInDay = 0L;
93 while (i < daySegmentLength + 4) {
94 milliInDay = milliInDay * 256 + toUnsigned(timeField[i++]);
95 }
96 final int milli = (int) (milliInDay % 1000L);
97 final int seconds = (int) ((milliInDay - milli) / 1000L);
98
99 double subMilli = 0;
100 double divisor = 1;
101 while (i < timeField.length) {
102 subMilli = subMilli * 256 + toUnsigned(timeField[i++]);
103 divisor *= 1000;
104 }
105
106 this.date = new DateComponents(epoch, day);
107 this.time = new TimeComponents(seconds);
108 this.subSecond = milli * 1.0e-3 + subMilli / divisor;
109
110 }
111
112 /** Build an instance from a CCSDS Calendar Segmented Time Code (CCS).
113 * <p>
114 * CCSDS Calendar Segmented Time Code is defined in the blue book:
115 * CCSDS Time Code Format (CCSDS 301.0-B-4) published in November 2010
116 * </p>
117 * @param preambleField field specifying the format, often not transmitted in
118 * data interfaces, as it is constant for a given data interface
119 * @param timeField byte array containing the time code
120 */
121 CcsdsSegmentedTimeCode(final byte preambleField, final byte[] timeField) {
122
123 // time code identification
124 if ((preambleField & 0xF0) != 0x50) {
125 throw new OrekitException(OrekitMessages.CCSDS_DATE_INVALID_PREAMBLE_FIELD,
126 formatByte(preambleField));
127 }
128
129 // time field length
130 final int length = 7 + (preambleField & 0x07);
131 if (length == 14) {
132 throw new OrekitException(OrekitMessages.CCSDS_DATE_INVALID_PREAMBLE_FIELD,
133 formatByte(preambleField));
134 }
135 if (timeField.length != length) {
136 throw new OrekitException(OrekitMessages.CCSDS_DATE_INVALID_LENGTH_TIME_FIELD,
137 timeField.length, length);
138 }
139
140 // date part in the first four bytes
141 if ((preambleField & 0x08) == 0x00) {
142 // month of year and day of month variation
143 this.date = new DateComponents(toUnsigned(timeField[0]) * 256 + toUnsigned(timeField[1]),
144 toUnsigned(timeField[2]),
145 toUnsigned(timeField[3]));
146 } else {
147 // day of year variation
148 this.date = new DateComponents(toUnsigned(timeField[0]) * 256 + toUnsigned(timeField[1]),
149 toUnsigned(timeField[2]) * 256 + toUnsigned(timeField[3]));
150 }
151
152 // time part from bytes 5 to last (between 7 and 13 depending on precision)
153 this.time = new TimeComponents(toUnsigned(timeField[4]),
154 toUnsigned(timeField[5]),
155 toUnsigned(timeField[6]));
156
157 double sub = 0;
158 double divisor = 1;
159 for (int i = 7; i < length; ++i) {
160 sub = sub * 100 + toUnsigned(timeField[i]);
161 divisor *= 100;
162 }
163
164 this.subSecond = sub / divisor;
165
166 }
167
168 /** Get the date part.
169 * @return date part
170 */
171 public DateComponents getDate() {
172 return date;
173 }
174
175 /** Get the time part.
176 * @return time part
177 */
178 public TimeComponents getTime() {
179 return time;
180 }
181
182 /** Get the sub-second part.
183 * @return sub-second part
184 */
185 public double getSubSecond() {
186 return subSecond;
187 }
188
189 }