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