• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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 <cinttypes>
18 
19 #include "chre.h"
20 #include "chre/util/macros.h"
21 #include "chre/util/memory.h"
22 #include "chre/util/nanoapp/log.h"
23 #include "chre/util/time.h"
24 #include "chre/util/unique_ptr.h"
25 
26 #ifdef CHRE_NANOAPP_INTERNAL
27 namespace chre {
28 namespace {
29 #endif  // CHRE_NANOAPP_INTERNAL
30 
31 bool gAsyncResultReceived = false;
32 uint32_t gTimerHandle = 0;
33 
34 //! A fake/unused cookie to pass into the session async and timer request.
35 const uint32_t kBleCookie = 0x1337;
36 //! The interval in seconds between updates.
37 const chreBleScanMode kScanModes[] = {CHRE_BLE_SCAN_MODE_BACKGROUND,
38                                       CHRE_BLE_SCAN_MODE_FOREGROUND,
39                                       CHRE_BLE_SCAN_MODE_AGGRESSIVE};
40 
41 enum ScanRequestType {
42   NO_FILTER = 0,
43   SERVICE_DATA_16 = 1,
44   STOP_SCAN = 2,
45 };
46 
getBleScanFilter(ScanRequestType & scanRequestType)47 chreBleScanFilter *getBleScanFilter(ScanRequestType &scanRequestType) {
48   chre::UniquePtr<chreBleScanFilter> filter =
49       chre::MakeUniqueZeroFill<chreBleScanFilter>();
50   filter->rssiThreshold = CHRE_BLE_RSSI_THRESHOLD_NONE;
51   filter->scanFilterCount = 1;
52   chre::UniquePtr<chreBleGenericFilter> scanFilter =
53       chre::MakeUniqueZeroFill<chreBleGenericFilter>();
54   switch (scanRequestType) {
55     case NO_FILTER:
56       filter = nullptr;
57       scanRequestType = SERVICE_DATA_16;
58       break;
59     case SERVICE_DATA_16:
60       scanFilter->type = CHRE_BLE_AD_TYPE_SERVICE_DATA_WITH_UUID_16;
61       scanFilter->len = 2;
62       filter->scanFilters = scanFilter.release();
63       scanRequestType = STOP_SCAN;
64       break;
65     case STOP_SCAN:
66       break;
67   }
68   return filter.release();
69 }
70 
makeBleScanRequest()71 void makeBleScanRequest() {
72   static uint8_t scanModeIndex = 0;
73   static ScanRequestType scanRequestType = NO_FILTER;
74   if (scanRequestType != STOP_SCAN) {
75     chreBleScanMode mode = kScanModes[scanModeIndex];
76     uint32_t reportDelayMs = 0;
77     chreBleScanFilter *filter = getBleScanFilter(scanRequestType);
78     LOGI("Sending BLE start scan request to PAL with parameters:");
79     LOGI("  mode=%" PRIu8, kScanModes[scanModeIndex]);
80     LOGI("  reportDelayMs=%" PRIu32, reportDelayMs);
81     if (filter != nullptr) {
82       LOGI("  rssiThreshold=%" PRIu32, filter->rssiThreshold);
83       LOGI("  scanFilterType=%" PRIx8, filter->scanFilters[0].type);
84       LOGI("  scanFilterLen=%" PRIu8, filter->scanFilters[0].len);
85       LOGI("  scanFilterData=%s", filter->scanFilters[0].data);
86       LOGI("  scanFilterDataMask=%s", filter->scanFilters[0].dataMask);
87     }
88     if (chreBleStartScanAsync(mode, 0, nullptr)) {
89       LOGI("BLE start scan request sent to PAL");
90     } else {
91       LOGE("Error sending BLE start scan request sent to PAL");
92     }
93     if (filter != nullptr) {
94       if (filter->scanFilters != nullptr) {
95         chre::memoryFree(
96             const_cast<chreBleGenericFilter *>(filter->scanFilters));
97       }
98       chre::memoryFree(filter);
99     }
100   } else {
101     if (chreBleStopScanAsync()) {
102       LOGI("BLE stop scan request sent to PAL");
103     } else {
104       LOGE("Error sending BLE stop scan request sent to PAL");
105     }
106     scanRequestType = NO_FILTER;
107     scanModeIndex = (scanModeIndex + 1) % ARRAY_SIZE(kScanModes);
108   }
109   gTimerHandle = chreTimerSet(CHRE_ASYNC_RESULT_TIMEOUT_NS, /* 5 sec */
110                               &kBleCookie, true /* oneShot */);
111 }
112 
handleAdvertismentEvent(const chreBleAdvertisementEvent * event)113 void handleAdvertismentEvent(const chreBleAdvertisementEvent *event) {
114   for (uint8_t i = 0; i < event->numReports; i++) {
115     LOGI("BLE Report %" PRIu8, i + 1);
116     LOGI("Scan data:");
117     const uint8_t *data = event->reports[i].data;
118     for (uint8_t j = 0; j < event->reports[i].dataLength; j++) {
119       LOGI("  %" PRIx8, data[j]);
120     }
121   }
122 }
123 
handleAsyncResultEvent(const chreAsyncResult * result)124 void handleAsyncResultEvent(const chreAsyncResult *result) {
125   gAsyncResultReceived = true;
126   const char *requestType =
127       result->requestType == CHRE_BLE_REQUEST_TYPE_START_SCAN ? "start"
128                                                               : "stop";
129   if (result->success) {
130     LOGI("BLE %s scan success", requestType);
131   } else {
132     LOGE("BLE %s scan failure: %" PRIu8, requestType, result->errorCode);
133   }
134 }
135 
handleTimerEvent(const void * eventData)136 void handleTimerEvent(const void *eventData) {
137   static uint32_t timerCount = 1;
138   if (eventData == &kBleCookie) {
139     LOGI("BLE timer event received, count %" PRIu32, timerCount++);
140     if (!gAsyncResultReceived) {
141       LOGE("BLE async result not received");
142     }
143     gAsyncResultReceived = false;
144     makeBleScanRequest();
145   } else {
146     LOGE("Invalid timer cookie");
147   }
148 }
149 
nanoappStart(void)150 bool nanoappStart(void) {
151   LOGI("nanoapp started");
152   makeBleScanRequest();
153   return true;
154 }
155 
nanoappEnd(void)156 void nanoappEnd(void) {
157   if (!chreBleStopScanAsync()) {
158     LOGE("Error sending BLE stop scan request sent to PAL");
159   }
160   if (!chreTimerCancel(gTimerHandle)) {
161     LOGE("Error canceling timer");
162   }
163   LOGI("nanoapp stopped");
164 }
165 
nanoappHandleEvent(uint32_t,uint16_t event_type,const void * event_data)166 void nanoappHandleEvent(uint32_t /* sender_instance_id */, uint16_t event_type,
167                         const void *event_data) {
168   if (event_type == CHRE_EVENT_BLE_ADVERTISEMENT) {
169     handleAdvertismentEvent(
170         static_cast<const chreBleAdvertisementEvent *>(event_data));
171   } else if (event_type == CHRE_EVENT_BLE_ASYNC_RESULT) {
172     handleAsyncResultEvent(static_cast<const chreAsyncResult *>(event_data));
173   } else if (event_type == CHRE_EVENT_TIMER) {
174     handleTimerEvent(event_data);
175   }
176 }
177 
178 #ifdef CHRE_NANOAPP_INTERNAL
179 }  // anonymous namespace
180 }  // namespace chre
181 
182 #include "chre/platform/static_nanoapp_init.h"
183 #include "chre/util/nanoapp/app_id.h"
184 #include "chre/util/system/napp_permissions.h"
185 
186 CHRE_STATIC_NANOAPP_INIT(BleWorld, kBleWorldAppId, 0,
187                          NanoappPermissions::CHRE_PERMS_BLE);
188 #endif  // CHRE_NANOAPP_INTERNAL
189