1 /*
2 * Copyright (C) 2017 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 #define LOG_TAG "GnssHalTestCases"
18
19 #include <gnss_hal_test.h>
20
21 #include <VtsHalHidlTargetTestBase.h>
22
23 #include <android/hardware/gnss/1.1/IGnssConfiguration.h>
24 #include <cutils/properties.h>
25
26 using android::hardware::hidl_vec;
27
28 using IGnssMeasurement_1_0 = android::hardware::gnss::V1_0::IGnssMeasurement;
29 using IGnssMeasurement_1_1 = android::hardware::gnss::V1_1::IGnssMeasurement;
30
31 using android::hardware::gnss::V1_0::GnssConstellationType;
32 using android::hardware::gnss::V1_0::GnssLocation;
33 using android::hardware::gnss::V1_0::IGnssDebug;
34 using android::hardware::gnss::V1_1::IGnssConfiguration;
35 using android::hardware::gnss::V1_1::IGnssMeasurement;
36
IsAutomotiveDevice()37 static bool IsAutomotiveDevice() {
38 char buffer[PROPERTY_VALUE_MAX] = {0};
39 property_get("ro.hardware.type", buffer, "");
40 return strncmp(buffer, "automotive", PROPERTY_VALUE_MAX) == 0;
41 }
42
43 /*
44 * SetupTeardownCreateCleanup:
45 * Requests the gnss HAL then calls cleanup
46 *
47 * Empty test fixture to verify basic Setup & Teardown
48 */
TEST_F(GnssHalTest,SetupTeardownCreateCleanup)49 TEST_F(GnssHalTest, SetupTeardownCreateCleanup) {}
50
51 /*
52 * TestGnssMeasurementCallback:
53 * Gets the GnssMeasurementExtension and verify that it returns an actual extension.
54 */
TEST_F(GnssHalTest,TestGnssMeasurementCallback)55 TEST_F(GnssHalTest, TestGnssMeasurementCallback) {
56 auto gnssMeasurement_1_1 = gnss_hal_->getExtensionGnssMeasurement_1_1();
57 ASSERT_TRUE(gnssMeasurement_1_1.isOk());
58 auto gnssMeasurement_1_0 = gnss_hal_->getExtensionGnssMeasurement();
59 ASSERT_TRUE(gnssMeasurement_1_0.isOk());
60 if (last_capabilities_ & IGnssCallback::Capabilities::MEASUREMENTS) {
61 sp<IGnssMeasurement_1_1> iGnssMeas_1_1 = gnssMeasurement_1_1;
62 sp<IGnssMeasurement_1_0> iGnssMeas_1_0 = gnssMeasurement_1_0;
63 // At least one interface must be non-null.
64 ASSERT_TRUE(iGnssMeas_1_1 != nullptr || iGnssMeas_1_0 != nullptr);
65 }
66 }
67
68 /*
69 * GetLocationLowPower:
70 * Turns on location, waits for at least 5 locations allowing max of LOCATION_TIMEOUT_SUBSEQUENT_SEC
71 * between one location and the next. Also ensure that MIN_INTERVAL_MSEC is respected by waiting
72 * NO_LOCATION_PERIOD_SEC and verfiy that no location is received. Also perform validity checks on
73 * each received location.
74 */
TEST_F(GnssHalTest,GetLocationLowPower)75 TEST_F(GnssHalTest, GetLocationLowPower) {
76 if (!IsGnssHalVersion_1_1()) {
77 ALOGI("Test GetLocationLowPower skipped. GNSS HAL version is greater than 1.1.");
78 return;
79 }
80
81 const int kMinIntervalMsec = 5000;
82 const int kLocationTimeoutSubsequentSec = (kMinIntervalMsec / 1000) * 2;
83 const int kNoLocationPeriodSec = (kMinIntervalMsec / 1000) / 2;
84 const int kLocationsToCheck = 5;
85 const bool kLowPowerMode = true;
86
87 // Warmup period - VTS doesn't have AGPS access via GnssLocationProvider
88 StartAndCheckLocations(5);
89 StopAndClearLocations();
90
91 // Start of Low Power Mode test
92 SetPositionMode(kMinIntervalMsec, kLowPowerMode);
93
94 // Don't expect true - as without AGPS access
95 if (!StartAndCheckFirstLocation()) {
96 ALOGW("GetLocationLowPower test - no first low power location received.");
97 }
98
99 for (int i = 1; i < kLocationsToCheck; i++) {
100 // Verify that kMinIntervalMsec is respected by waiting kNoLocationPeriodSec and
101 // ensure that no location is received yet
102
103 wait(kNoLocationPeriodSec);
104 // Tolerate (ignore) one extra location right after the first one
105 // to handle startup edge case scheduling limitations in some implementations
106 if ((i == 1) && (location_called_count_ == 2)) {
107 CheckLocation(last_location_, true);
108 continue; // restart the quiet wait period after this too-fast location
109 }
110 EXPECT_LE(location_called_count_, i);
111 if (location_called_count_ != i) {
112 ALOGW("GetLocationLowPower test - not enough locations received. %d vs. %d expected ",
113 location_called_count_, i);
114 }
115
116 if (std::cv_status::no_timeout !=
117 wait(kLocationTimeoutSubsequentSec - kNoLocationPeriodSec)) {
118 ALOGW("GetLocationLowPower test - timeout awaiting location %d", i);
119 } else {
120 CheckLocation(last_location_, true);
121 }
122 }
123
124 StopAndClearLocations();
125 }
126
127 /*
128 * FindStrongFrequentNonGpsSource:
129 *
130 * Search through a GnssSvStatus list for the strongest non-GPS satellite observed enough times
131 *
132 * returns the strongest source,
133 * or a source with constellation == UNKNOWN if none are found sufficient times
134 */
135
FindStrongFrequentNonGpsSource(const list<IGnssCallback::GnssSvStatus> list_gnss_sv_status,const int min_observations)136 IGnssConfiguration::BlacklistedSource FindStrongFrequentNonGpsSource(
137 const list<IGnssCallback::GnssSvStatus> list_gnss_sv_status, const int min_observations) {
138 struct ComparableBlacklistedSource {
139 IGnssConfiguration::BlacklistedSource id;
140
141 ComparableBlacklistedSource() {
142 id.constellation = GnssConstellationType::UNKNOWN;
143 id.svid = 0;
144 }
145
146 bool operator<(const ComparableBlacklistedSource& compare) const {
147 return ((id.svid < compare.id.svid) || ((id.svid == compare.id.svid) &&
148 (id.constellation < compare.id.constellation)));
149 }
150 };
151
152 struct SignalCounts {
153 int observations;
154 float max_cn0_dbhz;
155 };
156
157 std::map<ComparableBlacklistedSource, SignalCounts> mapSignals;
158
159 for (const auto& gnss_sv_status : list_gnss_sv_status) {
160 for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) {
161 const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv];
162 if ((gnss_sv.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX) &&
163 (gnss_sv.constellation != GnssConstellationType::GPS)) {
164 ComparableBlacklistedSource source;
165 source.id.svid = gnss_sv.svid;
166 source.id.constellation = gnss_sv.constellation;
167
168 const auto& itSignal = mapSignals.find(source);
169 if (itSignal == mapSignals.end()) {
170 SignalCounts counts;
171 counts.observations = 1;
172 counts.max_cn0_dbhz = gnss_sv.cN0Dbhz;
173 mapSignals.insert(
174 std::pair<ComparableBlacklistedSource, SignalCounts>(source, counts));
175 } else {
176 itSignal->second.observations++;
177 if (itSignal->second.max_cn0_dbhz < gnss_sv.cN0Dbhz) {
178 itSignal->second.max_cn0_dbhz = gnss_sv.cN0Dbhz;
179 }
180 }
181 }
182 }
183 }
184
185 float max_cn0_dbhz_with_sufficient_count = 0.;
186 int total_observation_count = 0;
187 int blacklisted_source_count_observation = 0;
188
189 ComparableBlacklistedSource source_to_blacklist; // initializes to zero = UNKNOWN constellation
190 for (auto const& pairSignal : mapSignals) {
191 total_observation_count += pairSignal.second.observations;
192 if ((pairSignal.second.observations >= min_observations) &&
193 (pairSignal.second.max_cn0_dbhz > max_cn0_dbhz_with_sufficient_count)) {
194 source_to_blacklist = pairSignal.first;
195 blacklisted_source_count_observation = pairSignal.second.observations;
196 max_cn0_dbhz_with_sufficient_count = pairSignal.second.max_cn0_dbhz;
197 }
198 }
199 ALOGD(
200 "Among %d observations, chose svid %d, constellation %d, "
201 "with %d observations at %.1f max CNo",
202 total_observation_count, source_to_blacklist.id.svid,
203 (int)source_to_blacklist.id.constellation, blacklisted_source_count_observation,
204 max_cn0_dbhz_with_sufficient_count);
205
206 return source_to_blacklist.id;
207 }
208
209 /*
210 * BlacklistIndividualSatellites:
211 *
212 * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding
213 * GnssStatus for common satellites (strongest and one other.)
214 * 2a & b) Turns off location, and blacklists common satellites.
215 * 3) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
216 * GnssStatus does not use those satellites.
217 * 4a & b) Turns off location, and send in empty blacklist.
218 * 5a) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
219 * GnssStatus does re-use at least the previously strongest satellite
220 * 5b) Retry a few times, in case GNSS search strategy takes a while to reacquire even the
221 * formerly strongest satellite
222 */
TEST_F(GnssHalTest,BlacklistIndividualSatellites)223 TEST_F(GnssHalTest, BlacklistIndividualSatellites) {
224 if (!IsGnssHalVersion_1_1()) {
225 ALOGI("Test BlacklistIndividualSatellites skipped. GNSS HAL version is greater than 1.1.");
226 return;
227 }
228
229 const int kLocationsToAwait = 3;
230 const int kRetriesToUnBlacklist = 10;
231
232 StartAndCheckLocations(kLocationsToAwait);
233
234 // Tolerate 1 less sv status to handle edge cases in reporting.
235 EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait);
236 ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)",
237 (int)list_gnss_sv_status_.size(), kLocationsToAwait, location_called_count_);
238
239 /*
240 * Identify strongest SV seen at least kLocationsToAwait -1 times
241 * Why -1? To avoid test flakiness in case of (plausible) slight flakiness in strongest signal
242 * observability (one epoch RF null)
243 */
244
245 IGnssConfiguration::BlacklistedSource source_to_blacklist =
246 FindStrongFrequentNonGpsSource(list_gnss_sv_status_, kLocationsToAwait - 1);
247
248 if (source_to_blacklist.constellation == GnssConstellationType::UNKNOWN) {
249 // Cannot find a non-GPS satellite. Let the test pass.
250 return;
251 }
252
253 // Stop locations, blacklist the common SV
254 StopAndClearLocations();
255
256 auto gnss_configuration_hal_return = gnss_hal_->getExtensionGnssConfiguration_1_1();
257 ASSERT_TRUE(gnss_configuration_hal_return.isOk());
258 sp<IGnssConfiguration> gnss_configuration_hal = gnss_configuration_hal_return;
259 ASSERT_NE(gnss_configuration_hal, nullptr);
260
261 hidl_vec<IGnssConfiguration::BlacklistedSource> sources;
262 sources.resize(1);
263 sources[0] = source_to_blacklist;
264
265 auto result = gnss_configuration_hal->setBlacklist(sources);
266 ASSERT_TRUE(result.isOk());
267 EXPECT_TRUE(result);
268
269 // retry and ensure satellite not used
270 list_gnss_sv_status_.clear();
271
272 StartAndCheckLocations(kLocationsToAwait);
273
274 // early exit if test is being run with insufficient signal
275 if (location_called_count_ == 0) {
276 ALOGE("0 Gnss locations received - ensure sufficient signal and retry");
277 }
278 ASSERT_TRUE(location_called_count_ > 0);
279
280 // Tolerate 1 less sv status to handle edge cases in reporting.
281 EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait);
282 ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)",
283 (int)list_gnss_sv_status_.size(), kLocationsToAwait, location_called_count_);
284 for (const auto& gnss_sv_status : list_gnss_sv_status_) {
285 for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) {
286 const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv];
287 EXPECT_FALSE((gnss_sv.svid == source_to_blacklist.svid) &&
288 (gnss_sv.constellation == source_to_blacklist.constellation) &&
289 (gnss_sv.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX));
290 }
291 }
292
293 // clear blacklist and restart - this time updating the blacklist while location is still on
294 sources.resize(0);
295
296 result = gnss_configuration_hal->setBlacklist(sources);
297 ASSERT_TRUE(result.isOk());
298 EXPECT_TRUE(result);
299
300 bool strongest_sv_is_reobserved = false;
301 // do several loops awaiting a few locations, allowing non-immediate reacquisition strategies
302 int unblacklist_loops_remaining = kRetriesToUnBlacklist;
303 while (!strongest_sv_is_reobserved && (unblacklist_loops_remaining-- > 0)) {
304 StopAndClearLocations();
305 list_gnss_sv_status_.clear();
306
307 StartAndCheckLocations(kLocationsToAwait);
308
309 // early exit loop if test is being run with insufficient signal
310 if (location_called_count_ == 0) {
311 ALOGE("0 Gnss locations received - ensure sufficient signal and retry");
312 }
313 ASSERT_TRUE(location_called_count_ > 0);
314
315 // Tolerate 1 less sv status to handle edge cases in reporting.
316 EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait);
317 ALOGD(
318 "Clear blacklist, observed %d GnssSvStatus, while awaiting %d Locations"
319 ", tries remaining %d",
320 (int)list_gnss_sv_status_.size(), kLocationsToAwait, unblacklist_loops_remaining);
321
322 for (const auto& gnss_sv_status : list_gnss_sv_status_) {
323 for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) {
324 const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv];
325 if ((gnss_sv.svid == source_to_blacklist.svid) &&
326 (gnss_sv.constellation == source_to_blacklist.constellation) &&
327 (gnss_sv.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX)) {
328 strongest_sv_is_reobserved = true;
329 break;
330 }
331 }
332 if (strongest_sv_is_reobserved) break;
333 }
334 }
335 EXPECT_TRUE(strongest_sv_is_reobserved);
336 StopAndClearLocations();
337 }
338
339 /*
340 * BlacklistConstellationWithLocationOff:
341 *
342 * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding
343 * GnssStatus for any non-GPS constellations.
344 * 2a & b) Turns off location, and blacklist first non-GPS constellations.
345 * 3) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
346 * GnssStatus does not use any constellation but GPS.
347 * 4a & b) Clean up by turning off location, and send in empty blacklist.
348 */
TEST_F(GnssHalTest,BlacklistConstellationWithLocationOff)349 TEST_F(GnssHalTest, BlacklistConstellationWithLocationOff) {
350 if (!IsGnssHalVersion_1_1()) {
351 ALOGI("Test BlacklistConstellation skipped. GNSS HAL version is greater than 1.1.");
352 return;
353 }
354
355 const int kLocationsToAwait = 3;
356 // Find first non-GPS constellation to blacklist
357 GnssConstellationType constellation_to_blacklist = startLocationAndGetNonGpsConstellation();
358
359 // Turns off location
360 StopAndClearLocations();
361
362 IGnssConfiguration::BlacklistedSource source_to_blacklist;
363 source_to_blacklist.constellation = constellation_to_blacklist;
364 source_to_blacklist.svid = 0; // documented wildcard for all satellites in this constellation
365
366 auto gnss_configuration_hal_return = gnss_hal_->getExtensionGnssConfiguration_1_1();
367 ASSERT_TRUE(gnss_configuration_hal_return.isOk());
368 sp<IGnssConfiguration> gnss_configuration_hal = gnss_configuration_hal_return;
369 ASSERT_NE(gnss_configuration_hal, nullptr);
370
371 hidl_vec<IGnssConfiguration::BlacklistedSource> sources;
372 sources.resize(1);
373 sources[0] = source_to_blacklist;
374
375 auto result = gnss_configuration_hal->setBlacklist(sources);
376 ASSERT_TRUE(result.isOk());
377 EXPECT_TRUE(result);
378
379 // retry and ensure constellation not used
380 list_gnss_sv_status_.clear();
381
382 location_called_count_ = 0;
383 StartAndCheckLocations(kLocationsToAwait);
384
385 // Tolerate 1 less sv status to handle edge cases in reporting.
386 EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait);
387 ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations", (int)list_gnss_sv_status_.size(),
388 kLocationsToAwait);
389 for (const auto& gnss_sv_status : list_gnss_sv_status_) {
390 for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) {
391 const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv];
392 EXPECT_FALSE((gnss_sv.constellation == source_to_blacklist.constellation) &&
393 (gnss_sv.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX));
394 }
395 }
396
397 // clean up
398 StopAndClearLocations();
399 sources.resize(0);
400 result = gnss_configuration_hal->setBlacklist(sources);
401 ASSERT_TRUE(result.isOk());
402 EXPECT_TRUE(result);
403 }
404
405 /*
406 * BlacklistConstellationWithLocationOn:
407 *
408 * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding
409 * GnssStatus for any non-GPS constellations.
410 * 2a & b) Blacklist first non-GPS constellations, and turns off location.
411 * 3) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
412 * GnssStatus does not use any constellation but GPS.
413 * 4a & b) Clean up by turning off location, and send in empty blacklist.
414 */
TEST_F(GnssHalTest,BlacklistConstellationWithLocationOn)415 TEST_F(GnssHalTest, BlacklistConstellationWithLocationOn) {
416 if (!IsGnssHalVersion_1_1()) {
417 ALOGI("Test BlacklistConstellation skipped. GNSS HAL version is greater than 1.1.");
418 return;
419 }
420
421 const int kLocationsToAwait = 3;
422 GnssConstellationType constellation_to_blacklist = startLocationAndGetNonGpsConstellation();
423
424 IGnssConfiguration::BlacklistedSource source_to_blacklist;
425 source_to_blacklist.constellation = constellation_to_blacklist;
426 source_to_blacklist.svid = 0; // documented wildcard for all satellites in this constellation
427
428 auto gnss_configuration_hal_return = gnss_hal_->getExtensionGnssConfiguration_1_1();
429 ASSERT_TRUE(gnss_configuration_hal_return.isOk());
430 sp<IGnssConfiguration> gnss_configuration_hal = gnss_configuration_hal_return;
431 ASSERT_NE(gnss_configuration_hal, nullptr);
432
433 hidl_vec<IGnssConfiguration::BlacklistedSource> sources;
434 sources.resize(1);
435 sources[0] = source_to_blacklist;
436
437 // setBlacklist when location is on.
438 auto result = gnss_configuration_hal->setBlacklist(sources);
439 ASSERT_TRUE(result.isOk());
440 EXPECT_TRUE(result);
441
442 // Turns off location
443 StopAndClearLocations();
444
445 // retry and ensure constellation not used
446 list_gnss_sv_status_.clear();
447
448 location_called_count_ = 0;
449 StartAndCheckLocations(kLocationsToAwait);
450
451 // Tolerate 1 less sv status to handle edge cases in reporting.
452 EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait);
453 ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations", (int)list_gnss_sv_status_.size(),
454 kLocationsToAwait);
455 for (const auto& gnss_sv_status : list_gnss_sv_status_) {
456 for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) {
457 const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv];
458 EXPECT_FALSE((gnss_sv.constellation == source_to_blacklist.constellation) &&
459 (gnss_sv.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX));
460 }
461 }
462
463 // clean up
464 StopAndClearLocations();
465 sources.resize(0);
466 result = gnss_configuration_hal->setBlacklist(sources);
467 ASSERT_TRUE(result.isOk());
468 EXPECT_TRUE(result);
469 }
470
471 /*
472 * InjectBestLocation
473 *
474 * Ensure successfully injecting a location.
475 */
TEST_F(GnssHalTest,InjectBestLocation)476 TEST_F(GnssHalTest, InjectBestLocation) {
477 StartAndCheckLocations(1);
478 GnssLocation gnssLocation = last_location_;
479 CheckLocation(gnssLocation, true);
480
481 auto result = gnss_hal_->injectBestLocation(gnssLocation);
482
483 ASSERT_TRUE(result.isOk());
484 EXPECT_TRUE(result);
485
486 auto resultVoid = gnss_hal_->deleteAidingData(IGnss::GnssAidingData::DELETE_POSITION);
487
488 ASSERT_TRUE(resultVoid.isOk());
489 }
490
491 /*
492 * GnssDebugValuesSanityTest:
493 * Ensures that GnssDebug values make sense.
494 */
TEST_F(GnssHalTest,GnssDebugValuesSanityTest)495 TEST_F(GnssHalTest, GnssDebugValuesSanityTest) {
496 auto gnssDebug = gnss_hal_->getExtensionGnssDebug();
497 ASSERT_TRUE(gnssDebug.isOk());
498 if (!IsAutomotiveDevice() && info_called_count_ > 0 && last_info_.yearOfHw >= 2017) {
499 sp<IGnssDebug> iGnssDebug = gnssDebug;
500 EXPECT_NE(iGnssDebug, nullptr);
501
502 IGnssDebug::DebugData data;
503 iGnssDebug->getDebugData(
504 [&data](const IGnssDebug::DebugData& debugData) { data = debugData; });
505
506 if (data.position.valid) {
507 EXPECT_GE(data.position.latitudeDegrees, -90);
508 EXPECT_LE(data.position.latitudeDegrees, 90);
509
510 EXPECT_GE(data.position.longitudeDegrees, -180);
511 EXPECT_LE(data.position.longitudeDegrees, 180);
512
513 EXPECT_GE(data.position.altitudeMeters, -1000); // Dead Sea: -414m
514 EXPECT_LE(data.position.altitudeMeters, 20000); // Mount Everest: 8850m
515
516 EXPECT_GE(data.position.speedMetersPerSec, 0);
517 EXPECT_LE(data.position.speedMetersPerSec, 600);
518
519 EXPECT_GE(data.position.bearingDegrees, -360);
520 EXPECT_LE(data.position.bearingDegrees, 360);
521
522 EXPECT_GT(data.position.horizontalAccuracyMeters, 0);
523 EXPECT_LE(data.position.horizontalAccuracyMeters, 20000000);
524
525 EXPECT_GT(data.position.verticalAccuracyMeters, 0);
526 EXPECT_LE(data.position.verticalAccuracyMeters, 20000);
527
528 EXPECT_GT(data.position.speedAccuracyMetersPerSecond, 0);
529 EXPECT_LE(data.position.speedAccuracyMetersPerSecond, 500);
530
531 EXPECT_GT(data.position.bearingAccuracyDegrees, 0);
532 EXPECT_LE(data.position.bearingAccuracyDegrees, 180);
533
534 EXPECT_GE(data.position.ageSeconds, 0);
535 }
536
537 EXPECT_GE(data.time.timeEstimate, 1483228800000); // Jan 01 2017 00:00:00 GMT.
538
539 EXPECT_GT(data.time.timeUncertaintyNs, 0);
540
541 EXPECT_GT(data.time.frequencyUncertaintyNsPerSec, 0);
542 EXPECT_LE(data.time.frequencyUncertaintyNsPerSec, 2.0e5); // 200 ppm
543 }
544 }
545