@stoprocent/noble 1.9.2-16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.editorconfig +11 -0
- package/.eslintrc.js +25 -0
- package/.github/FUNDING.yml +2 -0
- package/.github/workflows/fediverse-action.yml +16 -0
- package/.github/workflows/nodepackage.yml +77 -0
- package/.github/workflows/npm-publish.yml +26 -0
- package/.github/workflows/prebuild.yml +65 -0
- package/.nycrc.json +4 -0
- package/CHANGELOG.md +119 -0
- package/LICENSE +20 -0
- package/MAINTAINERS.md +1 -0
- package/README.md +833 -0
- package/assets/noble-logo.png +0 -0
- package/assets/noble-logo.svg +13 -0
- package/binding.gyp +19 -0
- package/codecov.yml +5 -0
- package/examples/advertisement-discovery.js +65 -0
- package/examples/cache-gatt-discovery.js +198 -0
- package/examples/cache-gatt-reconnect.js +164 -0
- package/examples/echo.js +104 -0
- package/examples/enter-exit.js +78 -0
- package/examples/peripheral-explorer-async.js +133 -0
- package/examples/peripheral-explorer.js +225 -0
- package/examples/pizza/README.md +15 -0
- package/examples/pizza/central.js +194 -0
- package/examples/pizza/pizza.js +60 -0
- package/index.d.ts +203 -0
- package/index.js +6 -0
- package/lib/characteristic.js +161 -0
- package/lib/characteristics.json +449 -0
- package/lib/descriptor.js +72 -0
- package/lib/descriptors.json +47 -0
- package/lib/distributed/bindings.js +326 -0
- package/lib/hci-socket/acl-stream.js +60 -0
- package/lib/hci-socket/bindings.js +788 -0
- package/lib/hci-socket/crypto.js +74 -0
- package/lib/hci-socket/gap.js +432 -0
- package/lib/hci-socket/gatt.js +809 -0
- package/lib/hci-socket/hci-status.json +71 -0
- package/lib/hci-socket/hci.js +1264 -0
- package/lib/hci-socket/signaling.js +76 -0
- package/lib/hci-socket/smp.js +140 -0
- package/lib/hci-uart/bindings.js +569 -0
- package/lib/hci-uart/hci-serial-parser.js +70 -0
- package/lib/hci-uart/hci.js +1336 -0
- package/lib/mac/binding.gyp +26 -0
- package/lib/mac/bindings.js +11 -0
- package/lib/mac/src/ble_manager.h +41 -0
- package/lib/mac/src/ble_manager.mm +435 -0
- package/lib/mac/src/callbacks.cc +222 -0
- package/lib/mac/src/callbacks.h +84 -0
- package/lib/mac/src/napi_objc.h +12 -0
- package/lib/mac/src/napi_objc.mm +50 -0
- package/lib/mac/src/noble_mac.h +34 -0
- package/lib/mac/src/noble_mac.mm +264 -0
- package/lib/mac/src/objc_cpp.h +26 -0
- package/lib/mac/src/objc_cpp.mm +126 -0
- package/lib/mac/src/peripheral.h +23 -0
- package/lib/manufacture.js +48 -0
- package/lib/noble.js +593 -0
- package/lib/peripheral.js +219 -0
- package/lib/resolve-bindings-web.js +9 -0
- package/lib/resolve-bindings.js +44 -0
- package/lib/service.js +72 -0
- package/lib/services.json +92 -0
- package/lib/webbluetooth/bindings.js +368 -0
- package/lib/websocket/bindings.js +321 -0
- package/lib/win/binding.gyp +23 -0
- package/lib/win/bindings.js +11 -0
- package/lib/win/src/ble_manager.cc +802 -0
- package/lib/win/src/ble_manager.h +77 -0
- package/lib/win/src/callbacks.cc +274 -0
- package/lib/win/src/callbacks.h +33 -0
- package/lib/win/src/napi_winrt.cc +76 -0
- package/lib/win/src/napi_winrt.h +12 -0
- package/lib/win/src/noble_winrt.cc +308 -0
- package/lib/win/src/noble_winrt.h +34 -0
- package/lib/win/src/notify_map.cc +62 -0
- package/lib/win/src/notify_map.h +50 -0
- package/lib/win/src/peripheral.h +23 -0
- package/lib/win/src/peripheral_winrt.cc +296 -0
- package/lib/win/src/peripheral_winrt.h +82 -0
- package/lib/win/src/radio_watcher.cc +125 -0
- package/lib/win/src/radio_watcher.h +61 -0
- package/lib/win/src/winrt_cpp.cc +82 -0
- package/lib/win/src/winrt_cpp.h +11 -0
- package/lib/win/src/winrt_guid.cc +12 -0
- package/lib/win/src/winrt_guid.h +13 -0
- package/misc/nrf52840dk.hex +6921 -0
- package/misc/prj.conf +43 -0
- package/package.json +96 -0
- package/test/lib/characteristic.test.js +791 -0
- package/test/lib/descriptor.test.js +249 -0
- package/test/lib/distributed/bindings.test.js +918 -0
- package/test/lib/hci-socket/acl-stream.test.js +188 -0
- package/test/lib/hci-socket/bindings.test.js +1756 -0
- package/test/lib/hci-socket/crypto.test.js +55 -0
- package/test/lib/hci-socket/gap.test.js +1089 -0
- package/test/lib/hci-socket/gatt.test.js +2392 -0
- package/test/lib/hci-socket/hci.test.js +1891 -0
- package/test/lib/hci-socket/signaling.test.js +94 -0
- package/test/lib/hci-socket/smp.test.js +268 -0
- package/test/lib/manufacture.test.js +77 -0
- package/test/lib/peripheral.test.js +623 -0
- package/test/lib/resolve-bindings.test.js +102 -0
- package/test/lib/service.test.js +195 -0
- package/test/lib/webbluetooth/bindings.test.js +190 -0
- package/test/lib/websocket/bindings.test.js +456 -0
- package/test/noble.test.js +1565 -0
- package/test.js +131 -0
- package/with-bindings.js +5 -0
- package/ws-slave.js +404 -0
|
@@ -0,0 +1,802 @@
|
|
|
1
|
+
//
|
|
2
|
+
// ble_manager.cc
|
|
3
|
+
// noble-winrt-native
|
|
4
|
+
//
|
|
5
|
+
// Created by Georg Vienna on 03.09.18.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#include "ble_manager.h"
|
|
9
|
+
#include "winrt_cpp.h"
|
|
10
|
+
|
|
11
|
+
#include <winrt/Windows.Foundation.Collections.h>
|
|
12
|
+
#include <winrt/Windows.Storage.Streams.h>
|
|
13
|
+
using winrt::Windows::Devices::Bluetooth::BluetoothCacheMode;
|
|
14
|
+
using winrt::Windows::Devices::Bluetooth::BluetoothConnectionStatus;
|
|
15
|
+
using winrt::Windows::Storage::Streams::DataReader;
|
|
16
|
+
using winrt::Windows::Storage::Streams::DataWriter;
|
|
17
|
+
|
|
18
|
+
template <typename T> auto inFilter(std::vector<T> filter, T object)
|
|
19
|
+
{
|
|
20
|
+
return filter.empty() || std::find(filter.begin(), filter.end(), object) != filter.end();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
template <typename O, typename M, class... Types> auto bind2(O* object, M method, Types&... args)
|
|
24
|
+
{
|
|
25
|
+
return std::bind(method, object, std::placeholders::_1, std::placeholders::_2, args...);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
#define LOGE(message, ...) printf(__FUNCTION__ ": " message "\n", __VA_ARGS__)
|
|
29
|
+
|
|
30
|
+
#define CHECK_DEVICE() \
|
|
31
|
+
if (mDeviceMap.find(uuid) == mDeviceMap.end()) \
|
|
32
|
+
{ \
|
|
33
|
+
LOGE("device with id %s not found", uuid.c_str()); \
|
|
34
|
+
return false; \
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
#define IFDEVICE(_device, _uuid) \
|
|
38
|
+
PeripheralWinrt& peripheral = mDeviceMap[_uuid]; \
|
|
39
|
+
if (!peripheral.device.has_value()) \
|
|
40
|
+
{ \
|
|
41
|
+
LOGE("device not connected"); \
|
|
42
|
+
return false; \
|
|
43
|
+
} \
|
|
44
|
+
BluetoothLEDevice& _device = *peripheral.device;
|
|
45
|
+
|
|
46
|
+
#define CHECK_RESULT(_result) \
|
|
47
|
+
if (!_result) \
|
|
48
|
+
{ \
|
|
49
|
+
LOGE("result is null"); \
|
|
50
|
+
return; \
|
|
51
|
+
} \
|
|
52
|
+
auto _commStatus = _result.Status(); \
|
|
53
|
+
if (_commStatus != GattCommunicationStatus::Success) \
|
|
54
|
+
{ \
|
|
55
|
+
LOGE("communication status: %d", _commStatus); \
|
|
56
|
+
return; \
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
#define FOR(object, vector) \
|
|
60
|
+
auto _vector = vector; \
|
|
61
|
+
if (!_vector) \
|
|
62
|
+
{ \
|
|
63
|
+
LOGE(#vector " is null"); \
|
|
64
|
+
return; \
|
|
65
|
+
} \
|
|
66
|
+
else \
|
|
67
|
+
for (auto&& object : _vector)
|
|
68
|
+
|
|
69
|
+
BLEManager::BLEManager(const Napi::Value& receiver, const Napi::Function& callback)
|
|
70
|
+
{
|
|
71
|
+
mRadioState = AdapterState::Initial;
|
|
72
|
+
mEmit.Wrap(receiver, callback);
|
|
73
|
+
auto onRadio = std::bind(&BLEManager::OnRadio, this, std::placeholders::_1);
|
|
74
|
+
mWatcher.Start(onRadio);
|
|
75
|
+
mAdvertismentWatcher.ScanningMode(BluetoothLEScanningMode::Active);
|
|
76
|
+
auto onReceived = bind2(this, &BLEManager::OnScanResult);
|
|
77
|
+
mReceivedRevoker = mAdvertismentWatcher.Received(winrt::auto_revoke, onReceived);
|
|
78
|
+
auto onStopped = bind2(this, &BLEManager::OnScanStopped);
|
|
79
|
+
mStoppedRevoker = mAdvertismentWatcher.Stopped(winrt::auto_revoke, onStopped);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const char* adapterStateToString(AdapterState state)
|
|
83
|
+
{
|
|
84
|
+
switch (state)
|
|
85
|
+
{
|
|
86
|
+
case AdapterState::Unsupported:
|
|
87
|
+
return "unsupported";
|
|
88
|
+
case AdapterState::On:
|
|
89
|
+
return "poweredOn";
|
|
90
|
+
break;
|
|
91
|
+
case AdapterState::Off:
|
|
92
|
+
return "poweredOff";
|
|
93
|
+
break;
|
|
94
|
+
case AdapterState::Disabled:
|
|
95
|
+
return "poweredOff";
|
|
96
|
+
break;
|
|
97
|
+
default:
|
|
98
|
+
return "unknown";
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
void BLEManager::OnRadio(Radio& radio)
|
|
103
|
+
{
|
|
104
|
+
auto state = AdapterState::Unsupported;
|
|
105
|
+
if (radio)
|
|
106
|
+
{
|
|
107
|
+
state = (AdapterState)radio.State();
|
|
108
|
+
}
|
|
109
|
+
if (state != mRadioState)
|
|
110
|
+
{
|
|
111
|
+
mRadioState = state;
|
|
112
|
+
mEmit.RadioState(adapterStateToString(state));
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
void BLEManager::Scan(const std::vector<winrt::guid>& serviceUUIDs, bool allowDuplicates)
|
|
117
|
+
{
|
|
118
|
+
mAdvertismentMap.clear();
|
|
119
|
+
mAllowDuplicates = allowDuplicates;
|
|
120
|
+
BluetoothLEAdvertisementFilter filter = BluetoothLEAdvertisementFilter();
|
|
121
|
+
BluetoothLEAdvertisement advertisment = BluetoothLEAdvertisement();
|
|
122
|
+
auto services = advertisment.ServiceUuids();
|
|
123
|
+
for (auto uuid : serviceUUIDs)
|
|
124
|
+
{
|
|
125
|
+
services.Append(uuid);
|
|
126
|
+
}
|
|
127
|
+
filter.Advertisement(advertisment);
|
|
128
|
+
mAdvertismentWatcher.AdvertisementFilter(filter);
|
|
129
|
+
mAdvertismentWatcher.Start();
|
|
130
|
+
mEmit.ScanState(true);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
void BLEManager::OnScanResult(BluetoothLEAdvertisementWatcher watcher,
|
|
134
|
+
const BluetoothLEAdvertisementReceivedEventArgs& args)
|
|
135
|
+
{
|
|
136
|
+
uint64_t bluetoothAddress = args.BluetoothAddress();
|
|
137
|
+
std::string uuid = formatBluetoothUuid(bluetoothAddress);
|
|
138
|
+
int16_t rssi = args.RawSignalStrengthInDBm();
|
|
139
|
+
auto advertismentType = args.AdvertisementType();
|
|
140
|
+
|
|
141
|
+
if (mDeviceMap.find(uuid) == mDeviceMap.end())
|
|
142
|
+
{
|
|
143
|
+
mAdvertismentMap.insert(uuid);
|
|
144
|
+
auto peripheral =
|
|
145
|
+
PeripheralWinrt(bluetoothAddress, advertismentType, rssi, args.Advertisement());
|
|
146
|
+
mEmit.Scan(uuid, rssi, peripheral);
|
|
147
|
+
mDeviceMap.emplace(std::make_pair(uuid, std::move(peripheral)));
|
|
148
|
+
}
|
|
149
|
+
else
|
|
150
|
+
{
|
|
151
|
+
PeripheralWinrt& peripheral = mDeviceMap[uuid];
|
|
152
|
+
peripheral.Update(rssi, args.Advertisement(), advertismentType);
|
|
153
|
+
if (mAllowDuplicates || mAdvertismentMap.find(uuid) == mAdvertismentMap.end())
|
|
154
|
+
{
|
|
155
|
+
mAdvertismentMap.insert(uuid);
|
|
156
|
+
mEmit.Scan(uuid, rssi, peripheral);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
void BLEManager::StopScan()
|
|
162
|
+
{
|
|
163
|
+
mAdvertismentWatcher.Stop();
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
void BLEManager::OnScanStopped(BluetoothLEAdvertisementWatcher watcher,
|
|
167
|
+
const BluetoothLEAdvertisementWatcherStoppedEventArgs& args)
|
|
168
|
+
{
|
|
169
|
+
mEmit.ScanState(false);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
bool BLEManager::Connect(const std::string& uuid)
|
|
173
|
+
{
|
|
174
|
+
if (mDeviceMap.find(uuid) == mDeviceMap.end())
|
|
175
|
+
{
|
|
176
|
+
mEmit.Connected(uuid, "device not found");
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
PeripheralWinrt& peripheral = mDeviceMap[uuid];
|
|
180
|
+
if (!peripheral.device.has_value())
|
|
181
|
+
{
|
|
182
|
+
auto completed = bind2(this, &BLEManager::OnConnected, uuid);
|
|
183
|
+
BluetoothLEDevice::FromBluetoothAddressAsync(peripheral.bluetoothAddress)
|
|
184
|
+
.Completed(completed);
|
|
185
|
+
}
|
|
186
|
+
else
|
|
187
|
+
{
|
|
188
|
+
mEmit.Connected(uuid);
|
|
189
|
+
}
|
|
190
|
+
return true;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
void BLEManager::OnConnected(IAsyncOperation<BluetoothLEDevice> asyncOp, AsyncStatus& status,
|
|
194
|
+
const std::string uuid)
|
|
195
|
+
{
|
|
196
|
+
if (status == AsyncStatus::Completed)
|
|
197
|
+
{
|
|
198
|
+
BluetoothLEDevice device = asyncOp.GetResults();
|
|
199
|
+
// device can be null if the connection failed
|
|
200
|
+
if (device)
|
|
201
|
+
{
|
|
202
|
+
auto onChanged = bind2(this, &BLEManager::OnConnectionStatusChanged);
|
|
203
|
+
auto token = device.ConnectionStatusChanged(onChanged);
|
|
204
|
+
auto uuid = formatBluetoothUuid(device.BluetoothAddress());
|
|
205
|
+
PeripheralWinrt& peripheral = mDeviceMap[uuid];
|
|
206
|
+
peripheral.device = device;
|
|
207
|
+
peripheral.connectionToken = token;
|
|
208
|
+
mEmit.Connected(uuid);
|
|
209
|
+
}
|
|
210
|
+
else
|
|
211
|
+
{
|
|
212
|
+
mEmit.Connected(uuid, "could not connect to device: result is null");
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
else
|
|
216
|
+
{
|
|
217
|
+
mEmit.Connected(uuid, "could not connect to device");
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
bool BLEManager::Disconnect(const std::string& uuid)
|
|
222
|
+
{
|
|
223
|
+
CHECK_DEVICE();
|
|
224
|
+
PeripheralWinrt& peripheral = mDeviceMap[uuid];
|
|
225
|
+
peripheral.Disconnect();
|
|
226
|
+
mNotifyMap.Remove(uuid);
|
|
227
|
+
mEmit.Disconnected(uuid);
|
|
228
|
+
return true;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
void BLEManager::OnConnectionStatusChanged(BluetoothLEDevice device,
|
|
232
|
+
winrt::Windows::Foundation::IInspectable inspectable)
|
|
233
|
+
{
|
|
234
|
+
if (device.ConnectionStatus() == BluetoothConnectionStatus::Disconnected)
|
|
235
|
+
{
|
|
236
|
+
auto uuid = formatBluetoothUuid(device.BluetoothAddress());
|
|
237
|
+
if (mDeviceMap.find(uuid) == mDeviceMap.end())
|
|
238
|
+
{
|
|
239
|
+
LOGE("device with id %s not found", uuid.c_str());
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
PeripheralWinrt& peripheral = mDeviceMap[uuid];
|
|
243
|
+
peripheral.Disconnect();
|
|
244
|
+
mNotifyMap.Remove(uuid);
|
|
245
|
+
mEmit.Disconnected(uuid);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
bool BLEManager::UpdateRSSI(const std::string& uuid)
|
|
250
|
+
{
|
|
251
|
+
CHECK_DEVICE();
|
|
252
|
+
|
|
253
|
+
PeripheralWinrt& peripheral = mDeviceMap[uuid];
|
|
254
|
+
// no way to get the rssi while we are connected, return the last value of advertisement
|
|
255
|
+
mEmit.RSSI(uuid, peripheral.rssi);
|
|
256
|
+
return true;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
bool BLEManager::DiscoverServices(const std::string& uuid,
|
|
260
|
+
const std::vector<winrt::guid>& serviceUUIDs)
|
|
261
|
+
{
|
|
262
|
+
CHECK_DEVICE();
|
|
263
|
+
IFDEVICE(device, uuid)
|
|
264
|
+
{
|
|
265
|
+
auto completed = bind2(this, &BLEManager::OnServicesDiscovered, uuid, serviceUUIDs);
|
|
266
|
+
device.GetGattServicesAsync(BluetoothCacheMode::Uncached).Completed(completed);
|
|
267
|
+
return true;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
void BLEManager::OnServicesDiscovered(IAsyncOperation<GattDeviceServicesResult> asyncOp,
|
|
272
|
+
AsyncStatus status, const std::string uuid,
|
|
273
|
+
const std::vector<winrt::guid> serviceUUIDs)
|
|
274
|
+
{
|
|
275
|
+
if (status == AsyncStatus::Completed)
|
|
276
|
+
{
|
|
277
|
+
GattDeviceServicesResult result = asyncOp.GetResults();
|
|
278
|
+
CHECK_RESULT(result);
|
|
279
|
+
std::vector<std::string> serviceUuids;
|
|
280
|
+
FOR(service, result.Services())
|
|
281
|
+
{
|
|
282
|
+
auto id = service.Uuid();
|
|
283
|
+
if (inFilter(serviceUUIDs, id))
|
|
284
|
+
{
|
|
285
|
+
serviceUuids.push_back(toStr(id));
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
mEmit.ServicesDiscovered(uuid, serviceUuids);
|
|
289
|
+
}
|
|
290
|
+
else
|
|
291
|
+
{
|
|
292
|
+
LOGE("status: %d", status);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
bool BLEManager::DiscoverIncludedServices(const std::string& uuid, const winrt::guid& serviceUuid,
|
|
297
|
+
const std::vector<winrt::guid>& serviceUUIDs)
|
|
298
|
+
{
|
|
299
|
+
CHECK_DEVICE();
|
|
300
|
+
IFDEVICE(device, uuid)
|
|
301
|
+
{
|
|
302
|
+
peripheral.GetService(serviceUuid, [=](std::optional<GattDeviceService> service) {
|
|
303
|
+
if (service)
|
|
304
|
+
{
|
|
305
|
+
std::string serviceId = toStr(serviceUuid);
|
|
306
|
+
service->GetIncludedServicesAsync(BluetoothCacheMode::Uncached)
|
|
307
|
+
.Completed(bind2(this, &BLEManager::OnIncludedServicesDiscovered, uuid,
|
|
308
|
+
serviceId, serviceUUIDs));
|
|
309
|
+
}
|
|
310
|
+
else
|
|
311
|
+
{
|
|
312
|
+
LOGE("GetService error");
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
return true;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
void BLEManager::OnIncludedServicesDiscovered(IAsyncOperation<GattDeviceServicesResult> asyncOp,
|
|
320
|
+
AsyncStatus status, const std::string uuid,
|
|
321
|
+
const std::string serviceId,
|
|
322
|
+
const std::vector<winrt::guid> serviceUUIDs)
|
|
323
|
+
{
|
|
324
|
+
if (status == AsyncStatus::Completed)
|
|
325
|
+
{
|
|
326
|
+
auto result = asyncOp.GetResults();
|
|
327
|
+
CHECK_RESULT(result);
|
|
328
|
+
std::vector<std::string> servicesUuids;
|
|
329
|
+
FOR(service, result.Services())
|
|
330
|
+
{
|
|
331
|
+
auto id = service.Uuid();
|
|
332
|
+
if (inFilter(serviceUUIDs, id))
|
|
333
|
+
{
|
|
334
|
+
servicesUuids.push_back(toStr(id));
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
mEmit.IncludedServicesDiscovered(uuid, serviceId, servicesUuids);
|
|
338
|
+
}
|
|
339
|
+
else
|
|
340
|
+
{
|
|
341
|
+
LOGE("status: %d", status);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
bool BLEManager::DiscoverCharacteristics(const std::string& uuid, const winrt::guid& serviceUuid,
|
|
346
|
+
const std::vector<winrt::guid>& characteristicUUIDs)
|
|
347
|
+
{
|
|
348
|
+
CHECK_DEVICE();
|
|
349
|
+
IFDEVICE(device, uuid)
|
|
350
|
+
{
|
|
351
|
+
peripheral.GetService(serviceUuid, [=](std::optional<GattDeviceService> service) {
|
|
352
|
+
if (service)
|
|
353
|
+
{
|
|
354
|
+
std::string serviceId = toStr(serviceUuid);
|
|
355
|
+
service->GetCharacteristicsAsync(BluetoothCacheMode::Uncached)
|
|
356
|
+
.Completed(bind2(this, &BLEManager::OnCharacteristicsDiscovered, uuid,
|
|
357
|
+
serviceId, characteristicUUIDs));
|
|
358
|
+
}
|
|
359
|
+
else
|
|
360
|
+
{
|
|
361
|
+
LOGE("GetService error");
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
return true;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
void BLEManager::OnCharacteristicsDiscovered(IAsyncOperation<GattCharacteristicsResult> asyncOp,
|
|
369
|
+
AsyncStatus status, const std::string uuid,
|
|
370
|
+
const std::string serviceId,
|
|
371
|
+
const std::vector<winrt::guid> characteristicUUIDs)
|
|
372
|
+
{
|
|
373
|
+
if (status == AsyncStatus::Completed)
|
|
374
|
+
{
|
|
375
|
+
auto result = asyncOp.GetResults();
|
|
376
|
+
CHECK_RESULT(result);
|
|
377
|
+
std::vector<std::pair<std::string, std::vector<std::string>>> characteristicsUuids;
|
|
378
|
+
FOR(characteristic, result.Characteristics())
|
|
379
|
+
{
|
|
380
|
+
auto id = characteristic.Uuid();
|
|
381
|
+
if (inFilter(characteristicUUIDs, id))
|
|
382
|
+
{
|
|
383
|
+
auto props = characteristic.CharacteristicProperties();
|
|
384
|
+
characteristicsUuids.push_back({ toStr(id), toPropertyArray(props) });
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
mEmit.CharacteristicsDiscovered(uuid, serviceId, characteristicsUuids);
|
|
388
|
+
}
|
|
389
|
+
else
|
|
390
|
+
{
|
|
391
|
+
LOGE("status: %d", status);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
bool BLEManager::Read(const std::string& uuid, const winrt::guid& serviceUuid,
|
|
396
|
+
const winrt::guid& characteristicUuid)
|
|
397
|
+
{
|
|
398
|
+
CHECK_DEVICE();
|
|
399
|
+
IFDEVICE(device, uuid)
|
|
400
|
+
{
|
|
401
|
+
peripheral.GetCharacteristic(
|
|
402
|
+
serviceUuid, characteristicUuid, [=](std::optional<GattCharacteristic> characteristic) {
|
|
403
|
+
if (characteristic)
|
|
404
|
+
{
|
|
405
|
+
std::string serviceId = toStr(serviceUuid);
|
|
406
|
+
std::string characteristicId = toStr(characteristicUuid);
|
|
407
|
+
characteristic->ReadValueAsync(BluetoothCacheMode::Uncached)
|
|
408
|
+
.Completed(
|
|
409
|
+
bind2(this, &BLEManager::OnRead, uuid, serviceId, characteristicId));
|
|
410
|
+
}
|
|
411
|
+
else
|
|
412
|
+
{
|
|
413
|
+
LOGE("GetCharacteristic error");
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
return true;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
void BLEManager::OnRead(IAsyncOperation<GattReadResult> asyncOp, AsyncStatus status,
|
|
421
|
+
const std::string uuid, const std::string serviceId,
|
|
422
|
+
const std::string characteristicId)
|
|
423
|
+
{
|
|
424
|
+
if (status == AsyncStatus::Completed)
|
|
425
|
+
{
|
|
426
|
+
GattReadResult result = asyncOp.GetResults();
|
|
427
|
+
CHECK_RESULT(result);
|
|
428
|
+
auto value = result.Value();
|
|
429
|
+
if (value)
|
|
430
|
+
{
|
|
431
|
+
auto reader = DataReader::FromBuffer(value);
|
|
432
|
+
Data data(reader.UnconsumedBufferLength());
|
|
433
|
+
reader.ReadBytes(data);
|
|
434
|
+
mEmit.Read(uuid, serviceId, characteristicId, data, false);
|
|
435
|
+
}
|
|
436
|
+
else
|
|
437
|
+
{
|
|
438
|
+
LOGE("value is null");
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
else
|
|
442
|
+
{
|
|
443
|
+
LOGE("status: %d", status);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
bool BLEManager::Write(const std::string& uuid, const winrt::guid& serviceUuid,
|
|
448
|
+
const winrt::guid& characteristicUuid, const Data& data,
|
|
449
|
+
bool withoutResponse)
|
|
450
|
+
{
|
|
451
|
+
CHECK_DEVICE();
|
|
452
|
+
IFDEVICE(device, uuid)
|
|
453
|
+
{
|
|
454
|
+
peripheral.GetCharacteristic(
|
|
455
|
+
serviceUuid, characteristicUuid, [=](std::optional<GattCharacteristic> characteristic) {
|
|
456
|
+
if (characteristic)
|
|
457
|
+
{
|
|
458
|
+
std::string serviceId = toStr(serviceUuid);
|
|
459
|
+
std::string characteristicId = toStr(characteristicUuid);
|
|
460
|
+
auto writer = DataWriter();
|
|
461
|
+
writer.WriteBytes(data);
|
|
462
|
+
auto value = writer.DetachBuffer();
|
|
463
|
+
GattWriteOption option = withoutResponse ? GattWriteOption::WriteWithoutResponse
|
|
464
|
+
: GattWriteOption::WriteWithResponse;
|
|
465
|
+
characteristic->WriteValueWithResultAsync(value, option)
|
|
466
|
+
.Completed(
|
|
467
|
+
bind2(this, &BLEManager::OnWrite, uuid, serviceId, characteristicId));
|
|
468
|
+
}
|
|
469
|
+
else
|
|
470
|
+
{
|
|
471
|
+
LOGE("GetCharacteristic error");
|
|
472
|
+
}
|
|
473
|
+
});
|
|
474
|
+
return true;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
void BLEManager::OnWrite(IAsyncOperation<GattWriteResult> asyncOp, AsyncStatus status,
|
|
479
|
+
const std::string uuid, const std::string serviceId,
|
|
480
|
+
const std::string characteristicId)
|
|
481
|
+
{
|
|
482
|
+
if (status == AsyncStatus::Completed)
|
|
483
|
+
{
|
|
484
|
+
mEmit.Write(uuid, serviceId, characteristicId);
|
|
485
|
+
}
|
|
486
|
+
else
|
|
487
|
+
{
|
|
488
|
+
LOGE("status: %d", status);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
GattClientCharacteristicConfigurationDescriptorValue
|
|
493
|
+
GetDescriptorValue(GattCharacteristicProperties properties)
|
|
494
|
+
{
|
|
495
|
+
if ((properties & GattCharacteristicProperties::Indicate) ==
|
|
496
|
+
GattCharacteristicProperties::Indicate)
|
|
497
|
+
{
|
|
498
|
+
return GattClientCharacteristicConfigurationDescriptorValue::Indicate;
|
|
499
|
+
}
|
|
500
|
+
else
|
|
501
|
+
{
|
|
502
|
+
return GattClientCharacteristicConfigurationDescriptorValue::Notify;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
bool BLEManager::Notify(const std::string& uuid, const winrt::guid& serviceUuid,
|
|
507
|
+
const winrt::guid& characteristicUuid, bool on)
|
|
508
|
+
{
|
|
509
|
+
CHECK_DEVICE();
|
|
510
|
+
IFDEVICE(device, uuid)
|
|
511
|
+
{
|
|
512
|
+
auto onCharacteristic = [=](std::optional<GattCharacteristic> characteristic) {
|
|
513
|
+
if (characteristic)
|
|
514
|
+
{
|
|
515
|
+
std::string serviceId = toStr(serviceUuid);
|
|
516
|
+
std::string characteristicId = toStr(characteristicUuid);
|
|
517
|
+
bool subscribed = mNotifyMap.IsSubscribed(uuid, *characteristic);
|
|
518
|
+
|
|
519
|
+
if (on)
|
|
520
|
+
{
|
|
521
|
+
if (subscribed)
|
|
522
|
+
{
|
|
523
|
+
// already listening
|
|
524
|
+
mEmit.Notify(uuid, serviceId, characteristicId, true);
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
auto descriptorValue =
|
|
528
|
+
GetDescriptorValue(characteristic->CharacteristicProperties());
|
|
529
|
+
|
|
530
|
+
auto completed = bind2(this, &BLEManager::OnNotify, *characteristic, uuid,
|
|
531
|
+
serviceId, characteristicId, on);
|
|
532
|
+
characteristic
|
|
533
|
+
->WriteClientCharacteristicConfigurationDescriptorWithResultAsync(
|
|
534
|
+
descriptorValue)
|
|
535
|
+
.Completed(completed);
|
|
536
|
+
}
|
|
537
|
+
else
|
|
538
|
+
{
|
|
539
|
+
if (!subscribed)
|
|
540
|
+
{
|
|
541
|
+
// already not listening
|
|
542
|
+
mEmit.Notify(uuid, serviceId, characteristicId, false);
|
|
543
|
+
return;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
mNotifyMap.Unsubscribe(uuid, *characteristic);
|
|
547
|
+
auto descriptorValue =
|
|
548
|
+
GattClientCharacteristicConfigurationDescriptorValue::None;
|
|
549
|
+
auto completed = bind2(this, &BLEManager::OnNotify, *characteristic, uuid,
|
|
550
|
+
serviceId, characteristicId, on);
|
|
551
|
+
characteristic
|
|
552
|
+
->WriteClientCharacteristicConfigurationDescriptorWithResultAsync(
|
|
553
|
+
descriptorValue)
|
|
554
|
+
.Completed(completed);
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
else
|
|
558
|
+
{
|
|
559
|
+
LOGE("GetCharacteristic error");
|
|
560
|
+
}
|
|
561
|
+
};
|
|
562
|
+
peripheral.GetCharacteristic(serviceUuid, characteristicUuid, onCharacteristic);
|
|
563
|
+
return true;
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
void BLEManager::OnNotify(IAsyncOperation<GattWriteResult> asyncOp, AsyncStatus status,
|
|
568
|
+
const GattCharacteristic characteristic, const std::string uuid,
|
|
569
|
+
const std::string serviceId, const std::string characteristicId,
|
|
570
|
+
const bool state)
|
|
571
|
+
{
|
|
572
|
+
if (status == AsyncStatus::Completed)
|
|
573
|
+
{
|
|
574
|
+
if (state == true)
|
|
575
|
+
{
|
|
576
|
+
auto onChanged = bind2(this, &BLEManager::OnValueChanged, uuid);
|
|
577
|
+
auto token = characteristic.ValueChanged(onChanged);
|
|
578
|
+
mNotifyMap.Add(uuid, characteristic, token);
|
|
579
|
+
}
|
|
580
|
+
mEmit.Notify(uuid, serviceId, characteristicId, state);
|
|
581
|
+
}
|
|
582
|
+
else
|
|
583
|
+
{
|
|
584
|
+
LOGE("status: %d", status);
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
void BLEManager::OnValueChanged(GattCharacteristic characteristic,
|
|
589
|
+
const GattValueChangedEventArgs& args, std::string deviceUuid)
|
|
590
|
+
{
|
|
591
|
+
auto reader = DataReader::FromBuffer(args.CharacteristicValue());
|
|
592
|
+
Data data(reader.UnconsumedBufferLength());
|
|
593
|
+
reader.ReadBytes(data);
|
|
594
|
+
auto characteristicUuid = toStr(characteristic.Uuid());
|
|
595
|
+
auto serviceUuid = toStr(characteristic.Service().Uuid());
|
|
596
|
+
mEmit.Read(deviceUuid, serviceUuid, characteristicUuid, data, true);
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
bool BLEManager::DiscoverDescriptors(const std::string& uuid, const winrt::guid& serviceUuid,
|
|
600
|
+
const winrt::guid& characteristicUuid)
|
|
601
|
+
{
|
|
602
|
+
CHECK_DEVICE();
|
|
603
|
+
IFDEVICE(device, uuid)
|
|
604
|
+
{
|
|
605
|
+
peripheral.GetCharacteristic(
|
|
606
|
+
serviceUuid, characteristicUuid, [=](std::optional<GattCharacteristic> characteristic) {
|
|
607
|
+
if (characteristic)
|
|
608
|
+
{
|
|
609
|
+
std::string serviceId = toStr(serviceUuid);
|
|
610
|
+
std::string characteristicId = toStr(characteristicUuid);
|
|
611
|
+
auto completed = bind2(this, &BLEManager::OnDescriptorsDiscovered, uuid,
|
|
612
|
+
serviceId, characteristicId);
|
|
613
|
+
characteristic->GetDescriptorsAsync(BluetoothCacheMode::Uncached)
|
|
614
|
+
.Completed(completed);
|
|
615
|
+
}
|
|
616
|
+
else
|
|
617
|
+
{
|
|
618
|
+
LOGE("GetCharacteristic error");
|
|
619
|
+
}
|
|
620
|
+
});
|
|
621
|
+
return true;
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
void BLEManager::OnDescriptorsDiscovered(IAsyncOperation<GattDescriptorsResult> asyncOp,
|
|
626
|
+
AsyncStatus status, const std::string uuid,
|
|
627
|
+
const std::string serviceId,
|
|
628
|
+
const std::string characteristicId)
|
|
629
|
+
{
|
|
630
|
+
if (status == AsyncStatus::Completed)
|
|
631
|
+
{
|
|
632
|
+
auto result = asyncOp.GetResults();
|
|
633
|
+
CHECK_RESULT(result);
|
|
634
|
+
std::vector<std::string> descriptorUuids;
|
|
635
|
+
FOR(descriptor, result.Descriptors())
|
|
636
|
+
{
|
|
637
|
+
descriptorUuids.push_back(toStr(descriptor.Uuid()));
|
|
638
|
+
}
|
|
639
|
+
mEmit.DescriptorsDiscovered(uuid, serviceId, characteristicId, descriptorUuids);
|
|
640
|
+
}
|
|
641
|
+
else
|
|
642
|
+
{
|
|
643
|
+
LOGE("status: %d", status);
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
bool BLEManager::ReadValue(const std::string& uuid, const winrt::guid& serviceUuid,
|
|
648
|
+
const winrt::guid& characteristicUuid, const winrt::guid& descriptorUuid)
|
|
649
|
+
{
|
|
650
|
+
CHECK_DEVICE();
|
|
651
|
+
IFDEVICE(device, uuid)
|
|
652
|
+
{
|
|
653
|
+
peripheral.GetDescriptor(
|
|
654
|
+
serviceUuid, characteristicUuid, descriptorUuid,
|
|
655
|
+
[=](std::optional<GattDescriptor> descriptor) {
|
|
656
|
+
if (descriptor)
|
|
657
|
+
{
|
|
658
|
+
std::string serviceId = toStr(serviceUuid);
|
|
659
|
+
std::string characteristicId = toStr(characteristicUuid);
|
|
660
|
+
std::string descriptorId = toStr(descriptorUuid);
|
|
661
|
+
auto completed = bind2(this, &BLEManager::OnReadValue, uuid, serviceId,
|
|
662
|
+
characteristicId, descriptorId);
|
|
663
|
+
descriptor->ReadValueAsync(BluetoothCacheMode::Uncached).Completed(completed);
|
|
664
|
+
}
|
|
665
|
+
else
|
|
666
|
+
{
|
|
667
|
+
LOGE("descriptor not found");
|
|
668
|
+
}
|
|
669
|
+
});
|
|
670
|
+
return true;
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
void BLEManager::OnReadValue(IAsyncOperation<GattReadResult> asyncOp, AsyncStatus status,
|
|
675
|
+
const std::string uuid, const std::string serviceId,
|
|
676
|
+
const std::string characteristicId, const std::string descriptorId)
|
|
677
|
+
{
|
|
678
|
+
if (status == AsyncStatus::Completed)
|
|
679
|
+
{
|
|
680
|
+
GattReadResult result = asyncOp.GetResults();
|
|
681
|
+
CHECK_RESULT(result);
|
|
682
|
+
auto value = result.Value();
|
|
683
|
+
if (value)
|
|
684
|
+
{
|
|
685
|
+
auto reader = DataReader::FromBuffer(value);
|
|
686
|
+
Data data(reader.UnconsumedBufferLength());
|
|
687
|
+
reader.ReadBytes(data);
|
|
688
|
+
mEmit.ReadValue(uuid, serviceId, characteristicId, descriptorId, data);
|
|
689
|
+
}
|
|
690
|
+
else
|
|
691
|
+
{
|
|
692
|
+
LOGE("value is null");
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
else
|
|
696
|
+
{
|
|
697
|
+
LOGE("status: %d", status);
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
bool BLEManager::WriteValue(const std::string& uuid, const winrt::guid& serviceUuid,
|
|
702
|
+
const winrt::guid& characteristicUuid,
|
|
703
|
+
const winrt::guid& descriptorUuid, const Data& data)
|
|
704
|
+
{
|
|
705
|
+
CHECK_DEVICE();
|
|
706
|
+
IFDEVICE(device, uuid)
|
|
707
|
+
{
|
|
708
|
+
auto onDescriptor = [=](std::optional<GattDescriptor> descriptor) {
|
|
709
|
+
if (descriptor)
|
|
710
|
+
{
|
|
711
|
+
std::string serviceId = toStr(serviceUuid);
|
|
712
|
+
std::string characteristicId = toStr(characteristicUuid);
|
|
713
|
+
std::string descriptorId = toStr(descriptorUuid);
|
|
714
|
+
auto writer = DataWriter();
|
|
715
|
+
writer.WriteBytes(data);
|
|
716
|
+
auto value = writer.DetachBuffer();
|
|
717
|
+
auto asyncOp = descriptor->WriteValueWithResultAsync(value);
|
|
718
|
+
asyncOp.Completed(bind2(this, &BLEManager::OnWriteValue, uuid, serviceId,
|
|
719
|
+
characteristicId, descriptorId));
|
|
720
|
+
}
|
|
721
|
+
else
|
|
722
|
+
{
|
|
723
|
+
LOGE("descriptor not found");
|
|
724
|
+
}
|
|
725
|
+
};
|
|
726
|
+
peripheral.GetDescriptor(serviceUuid, characteristicUuid, descriptorUuid, onDescriptor);
|
|
727
|
+
return true;
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
void BLEManager::OnWriteValue(IAsyncOperation<GattWriteResult> asyncOp, AsyncStatus status,
|
|
732
|
+
const std::string uuid, const std::string serviceId,
|
|
733
|
+
const std::string characteristicId, const std::string descriptorId)
|
|
734
|
+
{
|
|
735
|
+
if (status == AsyncStatus::Completed)
|
|
736
|
+
{
|
|
737
|
+
mEmit.WriteValue(uuid, serviceId, characteristicId, descriptorId);
|
|
738
|
+
}
|
|
739
|
+
else
|
|
740
|
+
{
|
|
741
|
+
LOGE("status: %d", status);
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
bool BLEManager::ReadHandle(const std::string& uuid, int handle)
|
|
746
|
+
{
|
|
747
|
+
CHECK_DEVICE();
|
|
748
|
+
IFDEVICE(device, uuid)
|
|
749
|
+
{
|
|
750
|
+
LOGE("not available");
|
|
751
|
+
return true;
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
void BLEManager::OnReadHandle(IAsyncOperation<GattReadResult> asyncOp, AsyncStatus status,
|
|
756
|
+
const std::string uuid, const int handle)
|
|
757
|
+
{
|
|
758
|
+
if (status == AsyncStatus::Completed)
|
|
759
|
+
{
|
|
760
|
+
GattReadResult result = asyncOp.GetResults();
|
|
761
|
+
CHECK_RESULT(result);
|
|
762
|
+
auto value = result.Value();
|
|
763
|
+
if (value)
|
|
764
|
+
{
|
|
765
|
+
auto reader = DataReader::FromBuffer(value);
|
|
766
|
+
Data data(reader.UnconsumedBufferLength());
|
|
767
|
+
reader.ReadBytes(data);
|
|
768
|
+
mEmit.ReadHandle(uuid, handle, data);
|
|
769
|
+
}
|
|
770
|
+
else
|
|
771
|
+
{
|
|
772
|
+
LOGE("value is null");
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
else
|
|
776
|
+
{
|
|
777
|
+
LOGE("status: %d", status);
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
bool BLEManager::WriteHandle(const std::string& uuid, int handle, Data data)
|
|
782
|
+
{
|
|
783
|
+
CHECK_DEVICE();
|
|
784
|
+
IFDEVICE(device, uuid)
|
|
785
|
+
{
|
|
786
|
+
LOGE("not available");
|
|
787
|
+
return true;
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
void BLEManager::OnWriteHandle(IAsyncOperation<GattWriteResult> asyncOp, AsyncStatus status,
|
|
792
|
+
const std::string uuid, const int handle)
|
|
793
|
+
{
|
|
794
|
+
if (status == AsyncStatus::Completed)
|
|
795
|
+
{
|
|
796
|
+
mEmit.WriteHandle(uuid, handle);
|
|
797
|
+
}
|
|
798
|
+
else
|
|
799
|
+
{
|
|
800
|
+
LOGE("status %d", status);
|
|
801
|
+
}
|
|
802
|
+
}
|