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