CcsdsUnsegmentedTimeCode.java

  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. 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.     /** Epoch part. */
  29.     private final T epoch;

  30.     /** Seconds part. */
  31.     private final long seconds;

  32.     /** Sub-second part. */
  33.     private final double subSecond;

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

  65.         // time code identification and reference epoch
  66.         switch (preambleField1 & 0x70) {
  67.             case 0x10:
  68.                 // the reference epoch is CCSDS epoch 1958-01-01T00:00:00 TAI
  69.                 epoch = ccsdsEpoch;
  70.                 break;
  71.             case 0x20:
  72.                 // the reference epoch is agency defined
  73.                 if (agencyDefinedEpoch == null) {
  74.                     throw new OrekitException(OrekitMessages.CCSDS_DATE_MISSING_AGENCY_EPOCH);
  75.                 }
  76.                 epoch = agencyDefinedEpoch;
  77.                 break;
  78.             default :
  79.                 throw new OrekitException(OrekitMessages.CCSDS_DATE_INVALID_PREAMBLE_FIELD,
  80.                                           formatByte(preambleField1));
  81.         }

  82.         // time field lengths
  83.         int coarseTimeLength = 1 + ((preambleField1 & 0x0C) >>> 2);
  84.         int fineTimeLength   = preambleField1 & 0x03;

  85.         if ((preambleField1 & 0x80) != 0x0) {
  86.             // there is an additional octet in preamble field
  87.             coarseTimeLength += (preambleField2 & 0x60) >>> 5;
  88.             fineTimeLength   += (preambleField2 & 0x1C) >>> 2;
  89.         }

  90.         if (timeField.length != coarseTimeLength + fineTimeLength) {
  91.             throw new OrekitException(OrekitMessages.CCSDS_DATE_INVALID_LENGTH_TIME_FIELD,
  92.                                       timeField.length, coarseTimeLength + fineTimeLength);
  93.         }

  94.         long s = 0L;
  95.         for (int i = 0; i < coarseTimeLength; ++i) {
  96.             s = s * 256 + toUnsigned(timeField[i]);
  97.         }
  98.         seconds = s;

  99.         double sub = 0;
  100.         for (int i = timeField.length - 1; i >= coarseTimeLength; --i) {
  101.             sub = (sub + toUnsigned(timeField[i])) / 256;
  102.         }
  103.         subSecond = sub;

  104.     }

  105.     /** Get the epoch part.
  106.      * @return epoch part
  107.      */
  108.     public T getEpoch() {
  109.         return epoch;
  110.     }

  111.     /** Get the seconds part.
  112.      * @return seconds part
  113.      */
  114.     public long getSeconds() {
  115.         return seconds;
  116.     }

  117.     /** Get the sub-second part.
  118.      * @return sub-second part
  119.      */
  120.     public double getSubSecond() {
  121.         return subSecond;
  122.     }

  123. }