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