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.util.FastMath;
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.errors.OrekitException;
26  import org.orekit.errors.OrekitMessages;
27  import org.orekit.gnss.SatelliteSystem;
28  import org.orekit.gnss.metric.messages.rtcm.ephemeris.Rtcm1019;
29  import org.orekit.gnss.metric.messages.rtcm.ephemeris.Rtcm1019Data;
30  import org.orekit.gnss.metric.parser.ByteArrayEncodedMessage;
31  import org.orekit.gnss.metric.parser.EncodedMessage;
32  import org.orekit.gnss.metric.parser.RtcmDataField;
33  import org.orekit.gnss.metric.parser.RtcmMessagesParser;
34  import org.orekit.propagation.analytical.gnss.GNSSPropagator;
35  import org.orekit.propagation.analytical.gnss.GNSSPropagatorBuilder;
36  import org.orekit.propagation.analytical.gnss.data.GPSLegacyNavigationMessage;
37  import org.orekit.time.GNSSDate;
38  
39  import java.util.ArrayList;
40  
41  public class Rtcm1019Test {
42  
43      private final double eps = 1.0e-15;
44  
45      @BeforeEach
46      public void setUp() {
47          Utils.setDataRoot("gnss");
48      }
49  
50      @Test
51      public void testParseMessage() {
52  
53          final String m = "001111111011" +                     // Message number: 1019
54                          "001100" +                           // Satellite ID
55                          "1111111011" +                       // Week Number
56                          "0001" +                             // SV Accuracy
57                          "11" +                               // GPS CODE ON L2
58                          "01011101111101" +                   // IDOT
59                          "10000100" +                         // IODE
60                          "0000111101101111" +                 // toc
61                          "01111111" +                         // af2
62                          "0000101011111101" +                 // af1
63                          "0100101011111101111111" +           // af0
64                          "1010110111" +                       // IODC
65                          "0000000000000000" +                 // Crs
66                          "0111111011001111" +                 // DELTA n
67                          "00000110110011111011100110011011" + // M0
68                          "0000000000000000" +                 // Cuc
69                          "00010011111101111000111000011001" + // ecc
70                          "0000000000000000" +                 // Cus
71                          "10100001000011000111111111111111" + // A^(1/2)
72                          "1000100011100011" +                 // toe
73                          "0000000000000000" +                 // Cic
74                          "00011100011100000111111000111111" + // OMEGA0
75                          "0000000000000000" +                 // Cis
76                          "00101000001111100011110011110000" + // i0
77                          "0000000000000000" +                 // Crc
78                          "00001100001111100011110011110000" + // Argument of perigee
79                          "111111111011111111110100" +         // OMEGADOT
80                          "00000011" +                         // tGD
81                          "000000" +                           // SV Health
82                          "0" +                                // L2 P data flag
83                          "0";                                 // Fit Interval
84  
85          final EncodedMessage message = new ByteArrayEncodedMessage(byteArrayFromBinary(m));
86          message.start();
87  
88          ArrayList<Integer> messages = new ArrayList<>();
89          messages.add(1019);
90  
91          final Rtcm1019             rtcm1019      = (Rtcm1019) new RtcmMessagesParser(messages, DataContext.getDefault().getTimeScales()).
92                                                     parse(message, false);
93          final Rtcm1019Data         ephemerisData = rtcm1019.getEphemerisData();
94          final GPSLegacyNavigationMessage gpsMessage    = ephemerisData.getGpsNavigationMessage();
95  
96          // Verify propagator initialization
97          final GNSSPropagator propagator = new GNSSPropagatorBuilder(gpsMessage).build();
98          Assertions.assertNotNull(propagator);
99          Assertions.assertEquals(0.0, gpsMessage.getDate().
100                             durationFrom(new GNSSDate(gpsMessage.getWeek(), gpsMessage.getTime(), SatelliteSystem.GPS).getDate()), eps);
101 
102         // Verify message number
103         Assertions.assertEquals(1019,                   rtcm1019.getTypeCode());
104         Assertions.assertEquals(1,                      rtcm1019.getData().size());
105 
106         // Verify navigation message
107         Assertions.assertEquals(12,                     gpsMessage.getPRN());
108         Assertions.assertEquals(1019,                   gpsMessage.getWeek());
109         Assertions.assertEquals(2.1475894557210572E-9,  gpsMessage.getIDot(),               eps);
110         Assertions.assertEquals(132,                    gpsMessage.getIODE(),               eps);
111         Assertions.assertEquals(3.524958E-15,           gpsMessage.getAf2(),                eps);
112         Assertions.assertEquals(3.1980107E-10,          gpsMessage.getAf1(),                eps);
113         Assertions.assertEquals(5.721445195376873E-4,   gpsMessage.getAf0(),                eps);
114         Assertions.assertEquals(695,                    gpsMessage.getIODC());
115         Assertions.assertEquals(0.0,                    gpsMessage.getCrs(),                eps);
116         Assertions.assertEquals(1.4586338170358127E-4,  gpsMessage.getMeanMotion0(),        eps);
117         Assertions.assertEquals(1.458749761151065E-4,   gpsMessage.getMeanMotion0() + gpsMessage.getDeltaN0(),        eps);
118         Assertions.assertEquals(0.1671775426328288,     gpsMessage.getM0(),                 eps);
119         Assertions.assertEquals(0.0,                    gpsMessage.getCuc(),                eps);
120         Assertions.assertEquals(0.03899807028938085,    gpsMessage.getE(),                  eps);
121         Assertions.assertEquals(0.0,                    gpsMessage.getCus(),                eps);
122         Assertions.assertEquals(5153.562498092651,      FastMath.sqrt(gpsMessage.getSma()), eps);
123         Assertions.assertEquals(560688.0,               gpsMessage.getTime(),               eps);
124         Assertions.assertEquals(0.0,                    gpsMessage.getCic(),                eps);
125         Assertions.assertEquals(0.0,                    gpsMessage.getCis(),                eps);
126         Assertions.assertEquals(0.987714701321906,      gpsMessage.getI0(),                 eps);
127         Assertions.assertEquals(0.0,                    gpsMessage.getCrc(),                eps);
128         Assertions.assertEquals(0.30049130834913723,    gpsMessage.getPa(),                 eps);
129         Assertions.assertEquals(-5.855958209879004E-9,  gpsMessage.getOmegaDot(),           eps);
130         Assertions.assertEquals(0.6980085385373721,     gpsMessage.getOmega0(),             eps);
131         Assertions.assertEquals(1.3969839E-9,           gpsMessage.getTGD(),                eps);
132         Assertions.assertEquals(0.0,                    gpsMessage.getSvHealth(),           eps);
133 
134         // Verify other data
135         Assertions.assertEquals(12,                     ephemerisData.getSatelliteID());
136         Assertions.assertEquals(63216,                  ephemerisData.getGpsToc(),          eps);
137         Assertions.assertEquals(3,                      ephemerisData.getGpsCodeOnL2());
138         Assertions.assertEquals(0,                      ephemerisData.getGpsFitInterval());
139         Assertions.assertTrue(ephemerisData.getGpsL2PDataFlag());
140         Assertions.assertEquals(ephemerisData.getAccuracyProvider().getAccuracy(), gpsMessage.getSvAccuracy(), eps);
141 
142     }
143 
144     @Test
145     public void testNullMessage() {
146 
147         final String m = "001111111011" +                     // Message number: 1019
148                         "001100" +                           // Satellite ID
149                         "1111111011" +                       // Week Number
150                         "0001" +                             // SV Accuracy
151                         "11" +                               // GPS CODE ON L2
152                         "01011101111101" +                   // IDOT
153                         "10000100" +                         // IODE
154                         "0000111101101111" +                 // toc
155                         "01111111" +                         // af2
156                         "0000101011111101" +                 // af1
157                         "0100101011111101111111" +           // af0
158                         "1010110111" +                       // IODC
159                         "0000000000000000" +                 // Crs
160                         "0111111011001111" +                 // DELTA n
161                         "00000110110011111011100110011011" + // M0
162                         "0000000000000000" +                 // Cuc
163                         "00010011111101111000111000011001" + // ecc
164                         "0000000000000000" +                 // Cus
165                         "10100001000011000111111111111111" + // A^(1/2)
166                         "1000100011100011" +                 // toe
167                         "0000000000000000" +                 // Cic
168                         "00011100011100000111111000111111" + // OMEGA0
169                         "0000000000000000" +                 // Cis
170                         "00101000001111100011110011110000" + // i0
171                         "0000000000000000" +                 // Crc
172                         "00001100001111100011110011110000" + // Argument of perigee
173                         "111111111011111111110100" +         // OMEGADOT
174                         "00000011" +                         // tGD
175                         "000000" +                           // SV Health
176                         "0" +                                // L2 P data flag
177                         "0";                                 // Fit Interval
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 Rtcm1019 rtcm1019 = (Rtcm1019) new RtcmMessagesParser(messages, DataContext.getDefault().getTimeScales()).
186                                  parse(message, false);
187 
188        Assertions.assertNull(rtcm1019);
189     }
190 
191     @Test
192     public void testDF103() {
193         final String m = "1111111111111111";
194         final EncodedMessage message = new ByteArrayEncodedMessage(byteArrayFromBinary(m));
195         Assertions.assertFalse(RtcmDataField.DF103.booleanValue(message));
196     }
197 
198     @Test
199     public void testEmptyMessage() {
200         try {
201             final byte[] array = new byte[0];
202             final EncodedMessage emptyMessage = new ByteArrayEncodedMessage(array);
203             new RtcmMessagesParser(new ArrayList<>(), DataContext.getDefault().getTimeScales()).
204                 parse(emptyMessage, false);
205             Assertions.fail("an exception should have been thrown");
206         } catch (OrekitException oe) {
207             Assertions.assertEquals(OrekitMessages.END_OF_ENCODED_MESSAGE, oe.getSpecifier());
208         }
209 
210     }
211 
212     private byte[] byteArrayFromBinary(String radix2Value) {
213         final byte[] array = new byte[radix2Value.length() / 8];
214         for (int i = 0; i < array.length; ++i) {
215             for (int j = 0; j < 8; ++j) {
216                 if (radix2Value.charAt(8 * i + j) != '0') {
217                     array[i] |= 0x1 << (7 - j);
218                 }
219             }
220         }
221         return array;
222     }
223 
224 }