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/nanoapp/log.h" 21#include "chre/util/time.h" 22#include "chre/util/nanoapp/wifi.h" 23 24#define LOG_TAG "[WifiWorld]" 25 26//#define WIFI_WORLD_VERBOSE_WIFI_RESULT_LOGS 27 28#ifdef CHRE_NANOAPP_INTERNAL 29namespace chre { 30namespace { 31#endif // CHRE_NANOAPP_INTERNAL 32 33//! A dummy cookie to pass into the configure scan monitoring async request. 34const uint32_t kScanMonitoringCookie = 0x1337; 35 36//! A dummy cookie to pass into request scan async. 37const uint32_t kOnDemandScanCookie = 0xcafe; 38 39//! The interval for on-demand wifi scans. 40const Nanoseconds kWifiScanInterval = Nanoseconds(Seconds(10)); 41 42//! A handle for the cyclic timer to request periodic on-demand wifi-scans. 43uint32_t gWifiScanTimerHandle; 44 45namespace { 46 47/** 48 * Logs a CHRE wifi scan result. 49 * 50 * @param result the scan result to log. 51 */ 52void logChreWifiResult(const chreWifiScanResult& result) { 53 const char *ssidStr = "<non-printable>"; 54 char ssidBuffer[kMaxSsidStrLen]; 55 if (result.ssidLen == 0) { 56 ssidStr = "<empty>"; 57 } else if (parseSsidToStr(ssidBuffer, kMaxSsidStrLen, 58 result.ssid, result.ssidLen)) { 59 ssidStr = ssidBuffer; 60 } 61 62 const char *bssidStr = "<non-printable>"; 63 char bssidBuffer[kBssidStrLen]; 64 if (parseBssidToStr(result.bssid, bssidBuffer, kBssidStrLen)) { 65 bssidStr = bssidBuffer; 66 } 67 68 LOGI("Found network with SSID: %s", ssidStr); 69#ifdef WIFI_WORLD_VERBOSE_WIFI_RESULT_LOGS 70 LOGI(" age (ms): %" PRIu32, result.ageMs); 71 LOGI(" capability info: %" PRIx16, result.capabilityInfo); 72 LOGI(" bssid: %s", bssidStr); 73 LOGI(" flags: %" PRIx8, result.flags); 74 LOGI(" rssi: %" PRId8 "dBm", result.rssi); 75 LOGI(" band: %s (%" PRIu8 ")", parseChreWifiBand(result.band), result.band); 76 LOGI(" primary channel: %" PRIu32, result.primaryChannel); 77 LOGI(" center frequency primary: %" PRIu32, result.centerFreqPrimary); 78 LOGI(" center frequency secondary: %" PRIu32, result.centerFreqSecondary); 79 LOGI(" channel width: %" PRIu8, result.channelWidth); 80 LOGI(" security mode: %" PRIx8, result.securityMode); 81#endif // WIFI_WORLD_VERBOSE_WIFI_RESULT_LOGS 82} 83 84/** 85 * Handles the result of an asynchronous request for a wifi resource. 86 * 87 * @param result a pointer to the event structure containing the result of the 88 * request. 89 */ 90void handleWifiAsyncResult(const chreAsyncResult *result) { 91 if (result->requestType == CHRE_WIFI_REQUEST_TYPE_CONFIGURE_SCAN_MONITOR) { 92 if (result->success) { 93 LOGI("Successfully requested wifi scan monitoring"); 94 } else { 95 LOGI("Error requesting wifi scan monitoring with %" PRIu8, 96 result->errorCode); 97 } 98 99 if (result->cookie != &kScanMonitoringCookie) { 100 LOGE("Scan monitoring request cookie mismatch"); 101 } 102 } else if (result->requestType == CHRE_WIFI_REQUEST_TYPE_REQUEST_SCAN) { 103 if (result->success) { 104 LOGI("Successfully requested an on-demand wifi scan"); 105 } else { 106 LOGE("Error requesting an on-demand wifi scan with %" PRIu8, 107 result->errorCode); 108 } 109 110 if (result->cookie != &kOnDemandScanCookie) { 111 LOGE("On-demand scan cookie mismatch"); 112 } 113 } 114} 115 116/** 117 * Handles a wifi scan event. 118 * 119 * @param event a pointer to the details of the wifi scan event. 120 */ 121void handleWifiScanEvent(const chreWifiScanEvent *event) { 122 for (uint8_t i = 0; i < event->resultCount; i++) { 123 const chreWifiScanResult& result = event->results[i]; 124 logChreWifiResult(result); 125 } 126} 127 128/** 129 * Handles a timer event. 130 * 131 * @param eventData The cookie passed to the timer request. 132 */ 133void handleTimerEvent(const void *eventData) { 134 const uint32_t *timerHandle = static_cast<const uint32_t *>(eventData); 135 if (*timerHandle == gWifiScanTimerHandle) { 136 if (chreWifiRequestScanAsyncDefault(&kOnDemandScanCookie)) { 137 LOGI("Requested a wifi scan successfully"); 138 } else { 139 LOGE("Failed to request a wifi scan"); 140 } 141 } else { 142 LOGE("Received invalid timer handle"); 143 } 144} 145 146} // namespace 147 148bool nanoappStart() { 149 LOGI("App started as instance %" PRIu32, chreGetInstanceId()); 150 151 const char *wifiCapabilitiesStr; 152 uint32_t wifiCapabilities = chreWifiGetCapabilities(); 153 switch (wifiCapabilities) { 154 case CHRE_WIFI_CAPABILITIES_ON_DEMAND_SCAN 155 | CHRE_WIFI_CAPABILITIES_SCAN_MONITORING: 156 wifiCapabilitiesStr = "ON_DEMAND_SCAN | SCAN_MONITORING"; 157 break; 158 case CHRE_WIFI_CAPABILITIES_ON_DEMAND_SCAN: 159 wifiCapabilitiesStr = "ON_DEMAND_SCAN"; 160 break; 161 case CHRE_WIFI_CAPABILITIES_SCAN_MONITORING: 162 wifiCapabilitiesStr = "SCAN_MONITORING"; 163 break; 164 case CHRE_WIFI_CAPABILITIES_NONE: 165 wifiCapabilitiesStr = "NONE"; 166 break; 167 default: 168 wifiCapabilitiesStr = "INVALID"; 169 } 170 171 LOGI("Detected WiFi support as: %s (%" PRIu32 ")", 172 wifiCapabilitiesStr, wifiCapabilities); 173 174 if (wifiCapabilities & CHRE_WIFI_CAPABILITIES_SCAN_MONITORING) { 175 if (chreWifiConfigureScanMonitorAsync(true, &kScanMonitoringCookie)) { 176 LOGI("Scan monitor enable request successful"); 177 } else { 178 LOGE("Error sending scan monitoring request"); 179 } 180 } 181 182 if (wifiCapabilities & CHRE_WIFI_CAPABILITIES_ON_DEMAND_SCAN) { 183 // Schedule a timer to send an active wifi scan. 184 gWifiScanTimerHandle = chreTimerSet(kWifiScanInterval.toRawNanoseconds(), 185 &gWifiScanTimerHandle /* data */, 186 false /* oneShot */); 187 if (gWifiScanTimerHandle == CHRE_TIMER_INVALID) { 188 LOGE("Failed to set periodic scan timer"); 189 } else { 190 LOGI("Set a timer to request periodic WiFi scans"); 191 } 192 } 193 194 return true; 195} 196 197void nanoappHandleEvent(uint32_t senderInstanceId, 198 uint16_t eventType, 199 const void *eventData) { 200 switch (eventType) { 201 case CHRE_EVENT_WIFI_ASYNC_RESULT: 202 handleWifiAsyncResult(static_cast<const chreAsyncResult *>(eventData)); 203 break; 204 case CHRE_EVENT_WIFI_SCAN_RESULT: 205 handleWifiScanEvent(static_cast<const chreWifiScanEvent *>(eventData)); 206 break; 207 case CHRE_EVENT_TIMER: 208 handleTimerEvent(eventData); 209 break; 210 default: 211 LOGW("Unhandled event type %" PRIu16, eventType); 212 } 213} 214 215void nanoappEnd() { 216 LOGI("Wifi world app stopped"); 217} 218 219#ifdef CHRE_NANOAPP_INTERNAL 220} // anonymous namespace 221} // namespace chre 222 223#include "chre/util/nanoapp/app_id.h" 224#include "chre/platform/static_nanoapp_init.h" 225 226CHRE_STATIC_NANOAPP_INIT(WifiWorld, chre::kWifiWorldAppId, 0); 227#endif // CHRE_NANOAPP_INTERNAL 228