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