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