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