1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.location.cts.common;
18 
19 import static org.junit.Assert.assertNotNull;
20 
21 import android.content.Context;
22 import android.content.pm.PackageManager;
23 import android.location.CorrelationVector;
24 import android.location.GnssClock;
25 import android.location.GnssMeasurement;
26 import android.location.GnssMeasurementsEvent;
27 import android.location.GnssNavigationMessage;
28 import android.location.GnssStatus;
29 import android.location.LocationManager;
30 import android.location.SatellitePvt;
31 import android.util.Log;
32 
33 import com.google.common.collect.Range;
34 
35 import java.util.ArrayList;
36 import java.util.Arrays;
37 import java.util.Collection;
38 import java.util.HashMap;
39 import java.util.HashSet;
40 import java.util.List;
41 import java.util.Map;
42 import java.util.Set;
43 import java.util.concurrent.TimeUnit;
44 
45 /**
46  * Helper class for GnssMeasurement Tests.
47  */
48 public final class TestMeasurementUtil {
49 
50     private static final String TAG = "TestMeasurementUtil";
51 
52     private static final long NSEC_IN_SEC = 1000_000_000L;
53     // Generally carrier phase quality prr's have uncertainties around 0.001-0.05 m/s, vs.
54     // doppler energy quality prr's closer to 0.25-10 m/s.  Threshold is chosen between those
55     // typical ranges.
56     private static final float THRESHOLD_FOR_CARRIER_PRR_UNC_METERS_PER_SEC = 0.15F;
57 
58     // For gpsTimeInNs >= 1.14 * 10^18 (year 2016+)
59     private static final long GPS_TIME_YEAR_2016_IN_NSEC = 1_140_000_000L * NSEC_IN_SEC;
60 
61     // Error message for GnssMeasurements Registration.
62     public static final String REGISTRATION_ERROR_MESSAGE = "Registration of GnssMeasurements" +
63             " listener has failed, this indicates a platform bug. Please report the issue with" +
64             " a full bugreport.";
65 
66     private static final Range<Double> GPS_L1_QZSS_J1_FREQ_RANGE_HZ =
67             Range.closed(1.563e9, 1.587e9);
68     private static final Range<Double> GPS_L5_QZSS_J5_FREQ_RANGE_HZ =
69             Range.closed(1.164e9, 1.189e9);
70     private static final Range<Double> BDS_B1_FREQ_RANGE_HZ =
71             Range.closed(1.559e9, 1.591e9);
72     private static final Range<Double> BDS_B2A_FREQ_RANGE_HZ =
73             Range.closed(1.166e9, 1.186e9);
74     private static final Range<Double> GAL_E5A_FREQ_RANGE_HZ =
75             Range.closed(1.166e9, 1.186e9);
76 
77     private enum GnssBand {
78         GNSS_L1,
79         GNSS_L2,
80         GNSS_L5,
81         GNSS_E6
82     }
83 
84     // The valid Gnss navigation message type as listed in
85     // android/hardware/libhardware/include/hardware/gps.h
86     public static final Set<Integer> GNSS_NAVIGATION_MESSAGE_TYPE =
87             new HashSet<Integer>(Arrays.asList(
88                     GnssNavigationMessage.TYPE_UNKNOWN,
89                     GnssNavigationMessage.TYPE_GPS_L1CA,
90                     GnssNavigationMessage.TYPE_GPS_L2CNAV,
91                     GnssNavigationMessage.TYPE_GPS_L5CNAV,
92                     GnssNavigationMessage.TYPE_GPS_CNAV2,
93                     GnssNavigationMessage.TYPE_SBS,
94                     GnssNavigationMessage.TYPE_GLO_L1CA,
95                     GnssNavigationMessage.TYPE_QZS_L1CA,
96                     GnssNavigationMessage.TYPE_BDS_D1,
97                     GnssNavigationMessage.TYPE_BDS_D2,
98                     GnssNavigationMessage.TYPE_BDS_CNAV1,
99                     GnssNavigationMessage.TYPE_BDS_CNAV2,
100                     GnssNavigationMessage.TYPE_GAL_I,
101                     GnssNavigationMessage.TYPE_GAL_F,
102                     GnssNavigationMessage.TYPE_IRN_L5CA
103             ));
104 
105     /**
106      * Check if test can be run on the current device.
107      *
108      * @param  testLocationManager TestLocationManager
109      * @return true if Build.VERSION &gt;= {@code androidSdkVersionCode} and Location GPS present on
110      *         device.
111      */
canTestRunOnCurrentDevice(TestLocationManager testLocationManager, String testTag)112     public static boolean canTestRunOnCurrentDevice(TestLocationManager testLocationManager,
113             String testTag) {
114         // If device does not have a GPS, skip the test.
115         if (!TestUtils.deviceHasGpsFeature(testLocationManager.getContext())) {
116             Log.i(TAG, "Skip the test since GPS is not supported on the device.");
117             return false;
118         }
119 
120         boolean gpsProviderEnabled = testLocationManager.getLocationManager()
121                 .isProviderEnabled(LocationManager.GPS_PROVIDER);
122         SoftAssert.failOrWarning(true, " GPS location disabled on the device. "
123                 + "Enable location in settings to continue test.", gpsProviderEnabled);
124         return gpsProviderEnabled;
125     }
126 
127     /**
128      * Check if current device is an Android Automotive OS device.
129      */
isAutomotiveDevice(Context context)130     public static boolean isAutomotiveDevice(Context context) {
131         return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
132     }
133 
134     /**
135      * Check if pseudorange rate uncertainty in Gnss Measurement is in the expected range.
136      * See field description in {@code gps.h}.
137      *
138      * @param measurement GnssMeasurement
139      * @return true if this measurement has prr uncertainty in a range indicative of carrier phase
140      */
gnssMeasurementHasCarrierPhasePrr(GnssMeasurement measurement)141     public static boolean gnssMeasurementHasCarrierPhasePrr(GnssMeasurement measurement) {
142       return (measurement.getPseudorangeRateUncertaintyMetersPerSecond() <
143               THRESHOLD_FOR_CARRIER_PRR_UNC_METERS_PER_SEC);
144     }
145 
146     /**
147      * Assert all mandatory fields in Gnss Clock are in expected range.
148      * See mandatory fields in {@code gps.h}.
149      *
150      * @param clock       GnssClock
151      * @param softAssert  custom SoftAssert
152      * @param timeInNs    event time in ns
153      */
assertGnssClockFields(GnssClock clock, SoftAssert softAssert, long timeInNs)154     public static void assertGnssClockFields(GnssClock clock,
155                                              SoftAssert softAssert,
156                                              long timeInNs) {
157         softAssert.assertTrue("time_ns: clock value",
158                 timeInNs,
159                 "X >= 0",
160                 String.valueOf(timeInNs),
161                 timeInNs >= 0L);
162 
163         // If full bias is valid and accurate within one sec. verify its sign & magnitude
164         if (clock.hasFullBiasNanos() &&
165                 ((!clock.hasBiasUncertaintyNanos()) ||
166                         (clock.getBiasUncertaintyNanos() < NSEC_IN_SEC))) {
167             long gpsTimeInNs = timeInNs - clock.getFullBiasNanos();
168             softAssert.assertTrue("TimeNanos - FullBiasNanos = GpsTimeNanos: clock value",
169                     gpsTimeInNs,
170                     "gpsTimeInNs >= 1.14 * 10^18 (year 2016+)",
171                     String.valueOf(gpsTimeInNs),
172                     gpsTimeInNs >= GPS_TIME_YEAR_2016_IN_NSEC);
173         }
174     }
175 
176     /**
177      * Asserts the same FullBiasNanos of multiple GnssMeasurementEvents at the same time epoch.
178      *
179      * <p>FullBiasNanos denotes the receiver clock bias calculated by the GNSS chipset. If multiple
180      * GnssMeasurementEvents are tagged with the same time epoch, their FullBiasNanos should be the
181      * same.
182      *
183      * @param softAssert custom SoftAssert
184      * @param events     GnssMeasurementEvents. Each event includes one GnssClock with a
185      *                   fullBiasNanos.
186      */
assertGnssClockHasConsistentFullBiasNanos(SoftAssert softAssert, List<GnssMeasurementsEvent> events)187     public static void assertGnssClockHasConsistentFullBiasNanos(SoftAssert softAssert,
188             List<GnssMeasurementsEvent> events) {
189         Map<Long, List<Long>> timeToFullBiasList = new HashMap<>();
190         for (GnssMeasurementsEvent event : events) {
191             long timeNanos = event.getClock().getTimeNanos();
192             long fullBiasNanos = event.getClock().getFullBiasNanos();
193 
194             timeToFullBiasList.putIfAbsent(timeNanos, new ArrayList<>());
195             List<Long> fullBiasNanosList = timeToFullBiasList.get(timeNanos);
196             fullBiasNanosList.add(fullBiasNanos);
197         }
198 
199         for (Map.Entry<Long, List<Long>> entry : timeToFullBiasList.entrySet()) {
200             long timeNanos = entry.getKey();
201             List<Long> fullBiasNanosList = entry.getValue();
202             if (fullBiasNanosList.size() < 2) {
203                 continue;
204             }
205             long fullBiasNanos = fullBiasNanosList.get(0);
206             for (int i = 1; i < fullBiasNanosList.size(); i++) {
207                 softAssert.assertTrue("FullBiasNanos are the same at the same timeNanos",
208                         timeNanos,
209                         "fullBiasNanosList.get(i) - fullBiasNanosList.get(0) == 0",
210                         String.valueOf(fullBiasNanosList.get(i) - fullBiasNanos),
211                         fullBiasNanosList.get(i) - fullBiasNanos == 0);
212             }
213         }
214     }
215 
216     /**
217      * Assert all mandatory fields in Gnss Measurement are in expected range.
218      * See mandatory fields in {@code gps.h}.
219      *
220      * @param testLocationManager TestLocationManager
221      * @param measurement GnssMeasurement
222      * @param softAssert  custom SoftAssert
223      * @param timeInNs    event time in ns
224      */
assertAllGnssMeasurementMandatoryFields( TestLocationManager testLocationManager, GnssMeasurement measurement, SoftAssert softAssert, long timeInNs)225     public static void assertAllGnssMeasurementMandatoryFields(
226         TestLocationManager testLocationManager, GnssMeasurement measurement,
227         SoftAssert softAssert, long timeInNs) {
228 
229         verifySvid(measurement, softAssert, timeInNs);
230         verifyReceivedSatelliteVehicleTimeInNs(measurement, softAssert, timeInNs);
231         verifyAccumulatedDeltaRanges(measurement, softAssert, timeInNs);
232 
233         int state = measurement.getState();
234         softAssert.assertTrue("state: Satellite code sync state",
235                 timeInNs,
236                 "X >= 0",
237                 String.valueOf(state),
238                 state >= 0);
239 
240         // Check received_gps_tow_uncertainty_ns
241         softAssert.assertTrueAsWarning("received_gps_tow_uncertainty_ns:" +
242                         " Uncertainty of received GPS Time-of-Week in ns",
243                 timeInNs,
244                 "X > 0",
245                 String.valueOf(measurement.getReceivedSvTimeUncertaintyNanos()),
246                 measurement.getReceivedSvTimeUncertaintyNanos() > 0L);
247 
248         long timeOffsetInSec = TimeUnit.NANOSECONDS.toSeconds(
249                 (long) measurement.getTimeOffsetNanos());
250         softAssert.assertTrue("time_offset_ns: Time offset",
251                 timeInNs,
252                 "-100 seconds < X < +10 seconds",
253                 String.valueOf(measurement.getTimeOffsetNanos()),
254                 (-100 < timeOffsetInSec) && (timeOffsetInSec < 10));
255 
256         softAssert.assertTrue("c_n0_dbhz: Carrier-to-noise density",
257                 timeInNs,
258                 "0.0 >= X <=63",
259                 String.valueOf(measurement.getCn0DbHz()),
260                 measurement.getCn0DbHz() >= 0.0 &&
261                         measurement.getCn0DbHz() <= 63.0);
262 
263         softAssert.assertTrue("pseudorange_rate_uncertainty_mps: " +
264                         "Pseudorange Rate Uncertainty in m/s",
265                 timeInNs,
266                 "X > 0.0",
267                 String.valueOf(
268                         measurement.getPseudorangeRateUncertaintyMetersPerSecond()),
269                 measurement.getPseudorangeRateUncertaintyMetersPerSecond() > 0.0);
270 
271         verifyGnssCarrierFrequency(softAssert, testLocationManager,
272                 measurement.hasCarrierFrequencyHz(),
273                 measurement.hasCarrierFrequencyHz() ? measurement.getCarrierFrequencyHz() : 0F);
274 
275         // Check carrier_phase.
276         if (measurement.hasCarrierPhase()) {
277             softAssert.assertTrue("carrier_phase: Carrier phase",
278                     timeInNs,
279                     "0.0 >= X <= 1.0",
280                     String.valueOf(measurement.getCarrierPhase()),
281                     measurement.getCarrierPhase() >= 0.0 && measurement.getCarrierPhase() <= 1.0);
282         }
283 
284         // Check carrier_phase_uncertainty..
285         if (measurement.hasCarrierPhaseUncertainty()) {
286             softAssert.assertTrue("carrier_phase_uncertainty: 1-Sigma uncertainty of the " +
287                             "carrier-phase",
288                     timeInNs,
289                     "X > 0.0",
290                     String.valueOf(measurement.getCarrierPhaseUncertainty()),
291                     measurement.getCarrierPhaseUncertainty() > 0.0);
292         }
293 
294         // Check GNSS Measurement's multipath_indicator.
295         softAssert.assertTrue("multipath_indicator: GNSS Measurement's multipath indicator",
296                 timeInNs,
297                 "0 >= X <= 2",
298                 String.valueOf(measurement.getMultipathIndicator()),
299                 measurement.getMultipathIndicator() >= 0
300                         && measurement.getMultipathIndicator() <= 2);
301 
302 
303         // Check Signal-to-Noise ratio (SNR).
304         if (measurement.hasSnrInDb()) {
305             softAssert.assertTrue("snr: Signal-to-Noise ratio (SNR) in dB",
306                     timeInNs,
307                     "0.0 >= X <= 63",
308                     String.valueOf(measurement.getSnrInDb()),
309                     measurement.getSnrInDb() >= 0.0 && measurement.getSnrInDb() <= 63);
310         }
311 
312         if (measurement.hasAutomaticGainControlLevelDb()) {
313             softAssert.assertTrue("Automatic Gain Control level in dB",
314                 timeInNs,
315                 "-100 >= X <= 100",
316                 String.valueOf(measurement.getAutomaticGainControlLevelDb()),
317                 measurement.getAutomaticGainControlLevelDb() >= -100
318                     && measurement.getAutomaticGainControlLevelDb() <= 100);
319         }
320     }
321 
322     /**
323      * Assert all SystemApi fields in Gnss Measurement are in expected range.
324      *
325      * @param measurement GnssMeasurement
326      * @param softAssert  custom SoftAssert
327      * @param timeInNs    event time in ns
328      */
assertAllGnssMeasurementSystemFields(GnssMeasurement measurement, SoftAssert softAssert, long timeInNs)329     public static void assertAllGnssMeasurementSystemFields(GnssMeasurement measurement,
330         SoftAssert softAssert, long timeInNs) {
331 
332         if (measurement.hasCorrelationVectors()) {
333             verifyCorrelationVectors(measurement, softAssert, timeInNs);
334         }
335 
336         if (measurement.hasSatellitePvt()) {
337             verifySatellitePvt(measurement, softAssert, timeInNs);
338         }
339     }
340 
341     /**
342      * Verify correlation vectors are in expected range.
343      *
344      * @param measurement GnssMeasurement
345      * @param softAssert  custom SoftAssert
346      * @param timeInNs    event time in ns
347      */
verifyCorrelationVectors(GnssMeasurement measurement, SoftAssert softAssert, long timeInNs)348     private static void verifyCorrelationVectors(GnssMeasurement measurement,
349         SoftAssert softAssert, long timeInNs) {
350         Collection<CorrelationVector> correlationVectors =
351                 measurement.getCorrelationVectors();
352         assertNotNull("CorrelationVectors cannot be null.", correlationVectors);
353         softAssert.assertTrue("CorrelationVectors count",
354                 timeInNs,
355                 "X > 0",
356                 String.valueOf(correlationVectors.size()),
357                 correlationVectors.size() > 0);
358         for (CorrelationVector correlationVector : correlationVectors) {
359             assertNotNull("CorrelationVector cannot be null.", correlationVector);
360             int[] magnitude = correlationVector.getMagnitude();
361             softAssert.assertTrue("frequency_offset_mps : "
362                     + "Frequency offset from reported pseudorange rate "
363                     + "for this CorrelationVector",
364                     timeInNs,
365                     "X >= 0.0",
366                     String.valueOf(correlationVector.getFrequencyOffsetMetersPerSecond()),
367                     correlationVector.getFrequencyOffsetMetersPerSecond() >= 0.0);
368             softAssert.assertTrue("sampling_width_m : "
369                     + "The space between correlation samples in meters",
370                     timeInNs,
371                     "X > 0.0",
372                     String.valueOf(correlationVector.getSamplingWidthMeters()),
373                     correlationVector.getSamplingWidthMeters() > 0.0);
374             softAssert.assertTrue("Magnitude count",
375                     timeInNs,
376                     "X > 0",
377                     String.valueOf(magnitude.length),
378                 magnitude.length > 0);
379             for (int value : magnitude) {
380                 softAssert.assertTrue("magnitude : Data representing normalized "
381                         + "correlation magnitude values",
382                         timeInNs,
383                         "-32768 <= X < 32767",
384                         String.valueOf(value),
385                         value >= -32768 && value < 32767);
386             }
387         }
388     }
389 
390     /**
391      * Verify accumulated delta ranges are in expected range.
392      *
393      * @param measurement GnssMeasurement
394      * @param softAssert  custom SoftAssert
395      * @param timeInNs    event time in ns
396      */
verifyAccumulatedDeltaRanges(GnssMeasurement measurement, SoftAssert softAssert, long timeInNs)397     private static void verifyAccumulatedDeltaRanges(GnssMeasurement measurement,
398         SoftAssert softAssert, long timeInNs) {
399 
400         int accumulatedDeltaRangeState = measurement.getAccumulatedDeltaRangeState();
401         softAssert.assertTrue("accumulated_delta_range_state: " +
402                 "Accumulated delta range state",
403                 timeInNs,
404                 "X & ~ADR_STATE_ALL == 0",
405                 String.valueOf(accumulatedDeltaRangeState),
406                 (accumulatedDeltaRangeState & ~GnssMeasurement.ADR_STATE_ALL) == 0);
407         softAssert.assertTrue("accumulated_delta_range_state: " +
408                 "Accumulated delta range state",
409                 timeInNs,
410                 "ADR_STATE_HALF_CYCLE_REPORTED, or !ADR_STATE_HALF_CYCLE_RESOLVED",
411                 String.valueOf(accumulatedDeltaRangeState),
412                 ((accumulatedDeltaRangeState &
413                   GnssMeasurement.ADR_STATE_HALF_CYCLE_REPORTED) != 0) ||
414                  (accumulatedDeltaRangeState &
415                   GnssMeasurement.ADR_STATE_HALF_CYCLE_RESOLVED) == 0);
416         if ((accumulatedDeltaRangeState & GnssMeasurement.ADR_STATE_VALID) != 0) {
417             double accumulatedDeltaRangeInMeters =
418                     measurement.getAccumulatedDeltaRangeMeters();
419             softAssert.assertTrue("accumulated_delta_range_m: " +
420                     "Accumulated delta range in meter",
421                     timeInNs,
422                     "X != 0.0",
423                     String.valueOf(accumulatedDeltaRangeInMeters),
424                     accumulatedDeltaRangeInMeters != 0.0);
425             double accumulatedDeltaRangeUncertainty =
426                     measurement.getAccumulatedDeltaRangeUncertaintyMeters();
427             softAssert.assertTrue("accumulated_delta_range_uncertainty_m: " +
428                     "Accumulated delta range uncertainty in meter",
429                     timeInNs,
430                     "X > 0.0",
431                     String.valueOf(accumulatedDeltaRangeUncertainty),
432                     accumulatedDeltaRangeUncertainty > 0.0);
433         }
434     }
435 
436     /**
437      * Verify svid's are in expected range.
438      *
439      * @param measurement GnssMeasurement
440      * @param softAssert  custom SoftAssert
441      * @param timeInNs    event time in ns
442      */
verifySvid(GnssMeasurement measurement, SoftAssert softAssert, long timeInNs)443     private static void verifySvid(GnssMeasurement measurement, SoftAssert softAssert,
444         long timeInNs) {
445 
446         int constellationType = measurement.getConstellationType();
447         int svid = measurement.getSvid();
448         validateSvidSub(softAssert, timeInNs, constellationType, svid);
449     }
450 
validateSvidSub(SoftAssert softAssert, Long timeInNs, int constellationType, int svid)451     public static void validateSvidSub(SoftAssert softAssert, Long timeInNs,
452         int constellationType, int svid) {
453 
454         String svidValue = String.valueOf(svid);
455 
456         switch (constellationType) {
457             case GnssStatus.CONSTELLATION_GPS:
458                 softAssert.assertTrue("svid: Space Vehicle ID. Constellation type " +
459                                 "= CONSTELLATION_GPS",
460                         timeInNs,
461                         "[1, 32]",
462                         svidValue,
463                         svid > 0 && svid <= 32);
464                 break;
465             case GnssStatus.CONSTELLATION_SBAS:
466                 softAssert.assertTrue("svid: Space Vehicle ID. Constellation type " +
467                                 "= CONSTELLATION_SBAS",
468                         timeInNs,
469                         "120 <= X <= 192",
470                         svidValue,
471                         svid >= 120 && svid <= 192);
472                 break;
473             case GnssStatus.CONSTELLATION_GLONASS:
474                 softAssert.assertTrue("svid: Slot ID, or if unknown, Frequency + 100 (93-106). " +
475                                 "Constellation type = CONSTELLATION_GLONASS",
476                         timeInNs,
477                         "1 <= svid <= 25 || 93 <= svid <= 106",
478                         svidValue,
479                         (svid >= 1 && svid <= 25) || (svid >= 93 && svid <= 106));
480                 break;
481             case GnssStatus.CONSTELLATION_QZSS:
482                 softAssert.assertTrue("svid: Space Vehicle ID. Constellation type " +
483                                 "= CONSTELLATION_QZSS",
484                         timeInNs,
485                         "183 <= X <= 206",
486                         svidValue,
487                         svid >= 183 && svid <= 206);
488                 break;
489             case GnssStatus.CONSTELLATION_BEIDOU:
490                 softAssert.assertTrue("svid: Space Vehicle ID. Constellation type " +
491                                 "= CONSTELLATION_BEIDOU",
492                         timeInNs,
493                         "1 <= X <= 63",
494                         svidValue,
495                         svid >= 1 && svid <= 63);
496                 break;
497             case GnssStatus.CONSTELLATION_GALILEO:
498                 softAssert.assertTrue("svid: Space Vehicle ID. Constellation type " +
499                                 "= CONSTELLATION_GALILEO",
500                         timeInNs,
501                         "1 <= X <= 36",
502                         String.valueOf(svid),
503                         svid >= 1 && svid <= 36);
504                 break;
505             case GnssStatus.CONSTELLATION_IRNSS:
506                 softAssert.assertTrue("svid: Space Vehicle ID. Constellation type " +
507                                 "= CONSTELLATION_IRNSS",
508                         timeInNs,
509                         "1 <= X <= 14",
510                         String.valueOf(svid),
511                         svid >= 1 && svid <= 14);
512                 break;
513             default:
514                 // Explicit fail if did not receive valid constellation type.
515                 softAssert.assertTrue("svid: Space Vehicle ID. Did not receive any valid " +
516                                 "constellation type.",
517                         timeInNs,
518                         "Valid constellation type.",
519                         svidValue,
520                         false);
521                 break;
522         }
523     }
524 
525     /**
526      * Verify sv times are in expected range.
527      *
528      * @param measurement GnssMeasurement
529      * @param softAssert  custom SoftAssert
530      * @param timeInNs    event time in ns
531      */
verifyReceivedSatelliteVehicleTimeInNs(GnssMeasurement measurement, SoftAssert softAssert, long timeInNs)532     private static void verifyReceivedSatelliteVehicleTimeInNs(GnssMeasurement measurement,
533         SoftAssert softAssert, long timeInNs) {
534 
535         int constellationType = measurement.getConstellationType();
536         int state = measurement.getState();
537         long received_sv_time_ns = measurement.getReceivedSvTimeNanos();
538         double sv_time_ms = TimeUnit.NANOSECONDS.toMillis(received_sv_time_ns);
539         double sv_time_sec = TimeUnit.NANOSECONDS.toSeconds(received_sv_time_ns);
540         double sv_time_days = TimeUnit.NANOSECONDS.toDays(received_sv_time_ns);
541 
542         // Check ranges for received_sv_time_ns for given Gps State
543         if (state == 0) {
544             softAssert.assertTrue("received_sv_time_ns:" +
545                             " Received SV Time-of-Week in ns." +
546                             " GNSS_MEASUREMENT_STATE_UNKNOWN.",
547                     timeInNs,
548                     "X == 0",
549                     String.valueOf(received_sv_time_ns),
550                     sv_time_ms == 0);
551         }
552 
553         switch (constellationType) {
554             case GnssStatus.CONSTELLATION_GPS:
555                 verifyGpsQzssSvTimes(measurement, softAssert, timeInNs, state, "CONSTELLATION_GPS");
556                 break;
557             case GnssStatus.CONSTELLATION_QZSS:
558                 verifyGpsQzssSvTimes(measurement, softAssert, timeInNs, state,
559                         "CONSTELLATION_QZSS");
560                 break;
561             case GnssStatus.CONSTELLATION_SBAS:
562                 if ((state & GnssMeasurement.STATE_SBAS_SYNC)
563                         == GnssMeasurement.STATE_SBAS_SYNC) {
564                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
565                                     "GNSS_MEASUREMENT_STATE_SBAS_SYNC",
566                                     "GnssStatus.CONSTELLATION_SBAS"),
567                             timeInNs,
568                             "0s >= X <= 1s",
569                             String.valueOf(sv_time_sec),
570                             sv_time_sec >= 0 && sv_time_sec <= 1);
571                 } else if ((state & GnssMeasurement.STATE_SYMBOL_SYNC)
572                         == GnssMeasurement.STATE_SYMBOL_SYNC) {
573                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
574                                     "GNSS_MEASUREMENT_STATE_SYMBOL_SYNC",
575                                     "GnssStatus.CONSTELLATION_SBAS"),
576                             timeInNs,
577                             "0ms >= X <= 2ms",
578                             String.valueOf(sv_time_ms),
579                             sv_time_ms >= 0 && sv_time_ms <= 2);
580                 } else if ((state & GnssMeasurement.STATE_CODE_LOCK)
581                         == GnssMeasurement.STATE_CODE_LOCK) {
582                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
583                                     "GNSS_MEASUREMENT_STATE_CODE_LOCK",
584                                     "GnssStatus.CONSTELLATION_SBAS"),
585                             timeInNs,
586                             "0ms >= X <= 1ms",
587                             String.valueOf(sv_time_ms),
588                             sv_time_ms >= 0 && sv_time_ms <= 1);
589                 }
590                 break;
591             case GnssStatus.CONSTELLATION_GLONASS:
592                 if ((state & GnssMeasurement.STATE_GLO_TOD_DECODED)
593                         == GnssMeasurement.STATE_GLO_TOD_DECODED) {
594                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
595                                     "GNSS_MEASUREMENT_STATE_GLO_TOD_DECODED",
596                                     "GnssStatus.CONSTELLATION_GLONASS"),
597                             timeInNs,
598                             "0 day >= X <= 1 day",
599                             String.valueOf(sv_time_days),
600                             sv_time_days >= 0 && sv_time_days <= 1);
601                 } else if ((state & GnssMeasurement.STATE_GLO_TOD_KNOWN)
602                          == GnssMeasurement.STATE_GLO_TOD_KNOWN) {
603                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
604                                     "GNSS_MEASUREMENT_STATE_GLO_TOD_KNOWN",
605                                     "GnssStatus.CONSTELLATION_GLONASS"),
606                             timeInNs,
607                             "0 day >= X <= 1 day",
608                             String.valueOf(sv_time_days),
609                             sv_time_days >= 0 && sv_time_days <= 1);
610                 } else if ((state & GnssMeasurement.STATE_GLO_STRING_SYNC)
611                         == GnssMeasurement.STATE_GLO_STRING_SYNC) {
612                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
613                                     "GNSS_MEASUREMENT_STATE_GLO_STRING_SYNC",
614                                     "GnssStatus.CONSTELLATION_GLONASS"),
615                             timeInNs,
616                             "0s >= X <= 2s",
617                             String.valueOf(sv_time_sec),
618                             sv_time_sec >= 0 && sv_time_sec <= 2);
619                 } else if ((state & GnssMeasurement.STATE_BIT_SYNC)
620                         == GnssMeasurement.STATE_BIT_SYNC) {
621                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
622                                     "GNSS_MEASUREMENT_STATE_BIT_SYNC",
623                                     "GnssStatus.CONSTELLATION_GLONASS"),
624                             timeInNs,
625                             "0ms >= X <= 20ms",
626                             String.valueOf(sv_time_ms),
627                             sv_time_ms >= 0 && sv_time_ms <= 20);
628                 } else if ((state & GnssMeasurement.STATE_SYMBOL_SYNC)
629                         == GnssMeasurement.STATE_SYMBOL_SYNC) {
630                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
631                                     "GNSS_MEASUREMENT_STATE_SYMBOL_SYNC",
632                                     "GnssStatus.CONSTELLATION_GLONASS"),
633                             timeInNs,
634                             "0ms >= X <= 10ms",
635                             String.valueOf(sv_time_ms),
636                             sv_time_ms >= 0 && sv_time_ms <= 10);
637                 } else if ((state & GnssMeasurement.STATE_CODE_LOCK)
638                         == GnssMeasurement.STATE_CODE_LOCK) {
639                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
640                                     "GNSS_MEASUREMENT_STATE_CODE_LOCK",
641                                     "GnssStatus.CONSTELLATION_GLONASS"),
642                             timeInNs,
643                             "0ms >= X <= 1ms",
644                             String.valueOf(sv_time_ms),
645                             sv_time_ms >= 0 && sv_time_ms <= 1);
646                 }
647                 break;
648             case GnssStatus.CONSTELLATION_GALILEO:
649                 if ((state & GnssMeasurement.STATE_TOW_DECODED)
650                         == GnssMeasurement.STATE_TOW_DECODED) {
651                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
652                                     "GNSS_MEASUREMENT_STATE_TOW_DECODED",
653                                     "GnssStatus.CONSTELLATION_GALILEO"),
654                             timeInNs,
655                             "0 >= X <= 7 days",
656                             String.valueOf(sv_time_days),
657                             sv_time_days >= 0 && sv_time_days <= 7);
658                 } else if ((state & GnssMeasurement.STATE_TOW_KNOWN)
659                               == GnssMeasurement.STATE_TOW_KNOWN) {
660                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
661                                     "GNSS_MEASUREMENT_STATE_TOW_DECODED",
662                                     "GnssStatus.CONSTELLATION_GALILEO"),
663                         timeInNs,
664                         "0 >= X <= 7 days",
665                         String.valueOf(sv_time_days),
666                         sv_time_days >= 0 && sv_time_days <= 7);
667                 } else if ((state & GnssMeasurement.STATE_GAL_E1B_PAGE_SYNC)
668                         == GnssMeasurement.STATE_GAL_E1B_PAGE_SYNC) {
669                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
670                                     "GNSS_MEASUREMENT_STATE_GAL_E1B_PAGE_SYNC",
671                                     "GnssStatus.CONSTELLATION_GALILEO"),
672                             timeInNs,
673                             "0s >= X <= 2s",
674                             String.valueOf(sv_time_sec),
675                             sv_time_sec >= 0 && sv_time_sec <= 2);
676                 } else if ((state & GnssMeasurement.STATE_GAL_E1C_2ND_CODE_LOCK)
677                         == GnssMeasurement.STATE_GAL_E1C_2ND_CODE_LOCK) {
678                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
679                                     "GNSS_MEASUREMENT_STATE_GAL_E1C_2ND_CODE_LOCK",
680                                     "GnssStatus.CONSTELLATION_GALILEO"),
681                             timeInNs,
682                             "0ms >= X <= 100ms",
683                             String.valueOf(sv_time_ms),
684                             sv_time_ms >= 0 && sv_time_ms <= 100);
685                 } else if ((state & GnssMeasurement.STATE_GAL_E1BC_CODE_LOCK)
686                         == GnssMeasurement.STATE_GAL_E1BC_CODE_LOCK) {
687                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
688                                     "GNSS_MEASUREMENT_STATE_GAL_E1BC_CODE_LOCK",
689                                     "GnssStatus.CONSTELLATION_GALILEO"),
690                             timeInNs,
691                             "0ms >= X <= 4ms",
692                             String.valueOf(sv_time_ms),
693                             sv_time_ms >= 0 && sv_time_ms <= 4);
694                 } else if ((state & GnssMeasurement.STATE_2ND_CODE_LOCK)
695                         == GnssMeasurement.STATE_2ND_CODE_LOCK
696                         && GAL_E5A_FREQ_RANGE_HZ.contains(
697                         (double) measurement.getCarrierFrequencyHz())) {
698                     // E5A
699                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
700                                     "GNSS_MEASUREMENT_STATE_2ND_CODE_LOCK",
701                                     "GnssStatus.CONSTELLATION_GALILEO"),
702                             timeInNs,
703                             "0ms >= X <= 100ms",
704                             String.valueOf(sv_time_ms),
705                             sv_time_ms >= 0 && sv_time_ms <= 100);
706                 }
707                 break;
708             case GnssStatus.CONSTELLATION_BEIDOU:
709                 if ((state & GnssMeasurement.STATE_TOW_DECODED)
710                         == GnssMeasurement.STATE_TOW_DECODED) {
711                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
712                                     "GNSS_MEASUREMENT_STATE_TOW_DECODED",
713                                     "GnssStatus.CONSTELLATION_BEIDOU"),
714                             timeInNs,
715                             "0 >= X <= 7 days",
716                             String.valueOf(sv_time_days),
717                             sv_time_days >= 0 && sv_time_days <= 7);
718                 } else if ((state & GnssMeasurement.STATE_TOW_KNOWN)
719                         == GnssMeasurement.STATE_TOW_KNOWN) {
720                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
721                                     "GNSS_MEASUREMENT_STATE_TOW_KNOWN",
722                                     "GnssStatus.CONSTELLATION_BEIDOU"),
723                             timeInNs,
724                             "0 >= X <= 7 days",
725                             String.valueOf(sv_time_days),
726                             sv_time_days >= 0 && sv_time_days <= 7);
727                 } else if ((state & GnssMeasurement.STATE_SUBFRAME_SYNC)
728                         == GnssMeasurement.STATE_SUBFRAME_SYNC) {
729                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
730                                     "GNSS_MEASUREMENT_STATE_SUBFRAME_SYNC",
731                                     "GnssStatus.CONSTELLATION_BEIDOU"),
732                             timeInNs,
733                             "0s >= X <= 6s",
734                             String.valueOf(sv_time_sec),
735                             sv_time_sec >= 0 && sv_time_sec <= 6);
736                 } else if ((state & GnssMeasurement.STATE_BDS_D2_SUBFRAME_SYNC)
737                         == GnssMeasurement.STATE_BDS_D2_SUBFRAME_SYNC) {
738                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
739                                     "GNSS_MEASUREMENT_STATE_BDS_D2_SUBFRAME_SYNC",
740                                     "GnssStatus.CONSTELLATION_BEIDOU"),
741                             timeInNs,
742                             "0ms >= X <= 600ms (0.6sec)",
743                             String.valueOf(sv_time_ms),
744                             sv_time_ms >= 0 && sv_time_ms <= 600);
745                 } else if ((state & GnssMeasurement.STATE_BIT_SYNC)
746                         == GnssMeasurement.STATE_BIT_SYNC) {
747                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
748                                     "GNSS_MEASUREMENT_STATE_BIT_SYNC",
749                                     "GnssStatus.CONSTELLATION_BEIDOU"),
750                             timeInNs,
751                             "0ms >= X <= 20ms",
752                             String.valueOf(sv_time_ms),
753                             sv_time_ms >= 0 && sv_time_ms <= 20);
754                 } else if ((state & GnssMeasurement.STATE_BDS_D2_BIT_SYNC)
755                         == GnssMeasurement.STATE_BDS_D2_BIT_SYNC) {
756                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
757                                     "GNSS_MEASUREMENT_STATE_BDS_D2_BIT_SYNC",
758                                     "GnssStatus.CONSTELLATION_BEIDOU"),
759                             timeInNs,
760                             "0ms >= X <= 2ms",
761                             String.valueOf(sv_time_ms),
762                             sv_time_ms >= 0 && sv_time_ms <= 2);
763                 } else if ((state & GnssMeasurement.STATE_CODE_LOCK)
764                         == GnssMeasurement.STATE_CODE_LOCK) {
765                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
766                                     "GNSS_MEASUREMENT_STATE_CODE_LOCK",
767                                     "GnssStatus.CONSTELLATION_BEIDOU"),
768                             timeInNs,
769                             "0ms >= X <= 1ms",
770                             String.valueOf(sv_time_ms),
771                             sv_time_ms >= 0 && sv_time_ms <= 1);
772                 } else if ((state & GnssMeasurement.STATE_2ND_CODE_LOCK)
773                         == GnssMeasurement.STATE_2ND_CODE_LOCK) {
774                     if (BDS_B1_FREQ_RANGE_HZ.contains(
775                             (double) measurement.getCarrierFrequencyHz())) {
776                         // B1C (P)
777                         softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
778                                         "GNSS_MEASUREMENT_STATE_2ND_CODE_LOCK",
779                                         "GnssStatus.CONSTELLATION_BEIDOU"),
780                                 timeInNs,
781                                 "0ms >= X <= 18000ms",
782                                 String.valueOf(sv_time_ms),
783                                 sv_time_ms >= 0 && sv_time_ms <= 18000);
784                     } else if (BDS_B2A_FREQ_RANGE_HZ.contains(
785                             (double) measurement.getCarrierFrequencyHz())) {
786                         // B2A
787                         softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
788                                         "GNSS_MEASUREMENT_STATE_2ND_CODE_LOCK",
789                                         "GnssStatus.CONSTELLATION_BEIDOU"),
790                                 timeInNs,
791                                 "0ms >= X <= 100ms",
792                                 String.valueOf(sv_time_ms),
793                                 sv_time_ms >= 0 && sv_time_ms <= 100);
794                     }
795                 }
796                 break;
797         }
798     }
799 
getReceivedSvTimeNsLogMessage(String state, String constellationType)800     private static String getReceivedSvTimeNsLogMessage(String state, String constellationType) {
801         return "received_sv_time_ns: Received SV Time-of-Week in ns. Constellation type = "
802                 + constellationType + ". State = " + state;
803     }
804 
805     /**
806      * Verify sv times are in expected range for given constellation type.
807      * This is common check for CONSTELLATION_GPS & CONSTELLATION_QZSS.
808      *
809      * @param measurement GnssMeasurement
810      * @param softAssert  custom SoftAssert
811      * @param timeInNs    event time in ns
812      * @param state       GnssMeasurement State
813      * @param constellationType Gnss Constellation type
814      */
verifyGpsQzssSvTimes(GnssMeasurement measurement, SoftAssert softAssert, long timeInNs, int state, String constellationType)815     private static void verifyGpsQzssSvTimes(GnssMeasurement measurement,
816         SoftAssert softAssert, long timeInNs, int state, String constellationType) {
817 
818         long received_sv_time_ns = measurement.getReceivedSvTimeNanos();
819         double sv_time_ms = TimeUnit.NANOSECONDS.toMillis(received_sv_time_ns);
820         double sv_time_sec = TimeUnit.NANOSECONDS.toSeconds(received_sv_time_ns);
821         double sv_time_days = TimeUnit.NANOSECONDS.toDays(received_sv_time_ns);
822 
823         if ((state & GnssMeasurement.STATE_TOW_DECODED)
824                 == GnssMeasurement.STATE_TOW_DECODED) {
825             softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
826                             "GNSS_MEASUREMENT_STATE_TOW_DECODED",
827                             constellationType),
828                     timeInNs,
829                     "0 >= X <= 7 days",
830                     String.valueOf(sv_time_days),
831                     sv_time_days >= 0 && sv_time_days <= 7);
832         } else if ((state & GnssMeasurement.STATE_TOW_KNOWN)
833                 == GnssMeasurement.STATE_TOW_KNOWN) {
834             softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
835                             "GNSS_MEASUREMENT_STATE_TOW_KNOWN",
836                             constellationType),
837                     timeInNs,
838                     "0 >= X <= 7 days",
839                     String.valueOf(sv_time_days),
840                     sv_time_days >= 0 && sv_time_days <= 7);
841         } else if ((state & GnssMeasurement.STATE_SUBFRAME_SYNC)
842                 == GnssMeasurement.STATE_SUBFRAME_SYNC) {
843             softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
844                             "GNSS_MEASUREMENT_STATE_SUBFRAME_SYNC",
845                             constellationType),
846                     timeInNs,
847                     "0s >= X <= 6s",
848                     String.valueOf(sv_time_sec),
849                     sv_time_sec >= 0 && sv_time_sec <= 6);
850         } else if ((state & GnssMeasurement.STATE_BIT_SYNC)
851                 == GnssMeasurement.STATE_BIT_SYNC) {
852             softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
853                     "GNSS_MEASUREMENT_STATE_BIT_SYNC",
854                     constellationType),
855                     timeInNs,
856                     "0ms >= X <= 20ms",
857                     String.valueOf(sv_time_ms),
858                     sv_time_ms >= 0 && sv_time_ms <= 20);
859 
860         } else if ((state & GnssMeasurement.STATE_2ND_CODE_LOCK)
861                 == GnssMeasurement.STATE_2ND_CODE_LOCK) {
862             int maxReceivedSvTimeMs = -1;
863             if (isGpsL5OrQzssJ5I(measurement)) {
864                 maxReceivedSvTimeMs = 10;
865             } else if (isGpsL5OrQzssJ5Q(measurement)) {
866                 maxReceivedSvTimeMs = 20;
867             } else if (isGpsOrQZSSL1C_P(measurement)) {
868                 maxReceivedSvTimeMs = 18000;
869             } else {
870                 softAssert.assertTrue(
871                         "Signal type does not have secondary code but has have "
872                                 + "STATE_2ND_CODE_LOCK state set. constellation="
873                                 + measurement.getConstellationType()
874                                 + ", carrierFrequencyHz=" + measurement.getCarrierFrequencyHz()
875                                 + ", codeType=" + measurement.getCodeType()
876                         , false);
877             }
878 
879             softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
880                     "GNSS_MEASUREMENT_STATE_2ND_CODE_LOCK",
881                     constellationType),
882                     timeInNs,
883                     "0ms >= X <= " + maxReceivedSvTimeMs + "ms",
884                     String.valueOf(sv_time_ms),
885                     sv_time_ms >= 0 && sv_time_ms <= maxReceivedSvTimeMs);
886         } else if ((state & GnssMeasurement.STATE_CODE_LOCK)
887                 == GnssMeasurement.STATE_CODE_LOCK) {
888             softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
889                             "GNSS_MEASUREMENT_STATE_CODE_LOCK",
890                             constellationType),
891                     timeInNs,
892                     "0ms >= X <= 1ms",
893                     String.valueOf(sv_time_ms),
894                     sv_time_ms >= 0 && sv_time_ms <= 1);
895         }
896     }
897 
898     /**
899      * Get a unique string for the SV including the constellation and the default L1 band.
900      *
901      * @param constellationType Gnss Constellation type
902      * @param svId Gnss Sv Identifier
903      */
getUniqueSvStringId(int constellationType, int svId)904     public static String getUniqueSvStringId(int constellationType, int svId) {
905         return getUniqueSvStringId(constellationType, svId, GnssBand.GNSS_L1);
906     }
907 
908     /**
909      * Get a unique string for the SV including the constellation and the band.
910      *
911      * @param constellationType Gnss Constellation type
912      * @param svId Gnss Sv Identifier
913      * @param carrierFrequencyHz Carrier Frequency for Sv in Hz
914      */
getUniqueSvStringId(int constellationType, int svId, float carrierFrequencyHz)915     public static String getUniqueSvStringId(int constellationType, int svId,
916         float carrierFrequencyHz) {
917         return getUniqueSvStringId(constellationType, svId,
918             frequencyToGnssBand(carrierFrequencyHz));
919     }
920 
getUniqueSvStringId(int constellationType, int svId, GnssBand gnssBand)921     private static String getUniqueSvStringId(int constellationType, int svId, GnssBand gnssBand) {
922         return gnssBand.toString() + "." + constellationType + "." + svId;
923     }
924 
925     /**
926      * Assert all mandatory fields in Gnss Navigation Message are in expected range.
927      * See mandatory fields in {@code gps.h}.
928      *
929      * @param testLocationManager TestLocationManager
930      * @param events GnssNavigationMessageEvents
931      */
verifyGnssNavMessageMandatoryField(TestLocationManager testLocationManager, List<GnssNavigationMessage> events)932     public static void verifyGnssNavMessageMandatoryField(TestLocationManager testLocationManager,
933                                                           List<GnssNavigationMessage> events) {
934         // Verify mandatory GnssNavigationMessage field values.
935         SoftAssert softAssert = new SoftAssert(TAG);
936         for (GnssNavigationMessage message : events) {
937             int type = message.getType();
938             softAssert.assertTrue("Gnss Navigation Message Type:expected [" +
939                 getGnssNavMessageTypes() + "] actual = " + type,
940                     GNSS_NAVIGATION_MESSAGE_TYPE.contains(type));
941 
942             int messageType = message.getType();
943             softAssert.assertTrue("Message ID cannot be 0", message.getMessageId() != 0);
944             if (messageType == GnssNavigationMessage.TYPE_GAL_I) {
945                 softAssert.assertTrue("Sub Message ID can not be negative.",
946                     message.getSubmessageId() >= 0);
947             } else {
948                 softAssert.assertTrue("Sub Message ID has to be greater than 0.",
949                     message.getSubmessageId() > 0);
950             }
951 
952             // if message type == TYPE_L1CA, verify PRN & Data Size.
953             if (messageType == GnssNavigationMessage.TYPE_GPS_L1CA) {
954                 int svid = message.getSvid();
955                 softAssert.assertTrue("Space Vehicle ID : expected = [1, 32], actual = " +
956                                 svid,
957                         svid >= 1 && svid <= 32);
958                 int dataSize = message.getData().length;
959                 softAssert.assertTrue("Data size: expected = 40, actual = " + dataSize,
960                         dataSize == 40);
961             } else {
962                 Log.i(TAG, "GnssNavigationMessage (type = " + messageType
963                         + ") skipped for verification.");
964             }
965         }
966         softAssert.assertAll();
967     }
968 
969     /**
970      * Asserts presence of CarrierFrequency and the values are in expected range.
971      * As per CDD 7.3.3 / C-3-3 Year 2107+ should have Carrier Frequency present
972      * As of 2018, per http://www.navipedia.net/index.php/GNSS_signal, all known GNSS bands
973      * lie within 2 frequency ranges [1100-1300] & [1500-1700].
974      *
975      * @param softAssert custom SoftAssert
976      * @param testLocationManager TestLocationManager
977      * @param hasCarrierFrequency Whether carrierFrequency is present
978      * @param carrierFrequencyHz Value of carrier frequency in Hz if hasCarrierFrequency is true.
979      *                              It is ignored when hasCarrierFrequency is false.
980      */
verifyGnssCarrierFrequency(SoftAssert softAssert, TestLocationManager testLocationManager, boolean hasCarrierFrequency, float carrierFrequencyHz)981     public static void verifyGnssCarrierFrequency(SoftAssert softAssert,
982         TestLocationManager testLocationManager,
983         boolean hasCarrierFrequency, float carrierFrequencyHz) {
984 
985         if (hasCarrierFrequency) {
986             float frequencyMhz = carrierFrequencyHz/1e6F;
987             softAssert.assertTrue("carrier_frequency_mhz: Carrier frequency in Mhz",
988                 "1100 < X < 1300 || 1500 < X < 1700",
989                 String.valueOf(frequencyMhz),
990                 (frequencyMhz > 1100.0 && frequencyMhz < 1300.0) ||
991                     (frequencyMhz > 1500.0 && frequencyMhz < 1700.0));
992         }
993     }
994 
getGnssNavMessageTypes()995     private static String getGnssNavMessageTypes() {
996         StringBuilder typesStr = new StringBuilder();
997         for (int type : GNSS_NAVIGATION_MESSAGE_TYPE) {
998             typesStr.append(String.format("0x%04X", type));
999             typesStr.append(", ");
1000         }
1001 
1002         return typesStr.length() > 2 ? typesStr.substring(0, typesStr.length() - 2) : "";
1003     }
1004 
1005     /**
1006      * The band information is as of 2018, per http://www.navipedia.net/index.php/GNSS_signal
1007      * Bands are combined for simplicity as the constellation is also tracked.
1008      *
1009      * @param frequencyHz Frequency in Hz
1010      * @return GnssBand where the frequency lies.
1011      */
frequencyToGnssBand(float frequencyHz)1012     private static GnssBand frequencyToGnssBand(float frequencyHz) {
1013         float frequencyMhz = frequencyHz/1e6F;
1014         if (frequencyMhz >= 1151 && frequencyMhz <= 1214) {
1015             return GnssBand.GNSS_L5;
1016         }
1017         if (frequencyMhz > 1214 && frequencyMhz <= 1255) {
1018             return GnssBand.GNSS_L2;
1019         }
1020         if (frequencyMhz > 1255 && frequencyMhz <= 1300) {
1021             return GnssBand.GNSS_E6;
1022         }
1023         return GnssBand.GNSS_L1; // default to L1 band
1024     }
1025 
1026     /**
1027      * Assert most of the fields in Satellite PVT are in expected range.
1028      *
1029      * @param measurement GnssMeasurement
1030      * @param softAssert  custom SoftAssert
1031      * @param timeInNs    event time in ns
1032      */
verifySatellitePvt(GnssMeasurement measurement, SoftAssert softAssert, long timeInNs)1033     private static void verifySatellitePvt(GnssMeasurement measurement,
1034         SoftAssert softAssert, long timeInNs) {
1035         SatellitePvt satellitePvt = measurement.getSatellitePvt();
1036         assertNotNull("SatellitePvt cannot be null when HAS_SATELLITE_PVT is true.", satellitePvt);
1037 
1038         if (satellitePvt.hasPositionVelocityClockInfo()){
1039             assertNotNull("PositionEcef cannot be null when "
1040                     + "HAS_POSITION_VELOCITY_CLOCK_INFO is true.", satellitePvt.getPositionEcef());
1041             assertNotNull("VelocityEcef cannot be null when "
1042                     + "HAS_POSITION_VELOCITY_CLOCK_INFO is true.", satellitePvt.getVelocityEcef());
1043             assertNotNull("ClockInfo cannot be null when "
1044                     + "HAS_POSITION_VELOCITY_CLOCK_INFO is true.", satellitePvt.getClockInfo());
1045             softAssert.assertTrue("x_meters : "
1046                     + "Satellite position X in WGS84 ECEF (meters)",
1047                     timeInNs,
1048                     "-43000000 <= X <= 43000000",
1049                     String.valueOf(satellitePvt.getPositionEcef().getXMeters()),
1050                     satellitePvt.getPositionEcef().getXMeters() >= -43000000 &&
1051                         satellitePvt.getPositionEcef().getXMeters() <= 43000000);
1052             softAssert.assertTrue("y_meters : "
1053                     + "Satellite position Y in WGS84 ECEF (meters)",
1054                     timeInNs,
1055                     "-43000000 <= X <= 43000000",
1056                     String.valueOf(satellitePvt.getPositionEcef().getYMeters()),
1057                     satellitePvt.getPositionEcef().getYMeters() >= -43000000 &&
1058                         satellitePvt.getPositionEcef().getYMeters() <= 43000000);
1059             softAssert.assertTrue("z_meters : "
1060                     + "Satellite position Z in WGS84 ECEF (meters)",
1061                     timeInNs,
1062                     "-43000000 <= X <= 43000000",
1063                     String.valueOf(satellitePvt.getPositionEcef().getZMeters()),
1064                     satellitePvt.getPositionEcef().getZMeters() >= -43000000 &&
1065                         satellitePvt.getPositionEcef().getZMeters() <= 43000000);
1066             softAssert.assertTrue("ure_meters : "
1067                     + "The Signal in Space User Range Error (URE) (meters)",
1068                     timeInNs,
1069                     "X > 0",
1070                     String.valueOf(satellitePvt.getPositionEcef().getUreMeters()),
1071                     satellitePvt.getPositionEcef().getUreMeters() > 0);
1072             softAssert.assertTrue("x_mps : "
1073                     + "Satellite velocity X in WGS84 ECEF (meters per second)",
1074                     timeInNs,
1075                     "-4000 <= X <= 4000",
1076                     String.valueOf(satellitePvt.getVelocityEcef().getXMetersPerSecond()),
1077                     satellitePvt.getVelocityEcef().getXMetersPerSecond() >= -4000 &&
1078                         satellitePvt.getVelocityEcef().getXMetersPerSecond() <= 4000);
1079             softAssert.assertTrue("y_mps : "
1080                     + "Satellite velocity Y in WGS84 ECEF (meters per second)",
1081                     timeInNs,
1082                     "-4000 <= X <= 4000",
1083                     String.valueOf(satellitePvt.getVelocityEcef().getYMetersPerSecond()),
1084                     satellitePvt.getVelocityEcef().getYMetersPerSecond() >= -4000 &&
1085                         satellitePvt.getVelocityEcef().getYMetersPerSecond() <= 4000);
1086             softAssert.assertTrue("z_mps : "
1087                     + "Satellite velocity Z in WGS84 ECEF (meters per second)",
1088                     timeInNs,
1089                     "-4000 <= X <= 4000",
1090                     String.valueOf(satellitePvt.getVelocityEcef().getZMetersPerSecond()),
1091                     satellitePvt.getVelocityEcef().getZMetersPerSecond() >= -4000 &&
1092                         satellitePvt.getVelocityEcef().getZMetersPerSecond() <= 4000);
1093             softAssert.assertTrue("ure_rate_mps : "
1094                     + "The Signal in Space User Range Error Rate (URE Rate) (meters per second)",
1095                     timeInNs,
1096                     "X > 0",
1097                     String.valueOf(satellitePvt.getVelocityEcef().getUreRateMetersPerSecond()),
1098                     satellitePvt.getVelocityEcef().getUreRateMetersPerSecond() > 0);
1099             softAssert.assertTrue("hardware_code_bias_meters : "
1100                     + "The satellite hardware code bias of the reported code type "
1101                     + "w.r.t ionosphere-free measurement in meters.",
1102                     timeInNs,
1103                     "-17.869 < X < 17.729",
1104                     String.valueOf(satellitePvt.getClockInfo().getHardwareCodeBiasMeters()),
1105                     satellitePvt.getClockInfo().getHardwareCodeBiasMeters() > -17.869 &&
1106                     satellitePvt.getClockInfo().getHardwareCodeBiasMeters() < 17.729);
1107             softAssert.assertTrue("time_correction_meters : "
1108                     + "The satellite time correction for ionospheric-free signal measurement "
1109                     + "(meters)",
1110                     timeInNs,
1111                     "-3e6 < X < 3e6",
1112                     String.valueOf(satellitePvt.getClockInfo().getTimeCorrectionMeters()),
1113                     satellitePvt.getClockInfo().getTimeCorrectionMeters() > -3e6 &&
1114                     satellitePvt.getClockInfo().getTimeCorrectionMeters() < 3e6);
1115             softAssert.assertTrue("clock_drift_mps : "
1116                     + "The satellite clock drift (meters per second)",
1117                     timeInNs,
1118                     "-1.117 < X < 1.117",
1119                     String.valueOf(satellitePvt.getClockInfo().getClockDriftMetersPerSecond()),
1120                     satellitePvt.getClockInfo().getClockDriftMetersPerSecond() > -1.117 &&
1121                     satellitePvt.getClockInfo().getClockDriftMetersPerSecond() < 1.117);
1122         }
1123 
1124         if (satellitePvt.hasIono()){
1125             softAssert.assertTrue("iono_delay_meters : "
1126                     + "The ionospheric delay in meters",
1127                     timeInNs,
1128                     "0 < X < 100",
1129                     String.valueOf(satellitePvt.getIonoDelayMeters()),
1130                     satellitePvt.getIonoDelayMeters() > 0 &&
1131                     satellitePvt.getIonoDelayMeters() < 100);
1132         }
1133 
1134         if (satellitePvt.hasTropo()){
1135             softAssert.assertTrue("tropo_delay_meters : "
1136                     + "The tropospheric delay in meters",
1137                     timeInNs,
1138                     "0 < X < 100",
1139                     String.valueOf(satellitePvt.getTropoDelayMeters()),
1140                     satellitePvt.getTropoDelayMeters() > 0 &&
1141                     satellitePvt.getTropoDelayMeters() < 100);
1142         }
1143     }
1144 
isGpsL5OrQzssJ5I(GnssMeasurement measurement)1145     private static boolean isGpsL5OrQzssJ5I(GnssMeasurement measurement) {
1146         return (measurement.getConstellationType() == GnssStatus.CONSTELLATION_GPS
1147                 || measurement.getConstellationType() == GnssStatus.CONSTELLATION_QZSS)
1148                 && GPS_L5_QZSS_J5_FREQ_RANGE_HZ.contains(
1149                 (double) measurement.getCarrierFrequencyHz())
1150                 && measurement.hasCodeType()
1151                 && "I".equals(measurement.getCodeType());
1152     }
1153 
isGpsL5OrQzssJ5Q(GnssMeasurement measurement)1154     private static boolean isGpsL5OrQzssJ5Q(GnssMeasurement measurement) {
1155         return (measurement.getConstellationType() == GnssStatus.CONSTELLATION_GPS
1156                 || measurement.getConstellationType() == GnssStatus.CONSTELLATION_QZSS)
1157                 && GPS_L5_QZSS_J5_FREQ_RANGE_HZ.contains(
1158                 (double) measurement.getCarrierFrequencyHz())
1159                 && measurement.hasCodeType()
1160                 && "Q".equals(measurement.getCodeType());
1161     }
1162 
isGpsOrQZSSL1C_P(GnssMeasurement measurement)1163     private static boolean isGpsOrQZSSL1C_P(GnssMeasurement measurement) {
1164         return (measurement.getConstellationType() == GnssStatus.CONSTELLATION_GPS
1165                 || measurement.getConstellationType() == GnssStatus.CONSTELLATION_QZSS)
1166                 && GPS_L1_QZSS_J1_FREQ_RANGE_HZ.contains(
1167                 (double) measurement.getCarrierFrequencyHz())
1168                 && measurement.hasCodeType()
1169                 && "L".equals(measurement.getCodeType());
1170     }
1171 }
1172