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/pal/gnss.h"
18 
19 #include "chre/util/memory.h"
20 #include "chre/util/unique_ptr.h"
21 
22 #include <chrono>
23 #include <cinttypes>
24 #include <future>
25 #include <thread>
26 
27 /**
28  * A simulated implementation of the GNSS PAL for the linux platform.
29  */
30 namespace {
31 const struct chrePalSystemApi *gSystemApi = nullptr;
32 const struct chrePalGnssCallbacks *gCallbacks = nullptr;
33 
34 //! Thread to deliver asynchronous location data after a CHRE request.
35 std::thread gLocationEventsThread;
36 std::promise<void> gStopLocationEventsThread;
37 
38 //! Thead to use when delivering a location status update.
39 std::thread gLocationStatusThread;
40 
41 //! Thread to deliver asynchronous measurement data after a CHRE request.
42 std::thread gMeasurementEventsThread;
43 std::promise<void> gStopMeasurementEventsThread;
44 
45 //! Thead to use when delivering a measurement status update.
46 std::thread gMeasurementStatusThread;
47 
sendLocationEvents(uint32_t minIntervalMs)48 void sendLocationEvents(uint32_t minIntervalMs) {
49   gCallbacks->locationStatusChangeCallback(true, CHRE_ERROR_NONE);
50 
51   std::future<void> signal = gStopLocationEventsThread.get_future();
52   while (signal.wait_for(std::chrono::milliseconds(minIntervalMs)) ==
53          std::future_status::timeout) {
54     auto event = chre::MakeUniqueZeroFill<struct chreGnssLocationEvent>();
55     event->timestamp = gSystemApi->getCurrentTime();
56     gCallbacks->locationEventCallback(event.release());
57   }
58 }
59 
sendMeasurementEvents(uint32_t minIntervalMs)60 void sendMeasurementEvents(uint32_t minIntervalMs) {
61   gCallbacks->measurementStatusChangeCallback(true, CHRE_ERROR_NONE);
62 
63   std::future<void> signal = gStopMeasurementEventsThread.get_future();
64   while (signal.wait_for(std::chrono::milliseconds(minIntervalMs)) ==
65          std::future_status::timeout) {
66     auto event = chre::MakeUniqueZeroFill<struct chreGnssDataEvent>();
67     auto measurement = chre::MakeUniqueZeroFill<struct chreGnssMeasurement>();
68     measurement->c_n0_dbhz = 63.0f;
69 
70     event->measurements = measurement.release();
71     event->measurement_count = 1;
72     event->clock.time_ns = static_cast<int64_t>(gSystemApi->getCurrentTime());
73     gCallbacks->measurementEventCallback(event.release());
74   }
75 }
76 
stopLocation()77 void stopLocation() {
78   gCallbacks->locationStatusChangeCallback(false, CHRE_ERROR_NONE);
79 }
80 
stopMeasurement()81 void stopMeasurement() {
82   gCallbacks->measurementStatusChangeCallback(false, CHRE_ERROR_NONE);
83 }
84 
stopLocationThreads()85 void stopLocationThreads() {
86   if (gLocationEventsThread.joinable()) {
87     gStopLocationEventsThread.set_value();
88     gLocationEventsThread.join();
89   }
90   if (gLocationStatusThread.joinable()) {
91     gLocationStatusThread.join();
92   }
93 }
94 
stopMeasurementThreads()95 void stopMeasurementThreads() {
96   if (gMeasurementEventsThread.joinable()) {
97     gStopMeasurementEventsThread.set_value();
98     gMeasurementEventsThread.join();
99   }
100   if (gMeasurementStatusThread.joinable()) {
101     gMeasurementStatusThread.join();
102   }
103 }
104 
chrePalGnssGetCapabilities()105 uint32_t chrePalGnssGetCapabilities() {
106   return CHRE_GNSS_CAPABILITIES_LOCATION | CHRE_GNSS_CAPABILITIES_MEASUREMENTS;
107 }
108 
chrePalControlLocationSession(bool enable,uint32_t minIntervalMs,uint32_t)109 bool chrePalControlLocationSession(bool enable, uint32_t minIntervalMs,
110                                    uint32_t /* minTimeToNextFixMs */) {
111   stopLocationThreads();
112 
113   if (enable) {
114     gStopLocationEventsThread = std::promise<void>();
115     gLocationEventsThread = std::thread(sendLocationEvents, minIntervalMs);
116   } else {
117     gLocationStatusThread = std::thread(stopLocation);
118   }
119 
120   return true;
121 }
122 
chrePalGnssReleaseLocationEvent(struct chreGnssLocationEvent * event)123 void chrePalGnssReleaseLocationEvent(struct chreGnssLocationEvent *event) {
124   chre::memoryFree(event);
125 }
126 
chrePalControlMeasurementSession(bool enable,uint32_t minIntervalMs)127 bool chrePalControlMeasurementSession(bool enable, uint32_t minIntervalMs) {
128   stopMeasurementThreads();
129 
130   if (enable) {
131     gStopMeasurementEventsThread = std::promise<void>();
132     gMeasurementEventsThread =
133         std::thread(sendMeasurementEvents, minIntervalMs);
134   } else {
135     gMeasurementStatusThread = std::thread(stopMeasurement);
136   }
137 
138   return true;
139 }
140 
chrePalGnssReleaseMeasurementDataEvent(struct chreGnssDataEvent * event)141 void chrePalGnssReleaseMeasurementDataEvent(struct chreGnssDataEvent *event) {
142   chre::memoryFree(
143       const_cast<struct chreGnssMeasurement *>(event->measurements));
144   chre::memoryFree(event);
145 }
146 
chrePalGnssApiClose()147 void chrePalGnssApiClose() {
148   stopLocationThreads();
149   stopMeasurementThreads();
150 }
151 
chrePalGnssApiOpen(const struct chrePalSystemApi * systemApi,const struct chrePalGnssCallbacks * callbacks)152 bool chrePalGnssApiOpen(const struct chrePalSystemApi *systemApi,
153                         const struct chrePalGnssCallbacks *callbacks) {
154   chrePalGnssApiClose();
155 
156   bool success = false;
157   if (systemApi != nullptr && callbacks != nullptr) {
158     gSystemApi = systemApi;
159     gCallbacks = callbacks;
160     success = true;
161   }
162 
163   return success;
164 }
165 
166 }  // anonymous namespace
167 
chrePalGnssGetApi(uint32_t requestedApiVersion)168 const struct chrePalGnssApi *chrePalGnssGetApi(uint32_t requestedApiVersion) {
169   static const struct chrePalGnssApi kApi = {
170       .moduleVersion = CHRE_PAL_GNSS_API_CURRENT_VERSION,
171       .open = chrePalGnssApiOpen,
172       .close = chrePalGnssApiClose,
173       .getCapabilities = chrePalGnssGetCapabilities,
174       .controlLocationSession = chrePalControlLocationSession,
175       .releaseLocationEvent = chrePalGnssReleaseLocationEvent,
176       .controlMeasurementSession = chrePalControlMeasurementSession,
177       .releaseMeasurementDataEvent = chrePalGnssReleaseMeasurementDataEvent,
178   };
179 
180   if (!CHRE_PAL_VERSIONS_ARE_COMPATIBLE(kApi.moduleVersion,
181                                         requestedApiVersion)) {
182     return nullptr;
183   } else {
184     return &kApi;
185   }
186 }
187