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_ble.h"
16
17 #include "napi_bluetooth_ble_advertise_callback.h"
18 #include "napi_bluetooth_ble_central_manager_callback.h"
19 #include "napi_bluetooth_error.h"
20 #include "napi_bluetooth_gatt_client.h"
21 #include "napi_bluetooth_gatt_server.h"
22 #include "napi_bluetooth_utils.h"
23 #include "napi_bluetooth_ble_utils.h"
24
25 #include "bluetooth_ble_advertiser.h"
26 #include "bluetooth_ble_central_manager.h"
27 #include "bluetooth_errorcode.h"
28 #include "bluetooth_utils.h"
29 #include "../parser/napi_parser_utils.h"
30
31 #include <memory>
32 namespace OHOS {
33 namespace Bluetooth {
34 namespace {
35 struct SysStopBLEContext {
36 napi_async_work work = nullptr;
37 napi_ref callbackSuccess = nullptr;
38 napi_ref callbackFail = nullptr;
39 napi_ref callbackComplete = nullptr;
40 };
41
42 namespace {
BleAdvertiserGetInstance(void)43 BleAdvertiser *BleAdvertiserGetInstance(void)
44 {
45 static BleAdvertiser instance;
46 return &instance;
47 }
48
BleCentralManagerGetInstance(void)49 BleCentralManager *BleCentralManagerGetInstance(void)
50 {
51 static BleCentralManager instance(NapiBluetoothBleCentralManagerCallback::GetInstance());
52 return &instance;
53 }
54 } // namespace {}
55
GetPropertyValueByNamed(napi_env env,napi_value object,std::string_view propertyName,napi_valuetype type)56 napi_value GetPropertyValueByNamed(napi_env env, napi_value object, std::string_view propertyName, napi_valuetype type)
57 {
58 napi_value value = nullptr;
59 bool hasProperty = false;
60 napi_valuetype paraType = napi_undefined;
61
62 NAPI_CALL(env, napi_has_named_property(env, object, propertyName.data(), &hasProperty));
63 if (hasProperty) {
64 NAPI_CALL(env, napi_get_named_property(env, object, propertyName.data(), &value));
65 NAPI_CALL(env, napi_typeof(env, value, ¶Type));
66 if (paraType != type) {
67 return NapiGetNull(env);
68 }
69 }
70 return value;
71 }
72
RegisterBLEObserver(napi_env env,napi_value val,int32_t callbackIndex,const std::string & type)73 void RegisterBLEObserver(napi_env env, napi_value val, int32_t callbackIndex, const std::string &type)
74 {
75 std::shared_ptr<BluetoothCallbackInfo> pCallbackInfo = std::make_shared<BluetoothCallbackInfo>();
76 pCallbackInfo->env_ = env;
77 napi_create_reference(env, val, 1, &pCallbackInfo->callback_);
78 RegisterSysBLEObserver(pCallbackInfo, callbackIndex, type);
79 }
80
ParseScanParameters(napi_env env,napi_value arg,ScanOptions & info)81 bool ParseScanParameters(napi_env env, napi_value arg, ScanOptions &info)
82 {
83 napi_value interval = GetPropertyValueByNamed(env, arg, "interval", napi_number);
84 if (interval) {
85 napi_get_value_int32(env, interval, &info.interval);
86 HILOGI("Scan interval is %{public}d", info.interval);
87 } else {
88 info.interval = 0;
89 }
90
91 std::array<std::string, ARGS_SIZE_THREE> funcArray {"success", "fail", "complete"};
92
93 for (size_t i = 0; i < funcArray.size(); i++) {
94 napi_value value = GetPropertyValueByNamed(env, arg, funcArray[i], napi_function);
95 if (value) {
96 RegisterBLEObserver(env, value, i, REGISTER_SYS_BLE_SCAN_TYPE);
97 } else {
98 UnregisterSysBLEObserver(REGISTER_SYS_BLE_SCAN_TYPE);
99 return false;
100 }
101 }
102 return true;
103 }
104
SysStartBLEScan(napi_env env,napi_callback_info info)105 napi_value SysStartBLEScan(napi_env env, napi_callback_info info)
106 {
107 size_t argc = ARGS_SIZE_ONE;
108 napi_value argv[] = {nullptr};
109 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
110 if (argc != 1) {
111 return NapiGetNull(env);
112 }
113
114 napi_valuetype valueType = napi_undefined;
115 NAPI_CALL(env, napi_typeof(env, argv[PARAM0], &valueType));
116 if (valueType != napi_object) {
117 return NapiGetNull(env);
118 }
119 ScanOptions scanOptions;
120 if (!ParseScanParameters(env, argv[PARAM0], scanOptions)) {
121 HILOGE("SysStartBLEScan Input parameter parsing failed!");
122 return NapiGetNull(env);
123 }
124
125 BleScanSettings settinngs;
126 settinngs.SetReportDelay(scanOptions.interval);
127 settinngs.SetScanMode(static_cast<int32_t>(scanOptions.dutyMode));
128
129 BleCentralManagerGetInstance()->StartScan(settinngs);
130 return NapiGetNull(env);
131 }
132
SysStopBLEScanExec(napi_env env,void * data)133 void SysStopBLEScanExec(napi_env env, void *data)
134 {
135 HILOGI("SysStopBLEScanExec");
136 BleCentralManagerGetInstance()->StopScan();
137 UnregisterSysBLEObserver(REGISTER_SYS_BLE_SCAN_TYPE);
138 }
139
SysStopBLEScanComplete(napi_env env,napi_status status,void * data)140 void SysStopBLEScanComplete(napi_env env, napi_status status, void *data)
141 {
142 NAPI_CALL_RETURN_VOID(env, (data == nullptr ? napi_invalid_arg : napi_ok));
143 std::unique_ptr<SysStopBLEContext> context(static_cast<SysStopBLEContext *>(data));
144
145 napi_value undefine = nullptr;
146 NAPI_CALL_RETURN_VOID(env, napi_get_undefined(env, &undefine));
147 napi_value funcComplete = nullptr;
148 napi_value funcSuccess = nullptr;
149 napi_value callbackResult = nullptr;
150 NAPI_CALL_RETURN_VOID(env, napi_get_reference_value(env, context->callbackSuccess, &funcSuccess));
151 NAPI_CALL_RETURN_VOID(env, napi_call_function(env, undefine, funcSuccess, 0, nullptr, &callbackResult));
152 NAPI_CALL_RETURN_VOID(env, napi_get_reference_value(env, context->callbackComplete, &funcComplete));
153 NAPI_CALL_RETURN_VOID(env, napi_call_function(env, undefine, funcComplete, 0, nullptr, &callbackResult));
154 NAPI_CALL_RETURN_VOID(env, napi_delete_reference(env, context->callbackSuccess));
155 NAPI_CALL_RETURN_VOID(env, napi_delete_reference(env, context->callbackComplete));
156 NAPI_CALL_RETURN_VOID(env, napi_delete_reference(env, context->callbackFail));
157 NAPI_CALL_RETURN_VOID(env, napi_delete_async_work(env, context->work));
158 HILOGI("SysStopBLEScanComplete end");
159 }
160
SysStopBLEScan(napi_env env,napi_callback_info info)161 napi_value SysStopBLEScan(napi_env env, napi_callback_info info)
162 {
163 size_t argc = ARGS_SIZE_ONE;
164 napi_value argv[] = {nullptr};
165 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
166 if (argc != 1) {
167 return NapiGetNull(env);
168 }
169
170 napi_valuetype valueType = napi_undefined;
171 NAPI_CALL(env, napi_typeof(env, argv[PARAM0], &valueType));
172 if (valueType != napi_object) {
173 return NapiGetNull(env);
174 }
175
176 std::unique_ptr<SysStopBLEContext> context = std::make_unique<SysStopBLEContext>();
177
178 std::array<std::string, ARGS_SIZE_THREE> funcArray {"success", "fail", "complete"};
179 for (size_t i = 0; i < funcArray.size(); i++) {
180 napi_value value = GetPropertyValueByNamed(env, argv[PARAM0], funcArray[i], napi_function);
181 if (value) {
182 napi_create_reference(env, value, 1,
183 &(i == PARAM0 ? context->callbackSuccess :
184 (i == PARAM1 ? context->callbackFail : context->callbackComplete)));
185 } else {
186 HILOGE("SysStopBLEScan Input parameter parsing failed!");
187 return NapiGetNull(env);
188 }
189 }
190
191 napi_value resourceName = nullptr;
192 NAPI_CALL(env, napi_create_string_utf8(env, "SysStopBLEScan", NAPI_AUTO_LENGTH, &resourceName));
193 SysStopBLEContext *pContext = context.release();
194 napi_status status = napi_create_async_work(env, nullptr, resourceName, SysStopBLEScanExec,
195 SysStopBLEScanComplete, static_cast<void *>(pContext), &pContext->work);
196 if (status != napi_ok) {
197 delete pContext;
198 return NapiGetNull(env);
199 }
200
201 if (napi_queue_async_work(env, pContext->work) != napi_ok) {
202 delete pContext;
203 }
204 return NapiGetNull(env);
205 }
206
ParseDeviceFoundParameters(napi_env env,napi_value arg)207 bool ParseDeviceFoundParameters(napi_env env, napi_value arg)
208 {
209 std::array<std::string, ARGS_SIZE_TWO> funcArray {"success", "fail"};
210
211 for (size_t i = 0; i < funcArray.size(); i++) {
212 napi_value value = GetPropertyValueByNamed(env, arg, funcArray[i], napi_function);
213 if (value) {
214 RegisterBLEObserver(env, value, i, REGISTER_SYS_BLE_FIND_DEVICE_TYPE);
215 } else {
216 UnregisterSysBLEObserver(REGISTER_SYS_BLE_FIND_DEVICE_TYPE);
217 return false;
218 }
219 }
220 return true;
221 }
222
SysSubscribeBLEFound(napi_env env,napi_callback_info info)223 napi_value SysSubscribeBLEFound(napi_env env, napi_callback_info info)
224 {
225 size_t argc = ARGS_SIZE_ONE;
226 napi_value argv[] = {nullptr};
227 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
228 if (argc != 1) {
229 return NapiGetNull(env);
230 }
231
232 napi_valuetype valueType = napi_undefined;
233 NAPI_CALL(env, napi_typeof(env, argv[PARAM0], &valueType));
234 if (valueType != napi_object) {
235 return NapiGetNull(env);
236 }
237 if (!ParseDeviceFoundParameters(env, argv[PARAM0])) {
238 HILOGE("SysSubscribeBLEFound Input parameter parsing failed!");
239 }
240 return NapiGetNull(env);
241 }
242
SysUnsubscribeBLEFound(napi_env env,napi_callback_info info)243 napi_value SysUnsubscribeBLEFound(napi_env env, napi_callback_info info)
244 {
245 UnregisterSysBLEObserver(REGISTER_SYS_BLE_FIND_DEVICE_TYPE);
246 return NapiGetNull(env);
247 }
248 } // namespace
249
DefineSystemBLEInterface(napi_env env,napi_value exports)250 void DefineSystemBLEInterface(napi_env env, napi_value exports)
251 {
252 napi_property_descriptor desc[] = {
253 DECLARE_NAPI_FUNCTION("startBLEScan", SysStartBLEScan),
254 DECLARE_NAPI_FUNCTION("stopBLEScan", SysStopBLEScan),
255 DECLARE_NAPI_FUNCTION("subscribeBLEFound", SysSubscribeBLEFound),
256 DECLARE_NAPI_FUNCTION("unsubscribeBLEFound", SysUnsubscribeBLEFound),
257 };
258 napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
259 HILOGI("DefineSystemBLEInterface init");
260 }
261
On(napi_env env,napi_callback_info info)262 static napi_value On(napi_env env, napi_callback_info info)
263 {
264 HILOGI("enter");
265 auto CheckBleOnFunc = [env, info]() -> napi_status {
266 size_t argc = ARGS_SIZE_TWO;
267 napi_value argv[ARGS_SIZE_TWO] = {nullptr};
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 != ARGS_SIZE_TWO, "Requires 2 arguments", napi_invalid_arg);
271
272 std::string type {};
273 NAPI_BT_CALL_RETURN(NapiParseString(env, argv[PARAM0], type));
274 if (type != REGISTER_BLE_FIND_DEVICE_TYPE) {
275 HILOGE("Invalid type: %{public}s", type.c_str());
276 return napi_invalid_arg;
277 }
278
279 NAPI_BT_CALL_RETURN(NapiIsFunction(env, argv[PARAM1]));
280 auto napiScanCallback = std::make_shared<NapiCallback>(env, argv[PARAM1]);
281 NapiBluetoothBleCentralManagerCallback::GetInstance().SetNapiScanCallback(napiScanCallback);
282 return napi_ok;
283 };
284
285 auto status = CheckBleOnFunc();
286 NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
287 return NapiGetUndefinedRet(env);
288 }
289
Off(napi_env env,napi_callback_info info)290 static napi_value Off(napi_env env, napi_callback_info info)
291 {
292 HILOGI("enter");
293 auto CheckBleOffFunc = [env, info]() -> napi_status {
294 size_t argc = ARGS_SIZE_TWO;
295 napi_value argv[ARGS_SIZE_TWO] = {nullptr};
296 napi_value thisVar = nullptr;
297 NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
298 NAPI_BT_RETURN_IF(
299 argc != ARGS_SIZE_ONE && argc != ARGS_SIZE_TWO, "Requires 1 or 2 arguments", napi_invalid_arg);
300
301 std::string type {};
302 NAPI_BT_CALL_RETURN(NapiParseString(env, argv[PARAM0], type));
303 if (type != REGISTER_BLE_FIND_DEVICE_TYPE) {
304 HILOGE("Invalid type: %{public}s", type.c_str());
305 return napi_invalid_arg;
306 }
307 NapiBluetoothBleCentralManagerCallback::GetInstance().SetNapiScanCallback(nullptr);
308 return napi_ok;
309 };
310
311 auto status = CheckBleOffFunc();
312 NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
313 return NapiGetUndefinedRet(env);
314 }
315
DefineBLEJSObject(napi_env env,napi_value exports)316 void DefineBLEJSObject(napi_env env, napi_value exports)
317 {
318 HILOGI("enter");
319 PropertyInit(env, exports);
320 napi_property_descriptor desc[] = {
321 DECLARE_NAPI_FUNCTION("createGattServer", NapiGattServer::CreateGattServer),
322 DECLARE_NAPI_FUNCTION("createGattClientDevice", NapiGattClient::CreateGattClientDevice),
323 DECLARE_NAPI_FUNCTION("startBLEScan", StartBLEScan),
324 DECLARE_NAPI_FUNCTION("stopBLEScan", StopBLEScan),
325 DECLARE_NAPI_FUNCTION("on", On),
326 DECLARE_NAPI_FUNCTION("off", Off),
327 DECLARE_NAPI_FUNCTION("getConnectedBLEDevices", GetConnectedBLEDevices),
328 #ifdef BLUETOOTH_API_SINCE_10
329 DECLARE_NAPI_FUNCTION("startAdvertising", StartAdvertising),
330 DECLARE_NAPI_FUNCTION("stopAdvertising", StopAdvertising),
331 #endif
332 };
333
334 #ifdef BLUETOOTH_API_SINCE_10
335 napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
336 #else
337 napi_value BLEObject = nullptr;
338 napi_create_object(env, &BLEObject);
339 napi_define_properties(env, BLEObject, sizeof(desc) / sizeof(desc[0]), desc);
340 napi_set_named_property(env, exports, "BLE", BLEObject);
341 #endif
342 }
343
ConvertMatchMode(ScanOptions & params,int32_t matchMode)344 static void ConvertMatchMode(ScanOptions ¶ms, int32_t matchMode)
345 {
346 switch (matchMode) {
347 case MatchMode::MATCH_MODE_AGGRESSIVE:
348 params.MatchMode = MatchMode::MATCH_MODE_AGGRESSIVE;
349 break;
350 case MatchMode::MATCH_MODE_STICKY:
351 params.MatchMode = MatchMode::MATCH_MODE_STICKY;
352 break;
353 default:
354 break;
355 }
356 }
357
ConvertDutyMode(ScanOptions & params,int32_t dutyMode)358 static void ConvertDutyMode(ScanOptions ¶ms, int32_t dutyMode)
359 {
360 switch (dutyMode) {
361 case static_cast<int32_t>(ScanDuty::SCAN_MODE_LOW_POWER):
362 params.dutyMode = ScanDuty::SCAN_MODE_LOW_POWER;
363 break;
364 case static_cast<int32_t>(ScanDuty::SCAN_MODE_BALANCED):
365 params.dutyMode = ScanDuty::SCAN_MODE_BALANCED;
366 break;
367 case static_cast<int32_t>(ScanDuty::SCAN_MODE_LOW_LATENCY):
368 params.dutyMode = ScanDuty::SCAN_MODE_LOW_LATENCY;
369 break;
370 default:
371 break;
372 }
373 }
374
ParseScanParameters(const napi_env & env,const napi_callback_info & info,const napi_value & scanArg,ScanOptions & params)375 static napi_status ParseScanParameters(
376 const napi_env &env, const napi_callback_info &info, const napi_value &scanArg, ScanOptions ¶ms)
377 {
378 (void)info;
379 NAPI_BT_CALL_RETURN(NapiCheckObjectPropertiesName(env, scanArg, {"interval", "dutyMode", "matchMode"}));
380
381 bool exist = false;
382 int32_t interval = 0;
383 NAPI_BT_CALL_RETURN(ParseInt32Params(env, scanArg, "interval", exist, interval));
384 if (exist) {
385 HILOGI("Scan interval is %{public}d", interval);
386 params.interval = interval;
387 }
388
389 int32_t dutyMode = 0;
390 NAPI_BT_CALL_RETURN(ParseInt32Params(env, scanArg, "dutyMode", exist, dutyMode));
391 if (exist) {
392 HILOGI("Scan dutyMode is %{public}d", dutyMode);
393 ConvertDutyMode(params, dutyMode);
394 }
395
396 int32_t matchMode = 0;
397 NAPI_BT_CALL_RETURN(ParseInt32Params(env, scanArg, "matchMode", exist, matchMode));
398 if (exist) {
399 HILOGI("Scan matchMode is %{public}d", matchMode);
400 ConvertMatchMode(params, matchMode);
401 }
402 return napi_ok;
403 }
404
ParseScanFilterDeviceIdParameters(const napi_env & env,napi_value & scanFilter,BleScanFilter & bleScanFilter)405 static napi_status ParseScanFilterDeviceIdParameters(
406 const napi_env &env, napi_value &scanFilter, BleScanFilter &bleScanFilter)
407 {
408 bool exist = false;
409 std::string deviceId {};
410 NAPI_BT_CALL_RETURN(ParseStringParams(env, scanFilter, "deviceId", exist, deviceId));
411 if (exist) {
412 if (!IsValidAddress(deviceId)) {
413 HILOGE("Invalid deviceId: %{public}s", deviceId.c_str());
414 return napi_invalid_arg;
415 }
416
417 HILOGI("Scan filter device id is %{public}s", GetEncryptAddr(deviceId).c_str());
418 bleScanFilter.SetDeviceId(deviceId);
419 }
420 return napi_ok;
421 }
422
ParseScanFilterLocalNameParameters(const napi_env & env,napi_value & scanFilter,BleScanFilter & bleScanFilter)423 static napi_status ParseScanFilterLocalNameParameters(
424 const napi_env &env, napi_value &scanFilter, BleScanFilter &bleScanFilter)
425 {
426 bool exist = false;
427 std::string name {};
428 NAPI_BT_CALL_RETURN(ParseStringParams(env, scanFilter, "name", exist, name));
429 if (exist) {
430 if (name.empty()) {
431 HILOGE("name is empty");
432 return napi_invalid_arg;
433 }
434 HILOGI("Scan filter name is %{public}s", name.c_str());
435 bleScanFilter.SetName(name);
436 }
437 return napi_ok;
438 }
439
ParseScanFilterServiceUuidParameters(const napi_env & env,napi_value & scanFilter,BleScanFilter & bleScanFilter)440 static napi_status ParseScanFilterServiceUuidParameters(
441 const napi_env &env, napi_value &scanFilter, BleScanFilter &bleScanFilter)
442 {
443 bool exist = false;
444 UUID uuid {};
445 NAPI_BT_CALL_RETURN(ParseUuidParams(env, scanFilter, "serviceUuid", exist, uuid));
446 if (exist) {
447 HILOGI("Scan filter serviceUuid is %{public}s", uuid.ToString().c_str());
448 bleScanFilter.SetServiceUuid(uuid);
449 }
450
451 UUID uuidMask {};
452 NAPI_BT_CALL_RETURN(ParseUuidParams(env, scanFilter, "serviceUuidMask", exist, uuidMask));
453 if (exist) {
454 HILOGI("Scan filter serviceUuidMask is %{public}s", uuidMask.ToString().c_str());
455 bleScanFilter.SetServiceUuidMask(uuidMask);
456 }
457 return napi_ok;
458 }
459
ParseScanFilterSolicitationUuidParameters(const napi_env & env,napi_value & scanFilter,BleScanFilter & bleScanFilter)460 static napi_status ParseScanFilterSolicitationUuidParameters(
461 const napi_env &env, napi_value &scanFilter, BleScanFilter &bleScanFilter)
462 {
463 bool exist = false;
464 UUID uuid {};
465 NAPI_BT_CALL_RETURN(ParseUuidParams(env, scanFilter, "serviceSolicitationUuid", exist, uuid));
466 if (exist) {
467 HILOGI("Scan filter serviceSolicitationUuid is %{public}s", uuid.ToString().c_str());
468 bleScanFilter.SetServiceSolicitationUuid(uuid);
469 }
470
471 UUID uuidMask {};
472 NAPI_BT_CALL_RETURN(ParseUuidParams(env, scanFilter, "serviceSolicitationUuidMask", exist, uuidMask));
473 if (exist) {
474 HILOGI("Scan filter serviceSolicitationUuidMask is %{public}s", uuidMask.ToString().c_str());
475 bleScanFilter.SetServiceSolicitationUuidMask(uuidMask);
476 }
477 return napi_ok;
478 }
479
ParseScanFilterServiceDataParameters(const napi_env & env,napi_value & scanFilter,BleScanFilter & bleScanFilter)480 static napi_status ParseScanFilterServiceDataParameters(
481 const napi_env &env, napi_value &scanFilter, BleScanFilter &bleScanFilter)
482 {
483 bool exist = false;
484 std::vector<uint8_t> data {};
485 NAPI_BT_CALL_RETURN(ParseArrayBufferParams(env, scanFilter, "serviceData", exist, data));
486 if (exist) {
487 bleScanFilter.SetServiceData(std::move(data));
488 }
489
490 std::vector<uint8_t> dataMask {};
491 NAPI_BT_CALL_RETURN(ParseArrayBufferParams(env, scanFilter, "serviceDataMask", exist, dataMask));
492 if (exist) {
493 bleScanFilter.SetServiceDataMask(std::move(dataMask));
494 }
495 return napi_ok;
496 }
497
ParseScanFilterManufactureDataParameters(const napi_env & env,napi_value & scanFilter,BleScanFilter & bleScanFilter)498 static napi_status ParseScanFilterManufactureDataParameters(
499 const napi_env &env, napi_value &scanFilter, BleScanFilter &bleScanFilter)
500 {
501 bool exist = false;
502 napi_value result;
503 NAPI_BT_CALL_RETURN(ParseNumberParams(env, scanFilter, "manufactureId", exist, result));
504 if (exist) {
505 uint32_t manufacturerId = 0;
506 NAPI_BT_CALL_RETURN(napi_get_value_uint32(env, result, &manufacturerId));
507 bleScanFilter.SetManufacturerId(manufacturerId);
508 HILOGI("Scan filter manufacturerId is %{public}#x", manufacturerId);
509 }
510
511 exist = false;
512 std::vector<uint8_t> data {};
513 NAPI_BT_CALL_RETURN(ParseArrayBufferParams(env, scanFilter, "manufactureData", exist, data));
514 if (exist) {
515 bleScanFilter.SetManufactureData(std::move(data));
516 }
517
518 std::vector<uint8_t> dataMask {};
519 NAPI_BT_CALL_RETURN(ParseArrayBufferParams(env, scanFilter, "manufactureDataMask", exist, dataMask));
520 if (exist) {
521 bleScanFilter.SetManufactureDataMask(std::move(dataMask));
522 }
523 return napi_ok;
524 }
525
ParseScanFilter(const napi_env & env,napi_value & scanFilter,BleScanFilter & bleScanFilter)526 static napi_status ParseScanFilter(const napi_env &env, napi_value &scanFilter, BleScanFilter &bleScanFilter)
527 {
528 HILOGI("enter");
529 std::vector<std::string> expectedNames {"deviceId", "name", "serviceUuid", "serviceUuidMask",
530 "serviceSolicitationUuid", "serviceSolicitationUuidMask", "serviceData", "serviceDataMask", "manufactureId",
531 "manufactureData", "manufactureDataMask"};
532 NAPI_BT_CALL_RETURN(NapiCheckObjectPropertiesName(env, scanFilter, expectedNames));
533
534 NAPI_BT_CALL_RETURN(ParseScanFilterDeviceIdParameters(env, scanFilter, bleScanFilter));
535 NAPI_BT_CALL_RETURN(ParseScanFilterLocalNameParameters(env, scanFilter, bleScanFilter));
536 NAPI_BT_CALL_RETURN(ParseScanFilterServiceUuidParameters(env, scanFilter, bleScanFilter));
537 NAPI_BT_CALL_RETURN(ParseScanFilterSolicitationUuidParameters(env, scanFilter, bleScanFilter));
538 NAPI_BT_CALL_RETURN(ParseScanFilterServiceDataParameters(env, scanFilter, bleScanFilter));
539 NAPI_BT_CALL_RETURN(ParseScanFilterManufactureDataParameters(env, scanFilter, bleScanFilter));
540 return napi_ok;
541 }
542
ParseScanFilterParameters(const napi_env & env,napi_value & args,std::vector<BleScanFilter> & params)543 static napi_status ParseScanFilterParameters(const napi_env &env, napi_value &args, std::vector<BleScanFilter> ¶ms)
544 {
545 HILOGI("enter");
546 NAPI_BT_CALL_RETURN(NapiIsArray(env, args));
547
548 uint32_t length = 0;
549 NAPI_BT_CALL_RETURN(napi_get_array_length(env, args, &length));
550 NAPI_BT_RETURN_IF(length == 0, "Requires array length > 0", napi_invalid_arg);
551 for (uint32_t i = 0; i < length; i++) {
552 napi_value scanFilter;
553 NAPI_BT_CALL_RETURN(napi_get_element(env, args, i, &scanFilter));
554 NAPI_BT_CALL_RETURN(NapiIsObject(env, scanFilter));
555 BleScanFilter bleScanFilter;
556 NAPI_BT_CALL_RETURN(ParseScanFilter(env, scanFilter, bleScanFilter));
557 params.push_back(bleScanFilter);
558 }
559 return napi_ok;
560 }
561
CheckBleScanParams(napi_env env,napi_callback_info info,std::vector<BleScanFilter> & outScanfilters,BleScanSettings & outSettinngs)562 static napi_status CheckBleScanParams(napi_env env, napi_callback_info info, std::vector<BleScanFilter> &outScanfilters,
563 BleScanSettings &outSettinngs)
564 {
565 size_t argc = ARGS_SIZE_TWO;
566 napi_value argv[ARGS_SIZE_TWO] = {nullptr};
567 napi_value thisVar = nullptr;
568 NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
569 NAPI_BT_RETURN_IF((argc == 0 || argc > ARGS_SIZE_TWO), "Requires 1 or 2 arguments.", napi_invalid_arg);
570
571 std::vector<BleScanFilter> scanfilters;
572 // Support null param
573 napi_valuetype type = napi_undefined;
574 NAPI_BT_CALL_RETURN(napi_typeof(env, argv[PARAM0], &type));
575 if (type == napi_null) {
576 BleScanFilter emptyFilter;
577 scanfilters.push_back(emptyFilter);
578 } else {
579 NAPI_BT_CALL_RETURN(ParseScanFilterParameters(env, argv[PARAM0], scanfilters));
580 }
581
582 if (argc == ARGS_SIZE_TWO) {
583 ScanOptions scanOptions;
584 NAPI_BT_CALL_RETURN(ParseScanParameters(env, info, argv[PARAM1], scanOptions));
585 outSettinngs.SetReportDelay(scanOptions.interval);
586 outSettinngs.SetScanMode(static_cast<int32_t>(scanOptions.dutyMode));
587 }
588
589 outScanfilters = std::move(scanfilters);
590 return napi_ok;
591 }
592
StartBLEScan(napi_env env,napi_callback_info info)593 napi_value StartBLEScan(napi_env env, napi_callback_info info)
594 {
595 HILOGI("enter");
596 std::vector<BleScanFilter> scanfilters;
597 BleScanSettings settinngs;
598 auto status = CheckBleScanParams(env, info, scanfilters, settinngs);
599 NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
600
601 int ret = BleCentralManagerGetInstance()->ConfigScanFilter(scanfilters);
602 NAPI_BT_ASSERT_RETURN_UNDEF(env, ret == NO_ERROR, ret);
603 ret = BleCentralManagerGetInstance()->StartScan(settinngs);
604 NAPI_BT_ASSERT_RETURN_UNDEF(env, ret == NO_ERROR, ret);
605
606 return NapiGetUndefinedRet(env);
607 }
608
StopBLEScan(napi_env env,napi_callback_info info)609 napi_value StopBLEScan(napi_env env, napi_callback_info info)
610 {
611 HILOGI("enter");
612 auto status = CheckEmptyParam(env, info);
613 NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
614
615 int ret = BleCentralManagerGetInstance()->StopScan();
616 NAPI_BT_ASSERT_RETURN_UNDEF(env, ret == NO_ERROR, ret);
617 return NapiGetUndefinedRet(env);
618 }
619
ParseAdvertisingSettingsParameters(const napi_env & env,const napi_callback_info & info,const napi_value & object,BleAdvertiserSettings & outSettings)620 static napi_status ParseAdvertisingSettingsParameters(
621 const napi_env &env, const napi_callback_info &info, const napi_value &object, BleAdvertiserSettings &outSettings)
622 {
623 HILOGI("enter");
624 NAPI_BT_CALL_RETURN(NapiCheckObjectPropertiesName(env, object, {"interval", "txPower", "connectable"}));
625
626 bool exist = false;
627 uint32_t interval = 0;
628 NAPI_BT_CALL_RETURN(NapiParseObjectUint32Optional(env, object, "interval", interval, exist));
629 if (exist) {
630 HILOGI("interval: %{public}u", interval);
631 outSettings.SetInterval(interval);
632 }
633
634 int32_t txPower = 0;
635 NAPI_BT_CALL_RETURN(NapiParseObjectInt32Optional(env, object, "txPower", txPower, exist));
636 if (exist) {
637 const int32_t minTxPower = -127;
638 const int32_t maxTxPower = 1;
639 if (txPower < minTxPower || txPower > maxTxPower) {
640 HILOGE("Invalid tx power: %{public}d", txPower);
641 return napi_invalid_arg;
642 }
643 HILOGI("txPower is %{public}d", txPower);
644 outSettings.SetTxPower(txPower);
645 }
646
647 bool connectable = false;
648 NAPI_BT_CALL_RETURN(NapiParseObjectBooleanOptional(env, object, "connectable", connectable, exist));
649 if (exist) {
650 HILOGI("connectable: %{public}d", connectable);
651 outSettings.SetConnectable(connectable);
652 }
653 return napi_ok;
654 }
655
ParseServiceUuidParameters(napi_env env,napi_value object,BleAdvertiserData & outData)656 static napi_status ParseServiceUuidParameters(napi_env env, napi_value object, BleAdvertiserData &outData)
657 {
658 HILOGI("enter");
659 std::vector<UUID> vec {};
660 NAPI_BT_CALL_RETURN(NapiParseObjectArray(env, object, "serviceUuids", vec));
661 for (size_t i = 0; i < vec.size(); ++i) {
662 outData.AddServiceUuid(vec[i]);
663 HILOGI("Service Uuid = %{public}s", vec[i].ToString().c_str());
664 }
665 return napi_ok;
666 }
667
ParseManufactureDataParameters(napi_env env,napi_value object,BleAdvertiserData & outData)668 static napi_status ParseManufactureDataParameters(napi_env env, napi_value object, BleAdvertiserData &outData)
669 {
670 HILOGI("enter");
671 std::vector<NapiAdvManufactureData> vec {};
672 NAPI_BT_CALL_RETURN(NapiParseObjectArray(env, object, "manufactureData", vec));
673 for (size_t i = 0; i < vec.size(); ++i) {
674 outData.AddManufacturerData(vec[i].id, vec[i].value);
675 }
676 return napi_ok;
677 }
678
ParseServiceDataParameters(napi_env env,napi_value object,BleAdvertiserData & outData)679 static napi_status ParseServiceDataParameters(napi_env env, napi_value object, BleAdvertiserData &outData)
680 {
681 HILOGI("enter");
682 std::vector<NapiAdvServiceData> vec {};
683 NAPI_BT_CALL_RETURN(NapiParseObjectArray(env, object, "serviceData", vec));
684 for (size_t i = 0; i < vec.size(); ++i) {
685 outData.AddServiceData(
686 ParcelUuid::FromString(vec[i].uuid),
687 std::string(vec[i].value.begin(), vec[i].value.end()));
688 }
689 return napi_ok;
690 }
691
ParseAdvertisDataParameters(const napi_env & env,const napi_callback_info & info,const napi_value & object,BleAdvertiserData & outData)692 static napi_status ParseAdvertisDataParameters(const napi_env &env, const napi_callback_info &info,
693 const napi_value &object, BleAdvertiserData &outData)
694 {
695 NAPI_BT_CALL_RETURN(NapiCheckObjectPropertiesName(
696 env, object, {"serviceUuids", "manufactureData", "serviceData", "includeDeviceName"}));
697
698 NAPI_BT_CALL_RETURN(ParseServiceUuidParameters(env, object, outData));
699 NAPI_BT_CALL_RETURN(ParseManufactureDataParameters(env, object, outData));
700 NAPI_BT_CALL_RETURN(ParseServiceDataParameters(env, object, outData));
701 bool exist = false;
702 bool includeDeviceName = false;
703 NAPI_BT_CALL_RETURN(NapiParseObjectBooleanOptional(env, object, "includeDeviceName", includeDeviceName, exist));
704 HILOGI("includeDeviceName: %{public}d", includeDeviceName);
705 outData.SetIncludeDeviceName(includeDeviceName);
706
707 return napi_ok;
708 }
709
CheckAdvertisingData(napi_env env,napi_callback_info info,BleAdvertiserSettings & outSettings,BleAdvertiserData & outAdvData,BleAdvertiserData & outRspData)710 napi_status CheckAdvertisingData(napi_env env, napi_callback_info info, BleAdvertiserSettings &outSettings,
711 BleAdvertiserData &outAdvData, BleAdvertiserData &outRspData)
712 {
713 size_t argc = ARGS_SIZE_THREE;
714 napi_value argv[ARGS_SIZE_THREE] = {nullptr};
715 napi_value thisVar = nullptr;
716 NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
717 NAPI_BT_RETURN_IF((argc != ARGS_SIZE_TWO && argc != ARGS_SIZE_THREE), "need 2 or 3 arguments.", napi_invalid_arg);
718
719 BleAdvertiserSettings settings;
720 NAPI_BT_CALL_RETURN(ParseAdvertisingSettingsParameters(env, info, argv[PARAM0], settings));
721 BleAdvertiserData advData;
722 NAPI_BT_CALL_RETURN(ParseAdvertisDataParameters(env, info, argv[PARAM1], advData));
723 BleAdvertiserData rspData;
724 if (argc == ARGS_SIZE_THREE) {
725 NAPI_BT_CALL_RETURN(ParseAdvertisDataParameters(env, info, argv[PARAM2], rspData));
726 }
727
728 outSettings = std::move(settings);
729 outAdvData = std::move(advData);
730 outRspData = std::move(rspData);
731 return napi_ok;
732 }
733
StartAdvertising(napi_env env,napi_callback_info info)734 napi_value StartAdvertising(napi_env env, napi_callback_info info)
735 {
736 HILOGI("enter");
737 BleAdvertiserSettings settings;
738 BleAdvertiserData advData;
739 BleAdvertiserData rspData;
740 auto status = CheckAdvertisingData(env, info, settings, advData, rspData);
741 NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
742
743 int ret = BleAdvertiserGetInstance()->StartAdvertising(
744 settings, advData, rspData, NapiBluetoothBleAdvertiseCallback::GetInstance());
745 NAPI_BT_ASSERT_RETURN_UNDEF(env, ret == BT_NO_ERROR, ret);
746 return NapiGetUndefinedRet(env);
747 }
748
CheckEmptyArgs(napi_env env,napi_callback_info info)749 static napi_status CheckEmptyArgs(napi_env env, napi_callback_info info)
750 {
751 size_t argc = 0;
752 napi_value thisVar = nullptr;
753 NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, nullptr, &thisVar, NULL));
754 NAPI_BT_RETURN_IF(argc > 0, "no needed arguments.", napi_invalid_arg);
755 return napi_ok;
756 }
757
StopAdvertising(napi_env env,napi_callback_info info)758 napi_value StopAdvertising(napi_env env, napi_callback_info info)
759 {
760 HILOGI("enter");
761 auto status = CheckEmptyArgs(env, info);
762 NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
763
764 int ret = BleAdvertiserGetInstance()->StopAdvertising(NapiBluetoothBleAdvertiseCallback::GetInstance());
765 NAPI_BT_ASSERT_RETURN_UNDEF(env, ret == BT_NO_ERROR, ret);
766 return NapiGetUndefinedRet(env);
767 }
768
GetConnectedBLEDevices(napi_env env,napi_callback_info info)769 napi_value GetConnectedBLEDevices(napi_env env, napi_callback_info info)
770 {
771 HILOGI("enter");
772 napi_value result = nullptr;
773 napi_create_array(env, &result);
774
775 auto status = ConvertStringVectorToJS(env, result, NapiGattServer::deviceList);
776 NAPI_BT_ASSERT_RETURN(env, status == napi_ok, BT_ERR_INTERNAL_ERROR, result);
777 return result;
778 }
779
PropertyInit(napi_env env,napi_value exports)780 napi_value PropertyInit(napi_env env, napi_value exports)
781 {
782 HILOGI("enter");
783
784 napi_value matchModeObj = nullptr;
785 napi_value scanDutyObj = nullptr;
786 napi_create_object(env, &matchModeObj);
787 napi_create_object(env, &scanDutyObj);
788
789 SetNamedPropertyByInteger(env, matchModeObj, MatchMode::MATCH_MODE_STICKY, "MATCH_MODE_STICKY");
790 SetNamedPropertyByInteger(env, matchModeObj, MatchMode::MATCH_MODE_AGGRESSIVE, "MATCH_MODE_AGGRESSIVE");
791 SetNamedPropertyByInteger(
792 env, scanDutyObj, static_cast<int32_t>(ScanDuty::SCAN_MODE_BALANCED), "SCAN_MODE_BALANCED");
793 SetNamedPropertyByInteger(
794 env, scanDutyObj, static_cast<int32_t>(ScanDuty::SCAN_MODE_LOW_LATENCY), "SCAN_MODE_LOW_LATENCY");
795 SetNamedPropertyByInteger(
796 env, scanDutyObj, static_cast<int32_t>(ScanDuty::SCAN_MODE_LOW_POWER), "SCAN_MODE_LOW_POWER");
797
798 #ifdef BLUETOOTH_API_SINCE_10
799 napi_value gattWriteTypeObj = nullptr;
800 napi_create_object(env, &gattWriteTypeObj);
801 SetNamedPropertyByInteger(env, gattWriteTypeObj, static_cast<int32_t>(NapiGattWriteType::WRITE), "WRITE");
802 SetNamedPropertyByInteger(
803 env, gattWriteTypeObj, static_cast<int32_t>(NapiGattWriteType::WRITE_NO_RESPONSE), "WRITE_NO_RESPONSE");
804 #endif
805
806 napi_property_descriptor exportFuncs[] = {
807 DECLARE_NAPI_PROPERTY("MatchMode", matchModeObj),
808 DECLARE_NAPI_PROPERTY("ScanDuty", scanDutyObj),
809 #ifdef BLUETOOTH_API_SINCE_10
810 DECLARE_NAPI_PROPERTY("GattWriteType", gattWriteTypeObj),
811 #endif
812 };
813
814 napi_define_properties(env, exports, sizeof(exportFuncs) / sizeof(*exportFuncs), exportFuncs);
815
816 return exports;
817 }
818 } // namespace Bluetooth
819 } // namespace OHOS
820