1 /*
2 * Copyright (C) 2021 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/pal/ble.h"
18
19 #include "chre/util/memory.h"
20 #include "chre/util/unique_ptr.h"
21
22 #include <future>
23 #include <thread>
24
25 /**
26 * A simulated implementation of the BLE PAL for the linux platform.
27 */
28 namespace {
29 const struct chrePalSystemApi *gSystemApi = nullptr;
30 const struct chrePalBleCallbacks *gCallbacks = nullptr;
31
32 std::thread gBleStartScanThread;
33 std::thread gBleStopScanThread;
34 std::promise<void> gStopAdvertisingEvents;
35
36 bool gBleEnabled = false;
37
scanModeToInterval(chreBleScanMode mode)38 std::chrono::milliseconds scanModeToInterval(chreBleScanMode mode) {
39 std::chrono::milliseconds interval(1000);
40 switch (mode) {
41 case CHRE_BLE_SCAN_MODE_BACKGROUND:
42 interval = std::chrono::milliseconds(2000);
43 break;
44 case CHRE_BLE_SCAN_MODE_FOREGROUND:
45 interval = std::chrono::milliseconds(1000);
46 break;
47 case CHRE_BLE_SCAN_MODE_AGGRESSIVE:
48 interval = std::chrono::milliseconds(500);
49 break;
50 }
51 return interval;
52 }
53
startScan(chreBleScanMode mode)54 void startScan(chreBleScanMode mode) {
55 gCallbacks->scanStatusChangeCallback(true, CHRE_ERROR_NONE);
56 std::future<void> signal = gStopAdvertisingEvents.get_future();
57 while (signal.wait_for(scanModeToInterval(mode)) ==
58 std::future_status::timeout) {
59 auto event = chre::MakeUniqueZeroFill<struct chreBleAdvertisementEvent>();
60 auto report = chre::MakeUniqueZeroFill<struct chreBleAdvertisingReport>();
61 uint8_t *data =
62 static_cast<uint8_t *>(chre::memoryAlloc(sizeof(uint8_t) * 2));
63 data[0] = 0x01;
64 data[1] = 0x16;
65 report->data = data;
66 report->dataLength = 2;
67 event->reports = report.release();
68 event->numReports = 1;
69 gCallbacks->advertisingEventCallback(event.release());
70 }
71 }
72
stopScan()73 void stopScan() {
74 gCallbacks->scanStatusChangeCallback(false, CHRE_ERROR_NONE);
75 }
76
stopThreads()77 void stopThreads() {
78 if (gBleStartScanThread.joinable()) {
79 gStopAdvertisingEvents.set_value();
80 gBleStartScanThread.join();
81 }
82 if (gBleStopScanThread.joinable()) {
83 gBleStopScanThread.join();
84 }
85 }
86
chrePalBleGetCapabilities()87 uint32_t chrePalBleGetCapabilities() {
88 return CHRE_BLE_CAPABILITIES_SCAN |
89 CHRE_BLE_CAPABILITIES_SCAN_RESULT_BATCHING |
90 CHRE_BLE_CAPABILITIES_SCAN_FILTER_BEST_EFFORT;
91 }
92
chrePalBleGetFilterCapabilities()93 uint32_t chrePalBleGetFilterCapabilities() {
94 return CHRE_BLE_FILTER_CAPABILITIES_RSSI |
95 CHRE_BLE_FILTER_CAPABILITIES_SERVICE_DATA;
96 }
97
chrePalBleStartScan(chreBleScanMode mode,uint32_t,const struct chreBleScanFilter *)98 bool chrePalBleStartScan(chreBleScanMode mode, uint32_t /* reportDelayMs */,
99 const struct chreBleScanFilter * /* filter */) {
100 stopThreads();
101 gStopAdvertisingEvents = std::promise<void>();
102 gBleStartScanThread = std::thread(startScan, mode);
103 gBleEnabled = true;
104 return true;
105 }
106
chrePalBleStopScan()107 bool chrePalBleStopScan() {
108 stopThreads();
109 gBleStopScanThread = std::thread(stopScan);
110 gBleEnabled = false;
111 return true;
112 }
113
chrePalBleReleaseAdvertisingEvent(struct chreBleAdvertisementEvent * event)114 void chrePalBleReleaseAdvertisingEvent(
115 struct chreBleAdvertisementEvent *event) {
116 for (size_t i = 0; i < event->numReports; i++) {
117 chre::memoryFree(
118 const_cast<chreBleAdvertisingReport *>(&(event->reports[i])));
119 }
120 chre::memoryFree(event);
121 }
122
chrePalBleApiClose()123 void chrePalBleApiClose() {
124 stopThreads();
125 }
126
chrePalBleApiOpen(const struct chrePalSystemApi * systemApi,const struct chrePalBleCallbacks * callbacks)127 bool chrePalBleApiOpen(const struct chrePalSystemApi *systemApi,
128 const struct chrePalBleCallbacks *callbacks) {
129 chrePalBleApiClose();
130
131 bool success = false;
132 if (systemApi != nullptr && callbacks != nullptr) {
133 gSystemApi = systemApi;
134 gCallbacks = callbacks;
135 success = true;
136 }
137
138 return success;
139 }
140
141 } // anonymous namespace
142
chrePalIsBleEnabled()143 bool chrePalIsBleEnabled() {
144 return gBleEnabled;
145 }
146
chrePalBleGetApi(uint32_t requestedApiVersion)147 const struct chrePalBleApi *chrePalBleGetApi(uint32_t requestedApiVersion) {
148 static const struct chrePalBleApi kApi = {
149 .moduleVersion = CHRE_PAL_BLE_API_CURRENT_VERSION,
150 .open = chrePalBleApiOpen,
151 .close = chrePalBleApiClose,
152 .getCapabilities = chrePalBleGetCapabilities,
153 .getFilterCapabilities = chrePalBleGetFilterCapabilities,
154 .startScan = chrePalBleStartScan,
155 .stopScan = chrePalBleStopScan,
156 .releaseAdvertisingEvent = chrePalBleReleaseAdvertisingEvent,
157 };
158
159 if (!CHRE_PAL_VERSIONS_ARE_COMPATIBLE(kApi.moduleVersion,
160 requestedApiVersion)) {
161 return nullptr;
162 } else {
163 return &kApi;
164 }
165 }
166