1 /*
2 * Copyright (C) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #ifndef LOG_TAG
16 #define LOG_TAG "bt_napi_ble_utils"
17 #endif
18
19 #include "napi_bluetooth_utils.h"
20 #include "napi_bluetooth_ble_utils.h"
21 #include <algorithm>
22 #include <functional>
23 #include <optional>
24 #include "bluetooth_errorcode.h"
25 #include "bluetooth_log.h"
26 #include "napi/native_api.h"
27 #include "napi/native_node_api.h"
28 #include "napi_bluetooth_error.h"
29 #include "securec.h"
30
31 namespace OHOS {
32 namespace Bluetooth {
33 using namespace std;
ConvertGattServiceToJS(napi_env env,napi_value result,GattService & service)34 void ConvertGattServiceToJS(napi_env env, napi_value result, GattService& service)
35 {
36 napi_value serviceUuid;
37 napi_create_string_utf8(env, service.GetUuid().ToString().c_str(), NAPI_AUTO_LENGTH, &serviceUuid);
38 napi_set_named_property(env, result, "serviceUuid", serviceUuid);
39
40 napi_value isPrimary;
41 napi_get_boolean(env, service.IsPrimary(), &isPrimary);
42 napi_set_named_property(env, result, "isPrimary", isPrimary);
43 HILOGI("uuid: %{public}s, isPrimary: %{public}d", service.GetUuid().ToString().c_str(), service.IsPrimary());
44
45 napi_value characteristics;
46 napi_create_array(env, &characteristics);
47 ConvertBLECharacteristicVectorToJS(env, characteristics, service.GetCharacteristics());
48 napi_set_named_property(env, result, "characteristics", characteristics);
49
50 napi_value includeServices;
51 napi_create_array(env, &includeServices);
52 vector<GattService> services;
53 vector<std::reference_wrapper<GattService>> srvs = service.GetIncludedServices();
54 for (auto &srv : srvs) {
55 services.push_back(srv.get());
56 }
57 ConvertGattServiceVectorToJS(env, includeServices, services);
58 napi_set_named_property(env, result, "includeServices", includeServices);
59 }
60
ConvertGattServiceVectorToJS(napi_env env,napi_value result,vector<GattService> & services)61 void ConvertGattServiceVectorToJS(napi_env env, napi_value result, vector<GattService>& services)
62 {
63 HILOGI("enter");
64 size_t idx = 0;
65
66 if (services.empty()) {
67 return;
68 }
69 HILOGI("size: %{public}zu", services.size());
70 for (auto& service : services) {
71 napi_value obj = nullptr;
72 napi_create_object(env, &obj);
73 ConvertGattServiceToJS(env, obj, service);
74 napi_set_element(env, result, idx, obj);
75 idx++;
76 }
77 }
78
ConvertBLECharacteristicVectorToJS(napi_env env,napi_value result,vector<GattCharacteristic> & characteristics)79 void ConvertBLECharacteristicVectorToJS(napi_env env, napi_value result,
80 vector<GattCharacteristic>& characteristics)
81 {
82 HILOGI("size: %{public}zu", characteristics.size());
83 size_t idx = 0;
84 if (characteristics.empty()) {
85 return;
86 }
87
88 for (auto &characteristic : characteristics) {
89 napi_value obj = nullptr;
90 napi_create_object(env, &obj);
91 ConvertBLECharacteristicToJS(env, obj, characteristic);
92 napi_set_element(env, result, idx, obj);
93 idx++;
94 }
95 }
96
HasProperty(int properties,int propertyMask)97 bool HasProperty(int properties, int propertyMask)
98 {
99 if (properties < 0 || propertyMask < 0) {
100 HILOGE("properties or propertyMask is less than 0");
101 return false;
102 }
103 return (static_cast<unsigned int>(properties) & static_cast<unsigned int>(propertyMask)) != 0;
104 }
ConvertGattPropertiesToJs(napi_env env,int properties)105 napi_value ConvertGattPropertiesToJs(napi_env env, int properties)
106 {
107 napi_value object;
108 napi_create_object(env, &object);
109
110 napi_value value;
111 napi_get_boolean(env, HasProperty(properties, GattCharacteristic::WRITE), &value);
112 napi_set_named_property(env, object, "write", value);
113
114 napi_get_boolean(env, HasProperty(properties, GattCharacteristic::WRITE_WITHOUT_RESPONSE), &value);
115 napi_set_named_property(env, object, "writeNoResponse", value);
116
117 napi_get_boolean(env, HasProperty(properties, GattCharacteristic::READ), &value);
118 napi_set_named_property(env, object, "read", value);
119
120 napi_get_boolean(env, HasProperty(properties, GattCharacteristic::NOTIFY), &value);
121 napi_set_named_property(env, object, "notify", value);
122
123 napi_get_boolean(env, HasProperty(properties, GattCharacteristic::INDICATE), &value);
124 napi_set_named_property(env, object, "indicate", value);
125 return object;
126 }
127
ConvertBLECharacteristicToJS(napi_env env,napi_value result,GattCharacteristic & characteristic)128 void ConvertBLECharacteristicToJS(napi_env env, napi_value result, GattCharacteristic& characteristic)
129 {
130 napi_value characteristicUuid;
131 HILOGI("uuid: %{public}s", characteristic.GetUuid().ToString().c_str());
132 napi_create_string_utf8(env, characteristic.GetUuid().ToString().c_str(), NAPI_AUTO_LENGTH, &characteristicUuid);
133 napi_set_named_property(env, result, "characteristicUuid", characteristicUuid);
134
135 if (characteristic.GetService() != nullptr) {
136 napi_value serviceUuid;
137 napi_create_string_utf8(env, characteristic.GetService()->GetUuid().ToString().c_str(), NAPI_AUTO_LENGTH,
138 &serviceUuid);
139 napi_set_named_property(env, result, "serviceUuid", serviceUuid);
140 }
141
142 size_t valueSize = 0;
143 uint8_t* valueData = characteristic.GetValue(&valueSize).get();
144 {
145 napi_value value = nullptr;
146 uint8_t* bufferData = nullptr;
147 napi_create_arraybuffer(env, valueSize, (void**)&bufferData, &value);
148 if (valueSize > 0 && memcpy_s(bufferData, valueSize, valueData, valueSize) != EOK) {
149 HILOGE("memcpy_s failed");
150 return;
151 }
152 napi_set_named_property(env, result, "characteristicValue", value);
153 }
154
155 napi_value propertiesValue = ConvertGattPropertiesToJs(env, characteristic.GetProperties());
156 napi_set_named_property(env, result, "properties", propertiesValue);
157
158 napi_value descriptors;
159 napi_create_array(env, &descriptors);
160 ConvertBLEDescriptorVectorToJS(env, descriptors, characteristic.GetDescriptors());
161 napi_set_named_property(env, result, "descriptors", descriptors);
162 }
163
ConvertBLEDescriptorVectorToJS(napi_env env,napi_value result,vector<GattDescriptor> & descriptors)164 void ConvertBLEDescriptorVectorToJS(napi_env env, napi_value result, vector<GattDescriptor>& descriptors)
165 {
166 HILOGI("size: %{public}zu", descriptors.size());
167 size_t idx = 0;
168
169 if (descriptors.empty()) {
170 return;
171 }
172
173 for (auto& descriptor : descriptors) {
174 napi_value obj = nullptr;
175 napi_create_object(env, &obj);
176 ConvertBLEDescriptorToJS(env, obj, descriptor);
177 napi_set_element(env, result, idx, obj);
178 idx++;
179 }
180 }
181
ConvertBLEDescriptorToJS(napi_env env,napi_value result,GattDescriptor & descriptor)182 void ConvertBLEDescriptorToJS(napi_env env, napi_value result, GattDescriptor& descriptor)
183 {
184 HILOGI("uuid: %{public}s", descriptor.GetUuid().ToString().c_str());
185
186 napi_value descriptorUuid;
187 napi_create_string_utf8(env, descriptor.GetUuid().ToString().c_str(), NAPI_AUTO_LENGTH, &descriptorUuid);
188 napi_set_named_property(env, result, "descriptorUuid", descriptorUuid);
189
190 if (descriptor.GetCharacteristic() != nullptr) {
191 napi_value characteristicUuid;
192 napi_create_string_utf8(env, descriptor.GetCharacteristic()->GetUuid().ToString().c_str(), NAPI_AUTO_LENGTH,
193 &characteristicUuid);
194 napi_set_named_property(env, result, "characteristicUuid", characteristicUuid);
195
196 if (descriptor.GetCharacteristic()->GetService() != nullptr) {
197 napi_value serviceUuid;
198 napi_create_string_utf8(env, descriptor.GetCharacteristic()->GetService()->GetUuid().ToString().c_str(),
199 NAPI_AUTO_LENGTH, &serviceUuid);
200 napi_set_named_property(env, result, "serviceUuid", serviceUuid);
201 }
202 }
203
204 napi_value value;
205 size_t valueSize;
206 uint8_t* valueData = descriptor.GetValue(&valueSize).get();
207 uint8_t* bufferData = nullptr;
208 napi_create_arraybuffer(env, valueSize, (void**)&bufferData, &value);
209 if (memcpy_s(bufferData, valueSize, valueData, valueSize) != EOK) {
210 HILOGE("memcpy_s error");
211 }
212 napi_set_named_property(env, result, "descriptorValue", value);
213 }
214
ConvertCharacteristicReadReqToJS(napi_env env,napi_value result,const std::string & device,const GattCharacteristic & characteristic,int requestId)215 void ConvertCharacteristicReadReqToJS(napi_env env, napi_value result, const std::string &device,
216 const GattCharacteristic &characteristic, int requestId)
217 {
218 napi_value deviceId;
219 napi_create_string_utf8(env, device.c_str(), NAPI_AUTO_LENGTH, &deviceId);
220 napi_set_named_property(env, result, "deviceId", deviceId);
221
222 napi_value transId;
223 napi_create_int32(env, requestId, &transId);
224 napi_set_named_property(env, result, "transId", transId);
225
226 napi_value offset;
227 napi_create_int32(env, 0, &offset);
228 napi_set_named_property(env, result, "offset", offset);
229 HILOGI("offset is %{public}d", 0);
230
231 napi_value characteristicUuid;
232 napi_create_string_utf8(env, characteristic.GetUuid().ToString().c_str(), NAPI_AUTO_LENGTH, &characteristicUuid);
233 napi_set_named_property(env, result, "characteristicUuid", characteristicUuid);
234 HILOGI("characteristicUuid is %{public}s", characteristic.GetUuid().ToString().c_str());
235
236 if (characteristic.GetService() != nullptr) {
237 napi_value serviceUuid;
238 napi_create_string_utf8(env, characteristic.GetService()->GetUuid().ToString().c_str(), NAPI_AUTO_LENGTH,
239 &serviceUuid);
240 napi_set_named_property(env, result, "serviceUuid", serviceUuid);
241 }
242 }
243
ConvertDescriptorReadReqToJS(napi_env env,napi_value result,const std::string & device,const GattDescriptor & descriptor,int requestId)244 void ConvertDescriptorReadReqToJS(napi_env env, napi_value result, const std::string &device,
245 const GattDescriptor& descriptor, int requestId)
246 {
247 napi_value deviceId;
248 napi_create_string_utf8(env, device.c_str(), NAPI_AUTO_LENGTH, &deviceId);
249 napi_set_named_property(env, result, "deviceId", deviceId);
250
251 napi_value transId;
252 napi_create_int32(env, requestId, &transId);
253 napi_set_named_property(env, result, "transId", transId);
254
255 napi_value offset;
256 napi_create_int32(env, 0, &offset);
257 napi_set_named_property(env, result, "offset", offset);
258 HILOGI("offset is %{public}d", 0);
259
260 napi_value descriptorUuid;
261 napi_create_string_utf8(env, descriptor.GetUuid().ToString().c_str(), NAPI_AUTO_LENGTH, &descriptorUuid);
262 napi_set_named_property(env, result, "descriptorUuid", descriptorUuid);
263 HILOGI("descriptorUuid is %{public}s", descriptor.GetUuid().ToString().c_str());
264
265 if (descriptor.GetCharacteristic() != nullptr) {
266 napi_value characteristicUuid;
267 napi_create_string_utf8(env, descriptor.GetCharacteristic()->GetUuid().ToString().c_str(), NAPI_AUTO_LENGTH,
268 &characteristicUuid);
269 napi_set_named_property(env, result, "characteristicUuid", characteristicUuid);
270
271 if (descriptor.GetCharacteristic()->GetService() != nullptr) {
272 napi_value serviceUuid;
273 napi_create_string_utf8(env, descriptor.GetCharacteristic()->GetService()->GetUuid().ToString().c_str(),
274 NAPI_AUTO_LENGTH, &serviceUuid);
275 napi_set_named_property(env, result, "serviceUuid", serviceUuid);
276 }
277 }
278 }
279
ConvertCharacteristicWriteReqToJS(napi_env env,napi_value result,const std::string & device,const GattCharacteristic & characteristic,int requestId)280 void ConvertCharacteristicWriteReqToJS(napi_env env, napi_value result, const std::string &device,
281 const GattCharacteristic& characteristic, int requestId)
282 {
283 napi_value deviceId;
284 napi_create_string_utf8(env, device.c_str(), NAPI_AUTO_LENGTH, &deviceId);
285 napi_set_named_property(env, result, "deviceId", deviceId);
286
287 napi_value transId;
288 napi_create_int32(env, requestId, &transId);
289 napi_set_named_property(env, result, "transId", transId);
290
291 napi_value offset;
292 napi_create_int32(env, 0, &offset);
293 napi_set_named_property(env, result, "offset", offset);
294 HILOGI("offset is %{public}d", 0);
295
296 napi_value isPrepared;
297 napi_get_boolean(env, false, &isPrepared);
298 napi_set_named_property(env, result, "isPrepared", isPrepared);
299
300 napi_value needRsp;
301 napi_get_boolean(env, characteristic.GetWriteType() == GattCharacteristic::WriteType::DEFAULT, &needRsp);
302 napi_set_named_property(env, result, "needRsp", needRsp);
303
304 napi_value value;
305 size_t valueSize;
306 uint8_t* valueData = characteristic.GetValue(&valueSize).get();
307 uint8_t* bufferData = nullptr;
308 napi_create_arraybuffer(env, valueSize, (void**)&bufferData, &value);
309 if (memcpy_s(bufferData, valueSize, valueData, valueSize) != EOK) {
310 HILOGE("memcpy_s error");
311 }
312 napi_set_named_property(env, result, "value", value);
313
314 napi_value characteristicUuid;
315 napi_create_string_utf8(env, characteristic.GetUuid().ToString().c_str(), NAPI_AUTO_LENGTH, &characteristicUuid);
316 napi_set_named_property(env, result, "characteristicUuid", characteristicUuid);
317 HILOGI("characteristicUuid is %{public}s", characteristic.GetUuid().ToString().c_str());
318
319 if (characteristic.GetService() != nullptr) {
320 napi_value serviceUuid;
321 napi_create_string_utf8(env, characteristic.GetService()->GetUuid().ToString().c_str(), NAPI_AUTO_LENGTH,
322 &serviceUuid);
323 napi_set_named_property(env, result, "serviceUuid", serviceUuid);
324 }
325 }
326
ConvertDescriptorWriteReqToJS(napi_env env,napi_value result,const std::string & device,const GattDescriptor & descriptor,int requestId)327 void ConvertDescriptorWriteReqToJS(napi_env env, napi_value result, const std::string &device,
328 const GattDescriptor &descriptor, int requestId)
329 {
330 napi_value deviceId;
331 napi_create_string_utf8(env, device.c_str(), NAPI_AUTO_LENGTH, &deviceId);
332 napi_set_named_property(env, result, "deviceId", deviceId);
333
334 napi_value transId;
335 napi_create_int32(env, requestId, &transId);
336 napi_set_named_property(env, result, "transId", transId);
337
338 napi_value offset;
339 napi_create_int32(env, 0, &offset);
340 napi_set_named_property(env, result, "offset", offset);
341 HILOGI("offset is %{public}d", 0);
342
343 napi_value isPrepared;
344 napi_get_boolean(env, false, &isPrepared);
345 napi_set_named_property(env, result, "isPrepared", isPrepared);
346
347 napi_value needRsp;
348 napi_get_boolean(env, true, &needRsp);
349 napi_set_named_property(env, result, "needRsp", needRsp);
350
351 napi_value value;
352 size_t valueSize;
353 uint8_t* valueData = descriptor.GetValue(&valueSize).get();
354 uint8_t* bufferData = nullptr;
355 napi_create_arraybuffer(env, valueSize, (void**)&bufferData, &value);
356 if (memcpy_s(bufferData, valueSize, valueData, valueSize) != EOK) {
357 HILOGE("memcpy_s error");
358 }
359 napi_set_named_property(env, result, "value", value);
360
361 napi_value descriptorUuid;
362 napi_create_string_utf8(env, descriptor.GetUuid().ToString().c_str(), NAPI_AUTO_LENGTH, &descriptorUuid);
363 napi_set_named_property(env, result, "descriptorUuid", descriptorUuid);
364 HILOGI("descriptorUuid is %{public}s", descriptor.GetUuid().ToString().c_str());
365
366 if (descriptor.GetCharacteristic() != nullptr) {
367 napi_value characteristicUuid;
368 napi_create_string_utf8(env, descriptor.GetCharacteristic()->GetUuid().ToString().c_str(), NAPI_AUTO_LENGTH,
369 &characteristicUuid);
370 napi_set_named_property(env, result, "characteristicUuid", characteristicUuid);
371
372 if (descriptor.GetCharacteristic()->GetService() != nullptr) {
373 napi_value serviceUuid;
374 napi_create_string_utf8(env, descriptor.GetCharacteristic()->GetService()->GetUuid().ToString().c_str(),
375 NAPI_AUTO_LENGTH, &serviceUuid);
376 napi_set_named_property(env, result, "serviceUuid", serviceUuid);
377 }
378 }
379 }
380
SetGattClientDeviceId(const std::string & deviceId)381 void SetGattClientDeviceId(const std::string &deviceId)
382 {
383 deviceAddr = deviceId;
384 }
385
GetGattClientDeviceId()386 std::string GetGattClientDeviceId()
387 {
388 return deviceAddr;
389 }
390
ToNapiValue(napi_env env) const391 napi_value NapiNativeBleCharacteristic::ToNapiValue(napi_env env) const
392 {
393 napi_value object;
394 napi_create_object(env, &object);
395 ConvertBLECharacteristicToJS(env, object, const_cast<GattCharacteristic &>(character_));
396 return object;
397 }
398
ToNapiValue(napi_env env) const399 napi_value NapiNativeBleDescriptor::ToNapiValue(napi_env env) const
400 {
401 napi_value object;
402 napi_create_object(env, &object);
403 ConvertBLEDescriptorToJS(env, object, const_cast<GattDescriptor &>(descriptor_));
404 return object;
405 }
406
ToNapiValue(napi_env env) const407 napi_value NapiNativeGattServiceArray::ToNapiValue(napi_env env) const
408 {
409 napi_value object;
410 napi_create_array(env, &object);
411 ConvertGattServiceVectorToJS(env, object, const_cast<vector<GattService> &>(gattServices_));
412 return object;
413 }
414
ToNapiValue(napi_env env) const415 napi_value NapiNativeAdvertisingStateInfo::ToNapiValue(napi_env env) const
416 {
417 napi_value object;
418 napi_create_object(env, &object);
419
420 napi_value value;
421 napi_create_int32(env, advHandle_, &value);
422 napi_set_named_property(env, object, "advertisingId", value);
423
424 napi_create_int32(env, advState_, &value);
425 napi_set_named_property(env, object, "state", value);
426 return object;
427 }
428
ToNapiValue(napi_env env) const429 napi_value NapiNativeGattsCharacterReadRequest::ToNapiValue(napi_env env) const
430 {
431 napi_value result = nullptr;
432 napi_create_object(env, &result);
433
434 ConvertCharacteristicReadReqToJS(env, result, deviceAddr_, character_, transId_);
435 return result;
436 }
437
ToNapiValue(napi_env env) const438 napi_value NapiNativeGattsCharacterWriteRequest::ToNapiValue(napi_env env) const
439 {
440 napi_value result = nullptr;
441 napi_create_object(env, &result);
442
443 ConvertCharacteristicWriteReqToJS(env, result, deviceAddr_, character_, transId_);
444 return result;
445 }
446
ToNapiValue(napi_env env) const447 napi_value NapiNativeGattsDescriptorWriteRequest::ToNapiValue(napi_env env) const
448 {
449 napi_value result = nullptr;
450 napi_create_object(env, &result);
451
452 ConvertDescriptorWriteReqToJS(env, result, deviceAddr_, descriptor_, transId_);
453 return result;
454 }
455
ToNapiValue(napi_env env) const456 napi_value NapiNativeGattsDescriptorReadRequest::ToNapiValue(napi_env env) const
457 {
458 napi_value result = nullptr;
459 napi_create_object(env, &result);
460
461 ConvertDescriptorReadReqToJS(env, result, deviceAddr_, descriptor_, transId_);
462 return result;
463 }
464 } // namespace Bluetooth
465 } // namespace OHOS
466