• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "napi_bluetooth_gatt_client.h"
16 #include <unistd.h>
17 #include "bluetooth_errorcode.h"
18 #include "bluetooth_host.h"
19 #include "bluetooth_log.h"
20 #include "napi_async_callback.h"
21 #include "napi_bluetooth_ble_utils.h"
22 #include "napi_bluetooth_error.h"
23 #include "napi_bluetooth_event.h"
24 #include "napi_bluetooth_host.h"
25 #include "napi_bluetooth_utils.h"
26 #include "../parser/napi_parser_utils.h"
27 
28 
29 namespace OHOS {
30 namespace Bluetooth {
31 using namespace std;
32 
33 thread_local napi_ref NapiGattClient::consRef_ = nullptr;
34 
CheckCreateGattClientDeviceParams(napi_env env,napi_callback_info info,napi_value & outResult)35 static napi_status CheckCreateGattClientDeviceParams(napi_env env, napi_callback_info info, napi_value &outResult)
36 {
37     size_t expectedArgsCount = ARGS_SIZE_ONE;
38     size_t argc = expectedArgsCount;
39     napi_value argv[ARGS_SIZE_ONE] = {0};
40 
41     NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
42     NAPI_BT_RETURN_IF(argc != expectedArgsCount, "expect 1 args", napi_invalid_arg);
43 
44     std::string deviceId {};
45     if (!ParseString(env, deviceId, argv[0])) {
46         HILOGE("expect string");
47         return napi_string_expected;
48     }
49     if (!IsValidAddress(deviceId)) {
50         HILOGE("Invalid deviceId: %{public}s", deviceId.c_str());
51         return napi_invalid_arg;
52     }
53 
54     napi_value constructor = nullptr;
55     NAPI_BT_CALL_RETURN(napi_get_reference_value(env, NapiGattClient::consRef_, &constructor));
56     NAPI_BT_CALL_RETURN(napi_new_instance(env, constructor, argc, argv, &outResult));
57     return napi_ok;
58 }
59 
CreateGattClientDevice(napi_env env,napi_callback_info info)60 napi_value NapiGattClient::CreateGattClientDevice(napi_env env, napi_callback_info info)
61 {
62     HILOGI("enter");
63     napi_value result;
64     auto status = CheckCreateGattClientDeviceParams(env, info, result);
65     NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
66     return result;
67 }
68 
DefineGattClientJSClass(napi_env env)69 void NapiGattClient::DefineGattClientJSClass(napi_env env)
70 {
71     napi_property_descriptor properties[] = {
72         DECLARE_NAPI_FUNCTION("connect", Connect),
73         DECLARE_NAPI_FUNCTION("disconnect", Disconnect),
74         DECLARE_NAPI_FUNCTION("close", Close),
75         DECLARE_NAPI_FUNCTION("getDeviceName", GetDeviceName),
76         DECLARE_NAPI_FUNCTION("getServices", GetServices),
77         DECLARE_NAPI_FUNCTION("readCharacteristicValue", ReadCharacteristicValue),
78         DECLARE_NAPI_FUNCTION("readDescriptorValue", ReadDescriptorValue),
79         DECLARE_NAPI_FUNCTION("getRssiValue", GetRssiValue),
80         DECLARE_NAPI_FUNCTION("setBLEMtuSize", SetBLEMtuSize),
81         DECLARE_NAPI_FUNCTION("on", On),
82         DECLARE_NAPI_FUNCTION("off", Off),
83 #ifdef BLUETOOTH_API_SINCE_10
84         DECLARE_NAPI_FUNCTION("writeCharacteristicValue", WriteCharacteristicValueEx),
85         DECLARE_NAPI_FUNCTION("writeDescriptorValue", WriteDescriptorValueEx),
86         DECLARE_NAPI_FUNCTION("setCharacteristicChangeNotification", setCharacteristicChangeNotification),
87         DECLARE_NAPI_FUNCTION("setCharacteristicChangeIndication", setCharacteristicChangeIndication),
88 #else
89         DECLARE_NAPI_FUNCTION("writeCharacteristicValue", WriteCharacteristicValue),
90         DECLARE_NAPI_FUNCTION("writeDescriptorValue", WriteDescriptorValue),
91         DECLARE_NAPI_FUNCTION("setNotifyCharacteristicChanged", SetNotifyCharacteristicChanged),
92 #endif
93     };
94 
95     napi_value constructor = nullptr;
96     napi_define_class(env, "GattClientDevice", NAPI_AUTO_LENGTH, GattClientConstructor, nullptr,
97         sizeof(properties) / sizeof(properties[0]), properties, &constructor);
98     napi_create_reference(env, constructor, 1, &consRef_);
99 }
100 
GattClientConstructor(napi_env env,napi_callback_info info)101 napi_value NapiGattClient::GattClientConstructor(napi_env env, napi_callback_info info)
102 {
103     HILOGI("enter");
104     napi_value thisVar = nullptr;
105 
106     size_t expectedArgsCount = ARGS_SIZE_ONE;
107     size_t argc = expectedArgsCount;
108     napi_value argv[ARGS_SIZE_ONE] = {0};
109 
110     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
111 
112     string deviceId;
113     ParseString(env, deviceId, argv[PARAM0]);
114     SetGattClientDeviceId(deviceId);
115 
116     NapiGattClient *gattClient = new NapiGattClient(deviceId);
117 
118     napi_wrap(
119         env, thisVar, gattClient,
120         [](napi_env env, void* data, void* hint) {
121             NapiGattClient* client = static_cast<NapiGattClient*>(data);
122             if (client) {
123                 delete client;
124                 client = nullptr;
125             }
126         },
127         nullptr,
128         nullptr);
129 
130     return thisVar;
131 }
132 
NapiGetGattClient(napi_env env,napi_value thisVar)133 static NapiGattClient *NapiGetGattClient(napi_env env, napi_value thisVar)
134 {
135     NapiGattClient *gattClient = nullptr;
136     auto status = napi_unwrap(env, thisVar, (void **)&gattClient);
137     if (status != napi_ok) {
138         return nullptr;
139     }
140     return gattClient;
141 }
142 
GetCharacteristic(const std::shared_ptr<GattClient> & client,const UUID & serviceUuid,const UUID & characterUuid)143 static GattCharacteristic *GetCharacteristic(const std::shared_ptr<GattClient> &client,
144     const UUID &serviceUuid, const UUID &characterUuid)
145 {
146     GattCharacteristic *character = nullptr;
147     if (client) {
148         auto service = client->GetService(serviceUuid);
149         if (service.has_value()) {
150             character = service->get().GetCharacteristic(characterUuid);
151         }
152     }
153     return character;
154 }
155 
GetGattcCharacteristic(const std::shared_ptr<GattClient> & client,const NapiBleCharacteristic & napiCharacter)156 static GattCharacteristic *GetGattcCharacteristic(const std::shared_ptr<GattClient> &client,
157     const NapiBleCharacteristic &napiCharacter)
158 {
159     GattCharacteristic *character = GetCharacteristic(client, napiCharacter.serviceUuid,
160         napiCharacter.characteristicUuid);
161     if (character) {
162         character->SetValue(napiCharacter.characteristicValue.data(), napiCharacter.characteristicValue.size());
163     }
164     return character;
165 }
166 
GetGattcDescriptor(const std::shared_ptr<GattClient> & client,const NapiBleDescriptor & napiDescriptor)167 static GattDescriptor *GetGattcDescriptor(const std::shared_ptr<GattClient> &client,
168     const NapiBleDescriptor &napiDescriptor)
169 {
170     GattDescriptor *descriptor = nullptr;
171     if (client) {
172         auto *character = GetCharacteristic(client, napiDescriptor.serviceUuid, napiDescriptor.characteristicUuid);
173         if (character == nullptr) {
174             HILOGE("character is nullptr");
175             return nullptr;
176         }
177         descriptor = character->GetDescriptor(napiDescriptor.descriptorUuid);
178         if (descriptor) {
179             descriptor->SetValue(napiDescriptor.descriptorValue.data(), napiDescriptor.descriptorValue.size());
180         }
181     }
182     return descriptor;
183 }
184 
NapiThreadSafeFunctionCallJs(napi_env env,napi_value jsCallback,void * context,void * data)185 static void NapiThreadSafeFunctionCallJs(napi_env env, napi_value jsCallback, void *context, void *data)
186 {
187     napi_value undefined = nullptr;
188     napi_value callRet = nullptr;
189     napi_value result = nullptr;
190     GattCharacteristic *character = static_cast<GattCharacteristic *>(data);
191     if (character == nullptr) {
192         HILOGE("character is nullptr");
193         return;
194     }
195 
196     napi_create_object(env, &result);
197     ConvertBLECharacteristicToJS(env, result, *character);
198     delete character;  // character is malloc in onCharacteristicChanged callback
199 
200     auto status = napi_call_function(env, undefined, jsCallback, ARGS_SIZE_ONE, &result, &callRet);
201     if (status != napi_ok) {
202         HILOGE("napi_call_function status: %{public}d", status);
203     }
204 }
205 
NapiGattClientCreateThreadSafeFunction(napi_env env,napi_value jsCallback,NapiGattClient * gattClient)206 static napi_status NapiGattClientCreateThreadSafeFunction(
207     napi_env env, napi_value jsCallback, NapiGattClient *gattClient)
208 {
209     if (gattClient == nullptr) {
210         HILOGE("gattClient is nullptr");
211         return napi_invalid_arg;
212     }
213     NAPI_BT_CALL_RETURN(NapiIsFunction(env, jsCallback));
214 
215     napi_value name;
216     napi_threadsafe_function tsfn;
217     const size_t maxQueueSize = 0;  // 0 means no limited
218     const size_t initialThreadCount = 1;
219     NAPI_BT_CALL_RETURN(napi_create_string_utf8(env, "GattClient", NAPI_AUTO_LENGTH, &name));
220     NAPI_BT_CALL_RETURN(napi_create_threadsafe_function(env, jsCallback, nullptr, name, maxQueueSize,
221         initialThreadCount, nullptr, nullptr, nullptr, NapiThreadSafeFunctionCallJs, &tsfn));
222 
223     gattClient->GetCallback().onBleCharacterChangedThreadSafeFunc_ = tsfn;
224     return napi_ok;
225 }
226 
CheckGattClientOn(napi_env env,napi_callback_info info)227 napi_status CheckGattClientOn(napi_env env, napi_callback_info info)
228 {
229     size_t argc = ARGS_SIZE_TWO;
230     napi_value argv[ARGS_SIZE_TWO] = {nullptr};
231     napi_value thisVar = nullptr;
232     NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
233     NAPI_BT_RETURN_IF(argc != ARGS_SIZE_TWO, "Requires 2 arguments.", napi_invalid_arg);
234 
235     std::string type {};
236     NAPI_BT_CALL_RETURN(NapiParseString(env, argv[PARAM0], type));
237     std::shared_ptr<BluetoothCallbackInfo> callbackInfo {nullptr};
238 
239     auto gattClient = NapiGetGattClient(env, thisVar);
240     NAPI_BT_RETURN_IF(gattClient == nullptr, "gattClient is nullptr.", napi_invalid_arg);
241 
242     if (type == STR_BT_GATT_CLIENT_CALLBACK_BLE_CHARACTERISTIC_CHANGE) {
243         return NapiGattClientCreateThreadSafeFunction(env, argv[PARAM1], gattClient);
244     } else {
245         callbackInfo = std::make_shared<BluetoothCallbackInfo>();
246     }
247     callbackInfo->env_ = env;
248 
249     NAPI_BT_CALL_RETURN(NapiIsFunction(env, argv[PARAM1]));
250     std::unique_lock<std::shared_mutex> guard(NapiGattClientCallback::g_gattClientCallbackInfosMutex);
251     NAPI_BT_CALL_RETURN(napi_create_reference(env, argv[PARAM1], 1, &callbackInfo->callback_));
252     gattClient->GetCallback().SetCallbackInfo(type, callbackInfo);
253     HILOGI("%{public}s is registered", type.c_str());
254     return napi_ok;
255 }
256 
On(napi_env env,napi_callback_info info)257 napi_value NapiGattClient::On(napi_env env, napi_callback_info info)
258 {
259     HILOGI("enter");
260     auto status = CheckGattClientOn(env, info);
261     NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
262     return NapiGetUndefinedRet(env);
263 }
264 
CheckGattClientOff(napi_env env,napi_callback_info info)265 napi_status CheckGattClientOff(napi_env env, napi_callback_info info)
266 {
267     size_t argc = ARGS_SIZE_TWO;
268     napi_value argv[ARGS_SIZE_TWO] = {nullptr};  // argv[PARAM1] is not used.
269     napi_value thisVar = nullptr;
270     NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
271     NAPI_BT_RETURN_IF(argc != ARGS_SIZE_ONE && argc != ARGS_SIZE_TWO, "Requires 1 or 2 arguments.", napi_invalid_arg);
272 
273     std::string type {};
274     NAPI_BT_CALL_RETURN(NapiParseString(env, argv[PARAM0], type));
275 
276     auto gattClient = NapiGetGattClient(env, thisVar);
277     NAPI_BT_RETURN_IF(gattClient == nullptr, "gattClient is nullptr.", napi_invalid_arg);
278 
279     // Clear 'BLECharacteristicChange' callback, different with others callback.
280     if (type == STR_BT_GATT_CLIENT_CALLBACK_BLE_CHARACTERISTIC_CHANGE) {
281         NAPI_BT_CALL_RETURN(napi_release_threadsafe_function(
282             gattClient->GetCallback().onBleCharacterChangedThreadSafeFunc_, napi_tsfn_abort));
283         gattClient->GetCallback().onBleCharacterChangedThreadSafeFunc_ = nullptr;
284         return napi_ok;
285     }
286 
287     // callback_ need unref before, see napi_bluetooth_gatt_client
288     std::unique_lock<std::shared_mutex> guard(NapiGattClientCallback::g_gattClientCallbackInfosMutex);
289     auto &gattClientCallback = gattClient->GetCallback();
290     uint32_t refCount = INVALID_REF_COUNT;
291     if (gattClientCallback.GetCallbackInfo(type) == nullptr) {
292         return napi_invalid_arg;
293     }
294     NAPI_BT_CALL_RETURN(napi_reference_unref(env, gattClientCallback.GetCallbackInfo(type)->callback_, &refCount));
295     HILOGI("decrements the refernce count, refCount: %{public}d", refCount);
296     if (refCount == 0) {
297         NAPI_BT_CALL_RETURN(napi_delete_reference(env, gattClientCallback.GetCallbackInfo(type)->callback_));
298     }
299     gattClientCallback.SetCallbackInfo(type, nullptr);
300     HILOGI("%{public}s is removed", type.c_str());
301     return napi_ok;
302 }
303 
Off(napi_env env,napi_callback_info info)304 napi_value NapiGattClient::Off(napi_env env, napi_callback_info info)
305 {
306     HILOGI("enter");
307     auto status = CheckGattClientOff(env, info);
308     NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
309     return NapiGetUndefinedRet(env);
310 }
311 
CheckGattClientNoArgc(napi_env env,napi_callback_info info,NapiGattClient ** outGattClient)312 static napi_status CheckGattClientNoArgc(napi_env env, napi_callback_info info, NapiGattClient **outGattClient)
313 {
314     size_t argc = 0;
315     napi_value thisVar = nullptr;
316     NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, nullptr, &thisVar, nullptr));
317     NAPI_BT_RETURN_IF(argc != 0, "No need arguments.", napi_invalid_arg);
318     NapiGattClient *gattClient = NapiGetGattClient(env, thisVar);
319     NAPI_BT_RETURN_IF(gattClient == nullptr || outGattClient == nullptr, "gattClient is nullptr.", napi_invalid_arg);
320 
321     *outGattClient = gattClient;
322     return napi_ok;
323 }
324 
Connect(napi_env env,napi_callback_info info)325 napi_value NapiGattClient::Connect(napi_env env, napi_callback_info info)
326 {
327     HILOGI("enter");
328     NapiGattClient *gattClient = nullptr;
329     auto status = CheckGattClientNoArgc(env, info, &gattClient);
330     NAPI_BT_ASSERT_RETURN_FALSE(env, status == napi_ok, BT_ERR_INVALID_PARAM);
331 
332     std::shared_ptr<GattClient> client = gattClient->GetClient();
333     NAPI_BT_ASSERT_RETURN_FALSE(env, client != nullptr, BT_ERR_INTERNAL_ERROR);
334 
335     int ret = client->Connect(gattClient->GetCallback(), true, GATT_TRANSPORT_TYPE_LE);
336     HILOGI("ret: %{public}d", ret);
337     NAPI_BT_ASSERT_RETURN_FALSE(env, ret == BT_NO_ERROR, ret);
338     return NapiGetBooleanTrue(env);
339 }
340 
Disconnect(napi_env env,napi_callback_info info)341 napi_value NapiGattClient::Disconnect(napi_env env, napi_callback_info info)
342 {
343     HILOGI("enter");
344     NapiGattClient* gattClient = nullptr;
345     auto status = CheckGattClientNoArgc(env, info, &gattClient);
346     NAPI_BT_ASSERT_RETURN_FALSE(env, status == napi_ok, BT_ERR_INVALID_PARAM);
347 
348     std::shared_ptr<GattClient> client = gattClient->GetClient();
349     NAPI_BT_ASSERT_RETURN_FALSE(env, client != nullptr, BT_ERR_INTERNAL_ERROR);
350 
351     int ret = client->Disconnect();
352     HILOGI("ret: %{public}d", ret);
353     NAPI_BT_ASSERT_RETURN_FALSE(env, ret == BT_NO_ERROR, ret);
354     return NapiGetBooleanTrue(env);
355 }
356 
ParseGattClientReadCharacteristicValue(napi_env env,napi_callback_info info,NapiGattClient ** outGattClient,GattCharacteristic ** outCharacter)357 static napi_status ParseGattClientReadCharacteristicValue(napi_env env, napi_callback_info info,
358     NapiGattClient **outGattClient, GattCharacteristic **outCharacter)
359 {
360     size_t expectedArgsCount = ARGS_SIZE_TWO;
361     size_t argc = expectedArgsCount;
362     napi_value argv[ARGS_SIZE_TWO] = {0};
363     napi_value thisVar = nullptr;
364     NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
365     NAPI_BT_RETURN_IF(argc != expectedArgsCount && argc != expectedArgsCount - CALLBACK_SIZE,
366         "Requires 1 or 2 arguments.", napi_invalid_arg);
367     NapiGattClient *gattClient = NapiGetGattClient(env, thisVar);
368     NAPI_BT_RETURN_IF(gattClient == nullptr || outGattClient == nullptr, "gattClient is nullptr.", napi_invalid_arg);
369 
370     NapiBleCharacteristic napiCharacter;
371     NAPI_BT_CALL_RETURN(NapiParseGattCharacteristic(env, argv[PARAM0], napiCharacter));
372     GattCharacteristic *character = GetGattcCharacteristic(gattClient->GetClient(), napiCharacter);
373     NAPI_BT_RETURN_IF(character == nullptr || outCharacter == nullptr, "Not found character", napi_invalid_arg);
374 
375     *outGattClient = gattClient;
376     *outCharacter = character;
377     return napi_ok;
378 }
379 
ReadCharacteristicValue(napi_env env,napi_callback_info info)380 napi_value NapiGattClient::ReadCharacteristicValue(napi_env env, napi_callback_info info)
381 {
382     HILOGI("enter");
383     NapiGattClient *client = nullptr;
384     GattCharacteristic *character = nullptr;
385     auto status = ParseGattClientReadCharacteristicValue(env, info, &client, &character);
386     NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok && client && character, BT_ERR_INVALID_PARAM);
387 
388     auto func = [gattClient = client->GetClient(), character]() {
389         if (character == nullptr) {
390             HILOGE("character is nullptr");
391             return NapiAsyncWorkRet(BT_ERR_INTERNAL_ERROR);
392         }
393         int ret = BT_ERR_INTERNAL_ERROR;
394         if (gattClient) {
395             ret = gattClient->ReadCharacteristic(*character);
396         }
397         return NapiAsyncWorkRet(ret);
398     };
399     auto asyncWork = NapiAsyncWorkFactory::CreateAsyncWork(env, info, func, ASYNC_WORK_NEED_CALLBACK);
400     NAPI_BT_ASSERT_RETURN_UNDEF(env, asyncWork, BT_ERR_INTERNAL_ERROR);
401 
402     bool success = client->GetCallback().asyncWorkMap_.TryPush(NapiAsyncType::GATT_CLIENT_READ_CHARACTER, asyncWork);
403     NAPI_BT_ASSERT_RETURN_UNDEF(env, success, BT_ERR_INTERNAL_ERROR);
404 
405     asyncWork->Run();
406     return asyncWork->GetRet();
407 }
408 
ParseGattClientReadDescriptorValue(napi_env env,napi_callback_info info,NapiGattClient ** outGattClient,GattDescriptor ** outDescriptor)409 static napi_status ParseGattClientReadDescriptorValue(napi_env env, napi_callback_info info,
410     NapiGattClient **outGattClient, GattDescriptor **outDescriptor)
411 {
412     size_t expectedArgsCount = ARGS_SIZE_TWO;
413     size_t argc = expectedArgsCount;
414     napi_value argv[ARGS_SIZE_TWO] = {0};
415     napi_value thisVar = nullptr;
416     NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
417     NAPI_BT_RETURN_IF(argc != expectedArgsCount && argc != expectedArgsCount - CALLBACK_SIZE,
418         "Requires 1 or 2 arguments.", napi_invalid_arg);
419 
420     NapiGattClient *gattClient = NapiGetGattClient(env, thisVar);
421     NAPI_BT_RETURN_IF(outGattClient == nullptr || gattClient == nullptr, "gattClient is nullptr.", napi_invalid_arg);
422 
423     NapiBleDescriptor napiDescriptor;
424     NAPI_BT_CALL_RETURN(NapiParseGattDescriptor(env, argv[PARAM0], napiDescriptor));
425     GattDescriptor *descriptor = GetGattcDescriptor(gattClient->GetClient(), napiDescriptor);
426     NAPI_BT_RETURN_IF(outDescriptor == nullptr || descriptor == nullptr, "Not found Descriptor", napi_invalid_arg);
427 
428     *outGattClient = gattClient;
429     *outDescriptor = descriptor;
430     return napi_ok;
431 }
432 
ReadDescriptorValue(napi_env env,napi_callback_info info)433 napi_value NapiGattClient::ReadDescriptorValue(napi_env env, napi_callback_info info)
434 {
435     HILOGI("enter");
436     NapiGattClient *client = nullptr;
437     GattDescriptor *descriptor = nullptr;
438     auto status = ParseGattClientReadDescriptorValue(env, info, &client, &descriptor);
439     NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok && client && descriptor, BT_ERR_INVALID_PARAM);
440 
441     auto func = [gattClient = client->GetClient(), descriptor]() {
442         if (descriptor == nullptr) {
443             HILOGE("descriptor is nullptr");
444             return NapiAsyncWorkRet(BT_ERR_INTERNAL_ERROR);
445         }
446         int ret = BT_ERR_INTERNAL_ERROR;
447         if (gattClient) {
448             ret = gattClient->ReadDescriptor(*descriptor);
449         }
450         return NapiAsyncWorkRet(ret);
451     };
452     auto asyncWork = NapiAsyncWorkFactory::CreateAsyncWork(env, info, func, ASYNC_WORK_NEED_CALLBACK);
453     NAPI_BT_ASSERT_RETURN_UNDEF(env, asyncWork, BT_ERR_INTERNAL_ERROR);
454 
455     bool success = client->GetCallback().asyncWorkMap_.TryPush(NapiAsyncType::GATT_CLIENT_READ_DESCRIPTOR, asyncWork);
456     NAPI_BT_ASSERT_RETURN_UNDEF(env, success, BT_ERR_INTERNAL_ERROR);
457 
458     asyncWork->Run();
459     return asyncWork->GetRet();
460 }
461 
ParseGattClientGetServices(napi_env env,napi_callback_info info,NapiGattClient ** outGattClient)462 static napi_status ParseGattClientGetServices(napi_env env, napi_callback_info info, NapiGattClient **outGattClient)
463 {
464     size_t argc = ARGS_SIZE_ONE;
465     napi_value argv[ARGS_SIZE_ONE] = {nullptr};
466     napi_value thisVar = nullptr;
467     NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
468     NAPI_BT_RETURN_IF(argc != ARGS_SIZE_ZERO && argc != ARGS_SIZE_ONE, "Requires 0 or 1 arguments.", napi_invalid_arg);
469     NapiGattClient *gattClient = NapiGetGattClient(env, thisVar);
470     NAPI_BT_RETURN_IF(gattClient == nullptr || outGattClient == nullptr, "gattClient is nullptr.", napi_invalid_arg);
471 
472     *outGattClient = gattClient;
473     return napi_ok;
474 }
475 
GetServices(napi_env env,napi_callback_info info)476 napi_value NapiGattClient::GetServices(napi_env env, napi_callback_info info)
477 {
478     HILOGI("enter");
479     NapiGattClient *client = nullptr;
480     auto status = ParseGattClientGetServices(env, info, &client);
481     NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok && client, BT_ERR_INVALID_PARAM);
482 
483     auto func = [gattClient = client->GetClient()]() {
484         if (gattClient == nullptr) {
485             return NapiAsyncWorkRet(BT_ERR_INTERNAL_ERROR);
486         }
487 
488         HILOGI("start discover services");
489         std::shared_ptr<NapiNativeObject> object {nullptr};
490         int ret = gattClient->DiscoverServices();
491         if (ret == BT_NO_ERROR) {
492             HILOGI("start get services");
493             object = std::make_shared<NapiNativeGattServiceArray>(gattClient->GetService());
494         }
495         return NapiAsyncWorkRet(ret, object);
496     };
497 
498     auto asyncWork = NapiAsyncWorkFactory::CreateAsyncWork(env, info, func, ASYNC_WORK_NO_NEED_CALLBACK);
499     NAPI_BT_ASSERT_RETURN_UNDEF(env, asyncWork, BT_ERR_INTERNAL_ERROR);
500     asyncWork->Run();
501     return asyncWork->GetRet();
502 }
503 
Close(napi_env env,napi_callback_info info)504 napi_value NapiGattClient::Close(napi_env env, napi_callback_info info)
505 {
506     HILOGI("enter");
507     NapiGattClient* gattClient = nullptr;
508     auto status = CheckGattClientNoArgc(env, info, &gattClient);
509     NAPI_BT_ASSERT_RETURN_FALSE(env, status == napi_ok, BT_ERR_INVALID_PARAM);
510 
511     std::shared_ptr<GattClient> client = gattClient->GetClient();
512     NAPI_BT_ASSERT_RETURN_FALSE(env, client != nullptr, BT_ERR_INTERNAL_ERROR);
513 
514     int ret = client->Close();
515     HILOGI("ret: %{public}d", ret);
516     NAPI_BT_ASSERT_RETURN_FALSE(env, ret == BT_NO_ERROR, ret);
517     return NapiGetBooleanTrue(env);
518 }
519 
CheckSetBLEMtuSize(napi_env env,napi_callback_info info,int32_t & mtuSize,NapiGattClient ** outGattClient)520 static napi_status CheckSetBLEMtuSize(napi_env env, napi_callback_info info,
521     int32_t &mtuSize, NapiGattClient **outGattClient)
522 {
523     size_t expectedArgsCount = ARGS_SIZE_ONE;
524     size_t argc = expectedArgsCount;
525     napi_value argv[ARGS_SIZE_ONE] = {0};
526     napi_value thisVar = nullptr;
527     NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
528     NAPI_BT_RETURN_IF(argc != expectedArgsCount, "Requires 1 arguments.", napi_invalid_arg);
529     NapiGattClient *gattClient = NapiGetGattClient(env, thisVar);
530     NAPI_BT_RETURN_IF(gattClient == nullptr || outGattClient == nullptr, "gattClient is nullptr.", napi_invalid_arg);
531 
532     NAPI_BT_CALL_RETURN(NapiParseInt32(env, argv[PARAM0], mtuSize));
533     *outGattClient = gattClient;
534 
535     return napi_ok;
536 }
537 
SetBLEMtuSize(napi_env env,napi_callback_info info)538 napi_value NapiGattClient::SetBLEMtuSize(napi_env env, napi_callback_info info)
539 {
540     HILOGI("enter");
541     NapiGattClient* gattClient = nullptr;
542     int32_t mtuSize = 0;
543 
544     auto status = CheckSetBLEMtuSize(env, info, mtuSize, &gattClient);
545     NAPI_BT_ASSERT_RETURN_FALSE(env, status == napi_ok, BT_ERR_INVALID_PARAM);
546 
547     std::shared_ptr<GattClient> client = gattClient->GetClient();
548     NAPI_BT_ASSERT_RETURN_FALSE(env, client != nullptr, BT_ERR_INTERNAL_ERROR);
549 
550     int ret = client->RequestBleMtuSize(mtuSize);
551     HILOGI("ret: %{public}d", ret);
552     NAPI_BT_ASSERT_RETURN_FALSE(env, ret == BT_NO_ERROR, ret);
553     return NapiGetBooleanTrue(env);
554 }
555 
ParseGattClientReadRssiValue(napi_env env,napi_callback_info info,NapiGattClient ** outGattClient)556 static napi_status ParseGattClientReadRssiValue(napi_env env, napi_callback_info info, NapiGattClient **outGattClient)
557 {
558     size_t expectedArgsCount = ARGS_SIZE_ONE;
559     size_t argc = expectedArgsCount;
560     napi_value argv[ARGS_SIZE_ONE] = {0};
561     napi_value thisVar = nullptr;
562     NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
563     NAPI_BT_RETURN_IF(argc != expectedArgsCount && argc != expectedArgsCount - CALLBACK_SIZE,
564         "Requires 0 or 1 arguments.", napi_invalid_arg);
565     NapiGattClient *gattClient = NapiGetGattClient(env, thisVar);
566     NAPI_BT_RETURN_IF(outGattClient == nullptr || gattClient == nullptr, "gattClient is nullptr.", napi_invalid_arg);
567     *outGattClient = gattClient;
568     return napi_ok;
569 }
570 
GetRssiValue(napi_env env,napi_callback_info info)571 napi_value NapiGattClient::GetRssiValue(napi_env env, napi_callback_info info)
572 {
573     HILOGI("enter");
574     NapiGattClient *napiGattClient = nullptr;
575     auto status = ParseGattClientReadRssiValue(env, info, &napiGattClient);
576     NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok && napiGattClient, BT_ERR_INVALID_PARAM);
577 
578     auto func = [gattClient = napiGattClient->GetClient()] {
579         int ret = BT_ERR_INTERNAL_ERROR;
580         if (gattClient) {
581             ret = gattClient->ReadRemoteRssiValue();
582         }
583         return NapiAsyncWorkRet(ret);
584     };
585     auto asyncWork = NapiAsyncWorkFactory::CreateAsyncWork(env, info, func, ASYNC_WORK_NEED_CALLBACK);
586     NAPI_BT_ASSERT_RETURN_UNDEF(env, asyncWork, BT_ERR_INTERNAL_ERROR);
587 
588     bool success = napiGattClient->GetCallback().asyncWorkMap_.TryPush(GATT_CLIENT_READ_REMOTE_RSSI_VALUE, asyncWork);
589     NAPI_BT_ASSERT_RETURN_UNDEF(env, success, BT_ERR_INTERNAL_ERROR);
590 
591     asyncWork->Run();
592     return asyncWork->GetRet();
593 }
594 
CheckGattClientGetDeviceName(napi_env env,napi_callback_info info)595 static napi_status CheckGattClientGetDeviceName(napi_env env, napi_callback_info info)
596 {
597     size_t argc = ARGS_SIZE_ONE;
598     napi_value argv[ARGS_SIZE_ONE] = {nullptr};
599     NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, nullptr, NULL));
600     NAPI_BT_RETURN_IF(argc != ARGS_SIZE_ZERO && argc != ARGS_SIZE_ONE, "Requires 0 or 1 arguments.", napi_invalid_arg);
601     return napi_ok;
602 }
603 
GetDeviceName(napi_env env,napi_callback_info info)604 napi_value NapiGattClient::GetDeviceName(napi_env env, napi_callback_info info)
605 {
606     HILOGI("start");
607 
608     auto status = CheckGattClientGetDeviceName(env, info);
609     NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
610 
611     auto func = []() {
612         std::string deviceName = "";
613         std::string deviceAddr = GetGattClientDeviceId();
614         int32_t err = BluetoothHost::GetDefaultHost().GetRemoteDevice(
615             deviceAddr, BT_TRANSPORT_BLE).GetDeviceName(deviceName);
616 
617         HILOGI("err: %{public}d, deviceName: %{public}s", err, deviceName.c_str());
618         auto object = std::make_shared<NapiNativeString>(deviceName);
619         return NapiAsyncWorkRet(err, object);
620     };
621     auto asyncWork = NapiAsyncWorkFactory::CreateAsyncWork(env, info, func, ASYNC_WORK_NO_NEED_CALLBACK);
622     NAPI_BT_ASSERT_RETURN_UNDEF(env, asyncWork, BT_ERR_INTERNAL_ERROR);
623     asyncWork->Run();
624     return asyncWork->GetRet();
625 }
626 
627 #ifdef BLUETOOTH_API_SINCE_10
628 
CheckWriteCharacteristicValueEx(napi_env env,napi_callback_info info,GattCharacteristic ** outCharacteristic,NapiGattClient ** outGattClient,std::vector<uint8_t> & outValue)629 static napi_status CheckWriteCharacteristicValueEx(napi_env env, napi_callback_info info,
630     GattCharacteristic **outCharacteristic, NapiGattClient **outGattClient, std::vector<uint8_t> &outValue)
631 {
632     size_t argc = ARGS_SIZE_THREE;
633     napi_value argv[ARGS_SIZE_THREE] = {0};
634     napi_value thisVar = nullptr;
635     NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
636     NAPI_BT_RETURN_IF(argc != ARGS_SIZE_TWO && argc != ARGS_SIZE_THREE, "Requires 2 or 3 arguments.", napi_invalid_arg);
637     NapiGattClient *gattClient = NapiGetGattClient(env, thisVar);
638     NAPI_BT_RETURN_IF(gattClient == nullptr || outGattClient == nullptr, "gattClient is nullptr.", napi_invalid_arg);
639 
640     NapiBleCharacteristic napiCharacter;
641     NAPI_BT_CALL_RETURN(NapiParseGattCharacteristic(env, argv[PARAM0], napiCharacter));
642     GattCharacteristic *character = GetGattcCharacteristic(gattClient->GetClient(), napiCharacter);
643     NAPI_BT_RETURN_IF(character == nullptr || outCharacteristic == nullptr, "Not found character", napi_invalid_arg);
644 
645     int writeType = GattCharacteristic::WriteType::DEFAULT;
646     NAPI_BT_CALL_RETURN(NapiParseGattWriteType(env, argv[PARAM1], writeType));
647     character->SetWriteType(writeType);
648 
649     outValue = std::move(napiCharacter.characteristicValue);
650     *outGattClient = gattClient;
651     *outCharacteristic = character;
652 
653     return napi_ok;
654 }
655 
WriteCharacteristicValueEx(napi_env env,napi_callback_info info)656 napi_value NapiGattClient::WriteCharacteristicValueEx(napi_env env, napi_callback_info info)
657 {
658     HILOGI("enter");
659     GattCharacteristic* character = nullptr;
660     NapiGattClient* client = nullptr;
661 
662     std::vector<uint8_t> value {};
663     auto status = CheckWriteCharacteristicValueEx(env, info, &character, &client, value);
664     NAPI_BT_ASSERT_RETURN_FALSE(env, status == napi_ok && character && client, BT_ERR_INVALID_PARAM);
665 
666     auto func = [gattClient = client->GetClient(), character]() {
667         if (character == nullptr) {
668             HILOGE("character is nullptr");
669             return NapiAsyncWorkRet(BT_ERR_INTERNAL_ERROR);
670         }
671         int ret = BT_ERR_INTERNAL_ERROR;
672         if (gattClient) {
673             ret = gattClient->WriteCharacteristic(*character);
674         }
675         return NapiAsyncWorkRet(ret);
676     };
677     auto asyncWork = NapiAsyncWorkFactory::CreateAsyncWork(env, info, func, ASYNC_WORK_NEED_CALLBACK);
678     NAPI_BT_ASSERT_RETURN_UNDEF(env, asyncWork, BT_ERR_INTERNAL_ERROR);
679 
680     bool success = client->GetCallback().asyncWorkMap_.TryPush(GATT_CLIENT_WRITE_CHARACTER, asyncWork);
681     NAPI_BT_ASSERT_RETURN_UNDEF(env, success, BT_ERR_INTERNAL_ERROR);
682 
683     asyncWork->Run();
684     return asyncWork->GetRet();
685 }
686 
CheckWriteDescriptorValueEx(napi_env env,napi_callback_info info,GattDescriptor ** outDescriptor,NapiGattClient ** outGattClient)687 static napi_status CheckWriteDescriptorValueEx(napi_env env, napi_callback_info info,
688     GattDescriptor **outDescriptor, NapiGattClient **outGattClient)
689 {
690     size_t argc = ARGS_SIZE_TWO;
691     napi_value argv[ARGS_SIZE_TWO] = {0};
692     napi_value thisVar = nullptr;
693     NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
694     NAPI_BT_RETURN_IF(argc != ARGS_SIZE_ONE && argc != ARGS_SIZE_TWO, "Requires 1 or 2 arguments.", napi_invalid_arg);
695     NapiGattClient *gattClient = NapiGetGattClient(env, thisVar);
696     NAPI_BT_RETURN_IF(gattClient == nullptr || outGattClient == nullptr, "gattClient is nullptr.", napi_invalid_arg);
697 
698     NapiBleDescriptor napiDescriptor;
699     NAPI_BT_CALL_RETURN(NapiParseGattDescriptor(env, argv[PARAM0], napiDescriptor));
700     GattDescriptor *descriptor = GetGattcDescriptor(gattClient->GetClient(), napiDescriptor);
701     NAPI_BT_RETURN_IF(descriptor == nullptr, "Not found Descriptor", napi_invalid_arg);
702 
703     *outGattClient = gattClient;
704     *outDescriptor = descriptor;
705     return napi_ok;
706 }
707 
WriteDescriptorValueEx(napi_env env,napi_callback_info info)708 napi_value NapiGattClient::WriteDescriptorValueEx(napi_env env, napi_callback_info info)
709 {
710     HILOGI("enter");
711     NapiGattClient* client = nullptr;
712     GattDescriptor* descriptor = nullptr;
713     auto status = CheckWriteDescriptorValueEx(env, info, &descriptor, &client);
714     NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok && client && descriptor, BT_ERR_INVALID_PARAM);
715 
716     auto func = [gattClient = client->GetClient(), descriptor]() {
717         if (descriptor == nullptr) {
718             HILOGE("descriptor is nullptr");
719             return NapiAsyncWorkRet(BT_ERR_INTERNAL_ERROR);
720         }
721         int ret = BT_ERR_INTERNAL_ERROR;
722         if (gattClient) {
723             ret = gattClient->WriteDescriptor(*descriptor);
724         }
725         return NapiAsyncWorkRet(ret);
726     };
727     auto asyncWork = NapiAsyncWorkFactory::CreateAsyncWork(env, info, func, ASYNC_WORK_NEED_CALLBACK);
728     NAPI_BT_ASSERT_RETURN_UNDEF(env, asyncWork, BT_ERR_INTERNAL_ERROR);
729 
730     bool success = client->GetCallback().asyncWorkMap_.TryPush(GATT_CLIENT_WRITE_DESCRIPTOR, asyncWork);
731     NAPI_BT_ASSERT_RETURN_UNDEF(env, success, BT_ERR_INTERNAL_ERROR);
732 
733     asyncWork->Run();
734     return asyncWork->GetRet();
735 }
736 
CheckSetCharacteristicChange(napi_env env,napi_callback_info info,GattCharacteristic ** outCharacteristic,bool & enable,NapiGattClient ** outGattClient)737 static napi_status CheckSetCharacteristicChange(napi_env env, napi_callback_info info,
738     GattCharacteristic **outCharacteristic, bool &enable, NapiGattClient **outGattClient)
739 {
740     size_t argc = ARGS_SIZE_THREE;
741     napi_value argv[ARGS_SIZE_THREE] = {0};
742     napi_value thisVar = nullptr;
743     NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
744     NAPI_BT_RETURN_IF(argc != ARGS_SIZE_TWO && argc != ARGS_SIZE_THREE, "Requires 2 or 3 arguments.", napi_invalid_arg);
745     NapiGattClient *gattClient = NapiGetGattClient(env, thisVar);
746     NAPI_BT_RETURN_IF(gattClient == nullptr || outGattClient == nullptr, "gattClient is nullptr.", napi_invalid_arg);
747 
748     NapiBleCharacteristic napiCharacter;
749     NAPI_BT_CALL_RETURN(NapiParseGattCharacteristic(env, argv[PARAM0], napiCharacter));
750     GattCharacteristic *character = GetGattcCharacteristic(gattClient->GetClient(), napiCharacter);
751     NAPI_BT_RETURN_IF(character == nullptr || outCharacteristic == nullptr, "Not found character", napi_invalid_arg);
752 
753     NAPI_BT_CALL_RETURN(NapiParseBoolean(env, argv[PARAM1], enable));
754     *outGattClient = gattClient;
755     *outCharacteristic = character;
756     return napi_ok;
757 }
758 
setCharacteristicChangeInner(napi_env env,napi_callback_info info,bool isNotify)759 static napi_value setCharacteristicChangeInner(napi_env env, napi_callback_info info, bool isNotify)
760 {
761     GattCharacteristic *character = nullptr;
762     bool enable = false;
763     NapiGattClient *client = nullptr;
764 
765     auto status = CheckSetCharacteristicChange(env, info, &character, enable, &client);
766     NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok && client && character, BT_ERR_INVALID_PARAM);
767 
768     auto func = [gattClient = client->GetClient(), character, enable, isNotify]() {
769         if (character == nullptr) {
770             HILOGE("character is nullptr");
771             return NapiAsyncWorkRet(BT_ERR_INTERNAL_ERROR);
772         }
773         int ret = BT_ERR_INTERNAL_ERROR;
774         if (gattClient) {
775             if (isNotify) {
776                 ret = gattClient->SetNotifyCharacteristic(*character, enable);
777             } else {
778                 ret = gattClient->SetIndicateCharacteristic(*character, enable);
779             }
780         }
781         return NapiAsyncWorkRet(ret);
782     };
783     auto asyncWork = NapiAsyncWorkFactory::CreateAsyncWork(env, info, func, ASYNC_WORK_NEED_CALLBACK);
784     NAPI_BT_ASSERT_RETURN_UNDEF(env, asyncWork, BT_ERR_INTERNAL_ERROR);
785 
786     bool success = client->GetCallback().asyncWorkMap_.TryPush(GATT_CLIENT_ENABLE_CHARACTER_CHANGED, asyncWork);
787     NAPI_BT_ASSERT_RETURN_UNDEF(env, success, BT_ERR_INTERNAL_ERROR);
788 
789     asyncWork->Run();
790     return asyncWork->GetRet();
791 }
792 
setCharacteristicChangeNotification(napi_env env,napi_callback_info info)793 napi_value NapiGattClient::setCharacteristicChangeNotification(napi_env env, napi_callback_info info)
794 {
795     HILOGI("enter");
796     return setCharacteristicChangeInner(env, info, true);
797 }
798 
setCharacteristicChangeIndication(napi_env env,napi_callback_info info)799 napi_value NapiGattClient::setCharacteristicChangeIndication(napi_env env, napi_callback_info info)
800 {
801     HILOGI("enter");
802     return setCharacteristicChangeInner(env, info, false);
803 }
804 
805 #else  // ! BLUETOOTH_API_SINCE_10
806 
CheckWriteCharacteristicValue(napi_env env,napi_callback_info info,GattCharacteristic ** outCharacteristic,NapiGattClient ** outGattClient,std::vector<uint8_t> & outValue)807 static napi_status CheckWriteCharacteristicValue(napi_env env, napi_callback_info info,
808     GattCharacteristic **outCharacteristic, NapiGattClient **outGattClient, std::vector<uint8_t> &outValue)
809 {
810     size_t expectedArgsCount = ARGS_SIZE_ONE;
811     size_t argc = expectedArgsCount;
812     napi_value argv[ARGS_SIZE_ONE] = {0};
813     napi_value thisVar = nullptr;
814     NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
815     NAPI_BT_RETURN_IF(argc != expectedArgsCount, "Requires 1 arguments.", napi_invalid_arg);
816     NapiGattClient *gattClient = NapiGetGattClient(env, thisVar);
817     NAPI_BT_RETURN_IF(gattClient == nullptr || outGattClient == nullptr, "gattClient is nullptr.", napi_invalid_arg);
818 
819     NapiBleCharacteristic napiCharacter;
820     NAPI_BT_CALL_RETURN(NapiParseGattCharacteristic(env, argv[PARAM0], napiCharacter));
821     GattCharacteristic *character = GetGattcCharacteristic(gattClient->GetClient(), napiCharacter);
822     NAPI_BT_RETURN_IF(character == nullptr, "Not found character", napi_invalid_arg);
823 
824     outValue = std::move(napiCharacter.characteristicValue);
825     *outGattClient = gattClient;
826     *outCharacteristic = character;
827 
828     return napi_ok;
829 }
830 
WriteCharacteristicValue(napi_env env,napi_callback_info info)831 napi_value NapiGattClient::WriteCharacteristicValue(napi_env env, napi_callback_info info)
832 {
833     HILOGI("enter");
834     GattCharacteristic* characteristic = nullptr;
835     NapiGattClient* gattClient = nullptr;
836 
837     std::vector<uint8_t> value {};
838     auto status = CheckWriteCharacteristicValue(env, info, &characteristic, &gattClient, value);
839     NAPI_BT_ASSERT_RETURN_FALSE(env, status == napi_ok, BT_ERR_INVALID_PARAM);
840     std::shared_ptr<GattClient> client = gattClient->GetClient();
841     NAPI_BT_ASSERT_RETURN_FALSE(env, client != nullptr, BT_ERR_INTERNAL_ERROR);
842     int ret = client->WriteCharacteristic(*characteristic, std::move(value));
843     HILOGI("ret: %{public}d", ret);
844     NAPI_BT_ASSERT_RETURN_FALSE(env, ret == BT_NO_ERROR, ret);
845     return NapiGetBooleanTrue(env);
846 }
847 
CheckWriteDescriptorValue(napi_env env,napi_callback_info info,GattDescriptor ** outDescriptor,NapiGattClient ** outGattClient)848 static napi_status CheckWriteDescriptorValue(napi_env env, napi_callback_info info,
849     GattDescriptor **outDescriptor, NapiGattClient **outGattClient)
850 {
851     size_t expectedArgsCount = ARGS_SIZE_ONE;
852     size_t argc = expectedArgsCount;
853     napi_value argv[ARGS_SIZE_ONE] = {0};
854     napi_value thisVar = nullptr;
855     NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
856     NAPI_BT_RETURN_IF(argc != expectedArgsCount, "Requires 1 arguments.", napi_invalid_arg);
857     NapiGattClient *gattClient = NapiGetGattClient(env, thisVar);
858     NAPI_BT_RETURN_IF(gattClient == nullptr || outGattClient == nullptr, "gattClient is nullptr.", napi_invalid_arg);
859 
860     NapiBleDescriptor napiDescriptor;
861     NAPI_BT_CALL_RETURN(NapiParseGattDescriptor(env, argv[PARAM0], napiDescriptor));
862     GattDescriptor *descriptor = GetGattcDescriptor(gattClient->GetClient(), napiDescriptor);
863     NAPI_BT_RETURN_IF(descriptor == nullptr, "Not found Descriptor", napi_invalid_arg);
864 
865     *outGattClient = gattClient;
866     *outDescriptor = descriptor;
867     return napi_ok;
868 }
869 
WriteDescriptorValue(napi_env env,napi_callback_info info)870 napi_value NapiGattClient::WriteDescriptorValue(napi_env env, napi_callback_info info)
871 {
872     HILOGI("enter");
873     GattDescriptor* descriptor = nullptr;
874     NapiGattClient* gattClient = nullptr;
875 
876     auto status = CheckWriteDescriptorValue(env, info, &descriptor, &gattClient);
877     NAPI_BT_ASSERT_RETURN_FALSE(env, status == napi_ok, BT_ERR_INVALID_PARAM);
878 
879     std::shared_ptr<GattClient> client = gattClient->GetClient();
880     NAPI_BT_ASSERT_RETURN_FALSE(env, client != nullptr, BT_ERR_INTERNAL_ERROR);
881 
882     int ret = client->WriteDescriptor(*descriptor);
883     HILOGI("ret: %{public}d", ret);
884     NAPI_BT_ASSERT_RETURN_FALSE(env, ret == BT_NO_ERROR, ret);
885     return NapiGetBooleanTrue(env);
886 }
887 
CheckSetNotifyCharacteristicChanged(napi_env env,napi_callback_info info,GattCharacteristic ** outCharacteristic,bool & enableNotify,NapiGattClient ** outGattClient)888 static napi_status CheckSetNotifyCharacteristicChanged(napi_env env, napi_callback_info info,
889     GattCharacteristic **outCharacteristic, bool &enableNotify, NapiGattClient **outGattClient)
890 {
891     size_t expectedArgsCount = ARGS_SIZE_TWO;
892     size_t argc = expectedArgsCount;
893     napi_value argv[ARGS_SIZE_TWO] = {0};
894     napi_value thisVar = nullptr;
895     NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
896     NAPI_BT_RETURN_IF(argc != expectedArgsCount, "Requires 2 arguments.", napi_invalid_arg);
897     NapiGattClient *gattClient = NapiGetGattClient(env, thisVar);
898     NAPI_BT_RETURN_IF(gattClient == nullptr || outGattClient == nullptr, "gattClient is nullptr.", napi_invalid_arg);
899 
900     NapiBleCharacteristic napiCharacter;
901     NAPI_BT_CALL_RETURN(NapiParseGattCharacteristic(env, argv[PARAM0], napiCharacter));
902     GattCharacteristic *character = GetGattcCharacteristic(gattClient->GetClient(), napiCharacter);
903     NAPI_BT_RETURN_IF(character == nullptr, "Not found character", napi_invalid_arg);
904 
905     NAPI_BT_CALL_RETURN(NapiParseBoolean(env, argv[PARAM1], enableNotify));
906     *outGattClient = gattClient;
907     *outCharacteristic = character;
908     return napi_ok;
909 }
910 
SetNotifyCharacteristicChanged(napi_env env,napi_callback_info info)911 napi_value NapiGattClient::SetNotifyCharacteristicChanged(napi_env env, napi_callback_info info)
912 {
913     HILOGI("enter");
914     GattCharacteristic* characteristic = nullptr;
915     bool enableNotify = false;
916     NapiGattClient* gattClient = nullptr;
917 
918     auto status = CheckSetNotifyCharacteristicChanged(env, info, &characteristic, enableNotify, &gattClient);
919     NAPI_BT_ASSERT_RETURN_FALSE(env, status == napi_ok, BT_ERR_INVALID_PARAM);
920 
921     std::shared_ptr<GattClient> client = gattClient->GetClient();
922     NAPI_BT_ASSERT_RETURN_FALSE(env, client != nullptr, BT_ERR_INTERNAL_ERROR);
923 
924     int ret = client->SetNotifyCharacteristic(*characteristic, enableNotify);
925     HILOGI("ret: %{public}d", ret);
926     NAPI_BT_ASSERT_RETURN_FALSE(env, ret == BT_NO_ERROR, ret);
927     return NapiGetBooleanTrue(env);
928 }
929 
930 #endif
931 
932 } // namespace Bluetooth
933 } // namespace OHOS
934