1   /* Copyright 2022-2025 Thales Alenia Space
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.gnss.rflink.gps;
18  
19  import org.hipparchus.util.MathUtils;
20  
21  /**
22   * Container for sub-frames 4, page 13.
23   * <p>
24   * Table 40-1, sheet 10 in
25   * <a href="https://navcen.uscg.gov/sites/default/files/pdf/gps/IS-GPS-200N.pdf">NAVSTAR
26   * GPS Space Segment/Navigation User Segment Interface</a>, IS-GPS-200N, 22 Aug 2022
27   * </p>
28   * @author Luc Maisonobe
29   * @since 12.0
30   */
31  public class SubFrame4C extends SubFrame45 {
32  
33      /** Number of Estimated Range Deviations. */
34      public static final int NB_ERD = 30;
35  
36      /** Index of availability indicator field. */
37      private static final int AVAILABILITY_INDICATOR = 9;
38  
39      /** Size of Estimated Range Deviations. */
40      private static final int ERD_SIZE = 6;
41  
42      /** Simple constructor.
43       * @param words raw words
44       */
45      SubFrame4C(final int[] words) {
46  
47          // create raw container
48          super(words, AVAILABILITY_INDICATOR + NB_ERD + 1);
49  
50          // populate container
51          int field = AVAILABILITY_INDICATOR;
52          int word  = 3;
53          int shift = 20;
54          setField(field, word, shift, 2, words);
55          for (int i = 0; i < NB_ERD; ++i) {
56              if (shift >= ERD_SIZE + PARITY_SIZE) {
57                  // current word contains a complete ERD
58                  shift -= ERD_SIZE;
59                  setField(++field, word, shift, ERD_SIZE, words);
60              } else {
61                  // current word contains only the MSF of next ERD
62                  final int msbBits = shift - PARITY_SIZE;
63                  shift += WORD_SIZE - ERD_SIZE;
64                  setField(++field,
65                           word,     PARITY_SIZE,                      msbBits,
66                           word + 1, WORD_SIZE - (ERD_SIZE - msbBits), ERD_SIZE - msbBits, words);
67                  ++word;
68              }
69          }
70  
71      }
72  
73      /** Get an Estimated Range Deviation.
74       * @param index index of the ERD (between 1 and {@link #NB_ERD})
75       * @return Estimated Range Deviation
76       */
77      public int getERD(final int index) {
78          MathUtils.checkRangeInclusive(index, 1, NB_ERD);
79          return getField(AVAILABILITY_INDICATOR + index);
80      }
81  
82  }