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   if (api_ != nullptr) {
173     api_->close();
174   }
175 }
176 
requestStateResync()177 void PalGnssTest::requestStateResync() {
178   // TODO:
179 }
180 
locationStatusChangeCallback(bool enabled,uint8_t errorCode)181 void PalGnssTest::locationStatusChangeCallback(bool enabled,
182                                                uint8_t errorCode) {
183   LOGI("Received location status change with enabled %d error %" PRIu8, enabled,
184        errorCode);
185   if (errorCode == CHRE_ERROR_LAST) {
186     LOGE("Received CHRE_ERROR_LAST");
187     errorCode = CHRE_ERROR;
188   }
189   chre::LockGuard<chre::Mutex> lock(mutex_);
190   errorCode_ = errorCode;
191   locationSessionEnabled_ = enabled;
192   condVar_.notify_one();
193 }
194 
locationEventCallback(struct chreGnssLocationEvent * event)195 void PalGnssTest::locationEventCallback(struct chreGnssLocationEvent *event) {
196   LOGI("Received location event");
197   chre::LockGuard<chre::Mutex> lock(mutex_);
198   if (!locationEventVector_.full()) {
199     locationEventVector_.push_back(event);
200     if (locationEventVector_.full()) {
201       condVar_.notify_one();
202     }
203   }
204 }
205 
measurementStatusChangeCallback(bool enabled,uint8_t errorCode)206 void PalGnssTest::measurementStatusChangeCallback(bool enabled,
207                                                   uint8_t errorCode) {
208   LOGI("Received measurement status change with enabled %d error %" PRIu8,
209        enabled, errorCode);
210   if (errorCode == CHRE_ERROR_LAST) {
211     LOGE("Received CHRE_ERROR_LAST");
212     errorCode = CHRE_ERROR;
213   }
214   chre::LockGuard<chre::Mutex> lock(mutex_);
215   errorCode_ = errorCode;
216   measurementSessionEnabled_ = enabled;
217   condVar_.notify_one();
218 }
219 
measurementEventCallback(struct chreGnssDataEvent * event)220 void PalGnssTest::measurementEventCallback(struct chreGnssDataEvent *event) {
221   LOGI("Received measurement event");
222   chre::LockGuard<chre::Mutex> lock(mutex_);
223   if (!measurementEventVector_.full()) {
224     measurementEventVector_.push_back(event);
225     if (measurementEventVector_.full()) {
226       condVar_.notify_one();
227     }
228   }
229 }
230 
waitForAsyncResponseAssertSuccess(chre::Nanoseconds timeoutNs)231 void PalGnssTest::waitForAsyncResponseAssertSuccess(
232     chre::Nanoseconds timeoutNs) {
233   bool waitSuccess = true;
234   while (errorCode_ == CHRE_ERROR_LAST && waitSuccess) {
235     waitSuccess = condVar_.wait_for(mutex_, timeoutNs);
236   }
237   ASSERT_TRUE(waitSuccess);
238   ASSERT_EQ(errorCode_, CHRE_ERROR_NONE);
239 }
240 
TEST_P(PalGnssTest,LocationSessionTest)241 TEST_P(PalGnssTest, LocationSessionTest) {
242   bool hasLocationCapability =
243       ((api_->getCapabilities() & CHRE_GNSS_CAPABILITIES_LOCATION) ==
244        CHRE_GNSS_CAPABILITIES_LOCATION);
245 #if PAL_IMPL_TEST_GNSS_LOCATION_REQUIRED
246   ASSERT_TRUE(hasLocationCapability);
247 #else
248   if (!hasLocationCapability) {
249     GTEST_SKIP();
250   }
251 #endif
252 
253   chre::LockGuard<chre::Mutex> lock(mutex_);
254 
255   prepareForAsyncResponse();
256   ASSERT_TRUE(api_->controlLocationSession(true /* enable */,
257                                            GetParam() /* minIntervalMs */,
258                                            0 /* minTimeToNextFixMs */));
259   waitForAsyncResponseAssertSuccess(kGnssAsyncResultTimeoutNs);
260   ASSERT_TRUE(locationSessionEnabled_);
261 
262   bool waitSuccess = true;
263   while (!locationEventVector_.full() && waitSuccess) {
264     waitSuccess = condVar_.wait_for(mutex_, kGnssEventTimeoutNs);
265   }
266 
267   for (size_t i = 0; i < locationEventVector_.size(); i++) {
268     logLocationEvent(*locationEventVector_[i]);
269     validateLocationEvent(*locationEventVector_[i]);
270     api_->releaseLocationEvent(locationEventVector_[i]);
271   }
272   EXPECT_TRUE(locationEventVector_.full());
273 
274   prepareForAsyncResponse();
275   ASSERT_TRUE(api_->controlLocationSession(
276       false /* enable */, 0 /* minIntervalMs */, 0 /* minTimeToNextFixMs */));
277   waitForAsyncResponseAssertSuccess(kGnssAsyncResultTimeoutNs);
278   ASSERT_FALSE(locationSessionEnabled_);
279 }
280 
TEST_P(PalGnssTest,MeasurementSessionTest)281 TEST_P(PalGnssTest, MeasurementSessionTest) {
282   bool hasMeasurementCapability =
283       ((api_->getCapabilities() & CHRE_GNSS_CAPABILITIES_MEASUREMENTS) ==
284        CHRE_GNSS_CAPABILITIES_MEASUREMENTS);
285 #if PAL_IMPL_TEST_GNSS_MEAUSUREMENT_REQUIRED
286   ASSERT_TRUE(hasMeasurementCapability);
287 #else
288   if (!hasMeasurementCapability) {
289     GTEST_SKIP();
290   }
291 #endif
292 
293   chre::LockGuard<chre::Mutex> lock(mutex_);
294 
295   prepareForAsyncResponse();
296   ASSERT_TRUE(api_->controlMeasurementSession(true /* enable */,
297                                               GetParam() /* minIntervalMs */));
298   waitForAsyncResponseAssertSuccess(kGnssAsyncResultTimeoutNs);
299   ASSERT_TRUE(measurementSessionEnabled_);
300 
301   bool waitSuccess = true;
302   while (!measurementEventVector_.full() && waitSuccess) {
303     waitSuccess = condVar_.wait_for(mutex_, kGnssEventTimeoutNs);
304   }
305   EXPECT_TRUE(measurementEventVector_.full());
306 
307   for (size_t i = 0; i < measurementEventVector_.size(); i++) {
308     logMeasurementEvent(*measurementEventVector_[i]);
309     validateMeasurementEvent(*measurementEventVector_[i]);
310     api_->releaseMeasurementDataEvent(measurementEventVector_[i]);
311   }
312 
313   prepareForAsyncResponse();
314   ASSERT_TRUE(api_->controlMeasurementSession(false /* enable */,
315                                               0 /* minIntervalMs */));
316   waitForAsyncResponseAssertSuccess(kGnssAsyncResultTimeoutNs);
317   ASSERT_FALSE(measurementSessionEnabled_);
318 }
319 
320 INSTANTIATE_TEST_SUITE_P(PalGnssTestRange, PalGnssTest,
321                          // Parameter: minIntervalMs argument
322                          testing::Values(1000, 8000));
323 
324 }  // namespace gnss_pal_impl_test
325