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 "chre/platform/linux/pal_gnss.h"
18 #include "chre/pal/gnss.h"
19 #include "chre/platform/linux/task_util/task_manager.h"
20 #include "chre/platform/log.h"
21
22 #include "chre/util/memory.h"
23 #include "chre/util/unique_ptr.h"
24
25 #include <chrono>
26 #include <cinttypes>
27 #include <mutex>
28 #include <optional>
29
30 /**
31 * A simulated implementation of the GNSS PAL for the linux platform.
32 */
33 namespace {
34
35 using ::chre::TaskManagerSingleton;
36
37 const struct chrePalSystemApi *gSystemApi = nullptr;
38 const struct chrePalGnssCallbacks *gCallbacks = nullptr;
39
40 // Task to deliver asynchronous location data after a CHRE request.
41 std::mutex gLocationEventsMutex;
42 std::optional<uint32_t> gLocationEventsTaskId;
43 uint32_t gLocationEventsMinIntervalMs = 0;
44 bool gDelaySendingLocationEvents = false;
45 bool gIsLocationEnabled = false;
46
47 // Task to use when delivering a location status update.
48 std::optional<uint32_t> gLocationStatusTaskId;
49
50 // Task to deliver asynchronous measurement data after a CHRE request.
51 std::optional<uint32_t> gMeasurementEventsTaskId;
52 bool gIsMeasurementEnabled = false;
53
54 // Task to use when delivering a measurement status update.
55 std::optional<uint32_t> gMeasurementStatusTaskId;
56
57 // Passive listener flag.
58 bool gIsPassiveListenerEnabled = false;
59
sendLocationEvents()60 void sendLocationEvents() {
61 if (!gIsLocationEnabled) {
62 return;
63 }
64
65 auto event = chre::MakeUniqueZeroFill<struct chreGnssLocationEvent>();
66 event->timestamp = gSystemApi->getCurrentTime();
67 gCallbacks->locationEventCallback(event.release());
68 }
69
startSendingLocationEvents(uint32_t minIntervalMs)70 void startSendingLocationEvents(uint32_t minIntervalMs) {
71 std::lock_guard<std::mutex> lock(gLocationEventsMutex);
72 if (gLocationEventsTaskId.has_value()) {
73 TaskManagerSingleton::get()->cancelTask(gLocationEventsTaskId.value());
74 gLocationEventsTaskId.reset();
75 }
76
77 TaskManagerSingleton::get()->addTask(
78 []() { gCallbacks->locationStatusChangeCallback(true, CHRE_ERROR_NONE); },
79 std::chrono::nanoseconds(0), true /* isOneShot */);
80
81 gLocationEventsTaskId = TaskManagerSingleton::get()->addTask(
82 sendLocationEvents, std::chrono::milliseconds(minIntervalMs));
83 }
84
sendMeasurementEvents()85 void sendMeasurementEvents() {
86 if (!gIsMeasurementEnabled) {
87 return;
88 }
89
90 auto event = chre::MakeUniqueZeroFill<struct chreGnssDataEvent>();
91 auto measurement = chre::MakeUniqueZeroFill<struct chreGnssMeasurement>();
92 measurement->c_n0_dbhz = 63.0f;
93 event->measurement_count = 1;
94 event->clock.time_ns = static_cast<int64_t>(gSystemApi->getCurrentTime());
95 event->measurements = measurement.release();
96 gCallbacks->measurementEventCallback(event.release());
97 }
98
stopLocation()99 void stopLocation() {
100 gCallbacks->locationStatusChangeCallback(false, CHRE_ERROR_NONE);
101 }
102
stopMeasurement()103 void stopMeasurement() {
104 gCallbacks->measurementStatusChangeCallback(false, CHRE_ERROR_NONE);
105 }
106
stopLocationTasks()107 void stopLocationTasks() {
108 {
109 std::lock_guard<std::mutex> lock(gLocationEventsMutex);
110
111 if (gLocationEventsTaskId.has_value()) {
112 TaskManagerSingleton::get()->cancelTask(gLocationEventsTaskId.value());
113 gLocationEventsTaskId.reset();
114 }
115 }
116
117 if (gLocationStatusTaskId.has_value()) {
118 TaskManagerSingleton::get()->cancelTask(gLocationStatusTaskId.value());
119 gLocationStatusTaskId.reset();
120 }
121 }
122
stopMeasurementTasks()123 void stopMeasurementTasks() {
124 if (gMeasurementEventsTaskId.has_value()) {
125 TaskManagerSingleton::get()->cancelTask(gMeasurementEventsTaskId.value());
126 gMeasurementEventsTaskId.reset();
127 }
128
129 if (gMeasurementStatusTaskId.has_value()) {
130 TaskManagerSingleton::get()->cancelTask(gMeasurementStatusTaskId.value());
131 gMeasurementStatusTaskId.reset();
132 }
133 }
134
chrePalGnssGetCapabilities()135 uint32_t chrePalGnssGetCapabilities() {
136 return CHRE_GNSS_CAPABILITIES_LOCATION | CHRE_GNSS_CAPABILITIES_MEASUREMENTS |
137 CHRE_GNSS_CAPABILITIES_GNSS_ENGINE_BASED_PASSIVE_LISTENER;
138 }
139
chrePalControlLocationSession(bool enable,uint32_t minIntervalMs,uint32_t)140 bool chrePalControlLocationSession(bool enable, uint32_t minIntervalMs,
141 uint32_t /* minTimeToNextFixMs */) {
142 stopLocationTasks();
143
144 gLocationEventsMinIntervalMs = minIntervalMs;
145 if (enable && !gDelaySendingLocationEvents) {
146 startSendingLocationEvents(minIntervalMs);
147 if (!gLocationEventsTaskId.has_value()) {
148 return false;
149 }
150 } else if (!enable) {
151 gLocationStatusTaskId = TaskManagerSingleton::get()->addTask(stopLocation);
152 if (!gLocationStatusTaskId.has_value()) {
153 return false;
154 }
155 }
156
157 gIsLocationEnabled = enable;
158 return true;
159 }
160
chrePalGnssReleaseLocationEvent(struct chreGnssLocationEvent * event)161 void chrePalGnssReleaseLocationEvent(struct chreGnssLocationEvent *event) {
162 chre::memoryFree(event);
163 }
164
chrePalControlMeasurementSession(bool enable,uint32_t minIntervalMs)165 bool chrePalControlMeasurementSession(bool enable, uint32_t minIntervalMs) {
166 stopMeasurementTasks();
167
168 if (enable) {
169 std::optional<uint32_t> measurementEventsChangeCallbackTaskId =
170 TaskManagerSingleton::get()->addTask(
171 []() {
172 gCallbacks->measurementStatusChangeCallback(true,
173 CHRE_ERROR_NONE);
174 },
175 std::chrono::nanoseconds(0), true /* isOneShot */);
176 if (!measurementEventsChangeCallbackTaskId.has_value()) {
177 return false;
178 }
179
180 gMeasurementEventsTaskId = TaskManagerSingleton::get()->addTask(
181 sendMeasurementEvents, std::chrono::milliseconds(minIntervalMs));
182 if (!gMeasurementEventsTaskId.has_value()) {
183 return false;
184 }
185 } else {
186 gMeasurementStatusTaskId =
187 TaskManagerSingleton::get()->addTask(stopMeasurement);
188 if (!gMeasurementStatusTaskId.has_value()) {
189 return false;
190 }
191 }
192
193 gIsMeasurementEnabled = enable;
194 return true;
195 }
196
chrePalGnssReleaseMeasurementDataEvent(struct chreGnssDataEvent * event)197 void chrePalGnssReleaseMeasurementDataEvent(struct chreGnssDataEvent *event) {
198 chre::memoryFree(
199 const_cast<struct chreGnssMeasurement *>(event->measurements));
200 chre::memoryFree(event);
201 }
202
chrePalGnssApiClose()203 void chrePalGnssApiClose() {
204 stopLocationTasks();
205 stopMeasurementTasks();
206 }
207
chrePalGnssApiOpen(const struct chrePalSystemApi * systemApi,const struct chrePalGnssCallbacks * callbacks)208 bool chrePalGnssApiOpen(const struct chrePalSystemApi *systemApi,
209 const struct chrePalGnssCallbacks *callbacks) {
210 chrePalGnssApiClose();
211
212 bool success = false;
213 if (systemApi != nullptr && callbacks != nullptr) {
214 gSystemApi = systemApi;
215 gCallbacks = callbacks;
216 success = true;
217 }
218
219 return success;
220 }
221
chrePalGnssconfigurePassiveLocationListener(bool enable)222 bool chrePalGnssconfigurePassiveLocationListener(bool enable) {
223 gIsPassiveListenerEnabled = enable;
224 return true;
225 }
226
227 } // anonymous namespace
228
chrePalGnssIsLocationEnabled()229 bool chrePalGnssIsLocationEnabled() {
230 return gIsLocationEnabled;
231 }
232
chrePalGnssIsMeasurementEnabled()233 bool chrePalGnssIsMeasurementEnabled() {
234 return gIsMeasurementEnabled;
235 }
236
chrePalGnssIsPassiveLocationListenerEnabled()237 bool chrePalGnssIsPassiveLocationListenerEnabled() {
238 return gIsPassiveListenerEnabled;
239 }
240
chrePalGnssDelaySendingLocationEvents(bool enabled)241 void chrePalGnssDelaySendingLocationEvents(bool enabled) {
242 gDelaySendingLocationEvents = enabled;
243 }
244
chrePalGnssStartSendingLocationEvents()245 void chrePalGnssStartSendingLocationEvents() {
246 CHRE_ASSERT(gDelaySendingLocationEvents);
247 startSendingLocationEvents(gLocationEventsMinIntervalMs);
248 }
249
chrePalGnssGetApi(uint32_t requestedApiVersion)250 const struct chrePalGnssApi *chrePalGnssGetApi(uint32_t requestedApiVersion) {
251 static const struct chrePalGnssApi kApi = {
252 .moduleVersion = CHRE_PAL_GNSS_API_CURRENT_VERSION,
253 .open = chrePalGnssApiOpen,
254 .close = chrePalGnssApiClose,
255 .getCapabilities = chrePalGnssGetCapabilities,
256 .controlLocationSession = chrePalControlLocationSession,
257 .releaseLocationEvent = chrePalGnssReleaseLocationEvent,
258 .controlMeasurementSession = chrePalControlMeasurementSession,
259 .releaseMeasurementDataEvent = chrePalGnssReleaseMeasurementDataEvent,
260 .configurePassiveLocationListener =
261 chrePalGnssconfigurePassiveLocationListener,
262 };
263
264 if (!CHRE_PAL_VERSIONS_ARE_COMPATIBLE(kApi.moduleVersion,
265 requestedApiVersion)) {
266 return nullptr;
267 } else {
268 return &kApi;
269 }
270 }
271