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,GattCharacteristic & characteristic,int requestId)212 void ConvertCharacteristicReadReqToJS(napi_env env, napi_value result, const std::string &device,
213 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,GattDescriptor & descriptor,int requestId)241 void ConvertDescriptorReadReqToJS(napi_env env, napi_value result, const std::string &device,
242 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,GattCharacteristic & characteristic,int requestId)277 void ConvertCharacteristicWriteReqToJS(napi_env env, napi_value result, const std::string &device,
278 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, true, &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 (void)memcpy_s(bufferData, valueSize, valueData, valueSize);
307 napi_set_named_property(env, result, "value", value);
308
309 napi_value characteristicUuid;
310 napi_create_string_utf8(env, characteristic.GetUuid().ToString().c_str(), NAPI_AUTO_LENGTH, &characteristicUuid);
311 napi_set_named_property(env, result, "characteristicUuid", characteristicUuid);
312 HILOGI("characteristicUuid is %{public}s", characteristic.GetUuid().ToString().c_str());
313
314 if (characteristic.GetService() != nullptr) {
315 napi_value serviceUuid;
316 napi_create_string_utf8(env, characteristic.GetService()->GetUuid().ToString().c_str(), NAPI_AUTO_LENGTH,
317 &serviceUuid);
318 napi_set_named_property(env, result, "serviceUuid", serviceUuid);
319 }
320 }
321
ConvertDescriptorWriteReqToJS(napi_env env,napi_value result,const std::string & device,GattDescriptor & descriptor,int requestId)322 void ConvertDescriptorWriteReqToJS(napi_env env, napi_value result, const std::string &device,
323 GattDescriptor &descriptor, int requestId)
324 {
325 napi_value deviceId;
326 napi_create_string_utf8(env, device.c_str(), NAPI_AUTO_LENGTH, &deviceId);
327 napi_set_named_property(env, result, "deviceId", deviceId);
328
329 napi_value transId;
330 napi_create_int32(env, requestId, &transId);
331 napi_set_named_property(env, result, "transId", transId);
332
333 napi_value offset;
334 napi_create_int32(env, 0, &offset);
335 napi_set_named_property(env, result, "offset", offset);
336 HILOGI("offset is %{public}d", 0);
337
338 napi_value isPrepared;
339 napi_get_boolean(env, false, &isPrepared);
340 napi_set_named_property(env, result, "isPrepared", isPrepared);
341
342 napi_value needRsp;
343 napi_get_boolean(env, true, &needRsp);
344 napi_set_named_property(env, result, "needRsp", needRsp);
345
346 napi_value value;
347 size_t valueSize;
348 uint8_t* valueData = descriptor.GetValue(&valueSize).get();
349 uint8_t* bufferData = nullptr;
350 napi_create_arraybuffer(env, valueSize, (void**)&bufferData, &value);
351 (void)memcpy_s(bufferData, valueSize, valueData, valueSize);
352 napi_set_named_property(env, result, "value", value);
353
354 napi_value descriptorUuid;
355 napi_create_string_utf8(env, descriptor.GetUuid().ToString().c_str(), NAPI_AUTO_LENGTH, &descriptorUuid);
356 napi_set_named_property(env, result, "descriptorUuid", descriptorUuid);
357 HILOGI("descriptorUuid is %{public}s", descriptor.GetUuid().ToString().c_str());
358
359 if (descriptor.GetCharacteristic() != nullptr) {
360 napi_value characteristicUuid;
361 napi_create_string_utf8(env, descriptor.GetCharacteristic()->GetUuid().ToString().c_str(), NAPI_AUTO_LENGTH,
362 &characteristicUuid);
363 napi_set_named_property(env, result, "characteristicUuid", characteristicUuid);
364
365 if (descriptor.GetCharacteristic()->GetService() != nullptr) {
366 napi_value serviceUuid;
367 napi_create_string_utf8(env, descriptor.GetCharacteristic()->GetService()->GetUuid().ToString().c_str(),
368 NAPI_AUTO_LENGTH, &serviceUuid);
369 napi_set_named_property(env, result, "serviceUuid", serviceUuid);
370 }
371 }
372 }
373
SetGattClientDeviceId(const std::string & deviceId)374 void SetGattClientDeviceId(const std::string &deviceId)
375 {
376 deviceAddr = deviceId;
377 }
378
GetGattClientDeviceId()379 std::string GetGattClientDeviceId()
380 {
381 return deviceAddr;
382 }
383
ToNapiValue(napi_env env) const384 napi_value NapiNativeBleCharacteristic::ToNapiValue(napi_env env) const
385 {
386 napi_value object;
387 napi_create_object(env, &object);
388 ConvertBLECharacteristicToJS(env, object, const_cast<GattCharacteristic &>(character_));
389 return object;
390 }
391
ToNapiValue(napi_env env) const392 napi_value NapiNativeBleDescriptor::ToNapiValue(napi_env env) const
393 {
394 napi_value object;
395 napi_create_object(env, &object);
396 ConvertBLEDescriptorToJS(env, object, const_cast<GattDescriptor &>(descriptor_));
397 return object;
398 }
399
ToNapiValue(napi_env env) const400 napi_value NapiNativeGattServiceArray::ToNapiValue(napi_env env) const
401 {
402 napi_value object;
403 napi_create_array(env, &object);
404 ConvertGattServiceVectorToJS(env, object, const_cast<vector<GattService> &>(gattServices_));
405 return object;
406 }
407 } // namespace Bluetooth
408 } // namespace OHOS
409