1 /*
2 * Copyright (C) 2021-2022 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 #include "napi_bluetooth_gatt_client.h"
16 #include <unistd.h>
17 #include "bluetooth_errorcode.h"
18 #include "bluetooth_log.h"
19 #include "napi_bluetooth_error.h"
20 #include "napi_bluetooth_utils.h"
21 #include "napi_bluetooth_host.h"
22 #include "napi_bluetooth_event.h"
23 #include "parser/napi_parser_utils.h"
24
25
26 namespace OHOS {
27 namespace Bluetooth {
28 using namespace std;
29
30 thread_local napi_ref NapiGattClient::consRef_ = nullptr;
31
CheckCreateGattClientDeviceParams(napi_env env,napi_callback_info info,napi_value & outResult)32 static napi_status CheckCreateGattClientDeviceParams(napi_env env, napi_callback_info info, napi_value &outResult)
33 {
34 size_t expectedArgsCount = ARGS_SIZE_ONE;
35 size_t argc = expectedArgsCount;
36 napi_value argv[ARGS_SIZE_ONE] = {0};
37
38 NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
39 NAPI_BT_RETURN_IF(argc != expectedArgsCount, "expect 1 args", napi_invalid_arg);
40
41 std::string deviceId {};
42 if (!ParseString(env, deviceId, argv[0])) {
43 HILOGE("expect string");
44 return napi_string_expected;
45 }
46 if (!IsValidAddress(deviceId)) {
47 HILOGE("Invalid deviceId: %{public}s", deviceId.c_str());
48 return napi_invalid_arg;
49 }
50
51 napi_value constructor = nullptr;
52 NAPI_BT_CALL_RETURN(napi_get_reference_value(env, NapiGattClient::consRef_, &constructor));
53 NAPI_BT_CALL_RETURN(napi_new_instance(env, constructor, argc, argv, &outResult));
54 return napi_ok;
55 }
56
CreateGattClientDevice(napi_env env,napi_callback_info info)57 napi_value NapiGattClient::CreateGattClientDevice(napi_env env, napi_callback_info info)
58 {
59 HILOGI("enter");
60 napi_value result;
61 auto status = CheckCreateGattClientDeviceParams(env, info, result);
62 NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
63 return result;
64 }
65
DefineGattClientJSClass(napi_env env)66 void NapiGattClient::DefineGattClientJSClass(napi_env env)
67 {
68 napi_property_descriptor properties[] = {
69 DECLARE_NAPI_FUNCTION("connect", Connect),
70 DECLARE_NAPI_FUNCTION("disconnect", Disconnect),
71 DECLARE_NAPI_FUNCTION("close", Close),
72 DECLARE_NAPI_FUNCTION("getDeviceName", GetDeviceName),
73 DECLARE_NAPI_FUNCTION("getServices", GetServices),
74 DECLARE_NAPI_FUNCTION("readCharacteristicValue", ReadCharacteristicValue),
75 DECLARE_NAPI_FUNCTION("readDescriptorValue", ReadDescriptorValue),
76 DECLARE_NAPI_FUNCTION("writeCharacteristicValue", WriteCharacteristicValue),
77 DECLARE_NAPI_FUNCTION("writeDescriptorValue", WriteDescriptorValue),
78 DECLARE_NAPI_FUNCTION("getRssiValue", GetRssiValue),
79 DECLARE_NAPI_FUNCTION("setBLEMtuSize", SetBLEMtuSize),
80 DECLARE_NAPI_FUNCTION("setNotifyCharacteristicChanged", SetNotifyCharacteristicChanged),
81 DECLARE_NAPI_FUNCTION("on", On),
82 DECLARE_NAPI_FUNCTION("off", Off),
83 };
84
85 napi_value constructor = nullptr;
86 napi_define_class(env, "GattClientDevice", NAPI_AUTO_LENGTH, GattClientConstructor, nullptr,
87 sizeof(properties) / sizeof(properties[0]), properties, &constructor);
88 napi_create_reference(env, constructor, 1, &consRef_);
89 }
90
GattClientConstructor(napi_env env,napi_callback_info info)91 napi_value NapiGattClient::GattClientConstructor(napi_env env, napi_callback_info info)
92 {
93 HILOGI("enter");
94 napi_value thisVar = nullptr;
95
96 size_t expectedArgsCount = ARGS_SIZE_ONE;
97 size_t argc = expectedArgsCount;
98 napi_value argv[ARGS_SIZE_ONE] = {0};
99
100 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
101
102 string deviceId;
103 ParseString(env, deviceId, argv[PARAM0]);
104 SetGattClientDeviceId(deviceId);
105
106 NapiGattClient *gattClient = new NapiGattClient(deviceId);
107
108 napi_wrap(
109 env, thisVar, gattClient,
110 [](napi_env env, void* data, void* hint) {
111 NapiGattClient* client = (NapiGattClient*)data;
112 if (client) {
113 delete client;
114 client = nullptr;
115 }
116 },
117 nullptr,
118 nullptr);
119
120 return thisVar;
121 }
122
NapiGetGattClient(napi_env env,napi_value thisVar)123 static NapiGattClient *NapiGetGattClient(napi_env env, napi_value thisVar)
124 {
125 NapiGattClient *gattClient = nullptr;
126 auto status = napi_unwrap(env, thisVar, (void **)&gattClient);
127 if (status != napi_ok) {
128 return nullptr;
129 }
130 return gattClient;
131 }
132
GetCharacteristic(const std::shared_ptr<GattClient> & client,const UUID & serviceUuid,const UUID & characterUuid)133 static GattCharacteristic *GetCharacteristic(const std::shared_ptr<GattClient> &client,
134 const UUID &serviceUuid, const UUID &characterUuid)
135 {
136 GattCharacteristic *character = nullptr;
137 if (client) {
138 auto service = client->GetService(serviceUuid);
139 if (service.has_value()) {
140 character = service->get().GetCharacteristic(characterUuid);
141 }
142 }
143 return character;
144 }
145
GetGattcCharacteristic(const std::shared_ptr<GattClient> & client,const NapiBleCharacteristic & napiCharacter)146 static GattCharacteristic *GetGattcCharacteristic(const std::shared_ptr<GattClient> &client,
147 const NapiBleCharacteristic &napiCharacter)
148 {
149 GattCharacteristic *character = GetCharacteristic(client, napiCharacter.serviceUuid,
150 napiCharacter.characteristicUuid);
151 if (character) {
152 character->SetValue(napiCharacter.characteristicValue.data(), napiCharacter.characteristicValue.size());
153 }
154 return character;
155 }
156
GetGattcDescriptor(const std::shared_ptr<GattClient> & client,const NapiBleDescriptor & napiDescriptor)157 static GattDescriptor *GetGattcDescriptor(const std::shared_ptr<GattClient> &client,
158 const NapiBleDescriptor &napiDescriptor)
159 {
160 GattDescriptor *descriptor = nullptr;
161 if (client) {
162 auto *character = GetCharacteristic(client, napiDescriptor.serviceUuid, napiDescriptor.characteristicUuid);
163 if (character == nullptr) {
164 HILOGE("character is nullptr");
165 return nullptr;
166 }
167 descriptor = character->GetDescriptor(napiDescriptor.descriptorUuid);
168 if (descriptor) {
169 descriptor->SetValue(napiDescriptor.descriptorValue.data(), napiDescriptor.descriptorValue.size());
170 }
171 }
172 return descriptor;
173 }
174
CheckGattClientOn(napi_env env,napi_callback_info info)175 napi_status CheckGattClientOn(napi_env env, napi_callback_info info)
176 {
177 size_t argc = ARGS_SIZE_TWO;
178 napi_value argv[ARGS_SIZE_TWO] = {nullptr};
179 napi_value thisVar = nullptr;
180 NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
181 NAPI_BT_RETURN_IF(argc != ARGS_SIZE_TWO, "Requires 2 arguments.", napi_invalid_arg);
182
183 std::string type {};
184 NAPI_BT_CALL_RETURN(NapiParseString(env, argv[PARAM0], type));
185 std::shared_ptr<BluetoothCallbackInfo> callbackInfo {nullptr};
186
187 if (type == STR_BT_GATT_CLIENT_CALLBACK_BLE_CHARACTERISTIC_CHANGE) {
188 callbackInfo = std::make_shared<GattCharacteristicCallbackInfo>();
189 } else {
190 callbackInfo = std::make_shared<BluetoothCallbackInfo>();
191 }
192 callbackInfo->env_ = env;
193
194 auto gattClient = NapiGetGattClient(env, thisVar);
195 NAPI_BT_RETURN_IF(gattClient == nullptr, "gattClient is nullptr.", napi_invalid_arg);
196
197 NAPI_BT_CALL_RETURN(NapiIsFunction(env, argv[PARAM1]));
198 std::unique_lock<std::shared_mutex> guard(NapiGattClientCallback::g_gattClientCallbackInfosMutex);
199 NAPI_BT_CALL_RETURN(napi_create_reference(env, argv[PARAM1], 1, &callbackInfo->callback_));
200 gattClient->GetCallback().SetCallbackInfo(type, callbackInfo);
201 HILOGI("%{public}s is registered", type.c_str());
202 return napi_ok;
203 }
204
On(napi_env env,napi_callback_info info)205 napi_value NapiGattClient::On(napi_env env, napi_callback_info info)
206 {
207 HILOGI("enter");
208 auto status = CheckGattClientOn(env, info);
209 NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
210 return NapiGetUndefinedRet(env);
211 }
212
CheckGattClientOff(napi_env env,napi_callback_info info)213 napi_status CheckGattClientOff(napi_env env, napi_callback_info info)
214 {
215 size_t argc = ARGS_SIZE_TWO;
216 napi_value argv[ARGS_SIZE_TWO] = {nullptr}; // argv[PARAM1] is not used.
217 napi_value thisVar = nullptr;
218 NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
219 NAPI_BT_RETURN_IF(argc != ARGS_SIZE_ONE && argc != ARGS_SIZE_TWO, "Requires 1 or 2 arguments.", napi_invalid_arg);
220
221 std::string type {};
222 NAPI_BT_CALL_RETURN(NapiParseString(env, argv[PARAM0], type));
223
224 auto gattClient = NapiGetGattClient(env, thisVar);
225 NAPI_BT_RETURN_IF(gattClient == nullptr, "gattClient is nullptr.", napi_invalid_arg);
226 // callback_ need unref before, see napi_bluetooth_gatt_client
227 std::unique_lock<std::shared_mutex> guard(NapiGattClientCallback::g_gattClientCallbackInfosMutex);
228 auto &gattClientCallback = gattClient->GetCallback();
229 uint32_t refCount = INVALID_REF_COUNT;
230 NAPI_BT_CALL_RETURN(napi_reference_unref(env, gattClientCallback.GetCallbackInfo(type)->callback_, &refCount));
231 HILOGI("decrements the refernce count, refCount: %{public}d", refCount);
232 if (refCount == 0) {
233 NAPI_BT_CALL_RETURN(napi_delete_reference(env, gattClientCallback.GetCallbackInfo(type)->callback_));
234 }
235 gattClientCallback.SetCallbackInfo(type, nullptr);
236 HILOGI("%{public}s is removed", type.c_str());
237 return napi_ok;
238 }
239
Off(napi_env env,napi_callback_info info)240 napi_value NapiGattClient::Off(napi_env env, napi_callback_info info)
241 {
242 HILOGI("enter");
243 auto status = CheckGattClientOff(env, info);
244 NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
245 return NapiGetUndefinedRet(env);
246 }
247
CheckGattClientNoArgc(napi_env env,napi_callback_info info,NapiGattClient ** outGattClient)248 static napi_status CheckGattClientNoArgc(napi_env env, napi_callback_info info, NapiGattClient **outGattClient)
249 {
250 size_t argc = 0;
251 napi_value thisVar = nullptr;
252 NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, nullptr, &thisVar, nullptr));
253 NAPI_BT_RETURN_IF(argc != 0, "No need arguments.", napi_invalid_arg);
254 NapiGattClient *gattClient = NapiGetGattClient(env, thisVar);
255 NAPI_BT_RETURN_IF(gattClient == nullptr || outGattClient == nullptr, "gattClient is nullptr.", napi_invalid_arg);
256
257 *outGattClient = gattClient;
258 return napi_ok;
259 }
260
Connect(napi_env env,napi_callback_info info)261 napi_value NapiGattClient::Connect(napi_env env, napi_callback_info info)
262 {
263 HILOGI("enter");
264 NapiGattClient *gattClient = nullptr;
265 auto status = CheckGattClientNoArgc(env, info, &gattClient);
266 NAPI_BT_ASSERT_RETURN_FALSE(env, status == napi_ok, BT_ERR_INVALID_PARAM);
267
268 std::shared_ptr<GattClient> client = gattClient->GetClient();
269 NAPI_BT_ASSERT_RETURN_FALSE(env, client != nullptr, BT_ERR_INTERNAL_ERROR);
270
271 int ret = client->Connect(gattClient->GetCallback(), true, GATT_TRANSPORT_TYPE_LE);
272 HILOGI("ret: %{public}d", ret);
273 NAPI_BT_ASSERT_RETURN_FALSE(env, ret == BT_SUCCESS, ret);
274 return NapiGetBooleanTrue(env);
275 }
276
Disconnect(napi_env env,napi_callback_info info)277 napi_value NapiGattClient::Disconnect(napi_env env, napi_callback_info info)
278 {
279 HILOGI("enter");
280 NapiGattClient* gattClient = nullptr;
281 auto status = CheckGattClientNoArgc(env, info, &gattClient);
282 NAPI_BT_ASSERT_RETURN_FALSE(env, status == napi_ok, BT_ERR_INVALID_PARAM);
283
284 std::shared_ptr<GattClient> client = gattClient->GetClient();
285 NAPI_BT_ASSERT_RETURN_FALSE(env, client != nullptr, BT_ERR_INTERNAL_ERROR);
286
287 int ret = client->Disconnect();
288 HILOGI("ret: %{public}d", ret);
289 NAPI_BT_ASSERT_RETURN_FALSE(env, ret == BT_SUCCESS, ret);
290 return NapiGetBooleanTrue(env);
291 }
292
ParseGattClientReadCharacteristicValue(napi_env env,napi_callback_info info,ReadCharacteristicValueCallbackInfo ** outCallbackInfo,napi_value & promise)293 static napi_status ParseGattClientReadCharacteristicValue(napi_env env, napi_callback_info info,
294 ReadCharacteristicValueCallbackInfo **outCallbackInfo, napi_value &promise)
295 {
296 size_t expectedArgsCount = ARGS_SIZE_TWO;
297 size_t argc = expectedArgsCount;
298 napi_value argv[ARGS_SIZE_TWO] = {0};
299 napi_value thisVar = nullptr;
300 NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
301 NAPI_BT_RETURN_IF(argc != expectedArgsCount && argc != expectedArgsCount - CALLBACK_SIZE,
302 "Requires 1 or 2 arguments.", napi_invalid_arg);
303 NapiGattClient *gattClient = NapiGetGattClient(env, thisVar);
304 NAPI_BT_RETURN_IF(gattClient == nullptr, "gattClient is nullptr.", napi_invalid_arg);
305
306 ReadCharacteristicValueCallbackInfo* callbackInfo = new ReadCharacteristicValueCallbackInfo();
307 gattClient->readCharacteristicValueCallbackInfo_ = callbackInfo;
308 callbackInfo->env_ = env;
309 callbackInfo->client_ = gattClient->GetClient();
310
311 NapiBleCharacteristic napiCharacter;
312 NAPI_BT_CALL_RETURN(NapiParseGattCharacteristic(env, argv[PARAM0], napiCharacter));
313 GattCharacteristic *character = GetGattcCharacteristic(gattClient->GetClient(), napiCharacter);
314 NAPI_BT_RETURN_IF(character == nullptr, "Not found character", napi_invalid_arg);
315 callbackInfo->inputCharacteristic_ = character;
316
317 *outCallbackInfo = callbackInfo;
318
319 if (argc == expectedArgsCount) {
320 // Callback mode
321 HILOGI("callback mode");
322 NAPI_BT_CALL_RETURN(NapiIsFunction(env, argv[PARAM1]));
323 NAPI_BT_CALL_RETURN(napi_create_reference(env, argv[PARAM1], 1, &callbackInfo->callback_));
324 napi_get_undefined(env, &promise);
325 } else {
326 // Promise mode
327 HILOGI("promise mode");
328 napi_create_promise(env, &callbackInfo->deferred_, &promise);
329 }
330 return napi_ok;
331 }
332
ReadCharacteristicValue(napi_env env,napi_callback_info info)333 napi_value NapiGattClient::ReadCharacteristicValue(napi_env env, napi_callback_info info)
334 {
335 HILOGI("enter");
336
337 ReadCharacteristicValueCallbackInfo *callbackInfo = nullptr;
338 napi_value promise = nullptr;
339
340 auto status = ParseGattClientReadCharacteristicValue(env, info, &callbackInfo, promise);
341 NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
342
343 napi_value resource = nullptr;
344 napi_create_string_utf8(env, "readCharacteristicValue", NAPI_AUTO_LENGTH, &resource);
345
346 napi_create_async_work(
347 env,
348 nullptr,
349 resource,
350 [](napi_env env, void *data) {
351 HILOGI("ReadCharacteristicValue(): execute");
352 ReadCharacteristicValueCallbackInfo* callbackInfo = (ReadCharacteristicValueCallbackInfo*)data;
353 callbackInfo->asyncState_ = ASYNC_START;
354 int status = -1;
355 if (callbackInfo->inputCharacteristic_ != nullptr) {
356 HILOGI("ReadCharacteristicValue(): Client read characteristic");
357 status = callbackInfo->client_->ReadCharacteristic(*(callbackInfo->inputCharacteristic_));
358 }
359
360 if (status == BT_SUCCESS) {
361 HILOGI("ReadCharacteristicValue(): successful");
362 callbackInfo->errorCode_ = CODE_SUCCESS;
363 int tryTime = 100;
364 while (callbackInfo->asyncState_ == ASYNC_START && tryTime > 0) {
365 usleep(SLEEP_TIME);
366 if (callbackInfo->asyncState_ == ASYNC_DONE) {
367 break;
368 }
369 tryTime--;
370 }
371 if (callbackInfo->asyncState_ != ASYNC_DONE) {
372 HILOGE("ReadCharacteristicValue(): failed, async not done");
373 callbackInfo->errorCode_ = CODE_FAILED;
374 }
375 } else {
376 HILOGE("ReadCharacteristicValue(): failed, status: %{public}d", status);
377 callbackInfo->errorCode_ = CODE_FAILED;
378 }
379 },
380 [](napi_env env, napi_status status, void *data) {
381 HILOGI("ReadCharacteristicValue(): execute back");
382 ReadCharacteristicValueCallbackInfo* callbackInfo = (ReadCharacteristicValueCallbackInfo*)data;
383 napi_value result[ARGS_SIZE_TWO] = {0};
384 napi_value callback = 0;
385 napi_value undefined = 0;
386 napi_value callResult = 0;
387 napi_get_undefined(env, &undefined);
388
389 HILOGI("ReadCharacteristicValue(): errorCode: %{public}d", callbackInfo->errorCode_);
390 if (callbackInfo->errorCode_ == BT_SUCCESS) {
391 napi_create_object(env, &result[PARAM1]);
392 ConvertBLECharacteristicToJS(env, result[PARAM1],
393 const_cast<GattCharacteristic&>(*(callbackInfo->outputCharacteristic_)));
394 } else {
395 napi_get_undefined(env, &result[PARAM1]);
396 }
397
398 if (callbackInfo->callback_) {
399 // Callback mode
400 result[PARAM0] = GetCallbackErrorValue(callbackInfo->env_, callbackInfo->errorCode_);
401 napi_get_reference_value(env, callbackInfo->callback_, &callback);
402 napi_call_function(env, undefined, callback, ARGS_SIZE_TWO, result, &callResult);
403 napi_delete_reference(env, callbackInfo->callback_);
404 } else {
405 if (callbackInfo->errorCode_ == CODE_SUCCESS) {
406 // Promise mode
407 napi_resolve_deferred(env, callbackInfo->deferred_, result[PARAM1]);
408 } else {
409 napi_reject_deferred(env, callbackInfo->deferred_, result[PARAM1]);
410 }
411 }
412 napi_delete_async_work(env, callbackInfo->asyncWork_);
413 delete callbackInfo;
414 callbackInfo = nullptr;
415 },
416 (void*)callbackInfo,
417 &callbackInfo->asyncWork_);
418 napi_queue_async_work(env, callbackInfo->asyncWork_);
419 return promise;
420 }
421
ParseGattClientReadDescriptorValue(napi_env env,napi_callback_info info,ReadDescriptorValueCallbackInfo ** outCallbackInfo,napi_value & promise)422 static napi_status ParseGattClientReadDescriptorValue(napi_env env, napi_callback_info info,
423 ReadDescriptorValueCallbackInfo **outCallbackInfo, napi_value &promise)
424 {
425 size_t expectedArgsCount = ARGS_SIZE_TWO;
426 size_t argc = expectedArgsCount;
427 napi_value argv[ARGS_SIZE_TWO] = {0};
428 napi_value thisVar = nullptr;
429 NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
430 NAPI_BT_RETURN_IF(argc != expectedArgsCount && argc != expectedArgsCount - CALLBACK_SIZE,
431 "Requires 1 or 2 arguments.", napi_invalid_arg);
432 NapiGattClient *gattClient = NapiGetGattClient(env, thisVar);
433 NAPI_BT_RETURN_IF(gattClient == nullptr, "gattClient is nullptr.", napi_invalid_arg);
434
435 ReadDescriptorValueCallbackInfo *callbackInfo = new ReadDescriptorValueCallbackInfo();
436 gattClient->readDescriptorValueCallbackInfo_ = callbackInfo;
437 callbackInfo->env_ = env;
438 callbackInfo->client_ = gattClient->GetClient();
439
440 NapiBleDescriptor napiDescriptor;
441 NAPI_BT_CALL_RETURN(NapiParseGattDescriptor(env, argv[PARAM0], napiDescriptor));
442 GattDescriptor *descriptor = GetGattcDescriptor(gattClient->GetClient(), napiDescriptor);
443 NAPI_BT_RETURN_IF(descriptor == nullptr, "Not found Descriptor", napi_invalid_arg);
444 callbackInfo->inputDescriptor_ = descriptor;
445
446 *outCallbackInfo = callbackInfo;
447
448 if (argc == expectedArgsCount) {
449 // Callback mode
450 HILOGI("callback mode");
451 NAPI_BT_CALL_RETURN(NapiIsFunction(env, argv[PARAM1]));
452 NAPI_BT_CALL_RETURN(napi_create_reference(env, argv[PARAM1], 1, &callbackInfo->callback_));
453 napi_get_undefined(env, &promise);
454 } else {
455 // Promise mode
456 HILOGI("promise mode");
457 napi_create_promise(env, &callbackInfo->deferred_, &promise);
458 }
459 return napi_ok;
460 }
461
ReadDescriptorValue(napi_env env,napi_callback_info info)462 napi_value NapiGattClient::ReadDescriptorValue(napi_env env, napi_callback_info info)
463 {
464 HILOGI("enter");
465
466 ReadDescriptorValueCallbackInfo *callbackInfo = nullptr;
467 napi_value promise = nullptr;
468
469 auto status = ParseGattClientReadDescriptorValue(env, info, &callbackInfo, promise);
470 NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
471
472 napi_value resource = nullptr;
473 napi_create_string_utf8(env, "readDescriptorValue", NAPI_AUTO_LENGTH, &resource);
474
475 napi_create_async_work(
476 env, nullptr, resource,
477 [](napi_env env, void* data) {
478 HILOGI("ReadDescriptorValue(): execute");
479 ReadDescriptorValueCallbackInfo* callbackInfo = (ReadDescriptorValueCallbackInfo*)data;
480 callbackInfo->asyncState_ = ASYNC_START;
481 int status = -1;
482 if (callbackInfo->inputDescriptor_ != nullptr) {
483 HILOGI("ReadDescriptorValue(): Client read descriptor");
484 status = callbackInfo->client_->ReadDescriptor(*(callbackInfo->inputDescriptor_));
485 } else {
486 HILOGI("callbackInfo->inputDescriptor_ is nullptr");
487 }
488
489 if (status == GattStatus::GATT_SUCCESS) {
490 HILOGI("ReadDescriptorValue(): successful");
491 callbackInfo->errorCode_ = CODE_SUCCESS;
492 int tryTime = 100;
493 while (callbackInfo->asyncState_ == ASYNC_START && tryTime > 0) {
494 usleep(SLEEP_TIME);
495 if (callbackInfo->asyncState_ == ASYNC_DONE) {
496 break;
497 }
498 tryTime--;
499 }
500 if (callbackInfo->asyncState_ != ASYNC_DONE) {
501 HILOGE("ReadDescriptorValue(): failed, async not done");
502 callbackInfo->errorCode_ = CODE_FAILED;
503 }
504 } else {
505 HILOGE("ReadDescriptorValue(): failed, status: %{public}d", status);
506 callbackInfo->errorCode_ = CODE_FAILED;
507 }
508 },
509 [](napi_env env, napi_status status, void* data) {
510 HILOGI("ReadDescriptorValue(): execute back");
511 ReadDescriptorValueCallbackInfo* callbackInfo = (ReadDescriptorValueCallbackInfo*)data;
512 napi_value result[ARGS_SIZE_TWO] = {0};
513 napi_value callback = 0;
514 napi_value undefined = 0;
515 napi_value callResult = 0;
516 napi_get_undefined(env, &undefined);
517
518 HILOGI("ReadDescriptorValue(): errorCode: %{public}d", callbackInfo->errorCode_);
519 if (callbackInfo->errorCode_ == CODE_SUCCESS) {
520 napi_create_object(env, &result[PARAM1]);
521 ConvertBLEDescriptorToJS(env, result[PARAM1],
522 const_cast<GattDescriptor&>(*(callbackInfo->outputDescriptor_)));
523 } else {
524 napi_get_undefined(env, &result[PARAM1]);
525 }
526
527 if (callbackInfo->callback_) {
528 // Callback mode
529 result[PARAM0] = GetCallbackErrorValue(callbackInfo->env_, callbackInfo->errorCode_);
530 napi_get_reference_value(env, callbackInfo->callback_, &callback);
531 napi_call_function(env, undefined, callback, ARGS_SIZE_TWO, result, &callResult);
532 napi_delete_reference(env, callbackInfo->callback_);
533 } else {
534 if (callbackInfo->errorCode_ == CODE_SUCCESS) {
535 // Promise mode
536 napi_resolve_deferred(env, callbackInfo->deferred_, result[PARAM1]);
537 } else {
538 napi_reject_deferred(env, callbackInfo->deferred_, result[PARAM1]);
539 }
540 }
541 napi_delete_async_work(env, callbackInfo->asyncWork_);
542 delete callbackInfo;
543 callbackInfo = nullptr;
544 },
545 (void*)callbackInfo,
546 &callbackInfo->asyncWork_);
547
548 napi_queue_async_work(env, callbackInfo->asyncWork_);
549 return promise;
550 }
551
ParseGattClientAsyncCallback(napi_env env,napi_callback_info info,GetServiceCallbackInfo * callbackInfo,napi_value & promise)552 static napi_status ParseGattClientAsyncCallback(napi_env env, napi_callback_info info,
553 GetServiceCallbackInfo *callbackInfo, napi_value &promise)
554 {
555 size_t expectedArgsCount = ARGS_SIZE_ONE;
556 size_t argc = expectedArgsCount;
557 napi_value argv[ARGS_SIZE_ONE] = {0};
558 napi_value thisVar = nullptr;
559 NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
560 NAPI_BT_RETURN_IF(argc != expectedArgsCount && argc != expectedArgsCount - CALLBACK_SIZE,
561 "Requires 0 or 1 arguments.", napi_invalid_arg);
562 NapiGattClient *gattClient = NapiGetGattClient(env, thisVar);
563 NAPI_BT_RETURN_IF(gattClient == nullptr, "gattClient is nullptr.", napi_invalid_arg);
564 callbackInfo->client_ = gattClient->GetClient();
565
566 if (argc == expectedArgsCount) {
567 // Callback mode
568 HILOGI("callback mode");
569 NAPI_BT_CALL_RETURN(NapiIsFunction(env, argv[PARAM0]));
570 napi_create_reference(env, argv[PARAM0], 1, &callbackInfo->callback_);
571 napi_get_undefined(env, &promise);
572 } else {
573 // Promise mode
574 HILOGI("promise mode");
575 napi_create_promise(env, &callbackInfo->deferred_, &promise);
576 }
577 return napi_ok;
578 }
579
GetServices(napi_env env,napi_callback_info info)580 napi_value NapiGattClient::GetServices(napi_env env, napi_callback_info info)
581 {
582 HILOGI("enter");
583
584 GetServiceCallbackInfo *callbackInfo = new GetServiceCallbackInfo();
585 callbackInfo->env_ = env;
586 napi_value promise = nullptr;
587
588 auto status = ParseGattClientAsyncCallback(env, info, callbackInfo, promise);
589 NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
590
591 napi_value resource = nullptr;
592 napi_create_string_utf8(env, "getServices", NAPI_AUTO_LENGTH, &resource);
593
594 napi_create_async_work(
595 env, nullptr, resource,
596 [](napi_env env, void* data) {
597 HILOGI("GetServices(): execute");
598 GetServiceCallbackInfo* callbackInfo = (GetServiceCallbackInfo*)data;
599 int status = callbackInfo->client_->DiscoverServices();
600 if (status != BT_SUCCESS) {
601 HILOGE("GetServices(): failed, status: %{public}d", status);
602 callbackInfo->errorCode_ = CODE_FAILED;
603 } else {
604 HILOGI("GetServices(): successful");
605 callbackInfo->services_ = callbackInfo->client_->GetService();
606 callbackInfo->errorCode_ = CODE_SUCCESS;
607 }
608 },
609 [](napi_env env, napi_status status, void* data) {
610 HILOGI("GetServices(): execute back");
611 GetServiceCallbackInfo* callbackInfo = (GetServiceCallbackInfo*)data;
612 napi_value result[ARGS_SIZE_TWO] = {0};
613 napi_value callback = 0;
614 napi_value undefined = 0;
615 napi_value callResult = 0;
616 napi_get_undefined(env, &undefined);
617
618 HILOGI("GetServices(): errorCode: %{public}d", callbackInfo->errorCode_);
619 if (callbackInfo->errorCode_ == CODE_SUCCESS) {
620 napi_create_array(env, &result[PARAM1]);
621 ConvertGattServiceVectorToJS(env, result[PARAM1], callbackInfo->services_);
622 } else {
623 napi_get_undefined(env, &result[PARAM1]);
624 }
625
626 if (callbackInfo->callback_) {
627 // Callback mode
628 result[PARAM0] = GetCallbackErrorValue(callbackInfo->env_, callbackInfo->errorCode_);
629 napi_get_reference_value(env, callbackInfo->callback_, &callback);
630 napi_call_function(env, undefined, callback, ARGS_SIZE_TWO, result, &callResult);
631 napi_delete_reference(env, callbackInfo->callback_);
632 } else {
633 if (callbackInfo->errorCode_ == CODE_SUCCESS) {
634 // Promise mode
635 napi_resolve_deferred(env, callbackInfo->deferred_, result[PARAM1]);
636 } else {
637 napi_reject_deferred(env, callbackInfo->deferred_, result[PARAM1]);
638 }
639 }
640 napi_delete_async_work(env, callbackInfo->asyncWork_);
641 delete callbackInfo;
642 callbackInfo = nullptr;
643 },
644 (void *)callbackInfo,
645 &callbackInfo->asyncWork_);
646
647 napi_queue_async_work(env, callbackInfo->asyncWork_);
648 return promise;
649 }
650
Close(napi_env env,napi_callback_info info)651 napi_value NapiGattClient::Close(napi_env env, napi_callback_info info)
652 {
653 HILOGI("enter");
654 NapiGattClient* gattClient = nullptr;
655 auto status = CheckGattClientNoArgc(env, info, &gattClient);
656 NAPI_BT_ASSERT_RETURN_FALSE(env, status == napi_ok, BT_ERR_INVALID_PARAM);
657
658 std::shared_ptr<GattClient> client = gattClient->GetClient();
659 NAPI_BT_ASSERT_RETURN_FALSE(env, client != nullptr, BT_ERR_INTERNAL_ERROR);
660
661 int ret = client->Close();
662 HILOGI("ret: %{public}d", ret);
663 NAPI_BT_ASSERT_RETURN_FALSE(env, ret == BT_SUCCESS, ret);
664 return NapiGetBooleanTrue(env);
665 }
666
CheckWriteCharacteristicValue(napi_env env,napi_callback_info info,GattCharacteristic ** outCharacteristic,NapiGattClient ** outGattClient)667 static napi_status CheckWriteCharacteristicValue(napi_env env, napi_callback_info info,
668 GattCharacteristic **outCharacteristic, NapiGattClient **outGattClient)
669 {
670 size_t expectedArgsCount = ARGS_SIZE_ONE;
671 size_t argc = expectedArgsCount;
672 napi_value argv[ARGS_SIZE_ONE] = {0};
673 napi_value thisVar = nullptr;
674 NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
675 NAPI_BT_RETURN_IF(argc != expectedArgsCount, "Requires 1 arguments.", napi_invalid_arg);
676 NapiGattClient *gattClient = NapiGetGattClient(env, thisVar);
677 NAPI_BT_RETURN_IF(gattClient == nullptr || outGattClient == nullptr, "gattClient is nullptr.", napi_invalid_arg);
678
679 NapiBleCharacteristic napiCharacter;
680 NAPI_BT_CALL_RETURN(NapiParseGattCharacteristic(env, argv[PARAM0], napiCharacter));
681 GattCharacteristic *character = GetGattcCharacteristic(gattClient->GetClient(), napiCharacter);
682 NAPI_BT_RETURN_IF(character == nullptr, "Not found character", napi_invalid_arg);
683
684 *outGattClient = gattClient;
685 *outCharacteristic = character;
686
687 return napi_ok;
688 }
689
WriteCharacteristicValue(napi_env env,napi_callback_info info)690 napi_value NapiGattClient::WriteCharacteristicValue(napi_env env, napi_callback_info info)
691 {
692 HILOGI("enter");
693 GattCharacteristic* characteristic = nullptr;
694 NapiGattClient* gattClient = nullptr;
695
696 auto status = CheckWriteCharacteristicValue(env, info, &characteristic, &gattClient);
697 NAPI_BT_ASSERT_RETURN_FALSE(env, status == napi_ok, BT_ERR_INVALID_PARAM);
698 std::shared_ptr<GattClient> client = gattClient->GetClient();
699 NAPI_BT_ASSERT_RETURN_FALSE(env, client != nullptr, BT_ERR_INTERNAL_ERROR);
700 int ret = client->WriteCharacteristic(*characteristic);
701 HILOGI("ret: %{public}d", ret);
702 NAPI_BT_ASSERT_RETURN_FALSE(env, ret == BT_SUCCESS, ret);
703 return NapiGetBooleanTrue(env);
704 }
705
CheckWriteDescriptorValue(napi_env env,napi_callback_info info,GattDescriptor ** outDescriptor,NapiGattClient ** outGattClient)706 static napi_status CheckWriteDescriptorValue(napi_env env, napi_callback_info info,
707 GattDescriptor **outDescriptor, NapiGattClient **outGattClient)
708 {
709 size_t expectedArgsCount = ARGS_SIZE_ONE;
710 size_t argc = expectedArgsCount;
711 napi_value argv[ARGS_SIZE_ONE] = {0};
712 napi_value thisVar = nullptr;
713 NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
714 NAPI_BT_RETURN_IF(argc != expectedArgsCount, "Requires 1 arguments.", napi_invalid_arg);
715 NapiGattClient *gattClient = NapiGetGattClient(env, thisVar);
716 NAPI_BT_RETURN_IF(gattClient == nullptr || outGattClient == nullptr, "gattClient is nullptr.", napi_invalid_arg);
717
718 NapiBleDescriptor napiDescriptor;
719 NAPI_BT_CALL_RETURN(NapiParseGattDescriptor(env, argv[PARAM0], napiDescriptor));
720 GattDescriptor *descriptor = GetGattcDescriptor(gattClient->GetClient(), napiDescriptor);
721 NAPI_BT_RETURN_IF(descriptor == nullptr, "Not found Descriptor", napi_invalid_arg);
722
723 *outGattClient = gattClient;
724 *outDescriptor = descriptor;
725 return napi_ok;
726 }
727
WriteDescriptorValue(napi_env env,napi_callback_info info)728 napi_value NapiGattClient::WriteDescriptorValue(napi_env env, napi_callback_info info)
729 {
730 HILOGI("enter");
731 GattDescriptor* descriptor = nullptr;
732 NapiGattClient* gattClient = nullptr;
733
734 auto status = CheckWriteDescriptorValue(env, info, &descriptor, &gattClient);
735 NAPI_BT_ASSERT_RETURN_FALSE(env, status == napi_ok, BT_ERR_INVALID_PARAM);
736
737 std::shared_ptr<GattClient> client = gattClient->GetClient();
738 NAPI_BT_ASSERT_RETURN_FALSE(env, client != nullptr, BT_ERR_INTERNAL_ERROR);
739
740 int ret = client->WriteDescriptor(*descriptor);
741 HILOGI("ret: %{public}d", ret);
742 NAPI_BT_ASSERT_RETURN_FALSE(env, ret == BT_SUCCESS, ret);
743 return NapiGetBooleanTrue(env);
744 }
745
CheckSetBLEMtuSize(napi_env env,napi_callback_info info,int32_t & mtuSize,NapiGattClient ** outGattClient)746 static napi_status CheckSetBLEMtuSize(napi_env env, napi_callback_info info,
747 int32_t &mtuSize, NapiGattClient **outGattClient)
748 {
749 size_t expectedArgsCount = ARGS_SIZE_ONE;
750 size_t argc = expectedArgsCount;
751 napi_value argv[ARGS_SIZE_ONE] = {0};
752 napi_value thisVar = nullptr;
753 NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
754 NAPI_BT_RETURN_IF(argc != expectedArgsCount, "Requires 1 arguments.", napi_invalid_arg);
755 NapiGattClient *gattClient = NapiGetGattClient(env, thisVar);
756 NAPI_BT_RETURN_IF(gattClient == nullptr || outGattClient == nullptr, "gattClient is nullptr.", napi_invalid_arg);
757
758 NAPI_BT_CALL_RETURN(NapiParseInt32(env, argv[PARAM0], mtuSize));
759 *outGattClient = gattClient;
760
761 return napi_ok;
762 }
763
SetBLEMtuSize(napi_env env,napi_callback_info info)764 napi_value NapiGattClient::SetBLEMtuSize(napi_env env, napi_callback_info info)
765 {
766 HILOGI("enter");
767 NapiGattClient* gattClient = nullptr;
768 int32_t mtuSize = 0;
769
770 auto status = CheckSetBLEMtuSize(env, info, mtuSize, &gattClient);
771 NAPI_BT_ASSERT_RETURN_FALSE(env, status == napi_ok, BT_ERR_INVALID_PARAM);
772
773 std::shared_ptr<GattClient> client = gattClient->GetClient();
774 NAPI_BT_ASSERT_RETURN_FALSE(env, client != nullptr, BT_ERR_INTERNAL_ERROR);
775
776 int ret = client->RequestBleMtuSize(mtuSize);
777 HILOGI("ret: %{public}d", ret);
778 NAPI_BT_ASSERT_RETURN_FALSE(env, ret == BT_SUCCESS, ret);
779 return NapiGetBooleanTrue(env);
780 }
781
CheckSetNotifyCharacteristicChanged(napi_env env,napi_callback_info info,GattCharacteristic ** outCharacteristic,bool & enableNotify,NapiGattClient ** outGattClient)782 static napi_status CheckSetNotifyCharacteristicChanged(napi_env env, napi_callback_info info,
783 GattCharacteristic **outCharacteristic, bool &enableNotify, NapiGattClient **outGattClient)
784 {
785 size_t expectedArgsCount = ARGS_SIZE_TWO;
786 size_t argc = expectedArgsCount;
787 napi_value argv[ARGS_SIZE_TWO] = {0};
788 napi_value thisVar = nullptr;
789 NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
790 NAPI_BT_RETURN_IF(argc != expectedArgsCount, "Requires 2 arguments.", napi_invalid_arg);
791 NapiGattClient *gattClient = NapiGetGattClient(env, thisVar);
792 NAPI_BT_RETURN_IF(gattClient == nullptr || outGattClient == nullptr, "gattClient is nullptr.", napi_invalid_arg);
793
794 NapiBleCharacteristic napiCharacter;
795 NAPI_BT_CALL_RETURN(NapiParseGattCharacteristic(env, argv[PARAM0], napiCharacter));
796 GattCharacteristic *character = GetGattcCharacteristic(gattClient->GetClient(), napiCharacter);
797 NAPI_BT_RETURN_IF(character == nullptr, "Not found character", napi_invalid_arg);
798
799 NAPI_BT_CALL_RETURN(NapiParseBoolean(env, argv[PARAM1], enableNotify));
800 *outGattClient = gattClient;
801 *outCharacteristic = character;
802 return napi_ok;
803 }
804
SetNotifyCharacteristicChanged(napi_env env,napi_callback_info info)805 napi_value NapiGattClient::SetNotifyCharacteristicChanged(napi_env env, napi_callback_info info)
806 {
807 HILOGI("enter");
808 GattCharacteristic* characteristic = nullptr;
809 bool enableNotify = false;
810 NapiGattClient* gattClient = nullptr;
811
812 auto status = CheckSetNotifyCharacteristicChanged(env, info, &characteristic, enableNotify, &gattClient);
813 NAPI_BT_ASSERT_RETURN_FALSE(env, status == napi_ok, BT_ERR_INVALID_PARAM);
814
815 std::shared_ptr<GattClient> client = gattClient->GetClient();
816 NAPI_BT_ASSERT_RETURN_FALSE(env, client != nullptr, BT_ERR_INTERNAL_ERROR);
817
818 int ret = client->SetNotifyCharacteristic(*characteristic, enableNotify);
819 HILOGI("ret: %{public}d", ret);
820 NAPI_BT_ASSERT_RETURN_FALSE(env, ret == BT_SUCCESS, ret);
821 return NapiGetBooleanTrue(env);
822 }
823 } // namespace Bluetooth
824 } // namespace OHOS
825