2 * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "bluetooth/bluetooth_le_adapter.h"
19 #include "common/logger.h"
20 #include "common/tools.h"
22 #include "bluetooth/bluetooth_instance.h"
23 #include "bluetooth/bluetooth_le_device.h"
24 #include "bluetooth/bluetooth_privilege.h"
25 #include "bluetooth/bluetooth_util.h"
26 using common::optional;
33 const std::string kData = "data";
34 const std::string kUuid = "uuid";
35 const std::string kUuids = "uuids";
36 const std::string kSolicitationUuids = "solicitationuuids";
37 const std::string kServiceData = "serviceData";
38 const std::string kServicesData = "servicesData";
40 class ParsedDataHolder {
42 ParsedDataHolder() : valid_(false) {
45 virtual ~ParsedDataHolder() {
64 HexData() : length_(0) {
67 void Parse(const std::string& d) {
69 const char* p_data = d.c_str();
70 int size = d.length();
71 if (size > 2 && (d.find("0x", 0) == 0 || d.find("0X", 0) == 0)) {
76 pointer_.reset(new char[length_]);
77 common::tools::HexToBin(p_data, size, (unsigned char*)pointer(), length_);
80 const char* pointer() const {
81 return pointer_.get();
89 std::unique_ptr<char[]> pointer_;
93 class BluetoothLEServiceData : public ParsedDataHolder {
95 const UUID& uuid() const {
99 const HexData& data() const {
103 static optional<BluetoothLEServiceData> Construct(const picojson::value& service_data_obj) {
106 const auto& data = service_data_obj.get(kData);
107 const auto& uuid_str = service_data_obj.get(kUuid);
108 if (!data.is<std::string>() || !uuid_str.is<std::string>()) {
109 LoggerE("Invalid data type in service data");
113 auto uuid = UUID::create(uuid_str.get<std::string>());
118 LoggerD("BluetoohtLEServiceData: %s : %s", uuid_str.get<std::string>().c_str(), data.get<std::string>().c_str());
119 return BluetoothLEServiceData{std::move(*uuid), data.get<std::string>()};
123 BluetoothLEServiceData(UUID&& uuid, const std::string& data_str) : uuid_{std::move(uuid)} {
124 ScopeLogger("UUID: %s, data_str: %s", uuid_.uuid_128_bit.c_str(), data_str.c_str());
126 data_.Parse(data_str);
135 class BluetoothLEManufacturerData : public ParsedDataHolder {
137 const std::string& id() const {
141 const HexData& data() const {
145 static bool Construct(const picojson::value& obj, BluetoothLEManufacturerData* out) {
147 if (!obj.is<picojson::object>() || !ParseId(obj, out) || !ParseData(obj, out)) {
157 static bool ParseId(const picojson::value& obj, BluetoothLEManufacturerData* out) {
159 const auto& id = obj.get("id");
160 if (id.is<std::string>()) {
161 out->id_ = id.get<std::string>();
169 static bool ParseData(const picojson::value& obj, BluetoothLEManufacturerData* out) {
172 const auto& val_data = obj.get("data");
174 if (val_data.is<std::string>()) {
175 out->data_.Parse(val_data.get<std::string>());
186 class BluetoothLEAdvertiseData : public ParsedDataHolder {
188 BluetoothLEAdvertiseData()
189 : ParsedDataHolder(),
190 include_name_(false),
191 appearance_(0), // 0 means unknown
192 include_tx_power_level_(false) {
196 bool include_name() const {
197 return include_name_;
200 const std::vector<UUID>& service_uuids() const {
201 return service_uuids_;
204 const std::vector<UUID>& solicitation_uuids() const {
205 return solicitation_uuids_;
208 int appearance() const {
212 bool include_tx_power_level() const {
213 return include_tx_power_level_;
216 const std::vector<BluetoothLEServiceData>& service_data() const {
217 return service_data_;
220 const BluetoothLEManufacturerData& manufacturer_data() const {
221 return manufacturer_data_;
224 static bool Construct(const picojson::value& obj, BluetoothLEAdvertiseData* out) {
226 if (!obj.is<picojson::object>() || !ParseIncludeName(obj, out) ||
227 !ParseServiceUUIDs(obj, out) || !ParseSolicitationUUIDs(obj, out) ||
228 !ParseAppearance(obj, out) || !ParseIncludeTxPowerLevel(obj, out) ||
229 !ParseServiceData(obj, out) || !ParseManufacturerData(obj, out)) {
239 static bool ParseIncludeName(const picojson::value& obj, BluetoothLEAdvertiseData* out) {
241 const auto& include_name = obj.get("includeName");
242 if (include_name.is<bool>()) {
243 out->include_name_ = include_name.get<bool>();
244 } else if (!include_name.is<picojson::null>()) {
251 static bool ParseServiceUUIDs(const picojson::value& obj, BluetoothLEAdvertiseData* out) {
253 const auto& service_uuids = obj.get(kUuids);
254 if (service_uuids.is<picojson::array>()) {
255 for (const auto& uuid : service_uuids.get<picojson::array>()) {
256 if (!uuid.is<std::string>()) {
257 LoggerE("uuid is not a string");
261 auto uuid_obj = UUID::create(uuid.get<std::string>());
263 out->service_uuids_.push_back(*uuid_obj);
268 } else if (!service_uuids.is<picojson::null>()) {
269 LoggerE("Invalid service_uuids type");
276 static bool ParseSolicitationUUIDs(const picojson::value& obj, BluetoothLEAdvertiseData* out) {
278 const auto& solicitation_uuids = obj.get(kSolicitationUuids);
279 if (solicitation_uuids.is<picojson::array>()) {
280 for (const auto& uuid : solicitation_uuids.get<picojson::array>()) {
281 if (!uuid.is<std::string>()) {
282 LoggerE("uuid is not a string");
286 auto uuid_obj = UUID::create(uuid.get<std::string>());
288 out->solicitation_uuids_.push_back(*uuid_obj);
293 } else if (!solicitation_uuids.is<picojson::null>()) {
300 static bool ParseAppearance(const picojson::value& obj, BluetoothLEAdvertiseData* out) {
302 const auto& appearance = obj.get("appearance");
303 if (appearance.is<double>()) {
304 out->appearance_ = static_cast<decltype(appearance_)>(appearance.get<double>());
305 } else if (!appearance.is<picojson::null>()) {
312 static bool ParseIncludeTxPowerLevel(const picojson::value& obj, BluetoothLEAdvertiseData* out) {
314 const auto& include_tx_power_level = obj.get("includeTxPowerLevel");
315 if (include_tx_power_level.is<bool>()) {
316 out->include_tx_power_level_ = include_tx_power_level.get<bool>();
317 } else if (!include_tx_power_level.is<picojson::null>()) {
324 static bool ParseServiceData(const picojson::value& obj, BluetoothLEAdvertiseData* out) {
327 const auto& service_data_obj = obj.get(kServiceData);
328 const auto& services_data_obj = obj.get(kServicesData);
330 if (service_data_obj.is<picojson::null>() && services_data_obj.is<picojson::null>()) {
331 LoggerD("Service data is null");
335 // check servicesData first and append services to a vector (higher priority)
336 if (!services_data_obj.is<picojson::null>() && services_data_obj.is<picojson::array>()) {
337 LoggerD("Parsing service data array");
338 for (auto single_service : services_data_obj.get<picojson::array>()) {
339 auto service_data = BluetoothLEServiceData::Construct(single_service);
343 out->service_data_.emplace_back(std::move(*service_data));
346 } else if (!service_data_obj.is<picojson::null>() && service_data_obj.is<picojson::object>()) {
347 LoggerD("Parsing single service data");
348 auto service_data = BluetoothLEServiceData::Construct(service_data_obj);
352 out->service_data_.emplace_back(std::move(*service_data));
358 static bool ParseManufacturerData(const picojson::value& obj, BluetoothLEAdvertiseData* out) {
360 const auto& manufacturer_data = obj.get("manufacturerData");
361 BluetoothLEManufacturerData data;
362 if (BluetoothLEManufacturerData::Construct(manufacturer_data, &data)) {
363 out->manufacturer_data_ = std::move(data);
364 } else if (!manufacturer_data.is<picojson::null>()) {
372 std::vector<UUID> service_uuids_;
373 std::vector<UUID> solicitation_uuids_;
375 bool include_tx_power_level_;
376 std::vector<BluetoothLEServiceData> service_data_;
377 BluetoothLEManufacturerData manufacturer_data_;
382 bool ToBool(bt_adapter_le_state_e state) {
383 return (BT_ADAPTER_LE_ENABLED == state) ? true : false;
387 const std::string kAction = "action";
389 const std::string kOnScanSuccess = "onsuccess";
390 const std::string kOnScanError = "onerror";
391 const std::string kScanEvent = "BluetoothLEScanCallback";
393 const std::string kOnAdvertiseState = "onstate";
394 const std::string kOnAdvertiseError = "onerror";
395 const std::string kAdvertiseEvent = "BluetoothLEAdvertiseCallback";
399 using common::ErrorCode;
400 using common::PlatformResult;
401 using common::tools::ReportError;
402 using common::tools::ReportSuccess;
404 BluetoothLEAdapter::BluetoothLEAdapter(BluetoothInstance& instance)
405 : instance_(instance), enabled_(false), scanning_(false), bt_advertiser_(nullptr) {
408 bt_adapter_le_state_e le_state = BT_ADAPTER_LE_DISABLED;
410 int ret = bt_adapter_le_get_state(&le_state);
412 if (BT_ERROR_NONE == ret) {
413 enabled_ = ToBool(le_state);
415 ret = bt_adapter_le_set_state_changed_cb(OnStateChanged, this);
416 if (BT_ERROR_NONE != ret) {
417 LoggerE("Failed to register BTLE state changed listener.");
420 LoggerE("Failed to obtain current state of BTLE.");
424 BluetoothLEAdapter::~BluetoothLEAdapter() {
426 bt_adapter_le_unset_state_changed_cb();
428 bt_adapter_le_stop_scan();
430 if (bt_advertiser_) {
431 bt_adapter_le_stop_advertising(bt_advertiser_);
432 bt_adapter_le_destroy_advertiser(bt_advertiser_);
436 void BluetoothLEAdapter::StartScan(const picojson::value& data, picojson::object& out) {
438 CHECK_BACKWARD_COMPABILITY_PRIVILEGE_ACCESS(Privilege::kBluetooth, Privilege::kBluetoothAdmin,
441 int ret = bt_adapter_le_start_scan(OnScanResult, this);
443 if (BT_ERROR_NONE != ret) {
444 if (BT_ERROR_NOW_IN_PROGRESS == ret) {
445 LogAndReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, "Scan already in progress"),
446 &out, ("Scan in progress %d (%s)", ret, get_error_message(ret)));
448 // other errors are reported asynchronously
449 picojson::value value = picojson::value(picojson::object());
450 picojson::object* data_obj = &value.get<picojson::object>();
451 data_obj->insert(std::make_pair(kAction, picojson::value(kOnScanError)));
452 LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to start scan"), data_obj,
453 ("Failed to start scan: %d (%s)", ret, get_error_message(ret)));
454 instance_.FireEvent(kScanEvent, value);
462 void BluetoothLEAdapter::StopScan(const picojson::value& data, picojson::object& out) {
464 CHECK_BACKWARD_COMPABILITY_PRIVILEGE_ACCESS(Privilege::kBluetooth, Privilege::kBluetoothAdmin,
467 int ret = bt_adapter_le_stop_scan();
469 if (BT_ERROR_NONE != ret && BT_ERROR_NOT_IN_PROGRESS != ret) {
470 LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to stop scan"), &out,
471 ("Failed to stop scan: %d (%s)", ret, get_error_message(ret)));
478 void BluetoothLEAdapter::IsScanning(picojson::object& out) {
482 int ret = bt_adapter_le_is_discovering(&is_scanning);
484 if (BT_ERROR_NONE != ret) {
486 PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to check for scanning in progress"), &out,
487 ("Failed to check for scanning in progress: %d (%s)", ret, get_error_message(ret)));
489 scanning_ = is_scanning;
490 ReportSuccess(picojson::value(is_scanning), out);
494 void BluetoothLEAdapter::StartAdvertise(const picojson::value& data, picojson::object& out) {
496 CHECK_BACKWARD_COMPABILITY_PRIVILEGE_ACCESS(Privilege::kBluetooth, Privilege::kBluetoothAdmin,
499 const auto& json_advertise_data = data.get("advertiseData");
500 const auto& json_packet_type = data.get("packetType");
501 const auto& json_mode = data.get("mode");
502 const auto& json_connectable = data.get("connectable");
504 if (!json_advertise_data.is<picojson::object>() || !json_packet_type.is<std::string>() ||
505 !json_mode.is<std::string>() || !json_connectable.is<bool>()) {
506 LogAndReportError(PlatformResult(ErrorCode::TYPE_MISMATCH_ERR, "Unexpected parameter type"),
511 BluetoothLEAdvertiseData advertise_data;
512 if (!BluetoothLEAdvertiseData::Construct(json_advertise_data, &advertise_data)) {
514 PlatformResult(ErrorCode::TYPE_MISMATCH_ERR, "Unexpected value of advertise data"), &out);
518 bt_adapter_le_packet_type_e packet_type = BT_ADAPTER_LE_PACKET_ADVERTISING;
520 const auto& str_packet_type = json_packet_type.get<std::string>();
521 if ("ADVERTISE" == str_packet_type) {
522 packet_type = BT_ADAPTER_LE_PACKET_ADVERTISING;
523 } else if ("SCAN_RESPONSE" == str_packet_type) {
524 packet_type = BT_ADAPTER_LE_PACKET_SCAN_RESPONSE;
527 PlatformResult(ErrorCode::TYPE_MISMATCH_ERR, "Unexpected value of packet type"), &out,
528 ("Wrong packet_type: %s", str_packet_type.c_str()));
533 bt_adapter_le_advertising_mode_e mode = BT_ADAPTER_LE_ADVERTISING_MODE_BALANCED;
535 const auto& str_mode = json_mode.get<std::string>();
536 if ("BALANCED" == str_mode) {
537 mode = BT_ADAPTER_LE_ADVERTISING_MODE_BALANCED;
538 } else if ("LOW_LATENCY" == str_mode) {
539 mode = BT_ADAPTER_LE_ADVERTISING_MODE_LOW_LATENCY;
540 } else if ("LOW_ENERGY" == str_mode) {
541 mode = BT_ADAPTER_LE_ADVERTISING_MODE_LOW_ENERGY;
543 LogAndReportError(PlatformResult(ErrorCode::TYPE_MISMATCH_ERR, "Unexpected value of mode"),
544 &out, ("Wrong mode: %s", str_mode.c_str()));
549 if (nullptr != bt_advertiser_) {
550 LogAndReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, "Advertise already in progress"),
555 bt_advertiser_h advertiser = nullptr;
557 int ret = bt_adapter_le_create_advertiser(&advertiser);
558 if (BT_ERROR_NONE != ret) {
560 util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
561 ("bt_adapter_le_create_advertiser() failed with: %d, (%s)", ret, get_error_message(ret)));
565 std::unique_ptr<std::remove_pointer<bt_advertiser_h>::type, int (*)(bt_advertiser_h)>
566 advertiser_ptr(advertiser,
567 &bt_adapter_le_destroy_advertiser); // automatically release the memory
569 // configure advertiser
570 if (advertise_data.include_name()) {
571 ret = bt_adapter_le_set_advertising_device_name(advertiser, packet_type,
572 advertise_data.include_name());
573 if (BT_ERROR_NONE != ret) {
574 LogAndReportError(util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
575 ("bt_adapter_le_set_advertising_device_name() failed with: %d (%s)", ret,
576 get_error_message(ret)));
581 for (const auto& uuid : advertise_data.service_uuids()) {
583 * This native function accepts 16 or 128 bit UUIDs.
584 * To handle also 32 bit UUIDs, we pass all UUIDs in their canonical form.
587 * The documentation of Native Bluetooth API says, this function advertises 128-bit UUIDs,
588 * that have 32-bit equivalents in the full 128-bit form.
589 * However, as of the day of writing this comment, packets advertised
590 * by the device contain these UUIDs in their 32-bit formats,
591 * i.e. AD fields with 0x04 («Incomplete List of 32-bit Service Class UUIDs») type.
592 * For example, "12345678-0000-1000-8000-00805F9B34FB" is advertised as "12345678".
594 ret = bt_adapter_le_add_advertising_service_uuid(advertiser, packet_type,
595 uuid.uuid_128_bit.c_str());
596 if (BT_ERROR_NONE != ret) {
597 LogAndReportError(util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
598 ("bt_adapter_le_add_advertising_service_uuid() failed with: %d (%s)", ret,
599 get_error_message(ret)));
604 for (const auto& uuid : advertise_data.solicitation_uuids()) {
606 * This native function accepts 16 or 128 bit UUIDs.
607 * To handle also 32 bit UUIDs, we pass all UUIDs in their canonical form.
610 * The documentation of Native Bluetooth API says, it advertises 128-bit UUIDs,
611 * that have 32-bit equivalents in the full 128-bit form.
612 * However, as of the day of writing this comment, packets advertised
613 * by the device contain these UUIDs in their 32-bit formats,
614 * i.e. AD fields with 0x1F («List of 32-bit Service Solicitation UUIDs») type.
615 * For example, "12345678-0000-1000-8000-00805F9B34FB" is advertised as "12345678".
617 ret = bt_adapter_le_add_advertising_service_solicitation_uuid(advertiser, packet_type,
618 uuid.uuid_128_bit.c_str());
619 if (BT_ERROR_NONE != ret) {
621 util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
622 ("bt_adapter_le_add_advertising_service_solicitation_uuid() failed with: %d (%s)", ret,
623 get_error_message(ret)));
628 ret = bt_adapter_le_set_advertising_appearance(advertiser, packet_type,
629 advertise_data.appearance());
630 if (BT_ERROR_NONE != ret) {
631 LogAndReportError(util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
632 ("bt_adapter_le_set_advertising_appearance() failed with: %d (%s)", ret,
633 get_error_message(ret)));
637 if (advertise_data.include_tx_power_level()) {
638 ret = bt_adapter_le_set_advertising_tx_power_level(advertiser, packet_type,
639 advertise_data.include_tx_power_level());
640 if (BT_ERROR_NONE != ret) {
641 LogAndReportError(util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
642 ("bt_adapter_le_set_advertising_tx_power_level() failed with: %d (%s)", ret,
643 get_error_message(ret)));
648 if (advertise_data.service_data().empty()) {
649 LoggerD("service data is empty");
651 for (const auto& service_data_obj : advertise_data.service_data()) {
652 ret = bt_adapter_le_add_advertising_service_data(
653 advertiser, packet_type, service_data_obj.uuid().ShortestPossibleFormat().c_str(),
654 service_data_obj.data().pointer(), service_data_obj.data().length());
655 if (BT_ERROR_NONE != ret) {
656 std::string error_message = "Failed to create advertiser";
657 if (BT_ERROR_QUOTA_EXCEEDED == ret && !service_data_obj.uuid().To16Bit()) {
659 "Failed to start advertising: only 16 bit values of BluetoothLEServiceData::uuid are "
661 } else if (BT_ERROR_ALREADY_DONE == ret) { // in case of duplicated advertiser data report it with correct message
662 LogAndReportError(util::GetBluetoothError(BT_ERROR_INVALID_PARAMETER, "Duplicated advertiser data"), &out,
663 ("bt_adapter_le_set_advertising_device_name() failed with: %d (%s)", ret,
664 get_error_message(ret)));
668 LogAndReportError(util::GetBluetoothError(ret, error_message), &out,
669 ("bt_adapter_le_add_advertising_service_data() failed with: %d (%s)", ret,
670 get_error_message(ret)));
676 const auto& manufacturer_data = advertise_data.manufacturer_data();
677 if (manufacturer_data.id().empty() && nullptr == manufacturer_data.data().pointer()) {
678 LoggerD("manufacturerData is empty");
680 if (manufacturer_data.valid()) {
681 ret = bt_adapter_le_add_advertising_manufacturer_data(
682 advertiser, packet_type, atoi(manufacturer_data.id().c_str()),
683 manufacturer_data.data().pointer(), manufacturer_data.data().length());
684 if (BT_ERROR_NONE != ret) {
685 LogAndReportError(util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
686 ("bt_adapter_le_add_advertising_manufacturer_data() failed with: %d (%s)",
687 ret, get_error_message(ret)));
693 ret = bt_adapter_le_set_advertising_mode(advertiser, mode);
694 if (BT_ERROR_NONE != ret) {
696 util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
697 ("bt_adapter_le_set_advertising_mode() failed with: %d (%s)", ret, get_error_message(ret)));
701 ret = bt_adapter_le_set_advertising_connectable(advertiser, json_connectable.get<bool>());
702 if (BT_ERROR_NONE != ret) {
703 LogAndReportError(util::GetBluetoothError(ret, "Failed to create advertiser"), &out,
704 ("bt_adapter_le_set_advertising_connectable() failed with: %d (%s)", ret,
705 get_error_message(ret)));
709 // advertiser is ready, let's start advertising
710 ret = bt_adapter_le_start_advertising_new(advertiser, OnAdvertiseResult, this);
711 if (BT_ERROR_NONE != ret) {
712 if (BT_ERROR_NOW_IN_PROGRESS == ret) {
714 PlatformResult(ErrorCode::INVALID_STATE_ERR, "Advertise already in progress"), &out,
715 ("bt_adapter_le_start_advertising_new error: %d (%s)", ret, get_error_message(ret)));
719 LogAndReportError(util::GetBluetoothError(ret, "Failed to start advertising"), &out,
720 ("bt_adapter_le_start_advertising_new() failed with: %d (%s)", ret,
721 get_error_message(ret)));
725 // everything went well, we want to store the pointer, so unique_ptr should no longer manage the
727 bt_advertiser_ = advertiser_ptr.release();
731 void BluetoothLEAdapter::StopAdvertise(const picojson::value& data, picojson::object& out) {
733 CHECK_BACKWARD_COMPABILITY_PRIVILEGE_ACCESS(Privilege::kBluetooth, Privilege::kBluetoothAdmin,
736 if (nullptr != bt_advertiser_) {
737 int ret = bt_adapter_le_stop_advertising(bt_advertiser_);
738 if (BT_ERROR_NONE != ret && BT_ERROR_NOT_IN_PROGRESS != ret) {
740 PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to stop advertising"), &out,
741 ("bt_adapter_le_stop_advertising() failed with: %d (%s)", ret, get_error_message(ret)));
745 bt_advertiser_ = nullptr;
747 LoggerD("Advertising is not in progress");
753 void BluetoothLEAdapter::OnStateChanged(int result, bt_adapter_le_state_e adapter_le_state,
757 auto adapter = static_cast<BluetoothLEAdapter*>(user_data);
760 LoggerE("user_data is NULL");
764 adapter->enabled_ = ToBool(adapter_le_state);
767 void BluetoothLEAdapter::OnScanResult(int result, bt_adapter_le_device_scan_result_info_s* info,
769 ScopeLogger("result: %d, info: %p, data: %p", result, info, user_data);
771 auto adapter = static_cast<BluetoothLEAdapter*>(user_data);
774 LoggerE("user_data is NULL");
778 picojson::value value = picojson::value(picojson::object());
779 picojson::object* data_obj = &value.get<picojson::object>();
781 if (BT_ERROR_NONE != result) {
782 LogAndReportError(util::GetBluetoothError(result, "Error during scanning"), data_obj,
783 ("Error during scanning: %d (%s)", result, get_error_message(result)));
784 data_obj->insert(std::make_pair(kAction, picojson::value(kOnScanError)));
786 // this is probably capi-network-bluetooth error: when scan is stopped info has 0x1 value
787 if (nullptr != info && reinterpret_cast<void*>(0x1) != info) {
789 LoggerD("Device found");
790 picojson::value data{picojson::object{}};
791 const auto& ret = BluetoothLEDevice::ToJson(info, &data.get<picojson::object>());
793 data_obj->insert(std::make_pair(kAction, picojson::value(kOnScanSuccess)));
794 data_obj->insert(std::make_pair(kData, data));
796 LogAndReportError(ret, data_obj, ("Failed to parse Bluetooth LE device"));
797 data_obj->insert(std::make_pair(kAction, picojson::value(kOnScanError)));
802 adapter->instance_.FireEvent(kScanEvent, value);
805 void BluetoothLEAdapter::OnAdvertiseResult(int result, bt_advertiser_h advertiser,
806 bt_adapter_le_advertising_state_e adv_state,
808 ScopeLogger("result: %d, advertiser: %p, adv_state: %d, user_data: %p", result, advertiser,
809 adv_state, user_data);
811 auto adapter = static_cast<BluetoothLEAdapter*>(user_data);
814 LoggerE("user_data is NULL");
818 picojson::value value = picojson::value(picojson::object());
819 picojson::object* data_obj = &value.get<picojson::object>();
821 if (BT_ERROR_NONE != result) {
822 LogAndReportError(util::GetBluetoothError(result, "Error during advertising"), data_obj,
823 ("Error during advertising: %d (%s)", result, get_error_message(result)));
824 data_obj->insert(std::make_pair(kAction, picojson::value(kOnAdvertiseError)));
826 const char* state = (BT_ADAPTER_LE_ADVERTISING_STARTED == adv_state) ? "STARTED" : "STOPPED";
827 LoggerD("Advertise state is: %s", state);
828 data_obj->insert(std::make_pair(kAction, picojson::value(kOnAdvertiseState)));
829 ReportSuccess(picojson::value(state), *data_obj);
830 if (adv_state == BT_ADAPTER_LE_ADVERTISING_STOPPED) {
831 LoggerD("Advertiser destroy");
832 int ret = bt_adapter_le_destroy_advertiser(advertiser);
834 * Destruction of advertiser should not fail.
835 * If it does, we only log the info and set the pointer to nullptr
836 * anyway to let the user start new advertising in the future.
838 adapter->bt_advertiser_ = nullptr;
839 if (BT_ERROR_NONE != ret && BT_ERROR_NOT_IN_PROGRESS != ret) {
840 LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to destroy advertiser"),
841 data_obj, ("bt_adapter_le_destroy_advertiser() failed with: %d (%s)", ret,
842 get_error_message(ret)));
845 LoggerD("bt_adapter_le_destroy_advertiser(): SUCCESS");
849 adapter->instance_.FireEvent(kAdvertiseEvent, value);
852 } // namespace bluetooth
853 } // namespace extension