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