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 //! A dummy cookie to pass into the location session async request.
32 const uint32_t kLocationSessionCookie = 0x1337;
33
34 //! The minimum time to the next fix for a location.
35 constexpr Milliseconds kLocationMinTimeToNextFix(0);
36
37 //! The interval in seconds between location updates.
38 const uint32_t kLocationIntervals[] = {
39 30,
40 15,
41 30,
42 15,
43 0,
44 10,
45 };
46
47 //! Whether Gnss Location capability is supported by the platform
48 bool gLocationSupported = false;
49
50 uint32_t gTimerHandle;
51 uint32_t gTimerCount = 0;
52
53 //! Whether an async result has been received.
54 bool gAsyncResultReceived = false;
55
makeLocationRequest()56 void makeLocationRequest() {
57 uint32_t interval = kLocationIntervals[gTimerCount++];
58 LOGI("Modifying location update interval to %" PRIu32 " sec", interval);
59
60 if (interval > 0) {
61 if (chreGnssLocationSessionStartAsync(
62 interval * 1000,
63 kLocationMinTimeToNextFix.getMilliseconds(),
64 &kLocationSessionCookie)) {
65 LOGI("Location session start request sent");
66 } else {
67 LOGE("Error sending location session start request");
68 }
69 } else {
70 if (chreGnssLocationSessionStopAsync(
71 &kLocationSessionCookie)) {
72 LOGI("Location session stop request sent");
73 } else {
74 LOGE("Error sending location session stop request");
75 }
76 }
77
78 // set a timer to verify reception of async result.
79 gTimerHandle = chreTimerSet(
80 CHRE_GNSS_ASYNC_RESULT_TIMEOUT_NS, /* 5 sec in CHRE 1.1 */
81 nullptr /* data */, true /* oneShot */);
82 }
83
handleTimerEvent(const void * eventData)84 void handleTimerEvent(const void *eventData) {
85 LOGI("Timer event received, count %d", gTimerCount);
86 if (!gAsyncResultReceived) {
87 LOGE("Async result not received!");
88 }
89 gAsyncResultReceived = false;
90
91 if (gLocationSupported && gTimerCount < ARRAY_SIZE(kLocationIntervals)) {
92 makeLocationRequest();
93 }
94 }
95
handleGnssAsyncResult(const chreAsyncResult * result)96 void handleGnssAsyncResult(const chreAsyncResult *result) {
97 if (result->requestType == CHRE_GNSS_REQUEST_TYPE_LOCATION_SESSION_START) {
98 if (result->success) {
99 LOGI("Successfully requested a GNSS location session");
100 gAsyncResultReceived = true;
101 } else {
102 LOGE("Error requesting GNSS scan monitoring with %" PRIu8,
103 result->errorCode);
104 }
105
106 if (result->cookie != &kLocationSessionCookie) {
107 LOGE("Location session start request cookie mismatch");
108 }
109 } else if (result->requestType
110 == CHRE_GNSS_REQUEST_TYPE_LOCATION_SESSION_STOP) {
111 if (result->success) {
112 LOGI("Successfully stopped a GNSS location session");
113 gAsyncResultReceived = true;
114 } else {
115 LOGE("Error stoppinging GNSS scan monitoring with %" PRIu8,
116 result->errorCode);
117 }
118
119 if (result->cookie != &kLocationSessionCookie) {
120 LOGE("Location session stop request cookie mismatch");
121 }
122 } else {
123 LOGE("Received invalid async result %" PRIu8, result->requestType);
124 }
125 }
126
handleGnssLocationEvent(const chreGnssLocationEvent * event)127 void handleGnssLocationEvent(const chreGnssLocationEvent *event) {
128 LOGI("Received location: %" PRId32 ", %" PRId32, event->latitude_deg_e7,
129 event->longitude_deg_e7);
130 LOGI(" timestamp (ms): %" PRIu64, event->timestamp);
131 LOGI(" altitude (m): %f", event->altitude);
132 LOGI(" speed (m/s): %f", event->speed);
133 LOGI(" bearing (deg): %f", event->bearing);
134 LOGI(" accuracy: %f", event->accuracy);
135 LOGI(" flags: %" PRIx16, event->flags);
136 }
137
nanoappStart()138 bool nanoappStart() {
139 LOGI("App started as instance %" PRIu32, chreGetInstanceId());
140
141 const char *gnssCapabilitiesStr;
142 uint32_t gnssCapabilities = chreGnssGetCapabilities();
143 switch (gnssCapabilities) {
144 case CHRE_GNSS_CAPABILITIES_LOCATION
145 | CHRE_GNSS_CAPABILITIES_MEASUREMENTS:
146 gnssCapabilitiesStr = "LOCATION | MEASUREMENTS";
147 gLocationSupported = true;
148 break;
149 case CHRE_GNSS_CAPABILITIES_LOCATION:
150 gnssCapabilitiesStr = "LOCATION";
151 gLocationSupported = true;
152 break;
153 case CHRE_GNSS_CAPABILITIES_MEASUREMENTS:
154 gnssCapabilitiesStr = "MEASUREMENTS";
155 break;
156 case CHRE_GNSS_CAPABILITIES_NONE:
157 gnssCapabilitiesStr = "NONE";
158 break;
159 default:
160 gnssCapabilitiesStr = "INVALID";
161 }
162
163 LOGI("Detected GNSS support as: %s (%" PRIu32 ")",
164 gnssCapabilitiesStr, gnssCapabilities);
165
166 if (gLocationSupported) {
167 makeLocationRequest();
168 }
169
170 return true;
171 }
172
nanoappHandleEvent(uint32_t senderInstanceId,uint16_t eventType,const void * eventData)173 void nanoappHandleEvent(uint32_t senderInstanceId,
174 uint16_t eventType,
175 const void *eventData) {
176 switch (eventType) {
177 case CHRE_EVENT_GNSS_ASYNC_RESULT:
178 handleGnssAsyncResult(static_cast<const chreAsyncResult *>(eventData));
179 break;
180 case CHRE_EVENT_GNSS_LOCATION:
181 handleGnssLocationEvent(
182 static_cast<const chreGnssLocationEvent *>(eventData));
183 break;
184 case CHRE_EVENT_TIMER:
185 handleTimerEvent(eventData);
186 break;
187 default:
188 LOGW("Unhandled event type %" PRIu16, eventType);
189 }
190 }
191
nanoappEnd()192 void nanoappEnd() {
193 LOGI("Stopped");
194 }
195
196 #ifdef CHRE_NANOAPP_INTERNAL
197 } // anonymous namespace
198 } // namespace chre
199
200 #include "chre/util/nanoapp/app_id.h"
201 #include "chre/platform/static_nanoapp_init.h"
202
203 CHRE_STATIC_NANOAPP_INIT(GnssWorld, chre::kGnssWorldAppId, 0);
204 #endif // CHRE_NANOAPP_INTERNAL
205