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 #include "gnss_pal_impl_test.h"
18
19 #include "chre/platform/log.h"
20 #include "chre/platform/shared/pal_system_api.h"
21 #include "chre/platform/system_time.h"
22 #include "chre/util/lock_guard.h"
23
24 #include <cinttypes>
25
26 //! Flag to require GNSS location sessions capability to be enabled for the test
27 //! to pass. Set to false to allow tests to pass on disabled platforms.
28 //! Note that it is required to run this test where location can be acquired.
29 //! The constants kGnssEventTimeoutNs and kEventArraySize may be tuned if
30 //! applicable.
31 #ifndef PAL_IMPL_TEST_GNSS_LOCATION_REQUIRED
32 #define PAL_IMPL_TEST_GNSS_LOCATION_REQUIRED true
33 #endif
34
35 //! Same as above for GNSS measurement sessions.
36 #ifndef PAL_IMPL_TEST_GNSS_MEASUREMENTS_REQUIRED
37 #define PAL_IMPL_TEST_GNSS_MEASUREMENTS_REQUIRED true
38 #endif
39
40 namespace gnss_pal_impl_test {
41
42 namespace {
43
44 using ::chre::Nanoseconds;
45 using ::chre::Seconds;
46 using ::chre::SystemTime;
47
48 //! A pointer to the current test running
49 gnss_pal_impl_test::PalGnssTest *gTest = nullptr;
50
51 //! Timeout as specified by the CHRE API
52 const Nanoseconds kGnssAsyncResultTimeoutNs =
53 Nanoseconds(CHRE_GNSS_ASYNC_RESULT_TIMEOUT_NS);
54
55 //! Timeout to wait for kEventArraySize events.
56 const Nanoseconds kGnssEventTimeoutNs = Seconds(60);
57
chrePalRequestStateResync()58 void chrePalRequestStateResync() {
59 if (gTest != nullptr) {
60 gTest->requestStateResync();
61 }
62 }
63
chrePalLocationStatusChangeCallback(bool enabled,uint8_t errorCode)64 void chrePalLocationStatusChangeCallback(bool enabled, uint8_t errorCode) {
65 if (gTest != nullptr) {
66 gTest->locationStatusChangeCallback(enabled, errorCode);
67 }
68 }
69
chrePalLocationEventCallback(struct chreGnssLocationEvent * event)70 void chrePalLocationEventCallback(struct chreGnssLocationEvent *event) {
71 if (gTest != nullptr) {
72 gTest->locationEventCallback(event);
73 }
74 }
75
chrePalMeasurementStatusChangeCallback(bool enabled,uint8_t errorCode)76 void chrePalMeasurementStatusChangeCallback(bool enabled, uint8_t errorCode) {
77 if (gTest != nullptr) {
78 gTest->measurementStatusChangeCallback(enabled, errorCode);
79 }
80 }
81
chrePalMeasurementEventCallback(struct chreGnssDataEvent * event)82 void chrePalMeasurementEventCallback(struct chreGnssDataEvent *event) {
83 if (gTest != nullptr) {
84 gTest->measurementEventCallback(event);
85 }
86 }
87
logLocationEvent(const struct chreGnssLocationEvent & event)88 void logLocationEvent(const struct chreGnssLocationEvent &event) {
89 LOGI("Received location: %" PRId32 ", %" PRId32, event.latitude_deg_e7,
90 event.longitude_deg_e7);
91 LOGI(" timestamp (ms): %" PRIu64, event.timestamp);
92 LOGI(" altitude (m): %f", event.altitude);
93 LOGI(" speed (m/s): %f", event.speed);
94 LOGI(" bearing (deg): %f", event.bearing);
95 LOGI(" accuracy: %f", event.accuracy);
96 LOGI(" flags: 0x%" PRIx16, event.flags);
97 LOGI(" altitude_accuracy: %f", event.altitude_accuracy);
98 LOGI(" speed_accuracy: %f", event.speed_accuracy);
99 LOGI(" bearing_accuracy: %f", event.bearing_accuracy);
100 }
101
validateLocationEvent(const struct chreGnssLocationEvent & event)102 void validateLocationEvent(const struct chreGnssLocationEvent &event) {
103 static uint64_t sLastTimestampNs = 0;
104 EXPECT_GE(event.timestamp, sLastTimestampNs);
105 sLastTimestampNs = event.timestamp;
106 if (event.flags & CHRE_GPS_LOCATION_HAS_LAT_LONG) {
107 EXPECT_GE(event.latitude_deg_e7, -90 * 1e7);
108 EXPECT_LE(event.latitude_deg_e7, 90 * 1e7);
109 EXPECT_GE(event.longitude_deg_e7, -180 * 1e7);
110 EXPECT_LE(event.longitude_deg_e7, 180 * 1e7);
111 }
112 if (event.flags & CHRE_GPS_LOCATION_HAS_BEARING) {
113 EXPECT_GE(event.bearing, 0);
114 EXPECT_LT(event.bearing, 360); // [0, 360) per API
115 }
116 }
117
logMeasurementEvent(const struct chreGnssDataEvent & event)118 void logMeasurementEvent(const struct chreGnssDataEvent &event) {
119 LOGI("Received data: %" PRIu8 " measurements", event.measurement_count);
120
121 for (uint8_t i = 0; i < event.measurement_count; i++) {
122 LOGI("%" PRIu8 ": const %" PRIu8 ", cn0 %.2f, freq %.3f MHz", i,
123 event.measurements[i].constellation, event.measurements[i].c_n0_dbhz,
124 event.measurements[i].carrier_frequency_hz / 1e6);
125 }
126 }
127
validateMeasurementEvent(const struct chreGnssDataEvent & event)128 void validateMeasurementEvent(const struct chreGnssDataEvent &event) {
129 EXPECT_GE(event.measurement_count, 0);
130 EXPECT_LE(event.measurement_count, CHRE_GNSS_MAX_MEASUREMENT);
131 if (event.measurement_count > 0) {
132 EXPECT_NE(event.measurements, nullptr);
133 }
134
135 static int64_t sLastClockTimeNs = INT64_MIN;
136 EXPECT_GE(event.clock.time_ns, sLastClockTimeNs);
137 sLastClockTimeNs = event.clock.time_ns;
138
139 for (uint8_t i = 0; i < event.measurement_count; i++) {
140 EXPECT_GE(event.measurements[i].c_n0_dbhz, 0);
141 EXPECT_LE(event.measurements[i].c_n0_dbhz, 63);
142 }
143 }
144
145 } // anonymous namespace
146
SetUp()147 void PalGnssTest::SetUp() {
148 api_ = chrePalGnssGetApi(CHRE_PAL_GNSS_API_CURRENT_VERSION);
149 ASSERT_NE(api_, nullptr);
150 EXPECT_EQ(api_->moduleVersion, CHRE_PAL_GNSS_API_CURRENT_VERSION);
151
152 // Open the PAL API
153 static const struct chrePalGnssCallbacks kCallbacks = {
154 .requestStateResync = chrePalRequestStateResync,
155 .locationStatusChangeCallback = chrePalLocationStatusChangeCallback,
156 .locationEventCallback = chrePalLocationEventCallback,
157 .measurementStatusChangeCallback = chrePalMeasurementStatusChangeCallback,
158 .measurementEventCallback = chrePalMeasurementEventCallback,
159 };
160 ASSERT_TRUE(api_->open(&chre::gChrePalSystemApi, &kCallbacks));
161 gTest = this;
162
163 errorCode_ = CHRE_ERROR_LAST;
164 locationSessionEnabled_ = false;
165 locationEventVector_.resize(0);
166 measurementSessionEnabled_ = false;
167 measurementEventVector_.resize(0);
168 }
169
TearDown()170 void PalGnssTest::TearDown() {
171 gTest = nullptr;
172 api_->close();
173 }
174
requestStateResync()175 void PalGnssTest::requestStateResync() {
176 // TODO:
177 }
178
locationStatusChangeCallback(bool enabled,uint8_t errorCode)179 void PalGnssTest::locationStatusChangeCallback(bool enabled,
180 uint8_t errorCode) {
181 LOGI("Received location status change with enabled %d error %" PRIu8, enabled,
182 errorCode);
183 if (errorCode == CHRE_ERROR_LAST) {
184 LOGE("Received CHRE_ERROR_LAST");
185 errorCode = CHRE_ERROR;
186 }
187 chre::LockGuard<chre::Mutex> lock(mutex_);
188 errorCode_ = errorCode;
189 locationSessionEnabled_ = enabled;
190 condVar_.notify_one();
191 }
192
locationEventCallback(struct chreGnssLocationEvent * event)193 void PalGnssTest::locationEventCallback(struct chreGnssLocationEvent *event) {
194 LOGI("Received location event");
195 chre::LockGuard<chre::Mutex> lock(mutex_);
196 if (!locationEventVector_.full()) {
197 locationEventVector_.push_back(event);
198 if (locationEventVector_.full()) {
199 condVar_.notify_one();
200 }
201 }
202 }
203
measurementStatusChangeCallback(bool enabled,uint8_t errorCode)204 void PalGnssTest::measurementStatusChangeCallback(bool enabled,
205 uint8_t errorCode) {
206 LOGI("Received measurement status change with enabled %d error %" PRIu8,
207 enabled, errorCode);
208 if (errorCode == CHRE_ERROR_LAST) {
209 LOGE("Received CHRE_ERROR_LAST");
210 errorCode = CHRE_ERROR;
211 }
212 chre::LockGuard<chre::Mutex> lock(mutex_);
213 errorCode_ = errorCode;
214 measurementSessionEnabled_ = enabled;
215 condVar_.notify_one();
216 }
217
measurementEventCallback(struct chreGnssDataEvent * event)218 void PalGnssTest::measurementEventCallback(struct chreGnssDataEvent *event) {
219 LOGI("Received measurement event");
220 chre::LockGuard<chre::Mutex> lock(mutex_);
221 if (!measurementEventVector_.full()) {
222 measurementEventVector_.push_back(event);
223 if (measurementEventVector_.full()) {
224 condVar_.notify_one();
225 }
226 }
227 }
228
waitForAsyncResponseAssertSuccess(chre::Nanoseconds timeoutNs)229 void PalGnssTest::waitForAsyncResponseAssertSuccess(
230 chre::Nanoseconds timeoutNs) {
231 bool waitSuccess = true;
232 while (errorCode_ == CHRE_ERROR_LAST && waitSuccess) {
233 waitSuccess = condVar_.wait_for(mutex_, timeoutNs);
234 }
235 ASSERT_TRUE(waitSuccess);
236 ASSERT_EQ(errorCode_, CHRE_ERROR_NONE);
237 }
238
TEST_F(PalGnssTest,LocationSessionTest)239 TEST_F(PalGnssTest, LocationSessionTest) {
240 bool hasLocationCapability =
241 ((api_->getCapabilities() & CHRE_GNSS_CAPABILITIES_LOCATION) ==
242 CHRE_GNSS_CAPABILITIES_LOCATION);
243 #if PAL_IMPL_TEST_GNSS_LOCATION_REQUIRED
244 ASSERT_TRUE(hasLocationCapability);
245 #else
246 if (!hasLocationCapability) {
247 GTEST_SKIP();
248 }
249 #endif
250
251 chre::LockGuard<chre::Mutex> lock(mutex_);
252
253 prepareForAsyncResponse();
254 ASSERT_TRUE(api_->controlLocationSession(
255 true /* enable */, 1000 /* minIntervalMs */, 0 /* minTimeToNextFixMs */));
256 waitForAsyncResponseAssertSuccess(kGnssAsyncResultTimeoutNs);
257 ASSERT_TRUE(locationSessionEnabled_);
258
259 bool waitSuccess = true;
260 while (!locationEventVector_.full() && waitSuccess) {
261 waitSuccess = condVar_.wait_for(mutex_, kGnssEventTimeoutNs);
262 }
263
264 for (size_t i = 0; i < locationEventVector_.size(); i++) {
265 logLocationEvent(*locationEventVector_[i]);
266 validateLocationEvent(*locationEventVector_[i]);
267 api_->releaseLocationEvent(locationEventVector_[i]);
268 }
269 EXPECT_TRUE(locationEventVector_.full());
270
271 prepareForAsyncResponse();
272 ASSERT_TRUE(api_->controlLocationSession(
273 false /* enable */, 0 /* minIntervalMs */, 0 /* minTimeToNextFixMs */));
274 waitForAsyncResponseAssertSuccess(kGnssAsyncResultTimeoutNs);
275 ASSERT_FALSE(locationSessionEnabled_);
276 }
277
TEST_F(PalGnssTest,MeasurementSessionTest)278 TEST_F(PalGnssTest, MeasurementSessionTest) {
279 bool hasMeasurementCapability =
280 ((api_->getCapabilities() & CHRE_GNSS_CAPABILITIES_MEASUREMENTS) ==
281 CHRE_GNSS_CAPABILITIES_MEASUREMENTS);
282 #if PAL_IMPL_TEST_GNSS_MEAUSUREMENT_REQUIRED
283 ASSERT_TRUE(hasMeasurementCapability);
284 #else
285 if (!hasMeasurementCapability) {
286 GTEST_SKIP();
287 }
288 #endif
289
290 chre::LockGuard<chre::Mutex> lock(mutex_);
291
292 prepareForAsyncResponse();
293 ASSERT_TRUE(api_->controlMeasurementSession(true /* enable */,
294 1000 /* minIntervalMs */));
295 waitForAsyncResponseAssertSuccess(kGnssAsyncResultTimeoutNs);
296 ASSERT_TRUE(measurementSessionEnabled_);
297
298 bool waitSuccess = true;
299 while (!measurementEventVector_.full() && waitSuccess) {
300 waitSuccess = condVar_.wait_for(mutex_, kGnssEventTimeoutNs);
301 }
302 EXPECT_TRUE(measurementEventVector_.full());
303
304 for (size_t i = 0; i < measurementEventVector_.size(); i++) {
305 logMeasurementEvent(*measurementEventVector_[i]);
306 validateMeasurementEvent(*measurementEventVector_[i]);
307 api_->releaseMeasurementDataEvent(measurementEventVector_[i]);
308 }
309
310 prepareForAsyncResponse();
311 ASSERT_TRUE(api_->controlMeasurementSession(false /* enable */,
312 0 /* minIntervalMs */));
313 waitForAsyncResponseAssertSuccess(kGnssAsyncResultTimeoutNs);
314 ASSERT_FALSE(measurementSessionEnabled_);
315 }
316
317 } // namespace gnss_pal_impl_test
318