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