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