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 27namespace chre { 28namespace { 29#endif // CHRE_NANOAPP_INTERNAL 30 31//! A dummy cookie to pass into the location session async request. 32const uint32_t kLocationSessionCookie = 0x1337; 33 34//! The minimum time to the next fix for a location. 35constexpr Milliseconds kLocationMinTimeToNextFix(0); 36 37//! The interval in seconds between location updates. 38const 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 48bool gLocationSupported = false; 49 50uint32_t gTimerHandle; 51uint32_t gTimerCount = 0; 52 53//! Whether an async result has been received. 54bool gAsyncResultReceived = false; 55 56void 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 84void 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 96void 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 127void 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 138bool 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 173void 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 192void 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 203CHRE_STATIC_NANOAPP_INIT(GnssWorld, chre::kGnssWorldAppId, 0); 204#endif // CHRE_NANOAPP_INTERNAL 205