1 /*
2  * Copyright (C) 2015 Google Inc.
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;
18 
19 import android.content.Context;
20 import android.content.pm.PackageManager;
21 import android.location.GnssClock;
22 import android.location.GnssMeasurement;
23 import android.location.GnssNavigationMessage;
24 import android.location.GnssStatus;
25 import android.location.LocationManager;
26 import android.os.Build;
27 import android.util.Log;
28 
29 import junit.framework.Assert;
30 
31 import java.util.List;
32 import java.util.concurrent.TimeUnit;
33 
34 /**
35  * Helper class for GnssMeasurement Tests.
36  */
37 public final class TestMeasurementUtil {
38 
39     private static final String TAG = "TestMeasurementUtil";
40 
41     private static final long NSEC_IN_SEC = 1000_000_000L;
42     // Generally carrier phase quality prr's have uncertainties around 0.001-0.05 m/s, vs.
43     // doppler energy quality prr's closer to 0.25-10 m/s.  Threshold is chosen between those
44     // typical ranges.
45     private static final float THRESHOLD_FOR_CARRIER_PRR_UNC_METERS_PER_SEC = 0.15F;
46 
47     // For gpsTimeInNs >= 1.14 * 10^18 (year 2016+)
48     private static final long GPS_TIME_YEAR_2016_IN_NSEC = 1_140_000_000L * NSEC_IN_SEC;
49 
50     // Error message for GnssMeasurements Registration.
51     public static final String REGISTRATION_ERROR_MESSAGE = "Registration of GnssMeasurements" +
52             " listener has failed, this indicates a platform bug. Please report the issue with" +
53             " a full bugreport.";
54 
55     /**
56      * Check if test can be run on the current device.
57      *
58      * @param  testLocationManager TestLocationManager
59      * @return true if Build.VERSION >=  Build.VERSION_CODES.N and Location GPS present on
60      *         device.
61      */
canTestRunOnCurrentDevice(TestLocationManager testLocationManager, String testTag, int minHardwareYear, boolean isCtsVerifier)62     public static boolean canTestRunOnCurrentDevice(TestLocationManager testLocationManager,
63                                                     String testTag,
64                                                     int minHardwareYear,
65                                                     boolean isCtsVerifier) {
66        // TODO(sumitk): Enable this check once api 24 for N is avaiable.
67        /*
68        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
69             Log.i(TAG, "This test is designed to work on N or newer. " +
70                     "Test is being skipped because the platform version is being run in " +
71                     Build.VERSION.SDK_INT);
72             return false;
73         }
74         */
75 
76         // If device does not have a GPS, skip the test.
77         PackageManager pm = testLocationManager.getContext().getPackageManager();
78         if (!pm.hasSystemFeature(PackageManager.FEATURE_LOCATION_GPS)) {
79           Log.w(testTag, "GPS feature not present on device, skipping GPS test.");
80           return false;
81         }
82 
83         // If device has a GPS, but it's turned off in settings, and this is CTS verifier,
84         // fail the test now, because there's no point in going further.
85         // If this is CTS only,we'll warn instead, and quickly pass the test.
86         // (Cts non-verifier deep-indoors-forgiveness happens later, *if* needed)
87         boolean gpsProviderEnabled = testLocationManager.getLocationManager()
88                 .isProviderEnabled(LocationManager.GPS_PROVIDER);
89         SoftAssert.failOrWarning(isCtsVerifier, " GPS location disabled on the device. " +
90                 "Enable location in settings to continue test.", gpsProviderEnabled);
91         // If CTS only, allow an early exit pass
92         if (!isCtsVerifier && !gpsProviderEnabled) {
93             return false;
94         }
95 
96         // TODO - add this to the test info page
97         int gnssYearOfHardware = testLocationManager.getLocationManager().getGnssYearOfHardware();
98         Log.i(testTag, "This device is reporting GNSS hardware from year "
99                 + (gnssYearOfHardware == 0 ? "2015 or earlier" : gnssYearOfHardware) + ". "
100                 + "Devices " + (gnssYearOfHardware >= minHardwareYear ? "like this one " : "")
101                 + "from year " + minHardwareYear + " or newer provide GnssMeasurement support." );
102 
103         return true;
104     }
105 
106     /**
107      * Check if pseudorange rate uncertainty in Gnss Measurement is in the expected range.
108      * See field description in {@code gps.h}.
109      *
110      * @param measurement GnssMeasurement
111      * @return true if this measurement has prr uncertainty in a range indicative of carrier phase
112      */
gnssMeasurementHasCarrierPhasePrr(GnssMeasurement measurement)113     public static boolean gnssMeasurementHasCarrierPhasePrr(GnssMeasurement measurement) {
114       return (measurement.getPseudorangeRateUncertaintyMetersPerSecond() <
115               THRESHOLD_FOR_CARRIER_PRR_UNC_METERS_PER_SEC);
116     }
117 
118     /**
119      * Assert all mandatory fields in Gnss Clock are in expected range.
120      * See mandatory fields in {@code gps.h}.
121      *
122      * @param clock       GnssClock
123      * @param softAssert  custom SoftAssert
124      * @param timeInNs    event time in ns
125      */
assertGnssClockFields(GnssClock clock, SoftAssert softAssert, long timeInNs)126     public static void assertGnssClockFields(GnssClock clock,
127                                              SoftAssert softAssert,
128                                              long timeInNs) {
129         softAssert.assertTrue("time_ns: clock value",
130                 timeInNs,
131                 "X >= 0",
132                 String.valueOf(timeInNs),
133                 timeInNs >= 0L);
134 
135         // If full bias is valid and accurate within one sec. verify its sign & magnitude
136         if (clock.hasFullBiasNanos() &&
137                 ((!clock.hasBiasUncertaintyNanos()) ||
138                         (clock.getBiasUncertaintyNanos() < NSEC_IN_SEC))) {
139             long gpsTimeInNs = timeInNs - clock.getFullBiasNanos();
140             softAssert.assertTrue("TimeNanos - FullBiasNanos = GpsTimeNanos: clock value",
141                     gpsTimeInNs,
142                     "gpsTimeInNs >= 1.14 * 10^18 (year 2016+)",
143                     String.valueOf(gpsTimeInNs),
144                     gpsTimeInNs >= GPS_TIME_YEAR_2016_IN_NSEC);
145         }
146 
147     }
148 
149     /**
150      * Assert all mandatory fields in Gnss Measurement are in expected range.
151      * See mandatory fields in {@code gps.h}.
152      *
153      * @param measurement GnssMeasurement
154      * @param softAssert  custom SoftAssert
155      * @param timeInNs    event time in ns
156      */
assertAllGnssMeasurementMandatoryFields(GnssMeasurement measurement, SoftAssert softAssert, long timeInNs)157     public static void assertAllGnssMeasurementMandatoryFields(GnssMeasurement measurement,
158         SoftAssert softAssert, long timeInNs) {
159 
160         verifySvid(measurement, softAssert, timeInNs);
161         verifyReceivedSatelliteVehicleTimeInNs(measurement, softAssert, timeInNs);
162         verifyAccumulatedDeltaRanges(measurement, softAssert, timeInNs);
163 
164         int state = measurement.getState();
165         softAssert.assertTrue("state: Satellite code sync state",
166                 timeInNs,
167                 "X > 0",
168                 String.valueOf(state),
169                 state > 0);
170 
171         // Check received_gps_tow_uncertainty_ns
172         softAssert.assertTrueAsWarning("received_gps_tow_uncertainty_ns:" +
173                         " Uncertainty of received GPS Time-of-Week in ns",
174                 timeInNs,
175                 "X > 0",
176                 String.valueOf(measurement.getReceivedSvTimeUncertaintyNanos()),
177                 measurement.getReceivedSvTimeUncertaintyNanos() > 0L);
178 
179         long timeOffsetInSec = TimeUnit.NANOSECONDS.toSeconds(
180                 (long) measurement.getTimeOffsetNanos());
181         softAssert.assertTrue("time_offset_ns: Time offset",
182                 timeInNs,
183                 "-100 seconds < X < +10 seconds",
184                 String.valueOf(measurement.getTimeOffsetNanos()),
185                 (-100 < timeOffsetInSec) && (timeOffsetInSec < 10));
186 
187         softAssert.assertTrue("c_n0_dbhz: Carrier-to-noise density",
188                 timeInNs,
189                 "0.0 >= X <=63",
190                 String.valueOf(measurement.getCn0DbHz()),
191                 measurement.getCn0DbHz() >= 0.0 &&
192                         measurement.getCn0DbHz() <= 63.0);
193 
194         softAssert.assertTrue("pseudorange_rate_mps: Pseudorange rate in m/s",
195                 timeInNs,
196                 "X != 0.0",
197                 String.valueOf(measurement.getPseudorangeRateMetersPerSecond()),
198                 measurement.getPseudorangeRateMetersPerSecond() != 0.0);
199 
200         softAssert.assertTrue("pseudorange_rate_uncertainty_mps: " +
201                         "Pseudorange Rate Uncertainty in m/s",
202                 timeInNs,
203                 "X > 0.0",
204                 String.valueOf(
205                         measurement.getPseudorangeRateUncertaintyMetersPerSecond()),
206                 measurement.getPseudorangeRateUncertaintyMetersPerSecond() > 0.0);
207 
208         // Check carrier_frequency_hz.
209         if (measurement.hasCarrierFrequencyHz()) {
210             softAssert.assertTrue("carrier_frequency_hz: Carrier frequency in hz",
211                     timeInNs,
212                     "X > 0.0",
213                     String.valueOf(measurement.getCarrierFrequencyHz()),
214                     measurement.getCarrierFrequencyHz() > 0.0);
215         }
216 
217         // Check carrier_phase.
218         if (measurement.hasCarrierPhase()) {
219             softAssert.assertTrue("carrier_phase: Carrier phase",
220                     timeInNs,
221                     "0.0 >= X <= 1.0",
222                     String.valueOf(measurement.getCarrierPhase()),
223                     measurement.getCarrierPhase() >= 0.0 && measurement.getCarrierPhase() <= 1.0);
224         }
225 
226         // Check carrier_phase_uncertainty..
227         if (measurement.hasCarrierPhaseUncertainty()) {
228             softAssert.assertTrue("carrier_phase_uncertainty: 1-Sigma uncertainty of the " +
229                             "carrier-phase",
230                     timeInNs,
231                     "X > 0.0",
232                     String.valueOf(measurement.getCarrierPhaseUncertainty()),
233                     measurement.getCarrierPhaseUncertainty() > 0.0);
234         }
235 
236         // Check GNSS Measurement's multipath_indicator.
237         softAssert.assertTrue("multipath_indicator: GNSS Measurement's multipath indicator",
238                 timeInNs,
239                 "0 >= X <= 2",
240                 String.valueOf(measurement.getMultipathIndicator()),
241                 measurement.getMultipathIndicator() >= 0
242                         && measurement.getMultipathIndicator() <= 2);
243 
244 
245         // Check Signal-to-Noise ratio (SNR).
246         if (measurement.hasSnrInDb()) {
247             softAssert.assertTrue("snr: Signal-to-Noise ratio (SNR) in dB",
248                     timeInNs,
249                     "0.0 >= X <= 63",
250                     String.valueOf(measurement.getSnrInDb()),
251                     measurement.getSnrInDb() >= 0.0 && measurement.getSnrInDb() <= 63);
252         }
253     }
254 
255     /**
256      * Verify accumulated delta ranges are in expected range.
257      *
258      * @param measurement GnssMeasurement
259      * @param softAssert  custom SoftAssert
260      * @param timeInNs    event time in ns
261      */
verifyAccumulatedDeltaRanges(GnssMeasurement measurement, SoftAssert softAssert, long timeInNs)262     private static void verifyAccumulatedDeltaRanges(GnssMeasurement measurement,
263         SoftAssert softAssert, long timeInNs) {
264 
265         int accumulatedDeltaRangeState = measurement.getAccumulatedDeltaRangeState();
266         softAssert.assertTrue("accumulated_delta_range_state: " +
267                         "Accumulated delta range state",
268                 timeInNs,
269                 "0 <= X <= 7",
270                 String.valueOf(accumulatedDeltaRangeState),
271                 accumulatedDeltaRangeState >= 0 && accumulatedDeltaRangeState <= 7);
272         if (accumulatedDeltaRangeState > 0) {
273             double accumulatedDeltaRangeInMeters =
274                     measurement.getAccumulatedDeltaRangeMeters();
275             softAssert.assertTrue("accumulated_delta_range_m: " +
276                             "Accumulated delta range in meter",
277                     timeInNs,
278                     "X != 0.0",
279                     String.valueOf(accumulatedDeltaRangeInMeters),
280                     accumulatedDeltaRangeInMeters != 0.0);
281             double accumulatedDeltaRangeUncertainty =
282                     measurement.getAccumulatedDeltaRangeUncertaintyMeters();
283             softAssert.assertTrue("accumulated_delta_range_uncertainty_m: " +
284                             "Accumulated delta range uncertainty in meter",
285                     timeInNs,
286                     "X > 0.0",
287                     String.valueOf(accumulatedDeltaRangeUncertainty),
288                     accumulatedDeltaRangeUncertainty > 0.0);
289         }
290     }
291 
292     /**
293      * Verify svid's are in expected range.
294      *
295      * @param measurement GnssMeasurement
296      * @param softAssert  custom SoftAssert
297      * @param timeInNs    event time in ns
298      */
verifySvid(GnssMeasurement measurement, SoftAssert softAssert, long timeInNs)299     private static void verifySvid(GnssMeasurement measurement, SoftAssert softAssert,
300         long timeInNs) {
301 
302         String svidLogMessageFormat = "svid: Space Vehicle ID. Constellation type = %s";
303         int constellationType = measurement.getConstellationType();
304         int svid = measurement.getSvid();
305         String svidValue = String.valueOf(svid);
306 
307         switch (constellationType) {
308             case GnssStatus.CONSTELLATION_GPS:
309                 softAssert.assertTrue("svid: Space Vehicle ID. Constellation type " +
310                                 "= CONSTELLATION_GPS",
311                         timeInNs,
312                         "[1, 32]",
313                         svidValue,
314                         svid > 0 && svid <= 32);
315                 break;
316             case GnssStatus.CONSTELLATION_SBAS:
317                 softAssert.assertTrue("svid: Space Vehicle ID. Constellation type " +
318                                 "= CONSTELLATION_SBAS",
319                         timeInNs,
320                         "120 <= X <= 192",
321                         svidValue,
322                         svid >= 120 && svid <= 192);
323                 break;
324             case GnssStatus.CONSTELLATION_GLONASS:
325                 // Check Upper 8 bit, signed
326                 int freq = (svid >> 8);
327                 softAssert.assertTrue("svid: upper 8 bits, frequency number. Constellation type " +
328                                 "= CONSTELLATION_GLONASS",
329                         timeInNs,
330                         "freq == -127 || -7 <= freq <= 6",
331                         svidValue,
332                         // future proof check allowing a change in definition under discussion
333                         (freq == -127) || (freq >= -7 && freq <= 6) || (freq >= 93 && freq <= 106));
334                 // Check lower 8 bits, signed
335                 byte slot = (byte) svid;
336                 softAssert.assertTrue("svid: lower 8 bits, slot. Constellation type " +
337                                 "= CONSTELLATION_GLONASS",
338                         timeInNs,
339                         "slot == -127 || 1 <= slot <= 24",
340                         svidValue,
341                         // future proof check allowingn a change in definition under discussion
342                         (slot == -127) || (slot >= 1 && slot <= 24) || (slot >= 93 && slot <= 106));
343                 softAssert.assertTrue("svid: one of slot or freq is set (not -127). " +
344                                 "ConstellationType = CONSTELLATION_GLONASS,",
345                         timeInNs,
346                         "slot != -127 || freq != -127",
347                         svidValue,
348                         (slot != -127) || (freq != -127));
349                 break;
350             case GnssStatus.CONSTELLATION_QZSS:
351                 softAssert.assertTrue("svid: Space Vehicle ID. Constellation type " +
352                                 "= CONSTELLATION_QZSS",
353                         timeInNs,
354                         "193 <= X <= 200",
355                         svidValue,
356                         svid >= 193 && svid <= 200);
357                 break;
358             case GnssStatus.CONSTELLATION_BEIDOU:
359                 softAssert.assertTrue("svid: Space Vehicle ID. Constellation type " +
360                                 "= CONSTELLATION_BEIDOU",
361                         timeInNs,
362                         "1 <= X <= 36",
363                         svidValue,
364                         svid >= 1 && svid <= 36);
365                 break;
366             case GnssStatus.CONSTELLATION_GALILEO:
367                 softAssert.assertTrue("svid: Space Vehicle ID. Constellation type " +
368                                 "= CONSTELLATION_GALILEO",
369                         timeInNs,
370                         "1 <= X <= 37",
371                         String.valueOf(svid),
372                         svid >= 1 && svid <= 37);
373                 break;
374             default:
375                 // Explicit fail if did not receive valid constellation type.
376                 softAssert.assertTrue("svid: Space Vehicle ID. Did not receive any valid " +
377                                 "constellation type.",
378                         timeInNs,
379                         "Valid constellation type.",
380                         svidValue,
381                         false);
382                 break;
383         }
384     }
385 
386     /**
387      * Verify sv times are in expected range.
388      *
389      * @param measurement GnssMeasurement
390      * @param softAssert  custom SoftAssert
391      * @param timeInNs    event time in ns
392      * */
verifyReceivedSatelliteVehicleTimeInNs(GnssMeasurement measurement, SoftAssert softAssert, long timeInNs)393     private static void verifyReceivedSatelliteVehicleTimeInNs(GnssMeasurement measurement,
394         SoftAssert softAssert, long timeInNs) {
395 
396         int constellationType = measurement.getConstellationType();
397         int state = measurement.getState();
398         long received_sv_time_ns = measurement.getReceivedSvTimeNanos();
399         double sv_time_ms = TimeUnit.NANOSECONDS.toMillis(received_sv_time_ns);
400         double sv_time_sec = TimeUnit.NANOSECONDS.toSeconds(received_sv_time_ns);
401         double sv_time_days = TimeUnit.NANOSECONDS.toDays(received_sv_time_ns);
402 
403         // Check ranges for received_sv_time_ns for given Gps State
404         if (state == 0) {
405             softAssert.assertTrue("received_sv_time_ns:" +
406                             " Received SV Time-of-Week in ns." +
407                             " GNSS_MEASUREMENT_STATE_UNKNOWN.",
408                     timeInNs,
409                     "X == 0",
410                     String.valueOf(received_sv_time_ns),
411                     sv_time_ms == 0);
412         }
413 
414         switch (constellationType) {
415             case GnssStatus.CONSTELLATION_GPS:
416                 verifyGpsQzssSvTimes(measurement, softAssert, timeInNs, state, "CONSTELLATION_GPS");
417                 break;
418             case GnssStatus.CONSTELLATION_QZSS:
419                 verifyGpsQzssSvTimes(measurement, softAssert, timeInNs, state,
420                         "CONSTELLATION_QZSS");
421                 break;
422             case GnssStatus.CONSTELLATION_SBAS:
423                 if ((state | GnssMeasurement.STATE_SBAS_SYNC)
424                         == GnssMeasurement.STATE_SBAS_SYNC) {
425                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
426                                     "GNSS_MEASUREMENT_STATE_SBAS_SYNC",
427                                     "GnssStatus.CONSTELLATION_SBAS"),
428                             timeInNs,
429                             "0s >= X <= 1s",
430                             String.valueOf(sv_time_sec),
431                             sv_time_sec >= 0 && sv_time_sec <= 1);
432                 } else if ((state | GnssMeasurement.STATE_SYMBOL_SYNC)
433                         == GnssMeasurement.STATE_SYMBOL_SYNC) {
434                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
435                                     "GNSS_MEASUREMENT_STATE_SYMBOL_SYNC",
436                                     "GnssStatus.CONSTELLATION_SBAS"),
437                             timeInNs,
438                             "0ms >= X <= 2ms",
439                             String.valueOf(sv_time_ms),
440                             sv_time_ms >= 0 && sv_time_ms <= 2);
441                 } else if ((state | GnssMeasurement.STATE_CODE_LOCK)
442                         == GnssMeasurement.STATE_CODE_LOCK) {
443                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
444                                     "GNSS_MEASUREMENT_STATE_CODE_LOCK",
445                                     "GnssStatus.CONSTELLATION_SBAS"),
446                             timeInNs,
447                             "0ms >= X <= 1ms",
448                             String.valueOf(sv_time_ms),
449                             sv_time_ms >= 0 && sv_time_ms <= 1);
450                 }
451                 break;
452             case GnssStatus.CONSTELLATION_GLONASS:
453                 if ((state | GnssMeasurement.STATE_GLO_TOD_DECODED)
454                         == GnssMeasurement.STATE_GLO_TOD_DECODED) {
455                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
456                                     "GNSS_MEASUREMENT_STATE_GLO_TOD_DECODED",
457                                     "GnssStatus.CONSTELLATION_GLONASS"),
458                             timeInNs,
459                             "0 day >= X <= 1 day",
460                             String.valueOf(sv_time_days),
461                             sv_time_days >= 0 && sv_time_days <= 1);
462                 } else if ((state | GnssMeasurement.STATE_GLO_STRING_SYNC)
463                         == GnssMeasurement.STATE_GLO_STRING_SYNC) {
464                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
465                                     "GNSS_MEASUREMENT_STATE_GLO_STRING_SYNC",
466                                     "GnssStatus.CONSTELLATION_GLONASS"),
467                             timeInNs,
468                             "0s >= X <= 2s",
469                             String.valueOf(sv_time_sec),
470                             sv_time_sec >= 0 && sv_time_sec <= 2);
471                 } else if ((state | GnssMeasurement.STATE_BIT_SYNC)
472                         == GnssMeasurement.STATE_BIT_SYNC) {
473                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
474                                     "GNSS_MEASUREMENT_STATE_BIT_SYNC",
475                                     "GnssStatus.CONSTELLATION_GLONASS"),
476                             timeInNs,
477                             "0ms >= X <= 20ms",
478                             String.valueOf(sv_time_ms),
479                             sv_time_ms >= 0 && sv_time_ms <= 20);
480                 } else if ((state | GnssMeasurement.STATE_SYMBOL_SYNC)
481                         == GnssMeasurement.STATE_SYMBOL_SYNC) {
482                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
483                                     "GNSS_MEASUREMENT_STATE_SYMBOL_SYNC",
484                                     "GnssStatus.CONSTELLATION_GLONASS"),
485                             timeInNs,
486                             "0ms >= X <= 10ms",
487                             String.valueOf(sv_time_ms),
488                             sv_time_ms >= 0 && sv_time_ms <= 10);
489                 } else if ((state | GnssMeasurement.STATE_CODE_LOCK)
490                         == GnssMeasurement.STATE_CODE_LOCK) {
491                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
492                                     "GNSS_MEASUREMENT_STATE_CODE_LOCK",
493                                     "GnssStatus.CONSTELLATION_GLONASS"),
494                             timeInNs,
495                             "0ms >= X <= 1ms",
496                             String.valueOf(sv_time_ms),
497                             sv_time_ms >= 0 && sv_time_ms <= 1);
498                 }
499                 break;
500             case GnssStatus.CONSTELLATION_GALILEO:
501                 if ((state | GnssMeasurement.STATE_TOW_DECODED)
502                         == GnssMeasurement.STATE_TOW_DECODED) {
503                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
504                                     "GNSS_MEASUREMENT_STATE_TOW_DECODED",
505                                     "GnssStatus.CONSTELLATION_GALILEO"),
506                             timeInNs,
507                             "0 >= X <= 7 days",
508                             String.valueOf(sv_time_days),
509                             sv_time_days >= 0 && sv_time_days <= 7);
510                 } else if ((state | GnssMeasurement.STATE_GAL_E1B_PAGE_SYNC)
511                         == GnssMeasurement.STATE_GAL_E1B_PAGE_SYNC) {
512                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
513                                     "GNSS_MEASUREMENT_STATE_GAL_E1B_PAGE_SYNC",
514                                     "GnssStatus.CONSTELLATION_GALILEO"),
515                             timeInNs,
516                             "0s >= X <= 2s",
517                             String.valueOf(sv_time_sec),
518                             sv_time_sec >= 0 && sv_time_sec <= 2);
519                 } else if ((state | GnssMeasurement.STATE_GAL_E1C_2ND_CODE_LOCK)
520                         == GnssMeasurement.STATE_GAL_E1C_2ND_CODE_LOCK) {
521                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
522                                     "GNSS_MEASUREMENT_STATE_GAL_E1C_2ND_CODE_LOCK",
523                                     "GnssStatus.CONSTELLATION_GALILEO"),
524                             timeInNs,
525                             "0ms >= X <= 100ms",
526                             String.valueOf(sv_time_ms),
527                             sv_time_ms >= 0 && sv_time_ms <= 100);
528                 } else if ((state | GnssMeasurement.STATE_GAL_E1BC_CODE_LOCK)
529                         == GnssMeasurement.STATE_GAL_E1BC_CODE_LOCK) {
530                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
531                                     "GNSS_MEASUREMENT_STATE_GAL_E1BC_CODE_LOCK",
532                                     "GnssStatus.CONSTELLATION_GALILEO"),
533                             timeInNs,
534                             "0ms >= X <= 4ms",
535                             String.valueOf(sv_time_ms),
536                             sv_time_ms >= 0 && sv_time_ms <= 4);
537                 }
538                 break;
539             case GnssStatus.CONSTELLATION_BEIDOU:
540                 if ((state | GnssMeasurement.STATE_TOW_DECODED)
541                         == GnssMeasurement.STATE_TOW_DECODED) {
542                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
543                                     "GNSS_MEASUREMENT_STATE_TOW_DECODED",
544                                     "GnssStatus.CONSTELLATION_BEIDOU"),
545                             timeInNs,
546                             "0 >= X <= 7 days",
547                             String.valueOf(sv_time_days),
548                             sv_time_days >= 0 && sv_time_days <= 7);
549                 } else if ((state | GnssMeasurement.STATE_SUBFRAME_SYNC)
550                         == GnssMeasurement.STATE_SUBFRAME_SYNC) {
551                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
552                                     "GNSS_MEASUREMENT_STATE_SUBFRAME_SYNC",
553                                     "GnssStatus.CONSTELLATION_BEIDOU"),
554                             timeInNs,
555                             "0s >= X <= 6s",
556                             String.valueOf(sv_time_sec),
557                             sv_time_sec >= 0 && sv_time_sec <= 6);
558                 } else if ((state | GnssMeasurement.STATE_BDS_D2_SUBFRAME_SYNC)
559                         == GnssMeasurement.STATE_BDS_D2_SUBFRAME_SYNC) {
560                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
561                                     "GNSS_MEASUREMENT_STATE_BDS_D2_SUBFRAME_SYNC",
562                                     "GnssStatus.CONSTELLATION_BEIDOU"),
563                             timeInNs,
564                             "0ms >= X <= 600ms (0.6sec)",
565                             String.valueOf(sv_time_ms),
566                             sv_time_ms >= 0 && sv_time_ms <= 600);
567                 } else if ((state | GnssMeasurement.STATE_BIT_SYNC)
568                         == GnssMeasurement.STATE_BIT_SYNC) {
569                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
570                                     "GNSS_MEASUREMENT_STATE_BIT_SYNC",
571                                     "GnssStatus.CONSTELLATION_BEIDOU"),
572                             timeInNs,
573                             "0ms >= X <= 20ms",
574                             String.valueOf(sv_time_ms),
575                             sv_time_ms >= 0 && sv_time_ms <= 20);
576                 } else if ((state | GnssMeasurement.STATE_BDS_D2_BIT_SYNC)
577                         == GnssMeasurement.STATE_BDS_D2_BIT_SYNC) {
578                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
579                                     "GNSS_MEASUREMENT_STATE_BDS_D2_BIT_SYNC",
580                                     "GnssStatus.CONSTELLATION_BEIDOU"),
581                             timeInNs,
582                             "0ms >= X <= 2ms",
583                             String.valueOf(sv_time_ms),
584                             sv_time_ms >= 0 && sv_time_ms <= 2);
585                 } else if ((state | GnssMeasurement.STATE_CODE_LOCK)
586                         == GnssMeasurement.STATE_CODE_LOCK) {
587                     softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
588                                     "GNSS_MEASUREMENT_STATE_CODE_LOCK",
589                                     "GnssStatus.CONSTELLATION_BEIDOU"),
590                             timeInNs,
591                             "0ms >= X <= 1ms",
592                             String.valueOf(sv_time_ms),
593                             sv_time_ms >= 0 && sv_time_ms <= 1);
594                 }
595                 break;
596         }
597     }
598 
getReceivedSvTimeNsLogMessage(String constellationType, String state)599     private static String getReceivedSvTimeNsLogMessage(String constellationType, String state) {
600         return "received_sv_time_ns: Received SV Time-of-Week in ns. Constellation type = "
601                 + constellationType + ". State = " + state;
602     }
603 
604     /**
605      * Verify sv times are in expected range for given constellation type.
606      * This is common check for CONSTELLATION_GPS & CONSTELLATION_QZSS.
607      *
608      * @param measurement GnssMeasurement
609      * @param softAssert  custom SoftAssert
610      * @param timeInNs    event time in ns
611      * @param state       GnssMeasurement State
612      * @param constellationType Gnss Constellation type
613      */
verifyGpsQzssSvTimes(GnssMeasurement measurement, SoftAssert softAssert, long timeInNs, int state, String constellationType)614     private static void verifyGpsQzssSvTimes(GnssMeasurement measurement,
615         SoftAssert softAssert, long timeInNs, int state, String constellationType) {
616 
617         long received_sv_time_ns = measurement.getReceivedSvTimeNanos();
618         double sv_time_ms = TimeUnit.NANOSECONDS.toMillis(received_sv_time_ns);
619         double sv_time_sec = TimeUnit.NANOSECONDS.toSeconds(received_sv_time_ns);
620         double sv_time_days = TimeUnit.NANOSECONDS.toDays(received_sv_time_ns);
621 
622         if ((state | GnssMeasurement.STATE_TOW_DECODED)
623                 == GnssMeasurement.STATE_TOW_DECODED) {
624             softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
625                             "GNSS_MEASUREMENT_STATE_TOW_DECODED",
626                             constellationType),
627                     timeInNs,
628                     "0 >= X <= 7 days",
629                     String.valueOf(sv_time_days),
630                     sv_time_days >= 0 && sv_time_days <= 7);
631         } else if ((state | GnssMeasurement.STATE_SUBFRAME_SYNC)
632                 == GnssMeasurement.STATE_SUBFRAME_SYNC) {
633             softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
634                             "GNSS_MEASUREMENT_STATE_SUBFRAME_SYNC",
635                             constellationType),
636                     timeInNs,
637                     "0s >= X <= 6s",
638                     String.valueOf(sv_time_sec),
639                     sv_time_sec >= 0 && sv_time_sec <= 6);
640         } else if ((state | GnssMeasurement.STATE_BIT_SYNC)
641                 == GnssMeasurement.STATE_BIT_SYNC) {
642             softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
643                             "GNSS_MEASUREMENT_STATE_BIT_SYNC",
644                             constellationType),
645                     timeInNs,
646                     "0ms >= X <= 20ms",
647                     String.valueOf(sv_time_ms),
648                     sv_time_ms >= 0 && sv_time_ms <= 20);
649 
650         } else if ((state | GnssMeasurement.STATE_CODE_LOCK)
651                 == GnssMeasurement.STATE_CODE_LOCK) {
652             softAssert.assertTrue(getReceivedSvTimeNsLogMessage(
653                             "GNSS_MEASUREMENT_STATE_CODE_LOCK",
654                             constellationType),
655                     timeInNs,
656                     "0ms >= X <= 1ms",
657                     String.valueOf(sv_time_ms),
658                     sv_time_ms >= 0 && sv_time_ms <= 1);
659         }
660     }
661 
662     /**
663      * Assert all mandatory fields in Gnss Navigation Message are in expected range.
664      * See mandatory fields in {@code gps.h}.
665      *
666      * @param events GnssNavigationMessageEvents
667      */
verifyGnssNavMessageMandatoryField(List<GnssNavigationMessage> events)668     public static void verifyGnssNavMessageMandatoryField(List<GnssNavigationMessage> events) {
669         // Verify mandatory GnssNavigationMessage field values.
670         SoftAssert softAssert = new SoftAssert(TAG);
671         for (GnssNavigationMessage message : events) {
672             int type = message.getType();
673             softAssert.assertTrue("Gnss Navigation Message Type:expected [0x0101 - 0x0104]," +
674                             " actual = " + type,
675                     type >= 0x0101 && type <= 0x0104);
676 
677             // if message type == TYPE_L1CA, verify PRN & Data Size.
678             int messageType = message.getType();
679             if (messageType == GnssNavigationMessage.TYPE_GPS_L1CA) {
680                 int svid = message.getSvid();
681                 softAssert.assertTrue("Space Vehicle ID : expected = [1, 32], actual = " +
682                                 svid,
683                         svid >= 1 && svid <= 32);
684                 int dataSize = message.getData().length;
685                 softAssert.assertTrue("Data size: expected = 40, actual = " + dataSize,
686                         dataSize == 40);
687             } else {
688                 Log.i(TAG, "GnssNavigationMessage (type = " + messageType
689                         + ") skipped for verification.");
690             }
691         }
692         softAssert.assertAll();
693     }
694 }
695