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