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.gnss.metric.messages.rtcm;
18  
19  import org.hipparchus.ode.nonstiff.ClassicalRungeKuttaIntegrator;
20  import org.junit.jupiter.api.Assertions;
21  import org.junit.jupiter.api.BeforeEach;
22  import org.junit.jupiter.api.Test;
23  import org.orekit.Utils;
24  import org.orekit.data.DataContext;
25  import org.orekit.gnss.metric.messages.rtcm.ephemeris.Rtcm1020;
26  import org.orekit.gnss.metric.messages.rtcm.ephemeris.Rtcm1020Data;
27  import org.orekit.gnss.metric.parser.ByteArrayEncodedMessage;
28  import org.orekit.gnss.metric.parser.EncodedMessage;
29  import org.orekit.gnss.metric.parser.RtcmDataField;
30  import org.orekit.gnss.metric.parser.RtcmMessagesParser;
31  import org.orekit.propagation.analytical.gnss.data.GLONASSNavigationMessage;
32  import org.orekit.propagation.numerical.GLONASSNumericalPropagator;
33  import org.orekit.propagation.numerical.GLONASSNumericalPropagatorBuilder;
34  import org.orekit.time.GLONASSDate;
35  
36  import java.util.ArrayList;
37  
38  public class Rtcm1020Test {
39  
40      private double eps = 1.0e-16;
41  
42      @BeforeEach
43      public void setUp() {
44          Utils.setDataRoot("gnss");
45      }
46  
47      @Test
48      public void testParseMessage() {
49  
50          final String m = "001111111100" +                     // Message number: 1020
51                          "001100" +                           // Satellite ID
52                          "10001" +                            // Channel number
53                          "1" +                                // Cn word
54                          "0" +                                // Health availability indicator
55                          "01" +                               // Word P1
56                          "001100011011" +                     // tk
57                          "0" +                                // Bn word
58                          "1" +                                // P2 flag
59                          "0011101" +                          // tb
60                          "000000111110000011111010" +         // xn first derivative
61                          "000011111110000011111010010" +      // xn
62                          "01101" +                            // xn second derivative
63                          "100000111110000011111010" +         // yn first derivative
64                          "100011111110000011111010010" +      // yn
65                          "11101" +                            // yn second derivative
66                          "110000111110000011111010" +         // zn first derivative
67                          "101011111110000011111010010" +      // zn
68                          "01101" +                            // zn second derivative
69                          "0" +                                // P3 flag
70                          "00111100101" +                      // GLONASS γn (tb)
71                          "11" +                               // Time Operation Mode
72                          "0" +                                // ln (third string)
73                          "0011101011001110101011" +           // τn (tb)
74                          "01110" +                            // Δτn
75                          "01110" +                            // En
76                          "1" +                                // P4 Flag
77                          "1110" +                             // Ft
78                          "10011011010" +                      // Nt
79                          "01" +                               // GLONASS-M Flag
80                          "1" +                                // Availability of additional data
81                          "10011011010" +                      // NA
82                          "00001100001111100011110011110000" + // τc
83                          "00111" +                            // N4
84                          "0011011100111101010111" +           // τGPS
85                          "0" +                                // ln (fifth string)
86                          "0000000";                           // Reserved
87  
88          final EncodedMessage message = new ByteArrayEncodedMessage(byteArrayFromBinary(m));
89          message.start();
90  
91          ArrayList<Integer> messages = new ArrayList<>();
92          messages.add(1020);
93  
94          final Rtcm1020                 rtcm1020       = (Rtcm1020) new RtcmMessagesParser(messages, DataContext.getDefault().getTimeScales()).
95                                                          parse(message, false);
96          final Rtcm1020Data             ephemerisData  = rtcm1020.getEphemerisData();
97          final GLONASSNavigationMessage glonassMessage = ephemerisData.getGlonassNavigationMessage();
98  
99          // Verify propagator initialization
100         final GLONASSNumericalPropagator propagator = new GLONASSNumericalPropagatorBuilder(new ClassicalRungeKuttaIntegrator(60.0), glonassMessage, true).build();
101         Assertions.assertNotNull(propagator);
102         Assertions.assertEquals(0.0, glonassMessage.getDate().
103                             durationFrom(new GLONASSDate(ephemerisData.getNt(), ephemerisData.getN4(), glonassMessage.getTime()).getDate()), eps);
104 
105         Assertions.assertEquals(12,                             glonassMessage.getPRN());
106         Assertions.assertEquals(10,                             glonassMessage.getFrequencyNumber());
107         Assertions.assertFalse(ephemerisData.isHealthAvailable());
108         Assertions.assertEquals(1800,                           ephemerisData.getP1());
109         Assertions.assertEquals(22410.0,                        ephemerisData.getTk(),    eps);
110         Assertions.assertEquals(0,                              ephemerisData.getBN());
111         Assertions.assertEquals(1,                              ephemerisData.getP2());
112         Assertions.assertEquals(26100.0,                        glonassMessage.getTime(), eps);
113         Assertions.assertEquals(242.42592,                      glonassMessage.getXDot(),          2.0e-6);
114         Assertions.assertEquals(1.21071935E-5,                  glonassMessage.getXDotDot(),       2.0e-6);
115         Assertions.assertEquals(4064977.5390625,                glonassMessage.getX(),             eps);
116         Assertions.assertEquals(-242.42592,                     glonassMessage.getYDot(),          2.0e-6);
117         Assertions.assertEquals(-1.21071935E-5,                 glonassMessage.getYDotDot(),       2.0e-6);
118         Assertions.assertEquals(-4064977.5390625,               glonassMessage.getY(),             eps);
119         Assertions.assertEquals(-4242.426,                      glonassMessage.getZDot(),          2.5e-4);
120         Assertions.assertEquals(1.21071935E-5,                  glonassMessage.getZDotDot(),       2.0e-6);
121         Assertions.assertEquals(-1.22569775390625E7,            glonassMessage.getZ(),             eps);
122         Assertions.assertEquals(4,                              ephemerisData.getP3());
123         Assertions.assertEquals(3,                              ephemerisData.getP());
124         Assertions.assertEquals(0,                              ephemerisData.getLNThirdString());
125         Assertions.assertEquals(14,                             ephemerisData.getEn());
126         Assertions.assertEquals(1.30385160446367E-8,            ephemerisData.getDeltaTN(), eps);
127         Assertions.assertEquals(1,                              ephemerisData.getP4());
128         Assertions.assertEquals(14,                             ephemerisData.getFT());
129         Assertions.assertEquals(1,                              ephemerisData.getM());
130         Assertions.assertTrue(ephemerisData.areAdditionalDataAvailable());
131         Assertions.assertEquals(1242,                           ephemerisData.getNA());
132         Assertions.assertEquals(0.095649354159832,              ephemerisData.getTauC(), eps);
133         Assertions.assertEquals(4.214453510940075E-4,           ephemerisData.getTauGps(), eps);
134         Assertions.assertEquals(0,                              ephemerisData.getLNFifthString());
135 
136     }
137 
138     @Test
139     public void testNullMessage() {
140 
141         final String m = "001111111100" +                     // Message number: 1020
142                         "001100" +                           // Satellite ID
143                         "10001" +                            // Channel number
144                         "1" +                                // Cn word
145                         "0" +                                // Health availability indicator
146                         "01" +                               // Word P1
147                         "001100011011" +                     // tk
148                         "0" +                                // Bn word
149                         "1" +                                // P2 flag
150                         "0011101" +                          // tb
151                         "000000111110000011111010" +         // xn first derivative
152                         "000011111110000011111010010" +      // xn
153                         "01101" +                            // xn second derivative
154                         "100000111110000011111010" +         // yn first derivative
155                         "100011111110000011111010010" +      // yn
156                         "11101" +                            // yn second derivative
157                         "110000111110000011111010" +         // zn first derivative
158                         "101011111110000011111010010" +      // zn
159                         "01101" +                            // zn second derivative
160                         "0" +                                // P3 flag
161                         "00111100101" +                      // GLONASS γn (tb)
162                         "11" +                               // Time Operation Mode
163                         "0" +                                // ln (third string)
164                         "0011101011001110101011" +           // τn (tb)
165                         "01110" +                            // Δτn
166                         "01110" +                            // En
167                         "1" +                                // P4 Flag
168                         "1110" +                             // Ft
169                         "10011011010" +                      // Nt
170                         "01" +                               // GLONASS-M Flag
171                         "1" +                                // Availability of additional data
172                         "10011011010" +                      // NA
173                         "00001100001111100011110011110000" + // τc
174                         "00111" +                            // N4
175                         "0011011100111101010111" +           // τGPS
176                         "0" +                                // ln (fifth string)
177                         "0000000";                           // Reserved
178 
179        final EncodedMessage message = new ByteArrayEncodedMessage(byteArrayFromBinary(m));
180        message.start();
181 
182        ArrayList<Integer> messages = new ArrayList<>();
183        messages.add(9999999);
184 
185        final Rtcm1020 rtcm1020 = (Rtcm1020) new RtcmMessagesParser(messages, DataContext.getDefault().getTimeScales()).
186                                  parse(message, false);
187 
188        Assertions.assertNull(rtcm1020);
189     }
190 
191     @Test
192     public void testAdditionalDataFields() {
193         String m = "11111111111111111";
194         EncodedMessage message = new ByteArrayEncodedMessage(byteArrayFromBinary(m));
195         Assertions.assertTrue(RtcmDataField.DF105.booleanValue(message));
196         m = "11111111111111111";
197         message = new ByteArrayEncodedMessage(byteArrayFromBinary(m));
198         Assertions.assertEquals(5, RtcmDataField.DF120.intValue(message));
199         m = "00000000000000000";
200         message = new ByteArrayEncodedMessage(byteArrayFromBinary(m));
201         Assertions.assertFalse(RtcmDataField.DF131.booleanValue(message));
202     }
203 
204     private byte[] byteArrayFromBinary(String radix2Value) {
205         final byte[] array = new byte[radix2Value.length() / 8];
206         for (int i = 0; i < array.length; ++i) {
207             for (int j = 0; j < 8; ++j) {
208                 if (radix2Value.charAt(8 * i + j) != '0') {
209                     array[i] |= 0x1 << (7 - j);
210                 }
211             }
212         }
213         return array;
214     }
215 
216 }