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