• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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.h>
18 #include <cinttypes>
19 
20 #include "chre/util/macros.h"
21 #include "chre/util/nanoapp/log.h"
22 #include "chre/util/time.h"
23 
24 #define LOG_TAG "[GnssWorld]"
25 
26 #ifdef CHRE_NANOAPP_INTERNAL
27 namespace chre {
28 namespace {
29 #endif  // CHRE_NANOAPP_INTERNAL
30 
31 //! Control which test(s) to run
32 constexpr bool kEnableLocationTest = true;
33 constexpr bool kEnableMeasurementTest = true;
34 
35 //! A dummy cookie to pass into the session async and timer request.
36 const uint32_t kLocationSessionCookie = 0x1337;
37 const uint32_t kMeasurementSessionCookie = 0xdaad;
38 
39 //! The minimum time to the next fix for a location.
40 constexpr Milliseconds kLocationMinTimeToNextFix(0);
41 
42 //! The interval in seconds between updates.
43 const uint32_t kReportIntervals[] = {
44   30,
45   15,
46   30,
47   15,
48   0,
49   10,
50 };
51 
52 //! Whether a specific Gnss capability is supported by the platform
53 bool gLocationSupported = false;
54 bool gMeasurementSupported = false;
55 
56 uint32_t gLocationTimerHandle;
57 uint32_t gLocationTimerCount = 0;
58 
59 uint32_t gMeasurementTimerHandle;
60 uint32_t gMeasurementTimerCount = 0;
61 
62 //! Whether an async result has been received.
63 bool gLocationAsyncResultReceived = false;
64 bool gMeasurementAsyncResultReceived = false;
65 
makeLocationRequest()66 void makeLocationRequest() {
67   uint32_t interval = kReportIntervals[gLocationTimerCount++];
68   LOGI("Modifying location update interval to %" PRIu32 " sec", interval);
69 
70   if (interval > 0) {
71     if (chreGnssLocationSessionStartAsync(
72           interval * 1000,
73           kLocationMinTimeToNextFix.getMilliseconds(),
74           &kLocationSessionCookie)) {
75       LOGI("Location session start request sent");
76     } else {
77       LOGE("Error sending location session start request");
78     }
79   } else {
80     if (chreGnssLocationSessionStopAsync(
81           &kLocationSessionCookie)) {
82       LOGI("Location session stop request sent");
83     } else {
84       LOGE("Error sending location session stop request");
85     }
86   }
87 
88   // set a timer to verify reception of async result.
89   gLocationTimerHandle = chreTimerSet(
90       CHRE_GNSS_ASYNC_RESULT_TIMEOUT_NS, /* 5 sec in CHRE 1.1 */
91       &kLocationSessionCookie, true /* oneShot */);
92 }
93 
makeMeasurementRequest()94 void makeMeasurementRequest() {
95   uint32_t interval = kReportIntervals[gMeasurementTimerCount++];
96   LOGI("Modifying measurement update interval to %" PRIu32 " sec", interval);
97 
98   if (interval > 0) {
99     if (chreGnssMeasurementSessionStartAsync(
100           interval * 1000, &kMeasurementSessionCookie)) {
101       LOGI("Measurement session start request sent");
102     } else {
103       LOGE("Error sending measurement session start request");
104     }
105   } else {
106     if (chreGnssMeasurementSessionStopAsync(
107           &kMeasurementSessionCookie)) {
108       LOGI("Measurement session stop request sent");
109     } else {
110       LOGE("Error sending measurement session stop request");
111     }
112   }
113 
114   // set a timer to verify reception of async result.
115   gMeasurementTimerHandle = chreTimerSet(
116       CHRE_GNSS_ASYNC_RESULT_TIMEOUT_NS, /* 5 sec in CHRE 1.1 */
117       &kMeasurementSessionCookie, true /* oneShot */);
118 }
119 
handleTimerEvent(const void * eventData)120 void handleTimerEvent(const void *eventData) {
121   bool validData = true;
122 
123   bool supported;
124   const char *name;
125   uint32_t timerCount;
126   bool *asyncResultReceived;
127   void (*makeRequest)();
128 
129   if (eventData == &kLocationSessionCookie) {
130     supported = gLocationSupported;
131     name = "location";
132     timerCount = gLocationTimerCount;
133     asyncResultReceived = &gLocationAsyncResultReceived;
134     makeRequest = makeLocationRequest;
135   } else if (eventData == &kMeasurementSessionCookie) {
136     supported = gMeasurementSupported;
137     name = "measurement";
138     timerCount = gMeasurementTimerCount;
139     asyncResultReceived = &gMeasurementAsyncResultReceived;
140     makeRequest = makeMeasurementRequest;
141   } else {
142     validData = false;
143     LOGE("Invalid timer cookie");
144   }
145 
146   if (validData) {
147     LOGI("%s timer event received, count %" PRIu32, name, timerCount);
148     if (!*asyncResultReceived) {
149       LOGE("%s async result not received!", name);
150     }
151     *asyncResultReceived = false;
152 
153     if (supported && timerCount < ARRAY_SIZE(kReportIntervals)) {
154       makeRequest();
155     }
156   }
157 }
158 
handleGnssAsyncResult(const chreAsyncResult * result)159 void handleGnssAsyncResult(const chreAsyncResult *result) {
160   bool validResult = true;
161   const char *action = nullptr;
162   const char *name;
163   bool *received;
164   const uint32_t *cookie;
165 
166   switch (result->requestType) {
167     case CHRE_GNSS_REQUEST_TYPE_LOCATION_SESSION_START:
168       action = "start";
169       // fall through to CHRE_GNSS_REQUEST_TYPE_LOCATION_SESSION_STOP
170 
171     case CHRE_GNSS_REQUEST_TYPE_LOCATION_SESSION_STOP:
172       if (action == nullptr) {
173         action = "stop";
174       }
175       name = "location";
176       received = &gLocationAsyncResultReceived;
177       cookie = &kLocationSessionCookie;
178       break;
179 
180     case CHRE_GNSS_REQUEST_TYPE_MEASUREMENT_SESSION_START:
181       action = "start";
182       // fall through to CHRE_GNSS_REQUEST_TYPE_MEASUREMENT_SESSION_STOP
183 
184     case CHRE_GNSS_REQUEST_TYPE_MEASUREMENT_SESSION_STOP:
185       if (action == nullptr) {
186         action = "stop";
187       }
188       name = "measurement";
189       received = &gMeasurementAsyncResultReceived;
190       cookie = &kMeasurementSessionCookie;
191       break;
192 
193     default:
194       LOGE("Received invalid async result %" PRIu8, result->requestType);
195       validResult = false;
196       break;
197   }
198 
199   if (validResult) {
200     *received = true;
201     if (result->success) {
202       LOGI("GNSS %s %s success", name, action);
203     } else {
204       LOGE("GNSS %s %s failure: %" PRIu8, name, action, result->errorCode);
205     }
206 
207     if (result->cookie != cookie) {
208       LOGE("GNSS %s session %s request cookie mismatch", name, action);
209     }
210   }
211 }
212 
handleGnssLocationEvent(const chreGnssLocationEvent * event)213 void handleGnssLocationEvent(const chreGnssLocationEvent *event) {
214   LOGI("Received location: %" PRId32 ", %" PRId32, event->latitude_deg_e7,
215        event->longitude_deg_e7);
216   LOGI("  timestamp (ms): %" PRIu64, event->timestamp);
217   LOGI("  altitude (m): %f", event->altitude);
218   LOGI("  speed (m/s): %f", event->speed);
219   LOGI("  bearing (deg): %f", event->bearing);
220   LOGI("  accuracy: %f", event->accuracy);
221   LOGI("  flags: %" PRIx16, event->flags);
222 }
223 
handleGnssDataEvent(const chreGnssDataEvent * event)224 void handleGnssDataEvent(const chreGnssDataEvent *event) {
225   LOGI("Received data: %" PRIu8 " measurements", event->measurement_count);
226 
227   const struct chreGnssMeasurement *measurement = event->measurements;
228   for (uint8_t i = 0; i < event->measurement_count; i++) {
229     LOGI("%" PRIu8 ": const %" PRIu8 ", cn0 %f",
230          i, measurement->constellation, measurement->c_n0_dbhz);
231     measurement++;
232   }
233 }
234 
nanoappStart()235 bool nanoappStart() {
236   LOGI("App started as instance %" PRIu32, chreGetInstanceId());
237 
238   const char *gnssCapabilitiesStr;
239   uint32_t gnssCapabilities = chreGnssGetCapabilities();
240   switch (gnssCapabilities) {
241     case CHRE_GNSS_CAPABILITIES_LOCATION
242         | CHRE_GNSS_CAPABILITIES_MEASUREMENTS:
243       gnssCapabilitiesStr = "LOCATION | MEASUREMENTS";
244       gLocationSupported = true;
245       gMeasurementSupported = true;
246       break;
247     case CHRE_GNSS_CAPABILITIES_LOCATION:
248       gnssCapabilitiesStr = "LOCATION";
249       gLocationSupported = true;
250       break;
251     case CHRE_GNSS_CAPABILITIES_MEASUREMENTS:
252       gnssCapabilitiesStr = "MEASUREMENTS";
253       gMeasurementSupported = true;
254       break;
255     case CHRE_GNSS_CAPABILITIES_NONE:
256       gnssCapabilitiesStr = "NONE";
257       break;
258     default:
259       gnssCapabilitiesStr = "INVALID";
260   }
261 
262   LOGI("Detected GNSS support as: %s (%" PRIu32 ")",
263        gnssCapabilitiesStr, gnssCapabilities);
264 
265   if (gLocationSupported && kEnableLocationTest) {
266     makeLocationRequest();
267   }
268 
269   if (gMeasurementSupported && kEnableMeasurementTest) {
270     makeMeasurementRequest();
271   }
272 
273   return true;
274 }
275 
nanoappHandleEvent(uint32_t senderInstanceId,uint16_t eventType,const void * eventData)276 void nanoappHandleEvent(uint32_t senderInstanceId,
277                         uint16_t eventType,
278                         const void *eventData) {
279   switch (eventType) {
280     case CHRE_EVENT_GNSS_ASYNC_RESULT:
281       handleGnssAsyncResult(static_cast<const chreAsyncResult *>(eventData));
282       break;
283     case CHRE_EVENT_GNSS_LOCATION:
284       handleGnssLocationEvent(
285           static_cast<const chreGnssLocationEvent *>(eventData));
286       break;
287     case CHRE_EVENT_GNSS_DATA:
288       handleGnssDataEvent(static_cast<const chreGnssDataEvent *>(eventData));
289       break;
290     case CHRE_EVENT_TIMER:
291       handleTimerEvent(eventData);
292       break;
293     default:
294       LOGW("Unhandled event type %" PRIu16, eventType);
295   }
296 }
297 
nanoappEnd()298 void nanoappEnd() {
299   LOGI("Stopped");
300 }
301 
302 #ifdef CHRE_NANOAPP_INTERNAL
303 }  // anonymous namespace
304 }  // namespace chre
305 
306 #include "chre/util/nanoapp/app_id.h"
307 #include "chre/platform/static_nanoapp_init.h"
308 
309 CHRE_STATIC_NANOAPP_INIT(GnssWorld, chre::kGnssWorldAppId, 0);
310 #endif  // CHRE_NANOAPP_INTERNAL
311