CcsdsUnsegmentedTimeCode.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 unsegmented time code.
  21.  * @param <T> type of the date
  22.  * @author Luc Maisonobe
  23.  * @since 12.1
  24.  * @see AbsoluteDate
  25.  * @see FieldAbsoluteDate
  26.  */
  27. class CcsdsUnsegmentedTimeCode<T> extends AbstractCcsdsTimeCode {

  28.     /** Numerator of scale of the sub-second part (10¹⁸/256ⁿ).
  29.      * @since 13.0
  30.      */
  31.     private static final long[] SUB_SCALE_NUM = new long[] {
  32.         3906250000000000L, 15258789062500L, 3814697265625L, 3814697265625L, 3814697265625L, 3814697265625L, 3814697265625L
  33.     };

  34.     /** Denominator of scale of the sub-second part (10¹⁸/256ⁿ).
  35.      * @since 13.0
  36.      */
  37.     private static final long[] SUB_SCALE_DEN = new long[] {
  38.         1L, 1L, 64L, 16384L, 4194304L, 1073741824L, 274877906944L
  39.     };

  40.     /** Epoch part. */
  41.     private final T epoch;

  42.     /** Time part.
  43.      * @since 13.0
  44.      */
  45.     private final TimeOffset time;

  46.     /** Create an instance CCSDS Day Unegmented Time Code (CDS).
  47.      * <p>
  48.      * CCSDS Unsegmented Time Code is defined in the blue book: CCSDS Time Code Format
  49.      * (CCSDS 301.0-B-4) published in November 2010
  50.      * </p>
  51.      * <p>
  52.      * If the date to be parsed is formatted using version 3 of the standard (CCSDS
  53.      * 301.0-B-3 published in 2002) or if the extension of the preamble field introduced
  54.      * in version 4 of the standard is not used, then the {@code preambleField2} parameter
  55.      * can be set to 0.
  56.      * </p>
  57.      * @param preambleField1     first byte of the field specifying the format, often not
  58.      *                           transmitted in data interfaces, as it is constant for a
  59.      *                           given data interface
  60.      * @param preambleField2     second byte of the field specifying the format (added in
  61.      *                           revision 4 of the CCSDS standard in 2010), often not
  62.      *                           transmitted in data interfaces, as it is constant for a
  63.      *                           given data interface (value ignored if presence not
  64.      *                           signaled in {@code preambleField1})
  65.      * @param timeField          byte array containing the time code
  66.      * @param agencyDefinedEpoch reference epoch, ignored if the preamble field specifies
  67.      *                           the {@link DateComponents#CCSDS_EPOCH CCSDS reference epoch} is used
  68.      *                           (and hence may be null in this case, but then {@code ccsdsEpoch} must be non-null)
  69.      * @param ccsdsEpoch         reference epoch, ignored if the preamble field specifies
  70.      *                           the agency epoch is used (and hence may be null in this case,
  71.      *                           but then {@code agencyDefinedEpoch} must be non-null).
  72.      */
  73.     CcsdsUnsegmentedTimeCode(final byte preambleField1,
  74.                              final byte preambleField2,
  75.                              final byte[] timeField,
  76.                              final T agencyDefinedEpoch,
  77.                              final T ccsdsEpoch) {

  78.         // time code identification and reference epoch
  79.         switch (preambleField1 & 0x70) {
  80.             case 0x10:
  81.                 // the reference epoch is CCSDS epoch 1958-01-01T00:00:00 TAI
  82.                 epoch = ccsdsEpoch;
  83.                 break;
  84.             case 0x20:
  85.                 // the reference epoch is agency defined
  86.                 if (agencyDefinedEpoch == null) {
  87.                     throw new OrekitException(OrekitMessages.CCSDS_DATE_MISSING_AGENCY_EPOCH);
  88.                 }
  89.                 epoch = agencyDefinedEpoch;
  90.                 break;
  91.             default :
  92.                 throw new OrekitException(OrekitMessages.CCSDS_DATE_INVALID_PREAMBLE_FIELD,
  93.                                           formatByte(preambleField1));
  94.         }

  95.         // time field lengths
  96.         int coarseTimeLength = 1 + ((preambleField1 & 0x0C) >>> 2);
  97.         int fineTimeLength   = preambleField1 & 0x03;

  98.         if ((preambleField1 & 0x80) != 0x0) {
  99.             // there is an additional octet in preamble field
  100.             coarseTimeLength += (preambleField2 & 0x60) >>> 5;
  101.             fineTimeLength   += (preambleField2 & 0x1C) >>> 2;
  102.         }

  103.         if (timeField.length != coarseTimeLength + fineTimeLength) {
  104.             throw new OrekitException(OrekitMessages.CCSDS_DATE_INVALID_LENGTH_TIME_FIELD,
  105.                                       timeField.length, coarseTimeLength + fineTimeLength);
  106.         }

  107.         long seconds = 0L;
  108.         for (int i = 0; i < coarseTimeLength; ++i) {
  109.             seconds = seconds * 256L + toUnsigned(timeField[i]);
  110.         }

  111.         long attoSeconds = 0L;
  112.         for (int i = coarseTimeLength; i < timeField.length; ++i) {
  113.             attoSeconds += (toUnsigned(timeField[i]) * SUB_SCALE_NUM[i - coarseTimeLength]) /
  114.                            SUB_SCALE_DEN[i - coarseTimeLength];
  115.         }

  116.         time = new TimeOffset(seconds, attoSeconds);

  117.     }

  118.     /** Get the epoch part.
  119.      * @return epoch part
  120.      */
  121.     public T getEpoch() {
  122.         return epoch;
  123.     }

  124.     /** Get the time part.
  125.      * @return time part
  126.      * @since 13.0
  127.      */
  128.     public TimeOffset getTime() {
  129.         return time;
  130.     }

  131. }