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