CcsdsSegmentedTimeCode.java

  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. import org.orekit.errors.OrekitException;
  19. import org.orekit.errors.OrekitMessages;

  20. /** This class represents a CCSDS segmented time code.
  21.  * @author Luc Maisonobe
  22.  * @since 12.1
  23.  * @see AbsoluteDate
  24.  * @see FieldAbsoluteDate
  25.  */
  26. class CcsdsSegmentedTimeCode extends AbstractCcsdsTimeCode {

  27.     /** Date part. */
  28.     private final DateComponents date;

  29.     /** Time part. */
  30.     private final TimeComponents time;

  31.     /** Create an instance CCSDS Day Segmented Time Code (CDS).
  32.      * <p>
  33.      * CCSDS Day Segmented Time Code is defined in the blue book:
  34.      * CCSDS Time Code Format (CCSDS 301.0-B-4) published in November 2010
  35.      * </p>
  36.      * @param preambleField field specifying the format, often not transmitted in
  37.      * data interfaces, as it is constant for a given data interface
  38.      * @param timeField byte array containing the time code
  39.      * @param agencyDefinedEpoch reference epoch, ignored if the preamble field
  40.      * specifies the {@link DateComponents#CCSDS_EPOCH CCSDS reference epoch} is used
  41.      * (and hence may be null in this case)
  42.      */
  43.     CcsdsSegmentedTimeCode(final byte preambleField, final byte[] timeField,
  44.                            final DateComponents agencyDefinedEpoch) {

  45.         // time code identification
  46.         if ((preambleField & 0xF0) != 0x40) {
  47.             throw new OrekitException(OrekitMessages.CCSDS_DATE_INVALID_PREAMBLE_FIELD,
  48.                                       formatByte(preambleField));
  49.         }

  50.         // reference epoch
  51.         final DateComponents epoch;
  52.         if ((preambleField & 0x08) == 0x00) {
  53.             // the reference epoch is CCSDS epoch 1958-01-01T00:00:00 TAI
  54.             epoch = DateComponents.CCSDS_EPOCH;
  55.         } else {
  56.             // the reference epoch is agency defined
  57.             if (agencyDefinedEpoch == null) {
  58.                 throw new OrekitException(OrekitMessages.CCSDS_DATE_MISSING_AGENCY_EPOCH);
  59.             }
  60.             epoch = agencyDefinedEpoch;
  61.         }

  62.         // time field lengths
  63.         final int daySegmentLength = ((preambleField & 0x04) == 0x0) ? 2 : 3;
  64.         final int subMillisecondLength = (preambleField & 0x03) << 1;
  65.         if (subMillisecondLength == 6) {
  66.             throw new OrekitException(OrekitMessages.CCSDS_DATE_INVALID_PREAMBLE_FIELD,
  67.                                       formatByte(preambleField));
  68.         }
  69.         if (timeField.length != daySegmentLength + 4 + subMillisecondLength) {
  70.             throw new OrekitException(OrekitMessages.CCSDS_DATE_INVALID_LENGTH_TIME_FIELD,
  71.                                       timeField.length, daySegmentLength + 4 + subMillisecondLength);
  72.         }


  73.         int i   = 0;
  74.         int day = 0;
  75.         while (i < daySegmentLength) {
  76.             day = day * 256 + toUnsigned(timeField[i++]);
  77.         }

  78.         long milliInDay = 0L;
  79.         while (i < daySegmentLength + 4) {
  80.             milliInDay = milliInDay * 256 + toUnsigned(timeField[i++]);
  81.         }
  82.         final int milli   = (int) (milliInDay % 1000L);
  83.         final int seconds = (int) ((milliInDay - milli) / 1000L);

  84.         long subMilli = 0;
  85.         while (i < timeField.length) {
  86.             subMilli = subMilli * 256 + toUnsigned(timeField[i++]);
  87.         }
  88.         final TimeOffset timeOffset =
  89.             new TimeOffset(seconds, TimeOffset.SECOND,
  90.                            milli, TimeOffset.MILLISECOND,
  91.                            subMilli, subMillisecondLength == 2 ? TimeOffset.MICROSECOND : TimeOffset.PICOSECOND);

  92.         this.date = new DateComponents(epoch, day);
  93.         this.time = new TimeComponents(timeOffset);

  94.     }

  95.     /** Build an instance from a CCSDS Calendar Segmented Time Code (CCS).
  96.      * <p>
  97.      * CCSDS Calendar Segmented Time Code is defined in the blue book:
  98.      * CCSDS Time Code Format (CCSDS 301.0-B-4) published in November 2010
  99.      * </p>
  100.      * @param preambleField field specifying the format, often not transmitted in
  101.      * data interfaces, as it is constant for a given data interface
  102.      * @param timeField byte array containing the time code
  103.      */
  104.     CcsdsSegmentedTimeCode(final byte preambleField, final byte[] timeField) {

  105.         // time code identification
  106.         if ((preambleField & 0xF0) != 0x50) {
  107.             throw new OrekitException(OrekitMessages.CCSDS_DATE_INVALID_PREAMBLE_FIELD,
  108.                                       formatByte(preambleField));
  109.         }

  110.         // time field length
  111.         final int length = 7 + (preambleField & 0x07);
  112.         if (length == 14) {
  113.             throw new OrekitException(OrekitMessages.CCSDS_DATE_INVALID_PREAMBLE_FIELD,
  114.                                       formatByte(preambleField));
  115.         }
  116.         if (timeField.length != length) {
  117.             throw new OrekitException(OrekitMessages.CCSDS_DATE_INVALID_LENGTH_TIME_FIELD,
  118.                                       timeField.length, length);
  119.         }

  120.         // date part in the first four bytes
  121.         if ((preambleField & 0x08) == 0x00) {
  122.             // month of year and day of month variation
  123.             this.date = new DateComponents(toUnsigned(timeField[0]) * 256 + toUnsigned(timeField[1]),
  124.                                            toUnsigned(timeField[2]),
  125.                                            toUnsigned(timeField[3]));
  126.         } else {
  127.             // day of year variation
  128.             this.date = new DateComponents(toUnsigned(timeField[0]) * 256 + toUnsigned(timeField[1]),
  129.                                            toUnsigned(timeField[2]) * 256 + toUnsigned(timeField[3]));
  130.         }

  131.         // time part from bytes 5 to last (between 7 and 13 depending on precision)
  132.         final int hour        = toUnsigned(timeField[4]);
  133.         final int minute      = toUnsigned(timeField[5]);
  134.         final int second      = toUnsigned(timeField[6]);
  135.         final int secondInDay = 3600 * hour + 60 * minute + second;

  136.         long sub                  = 0;
  137.         long attoSecondMultiplier = 1000000000000000000L;
  138.         for (int i = 7; i < length; ++i) {
  139.             sub                   = sub * 100L + toUnsigned(timeField[i]);
  140.             attoSecondMultiplier /= 100L;
  141.         }

  142.         this.time = new TimeComponents(new TimeOffset(secondInDay, sub * attoSecondMultiplier));

  143.     }

  144.     /** Get the date part.
  145.      * @return date part
  146.      */
  147.     public DateComponents getDate() {
  148.         return date;
  149.     }

  150.     /** Get the time part.
  151.      * @return time part
  152.      */
  153.     public TimeComponents getTime() {
  154.         return time;
  155.     }

  156. }