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