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