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