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 >= 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