From 54d31abedf388d257f2e06b723990be217871143 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Fri, 8 Sep 2023 16:53:49 +0530 Subject: [PATCH] Add an initial BLE v2 implementation. --- internal/platform/implementation/linux/BUILD | 16 +- .../implementation/linux/ble_gatt_server.cc | 147 ++++++ .../implementation/linux/ble_gatt_server.h | 96 ++++ .../implementation/linux/ble_v2_medium.cc | 436 ++++++++++++++++++ .../implementation/linux/ble_v2_medium.h | 104 ++++- .../linux/ble_v2_server_socket.h | 42 ++ .../linux/bluez_advertisement_monitor.cc | 73 +++ .../linux/bluez_advertisement_monitor.h | 95 ++++ .../bluez_advertisement_monitor_manager.h | 87 ++++ .../linux/bluez_gatt_characteristic.cc | 231 ++++++++++ .../linux/bluez_gatt_characteristic.h | 125 +++++ .../implementation/linux/bluez_gatt_manager.h | 44 ++ .../linux/bluez_gatt_service.cc | 63 +++ .../implementation/linux/bluez_gatt_service.h | 110 +++++ .../linux/bluez_le_advertisement.cc | 54 +++ .../linux/bluez_le_advertisement.h | 112 +++++ .../advertisement_monitor_manager_client.h | 57 +++ .../dbus/bluez/advertisement_monitor_server.h | 57 +++ .../dbus/bluez/gatt_characteristic_client.h | 89 ++++ .../dbus/bluez/gatt_characteristic_server.h | 59 +++ .../dbus/bluez/gatt_manager_client.h | 46 ++ .../dbus/bluez/gatt_service_server.h | 45 ++ .../bluez/le_advertisement_manager_client.h | 77 ++++ .../dbus/bluez/le_advertisement_server.h | 65 +++ .../bluez/org.bluez.AdvertisementMonitor1.xml | 27 ++ ...org.bluez.AdvertisementMonitorManager1.xml | 14 + .../bluez/org.bluez.GattCharacteristic1.xml | 28 ++ .../dbus/bluez/org.bluez.GattManager1.xml | 13 + .../dbus/bluez/org.bluez.GattService1.xml | 10 + .../dbus/bluez/org.bluez.LEAdvertisement1.xml | 21 + .../org.bluez.LEAdvertisementManager1.xml | 19 + .../platform/implementation/linux/platform.cc | 8 +- 32 files changed, 2442 insertions(+), 28 deletions(-) create mode 100644 internal/platform/implementation/linux/ble_gatt_server.cc create mode 100644 internal/platform/implementation/linux/ble_gatt_server.h create mode 100644 internal/platform/implementation/linux/ble_v2_medium.cc create mode 100644 internal/platform/implementation/linux/ble_v2_server_socket.h create mode 100644 internal/platform/implementation/linux/bluez_advertisement_monitor.cc create mode 100644 internal/platform/implementation/linux/bluez_advertisement_monitor.h create mode 100644 internal/platform/implementation/linux/bluez_advertisement_monitor_manager.h create mode 100644 internal/platform/implementation/linux/bluez_gatt_characteristic.cc create mode 100644 internal/platform/implementation/linux/bluez_gatt_characteristic.h create mode 100644 internal/platform/implementation/linux/bluez_gatt_manager.h create mode 100644 internal/platform/implementation/linux/bluez_gatt_service.cc create mode 100644 internal/platform/implementation/linux/bluez_gatt_service.h create mode 100644 internal/platform/implementation/linux/bluez_le_advertisement.cc create mode 100644 internal/platform/implementation/linux/bluez_le_advertisement.h create mode 100644 internal/platform/implementation/linux/generated/dbus/bluez/advertisement_monitor_manager_client.h create mode 100644 internal/platform/implementation/linux/generated/dbus/bluez/advertisement_monitor_server.h create mode 100644 internal/platform/implementation/linux/generated/dbus/bluez/gatt_characteristic_client.h create mode 100644 internal/platform/implementation/linux/generated/dbus/bluez/gatt_characteristic_server.h create mode 100644 internal/platform/implementation/linux/generated/dbus/bluez/gatt_manager_client.h create mode 100644 internal/platform/implementation/linux/generated/dbus/bluez/gatt_service_server.h create mode 100644 internal/platform/implementation/linux/generated/dbus/bluez/le_advertisement_manager_client.h create mode 100644 internal/platform/implementation/linux/generated/dbus/bluez/le_advertisement_server.h create mode 100644 internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.AdvertisementMonitor1.xml create mode 100644 internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.AdvertisementMonitorManager1.xml create mode 100644 internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.GattCharacteristic1.xml create mode 100644 internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.GattManager1.xml create mode 100644 internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.GattService1.xml create mode 100644 internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.LEAdvertisement1.xml create mode 100644 internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.LEAdvertisementManager1.xml diff --git a/internal/platform/implementation/linux/BUILD b/internal/platform/implementation/linux/BUILD index 60e094a7..2658d196 100644 --- a/internal/platform/implementation/linux/BUILD +++ b/internal/platform/implementation/linux/BUILD @@ -55,8 +55,10 @@ cc_library( name = "comm", hdrs = [ "avahi.h", + "ble_gatt_server.h", "ble_medium.h", "ble_v2_medium.h", + "ble_v2_server_socket.h", "bluetooth_adapter.h", "bluetooth_bluez_profile.h", "bluetooth_classic_device.h", @@ -66,6 +68,12 @@ cc_library( "bluetooth_devices.h", "bluetooth_pairing.h", "bluez.h", + "bluez_advertisement_monitor.h", + "bluez_advertisement_monitor_manager.h", + "bluez_gatt_characteristic.h", + "bluez_gatt_manager.h", + "bluez_gatt_service.h", + "bluez_le_advertisement.h", "dbus.h", "network_manager.h", "network_manager_active_connection.h", @@ -125,6 +133,8 @@ cc_library( name = "linux", srcs = [ "avahi.cc", + "ble_gatt_server.cc", + "ble_v2_medium.cc", "bluetooth_adapter.cc", "bluetooth_bluez_profile.cc", "bluetooth_classic_socket.cc", @@ -134,6 +144,10 @@ cc_library( "bluetooth_devices.cc", "bluetooth_pairing.cc", "bluez.cc", + "bluez_advertisement_monitor.cc", + "bluez_gatt_characteristic.cc", + "bluez_gatt_service.cc", + "bluez_le_advertisement.cc", "dbus.cc", "executor.cc", "network_manager.cc", @@ -224,6 +238,7 @@ cc_test( "atomic_boolean_test.cc", "atomic_reference_test.cc", "mutex_test.cc", + "utils_test.cc", # "bluetooth_adapter_test.cc", # "crypto_test.cc", # "device_info_test.cc", @@ -236,7 +251,6 @@ cc_test( # "submittable_executor_test.cc", # "thread_pool_test.cc", # "timer_test.cc", - # "utils_test.cc", ], tags = ["notap"], deps = [ diff --git a/internal/platform/implementation/linux/ble_gatt_server.cc b/internal/platform/implementation/linux/ble_gatt_server.cc new file mode 100644 index 00000000..f943016a --- /dev/null +++ b/internal/platform/implementation/linux/ble_gatt_server.cc @@ -0,0 +1,147 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "internal/platform/implementation/linux/ble_gatt_server.h" +#include "absl/strings/substitute.h" +#include "internal/platform/implementation/ble_v2.h" +#include "internal/platform/implementation/linux/bluez_gatt_characteristic.h" +#include "internal/platform/implementation/linux/bluez_gatt_manager.h" +#include "internal/platform/implementation/linux/bluez_gatt_service.h" +#include "internal/platform/implementation/linux/dbus.h" +#include "internal/platform/implementation/linux/generated/dbus/bluez/gatt_service_server.h" +#include "internal/platform/uuid.h" + +namespace nearby { +namespace linux { +absl::optional +GattServer::CreateCharacteristic( + const Uuid& service_uuid, const Uuid& characteristic_uuid, + api::ble_v2::GattCharacteristic::Permission permission, + api::ble_v2::GattCharacteristic::Property property) { + absl::MutexLock lock(&services_mutex_); + if (services_.count(service_uuid) == 1) { + if (services_[service_uuid]->AddCharacteristic( + service_uuid, characteristic_uuid, permission, property)) { + api::ble_v2::GattCharacteristic characteristic{ + characteristic_uuid, service_uuid, permission, property}; + return characteristic; + } + return std::nullopt; + } + + auto count = services_.size(); + auto service = std::make_unique( + system_bus_, count, service_uuid, server_cb_, devices_); + try { + service->emitInterfacesAddedSignal( + {org::bluez::GattService1_adaptor::INTERFACE_NAME}); + } catch (const sdbus::Error& e) { + NEARBY_LOGS(ERROR) + << __func__ + << ": error emitting InterfacesAdded signal for object path " + << service->getObjectPath() << " with name '" << e.getName() + << "' and message '" << e.getMessage() << "'"; + return std::nullopt; + } + + if (service->AddCharacteristic(service_uuid, characteristic_uuid, permission, + property)) { + bluez::GattManager manager(system_bus_, adapter_.GetObjectPath()); + try { + NEARBY_LOGS(VERBOSE) << __func__ << ": registering service " + << service->getObjectPath(); + manager.RegisterApplication("/", {}); + } catch (const sdbus::Error& e) { + DBUS_LOG_METHOD_CALL_ERROR(&manager, "RegisterApplication", e); + return std::nullopt; + } + + services_.insert({service_uuid, std::move(service)}); + + api::ble_v2::GattCharacteristic characteristic{ + characteristic_uuid, service_uuid, permission, property}; + return characteristic; + } + + return std::nullopt; +} + +bool GattServer::UpdateCharacteristic( + const api::ble_v2::GattCharacteristic& characteristic, + const nearby::ByteArray& value) { + std::shared_ptr chr = nullptr; + { + absl::ReaderMutexLock lock(&services_mutex_); + if (services_.count(characteristic.service_uuid) == 0) { + NEARBY_LOGS(ERROR) << __func__ << ": GATT Service " + << std::string{characteristic.service_uuid} + << " doesn't exist"; + return false; + } + chr = services_[characteristic.service_uuid]->GetCharacteristic( + characteristic.uuid); + } + if (chr == nullptr) { + NEARBY_LOGS(ERROR) << __func__ << ": Characteristic " + << std::string{characteristic.uuid} + << " does not exist under service " + << std::string{characteristic.service_uuid}; + return false; + } + assert(chr != nullptr); + chr->Update(value); + return true; +} + +absl::Status GattServer::NotifyCharacteristicChanged( + const api::ble_v2::GattCharacteristic& characteristic, bool confirm, + const ByteArray& new_value) { + std::shared_ptr chr = nullptr; + { + absl::ReaderMutexLock lock(&services_mutex_); + if (services_.count(characteristic.service_uuid) == 0) { + return absl::NotFoundError( + absl::Substitute("Service $0 doesn't exist", + std::string{characteristic.service_uuid})); + } + chr = services_[characteristic.service_uuid]->GetCharacteristic( + characteristic.uuid); + } + if (chr == nullptr) { + return absl::NotFoundError( + absl::Substitute("characteristic $0 doesn't exist under service $1", + std::string{characteristic.uuid}, + std::string{characteristic.service_uuid})); + } + + return chr->NotifyChanged(confirm, new_value); +} + +void GattServer::Stop() { + bluez::GattManager manager(system_bus_, adapter_.GetObjectPath()); + absl::MutexLock lock(&services_mutex_); + for (auto& [uuid, service] : services_) { + NEARBY_LOGS(VERBOSE) << __func__ << ": Unregistering service " + << service->getObjectPath(); + try { + manager.UnregisterApplication("/"); + } catch (const sdbus::Error& e) { + DBUS_LOG_METHOD_CALL_ERROR(&manager, "UnregisterApplication", e); + } + } + // services_.clear(); +} + +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/ble_gatt_server.h b/internal/platform/implementation/linux/ble_gatt_server.h new file mode 100644 index 00000000..1ac26939 --- /dev/null +++ b/internal/platform/implementation/linux/ble_gatt_server.h @@ -0,0 +1,96 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef PLATFORM_IMPL_LINUX_API_BLE_GATT_SERVER_H_ +#define PLATFORM_IMPL_LINUX_API_BLE_GATT_SERVER_H_ + +#include + +#include + +#include "absl/container/flat_hash_map.h" +#include "absl/synchronization/mutex.h" +#include "absl/types/optional.h" +#include "internal/platform/bluetooth_utils.h" +#include "internal/platform/byte_array.h" +#include "internal/platform/implementation/ble_v2.h" +#include "internal/platform/implementation/linux/bluetooth_adapter.h" +#include "internal/platform/implementation/linux/bluetooth_devices.h" +#include "internal/platform/implementation/linux/bluez_gatt_service.h" +#include "internal/platform/uuid.h" + +namespace nearby { +namespace linux { +class LocalBlePeripheral : public api::ble_v2::BlePeripheral { + public: + explicit LocalBlePeripheral(BluetoothAdapter& adapter) : adapter_(adapter) { + unique_id_ = BluetoothUtils::ToNumber(adapter_.GetMacAddress()); + } + + std::string GetAddress() const override { return adapter_.GetMacAddress(); } + UniqueId GetUniqueId() const override { return unique_id_; } + + private: + BluetoothAdapter adapter_; + UniqueId unique_id_; +}; + +class GattServer : public api::ble_v2::GattServer { + public: + GattServer(const GattServer&) = delete; + GattServer(GattServer&&) = delete; + GattServer& operator=(const GattServer&) = delete; + GattServer& operator=(GattServer&&) = delete; + + explicit GattServer(sdbus::IConnection& system_bus, BluetoothAdapter& adapter, + std::shared_ptr devices, + api::ble_v2::ServerGattConnectionCallback server_cb) + : system_bus_(system_bus), + devices_(std::move(devices)), + adapter_(adapter), + local_peripheral_(adapter_), + server_cb_(std::make_shared( + std::move(server_cb))) {} + ~GattServer() override = default; + + api::ble_v2::BlePeripheral& GetBlePeripheral() override { + return local_peripheral_; + } + absl::optional CreateCharacteristic( + const Uuid& service_uuid, const Uuid& characteristic_uuid, + api::ble_v2::GattCharacteristic::Permission permission, + api::ble_v2::GattCharacteristic::Property property) override; + bool UpdateCharacteristic( + const api::ble_v2::GattCharacteristic& characteristic, + const nearby::ByteArray& value) override; + absl::Status NotifyCharacteristicChanged( + const api::ble_v2::GattCharacteristic& characteristic, bool confirm, + const ByteArray& new_value) override; + void Stop() override; + + private: + sdbus::IConnection& system_bus_; + std::shared_ptr devices_; + BluetoothAdapter adapter_; + LocalBlePeripheral local_peripheral_; + + std::shared_ptr server_cb_; + absl::Mutex services_mutex_; + absl::flat_hash_map> services_ + ABSL_GUARDED_BY(services_mutex_); +}; + +} // namespace linux +} // namespace nearby +#endif diff --git a/internal/platform/implementation/linux/ble_v2_medium.cc b/internal/platform/implementation/linux/ble_v2_medium.cc new file mode 100644 index 00000000..56289bcc --- /dev/null +++ b/internal/platform/implementation/linux/ble_v2_medium.cc @@ -0,0 +1,436 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +#include +#include + +#include +#include "absl/synchronization/mutex.h" +#include "internal/platform/implementation/ble_v2.h" +#include "internal/platform/implementation/linux/ble_gatt_server.h" +#include "internal/platform/implementation/linux/ble_v2_medium.h" +#include "internal/platform/implementation/linux/bluez_advertisement_monitor.h" +#include "internal/platform/implementation/linux/bluez_advertisement_monitor_manager.h" +#include "internal/platform/implementation/linux/bluez_le_advertisement.h" +#include "internal/platform/implementation/linux/dbus.h" +#include "internal/platform/implementation/linux/generated/dbus/bluez/advertisement_monitor_server.h" +#include "internal/platform/implementation/linux/generated/dbus/bluez/le_advertisement_manager_client.h" + +namespace nearby { +namespace linux { +BleV2Medium::BleV2Medium(sdbus::IConnection &system_bus, + BluetoothAdapter &adapter) + : system_bus_(system_bus), + adapter_(adapter), + devices_(std::make_unique( + system_bus_, adapter_.GetObjectPath(), observers_)), + adv_monitor_manager_( + bluez::AdvertisementMonitorManager:: + DiscoverAdvertisementMonitorManager(system_bus, adapter_)), + adv_manager_( + std::make_unique(system_bus, adapter)), + cur_adv_(nullptr) { + if (adv_monitor_manager_) { + NEARBY_LOGS(VERBOSE) + << __func__ + << ": Registering path / with AdvertisementMonitorManager at " + << adv_monitor_manager_->getObjectPath(); + try { + adv_monitor_manager_->RegisterMonitor("/"); + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(adv_monitor_manager_, "RegisterMonitor", e); + } + } +} + +bool BleV2Medium::StartAdvertising( + const api::ble_v2::BleAdvertisementData &advertising_data, + api::ble_v2::AdvertiseParameters advertise_set_parameters) { + if (!adapter_.IsEnabled()) { + NEARBY_LOGS(WARNING) << "BLE cannot start advertising because the " + "bluetooth adapter is not enabled."; + return false; + } + + if (advertising_data.service_data.empty()) { + NEARBY_LOGS(WARNING) + << "BLE cannot start to advertise due to invalid service data."; + return false; + } + + absl::MutexLock lock(&cur_adv_mutex_); + if (cur_adv_ != nullptr) { + NEARBY_LOGS(ERROR) << __func__ + << "Advertising is already enabled for this medium."; + return false; + } + + cur_adv_ = bluez::LEAdvertisement::CreateLEAdvertisement( + system_bus_, advertising_data, advertise_set_parameters); + + NEARBY_LOGS(INFO) << __func__ << ": Registering advertisement " + << cur_adv_->getObjectPath() << " on bluetooth adapter " + << adapter_.GetObjectPath(); + + try { + adv_manager_->RegisterAdvertisement(cur_adv_->getObjectPath(), {}); + } catch (const sdbus::Error &e) { + cur_adv_ = nullptr; + DBUS_LOG_METHOD_CALL_ERROR(adv_manager_, "RegisterAdvertisement", e); + return false; + } + + return true; +} + +bool BleV2Medium::StopAdvertising() { + absl::MutexLock lock(&cur_adv_mutex_); + if (cur_adv_ == nullptr) { + NEARBY_LOGS(ERROR) << __func__ << ": Advertising is not enabled."; + return false; + } + NEARBY_LOGS(VERBOSE) << __func__ << "Unregistering advertisement object " + << cur_adv_->getObjectPath(); + + try { + adv_manager_->UnregisterAdvertisement(cur_adv_->getObjectPath()); + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(adv_manager_, "UnregisterAdvertisement", e); + return false; + } + + cur_adv_ = nullptr; + return true; +} + +std::unique_ptr +BleV2Medium::StartAdvertising( + const api::ble_v2::BleAdvertisementData &advertising_data, + api::ble_v2::AdvertiseParameters advertise_set_parameters, + AdvertisingCallback callback) { + if (!adapter_.IsEnabled()) { + NEARBY_LOGS(WARNING) << ": BLE cannot start advertising because the " + "bluetooth adapter is not enabled."; + return nullptr; + } + + if (advertising_data.service_data.empty()) { + NEARBY_LOGS(WARNING) + << ": BLE cannot start to advertise due to invalid service data."; + return nullptr; + } + + std::shared_ptr proxy = + sdbus::createProxy(system_bus_, "org.bluez", adapter_.GetObjectPath()); + proxy->finishRegistration(); + + std::shared_ptr shared_cb = + std::make_shared(std::move(callback)); + + absl::MutexLock lock(&advs_mutex_); + advs_.push_front(bluez::LEAdvertisement::CreateLEAdvertisement( + system_bus_, advertising_data, advertise_set_parameters)); + auto adv_it = advs_.begin(); + + auto pending_call = + proxy->callMethodAsync("RegisterAdvertisement") + .onInterface(org::bluez::LEAdvertisingManager1_proxy::INTERFACE_NAME) + .withArguments((*adv_it)->getObjectPath(), + std::map{}) + .uponReplyInvoke( + [this, proxy, shared_cb, adv_it](const sdbus::Error *error) { + if (error != nullptr && error->isValid()) { + { + absl::MutexLock lock(&advs_mutex_); + advs_.erase(adv_it); + } + DBUS_LOG_METHOD_CALL_ERROR(adv_manager_, + "RegisterAdvertisement", *error); + auto name = error->getName(); + std::string msg = error->getMessage(); + absl::Status status; + + if (name == "org.bluez.Error.InvalidArguments" || + name == "org.bluez.Error.InvalidLength") { + status = absl::InvalidArgumentError(msg); + } else if (name == "org.bluez.Error.AlreadyExists") { + status = absl::AlreadyExistsError(msg); + } else if (name == "org.bluez.Error.NotPermitted") { + status = absl::ResourceExhaustedError(msg); + } else { + status = absl::UnknownError(msg); + } + shared_cb->start_advertising_result(std::move(status)); + } else { + shared_cb->start_advertising_result(absl::OkStatus()); + } + }); + + absl::AnyInvocable stop_adv = [&, adv_it]() { + NEARBY_LOGS(VERBOSE) << __func__ << ": Unregistering advertisement object " + << (*adv_it)->getObjectPath(); + absl::MutexLock lock(&advs_mutex_); + try { + adv_manager_->UnregisterAdvertisement((*adv_it)->getObjectPath()); + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(adv_manager_, "UnregisterAdvertisement", e); + return absl::UnknownError(e.getMessage()); + } + advs_.erase(adv_it); + return absl::OkStatus(); + }; + + return std::make_unique( + api::ble_v2::BleMedium::AdvertisingSession{std::move(stop_adv)}); +} + +std::unique_ptr BleV2Medium::StartGattServer( + api::ble_v2::ServerGattConnectionCallback callback) { + return std::make_unique(system_bus_, adapter_, devices_, + std::move(callback)); +} + +bool BleV2Medium::StartLEDiscovery() { + std::map filter; + filter["Transport"] = "le"; + auto &adapter = adapter_.GetBluezAdapterObject(); + + try { + adapter.SetDiscoveryFilter(filter); + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(&adapter, "SetDiscoveryFilter", e); + return false; + } + try { + NEARBY_LOGS(INFO) << __func__ << ": Starting LE discovery on " + << adapter.getObjectPath(); + adapter.StartDiscovery(); + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(&adapter, "StartDiscovery", e); + return false; + } + + return true; +} + +bool BleV2Medium::StartScanning(const Uuid &service_uuid, + api::ble_v2::TxPowerLevel tx_power_level, + ScanCallback callback) { + if (cur_monitored_service_uuid_.has_value()) { + NEARBY_LOGS(ERROR) << __func__ + << ": A sync scanning session is already active for " + << std::string{*cur_monitored_service_uuid_}; + return false; + } + + if (adv_monitor_manager_ == nullptr) { + NEARBY_LOGS(WARNING) << __func__ + << ": Advertising monitor not supported by BlueZ"; + // TODO: Implement manual monitoring. + return false; + } + + if (!MonitorManagerSupportsOr()) { + NEARBY_LOGS(WARNING) + << __func__ + << ": \"or_patterns\" not supported by AdvertisementMonitorManager"; + // TODO: Implement manual monitoring. + return false; + } + + absl::MutexLock lock(&active_adv_monitors_mutex_); + if (active_adv_monitors_.count(service_uuid) == 1) { + NEARBY_LOGS(ERROR) << __func__ << ": an advertising session for service " + << std::string{service_uuid} << " already exists"; + return false; + } + + auto monitor = std::make_unique( + system_bus_, service_uuid, tx_power_level, "or_patterns", devices_, + std::move(callback)); + try { + monitor->emitInterfacesAddedSignal( + {org::bluez::AdvertisementMonitor1_adaptor::INTERFACE_NAME}); + } catch (const sdbus::Error &e) { + NEARBY_LOGS(ERROR) + << __func__ + << ": error emitting InterfacesAdded signal for object path " + << monitor->getObjectPath() << " with name '" << e.getName() + << "' and message '" << e.getMessage() << "'"; + return false; + } + + if (!StartLEDiscovery()) { + NEARBY_LOGS(ERROR) << __func__ + << ": Could not start LE discovery on adapter " + << adapter_.GetObjectPath(); + try { + monitor->emitInterfacesRemovedSignal( + {org::bluez::AdvertisementMonitor1_adaptor::INTERFACE_NAME}); + } catch (const sdbus::Error &e) { + NEARBY_LOGS(ERROR) + << __func__ + << ": error emitting InterfacesRemoved signal for object path " + << monitor->getObjectPath() << " with name '" << e.getName() + << "' and message '" << e.getMessage() << "'"; + } + return false; + } + + active_adv_monitors_[service_uuid] = std::move(monitor); + cur_monitored_service_uuid_ = service_uuid; + return true; +} + +bool BleV2Medium::StopScanning() { + if (!cur_monitored_service_uuid_.has_value()) { + NEARBY_LOGS(ERROR) << __func__ + << ": No sync scanning session is currently active."; + return false; + } + + if (adv_monitor_manager_ == nullptr) { + // TODO: Implement manual monitoring. + return false; + } + + auto &adapter = adapter_.GetBluezAdapterObject(); + NEARBY_LOGS(VERBOSE) << __func__ << ": Stopping discovery for adapter " + << adapter.getObjectPath(); + try { + adapter.StopDiscovery(); + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(&adapter, "StopDiscovery", e); + } + + absl::MutexLock lock(&active_adv_monitors_mutex_); + auto monitor_it = active_adv_monitors_.find(*cur_monitored_service_uuid_); + assert(monitor_it != active_adv_monitors_.end()); + + auto &[_uuid, adv_monitor] = *monitor_it; + NEARBY_LOGS(VERBOSE) << __func__ << ": Removing advertising monitor " + << adv_monitor->getObjectPath(); + adv_monitor->emitInterfacesRemovedSignal( + {org::bluez::AdvertisementMonitor1_adaptor::INTERFACE_NAME}); + active_adv_monitors_.erase(monitor_it); + cur_monitored_service_uuid_ = std::nullopt; + + return true; +} + +std::unique_ptr +BleV2Medium::StartScanning(const Uuid &service_uuid, + api::ble_v2::TxPowerLevel tx_power_level, + ScanningCallback callback) { + if (adv_monitor_manager_ == nullptr) { + // TODO: Implement manual monitoring. + return nullptr; + } + + absl::MutexLock lock(&active_adv_monitors_mutex_); + if (active_adv_monitors_.count(service_uuid) == 1) { + NEARBY_LOGS(ERROR) << __func__ << ": Service " << std::string{service_uuid} + << " is already being advertised"; + return nullptr; + } + + auto monitor = std::make_unique( + system_bus_, service_uuid, tx_power_level, "or_patterns", devices_, + std::move(callback)); + try { + monitor->emitInterfacesAddedSignal( + {org::bluez::AdvertisementMonitor1_adaptor::INTERFACE_NAME}); + } catch (const sdbus::Error &e) { + NEARBY_LOGS(ERROR) + << __func__ + << ": error emitting InterfacesAdded signal for object path " + << monitor->getObjectPath() << " with name '" << e.getName() + << "' and message '" << e.getMessage() << "'"; + return nullptr; + } + + if (!StartLEDiscovery()) { + NEARBY_LOGS(ERROR) << __func__ + << ": Could not start LE discovery on adapter " + << adapter_.GetObjectPath(); + try { + monitor->emitInterfacesRemovedSignal( + {org::bluez::AdvertisementMonitor1_adaptor::INTERFACE_NAME}); + } catch (const sdbus::Error &e) { + NEARBY_LOGS(ERROR) + << __func__ + << ": error emitting InterfacesRemoved signal for object path " + << monitor->getObjectPath() << " with name '" << e.getName() + << "' and message '" << e.getMessage() << "'"; + } + return nullptr; + } + + active_adv_monitors_[service_uuid] = std::move(monitor); + return std::make_unique( + ScanningSession{.stop_scanning = [this, service_uuid]() { + absl::MutexLock lock(&active_adv_monitors_mutex_); + if (active_adv_monitors_.count(service_uuid) == 0) { + NEARBY_LOGS(ERROR) + << __func__ << ": Advertising monitor for service " + << std::string{service_uuid} << " does not exist anymore"; + return absl::NotFoundError( + "Advertising monitor for this service does not exist"); + } + + auto &monitor = active_adv_monitors_[service_uuid]; + try { + monitor->emitInterfacesRemovedSignal( + {org::bluez::AdvertisementMonitor1_adaptor::INTERFACE_NAME}); + } catch (const sdbus::Error &e) { + NEARBY_LOGS(ERROR) + << __func__ + << ": error emitting InterfacesRemoved signal for object path " + << monitor->getObjectPath() << " with name '" << e.getName() + << "' and message '" << e.getMessage() << "'"; + } + + active_adv_monitors_.erase(service_uuid); + + auto &adapter = adapter_.GetBluezAdapterObject(); + try { + adapter.StopDiscovery(); + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(&adapter, "StopDiscovery", e); + return absl::InternalError(e.getMessage()); + } + return absl::OkStatus(); + }}); +} + +bool BleV2Medium::GetRemotePeripheral(const std::string &mac_address, + GetRemotePeripheralCallback callback) { + auto device = devices_->get_device_by_address(mac_address); + if (device == nullptr) return false; + callback(*device); + return true; +} + +bool BleV2Medium::GetRemotePeripheral(api::ble_v2::BlePeripheral::UniqueId id, + GetRemotePeripheralCallback callback) { + auto device = devices_->get_device_by_unique_id(id); + if (device == nullptr) return false; + callback(*device); + return true; +} +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/ble_v2_medium.h b/internal/platform/implementation/linux/ble_v2_medium.h index ee0d1d7d..4c627b5b 100644 --- a/internal/platform/implementation/linux/ble_v2_medium.h +++ b/internal/platform/implementation/linux/ble_v2_medium.h @@ -15,41 +15,57 @@ #ifndef PLATFORM_IMPL_LINUX_API_BLE_V2_MEDIUM_H_ #define PLATFORM_IMPL_LINUX_API_BLE_V2_MEDIUM_H_ +#include + +#include + +#include "absl/base/attributes.h" +#include "absl/container/flat_hash_map.h" +#include "absl/synchronization/mutex.h" #include "internal/platform/implementation/ble_v2.h" +#include "internal/platform/implementation/linux/ble_v2_server_socket.h" +#include "internal/platform/implementation/linux/bluetooth_adapter.h" +#include "internal/platform/implementation/linux/bluetooth_devices.h" +#include "internal/platform/implementation/linux/bluez_advertisement_monitor.h" +#include "internal/platform/implementation/linux/bluez_advertisement_monitor_manager.h" +#include "internal/platform/implementation/linux/bluez_le_advertisement.h" +#include "internal/platform/uuid.h" namespace nearby { namespace linux { -class BleV2Medium : public api::ble_v2::BleMedium { +class BleV2Medium final : public api::ble_v2::BleMedium { + public: + BleV2Medium(const BleV2Medium &) = delete; + BleV2Medium(BleV2Medium &&) = delete; + BleV2Medium &operator=(const BleV2Medium &) = delete; + BleV2Medium &operator=(BleV2Medium &&) = delete; + + BleV2Medium(sdbus::IConnection &system_bus ABSL_ATTRIBUTE_LIFETIME_BOUND, + BluetoothAdapter &adapter); + ~BleV2Medium() override = default; + bool StartAdvertising( const api::ble_v2::BleAdvertisementData &advertising_data, - api::ble_v2::AdvertiseParameters advertise_set_parameters) override { - return false; - } + api::ble_v2::AdvertiseParameters advertise_set_parameters) override + ABSL_LOCKS_EXCLUDED(cur_adv_mutex_); std::unique_ptr StartAdvertising( const api::ble_v2::BleAdvertisementData &advertising_data, api::ble_v2::AdvertiseParameters advertise_set_parameters, - AdvertisingCallback callback) override { - return nullptr; - } - bool StopAdvertising() override { return false; } + AdvertisingCallback callback) ABSL_LOCKS_EXCLUDED(advs_mutex_) override; + bool StopAdvertising() override ABSL_LOCKS_EXCLUDED(advs_mutex_); bool StartScanning(const Uuid &service_uuid, api::ble_v2::TxPowerLevel tx_power_level, - ScanCallback callback) override { - return false; - } - bool StopScanning() override { return false; } + ScanCallback callback) override + ABSL_LOCKS_EXCLUDED(active_adv_monitors_mutex_); + bool StopScanning() override ABSL_LOCKS_EXCLUDED(active_adv_monitors_mutex_); std::unique_ptr StartScanning( const Uuid &service_uuid, api::ble_v2::TxPowerLevel tx_power_level, - ScanningCallback callback) override { - return nullptr; - }; + ScanningCallback callback) override; std::unique_ptr StartGattServer( - api::ble_v2::ServerGattConnectionCallback callback) override { - return nullptr; - } + api::ble_v2::ServerGattConnectionCallback callback) override; std::unique_ptr ConnectToGattServer( api::ble_v2::BlePeripheral &peripheral, @@ -60,7 +76,7 @@ class BleV2Medium : public api::ble_v2::BleMedium { std::unique_ptr OpenServerSocket( const std::string &service_id) override { - return nullptr; + return std::make_unique(); } std::unique_ptr Connect( @@ -71,13 +87,53 @@ class BleV2Medium : public api::ble_v2::BleMedium { } bool IsExtendedAdvertisementsAvailable() override { return false; } bool GetRemotePeripheral(const std::string &mac_address, - GetRemotePeripheralCallback callback) override { - return false; - } + GetRemotePeripheralCallback callback) override; bool GetRemotePeripheral(api::ble_v2::BlePeripheral::UniqueId id, - GetRemotePeripheralCallback callback) override { - return false; + GetRemotePeripheralCallback callback) override; + + private: + bool StartLEDiscovery(); + + bool MonitorManagerSupportsOr() { + std::vector supported_types; + try { + supported_types = adv_monitor_manager_->SupportedMonitorTypes(); + } catch (const sdbus::Error &e) { + DBUS_LOG_PROPERTY_GET_ERROR(adv_monitor_manager_, "SupportedMonitorTypes", + e); + return false; + } + + auto is_supported_type = [](std::string pattern) { + return pattern == "or_patterns"; + }; + + auto end = supported_types.cend(); + return std::find_if(supported_types.cbegin(), end, is_supported_type) != + end; } + + sdbus::IConnection &system_bus_; + BluetoothAdapter adapter_; + ObserverList observers_ = {}; + std::shared_ptr devices_; + + std::unique_ptr adv_monitor_manager_; + absl::Mutex active_adv_monitors_mutex_; + absl::flat_hash_map> + active_adv_monitors_ ABSL_GUARDED_BY(active_adv_monitors_mutex_); + // Used by the synchronous variant of StartScanning + std::optional cur_monitored_service_uuid_; + + std::unique_ptr adv_manager_; + + absl::Mutex cur_adv_mutex_; + std::unique_ptr cur_adv_ + ABSL_GUARDED_BY(cur_adv_mutex_); + + absl::Mutex advs_mutex_; + std::list> advs_ + ABSL_GUARDED_BY(advs_mutex_); }; } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/ble_v2_server_socket.h b/internal/platform/implementation/linux/ble_v2_server_socket.h new file mode 100644 index 00000000..ea6734c7 --- /dev/null +++ b/internal/platform/implementation/linux/ble_v2_server_socket.h @@ -0,0 +1,42 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef PLATFORM_IMPL_LINUX_API_BLE_V2_SERVER_SOCKET_H_ +#define PLATFORM_IMPL_LINUX_API_BLE_V2_SERVER_SOCKET_H_ + +#include "absl/synchronization/notification.h" +#include "internal/platform/implementation/ble_v2.h" + +namespace nearby { +namespace linux { +class BleV2ServerSocket final : public api::ble_v2::BleServerSocket { + public: + std::unique_ptr Accept() override { + stopped_.WaitForNotification(); + return nullptr; + } + + Exception Close() override { + if (stopped_.HasBeenNotified()) return {Exception::kIo}; + stopped_.Notify(); + return {Exception::kSuccess}; + } + + private: + absl::Notification stopped_; +}; +} // namespace linux +} // namespace nearby + +#endif diff --git a/internal/platform/implementation/linux/bluez_advertisement_monitor.cc b/internal/platform/implementation/linux/bluez_advertisement_monitor.cc new file mode 100644 index 00000000..a695807a --- /dev/null +++ b/internal/platform/implementation/linux/bluez_advertisement_monitor.cc @@ -0,0 +1,73 @@ +#include "internal/platform/implementation/linux/bluez_advertisement_monitor.h" +#include "internal/platform/byte_array.h" +#include "internal/platform/implementation/ble_v2.h" +#include "internal/platform/implementation/linux/dbus.h" +#include "internal/platform/implementation/linux/utils.h" +#include "internal/platform/uuid.h" +namespace nearby { +namespace linux { +namespace bluez { +AdvertisementMonitor::AdvertisementMonitor( + sdbus::IConnection &system_bus, Uuid service_uuid, + api::ble_v2::TxPowerLevel tx_power_level, absl::string_view type, + std::shared_ptr devices, + api::ble_v2::BleMedium::ScanCallback scan_callback) + : AdvertisementMonitor( + system_bus, service_uuid, tx_power_level, type, std::move(devices), + api::ble_v2::BleMedium::ScanningCallback{ + .start_scanning_result = nullptr, + .advertisement_found_cb = + std::move(scan_callback.advertisement_found_cb)}) {} + +AdvertisementMonitor::AdvertisementMonitor( + sdbus::IConnection &system_bus, Uuid service_uuid, + api::ble_v2::TxPowerLevel tx_power_level, absl::string_view type, + std::shared_ptr devices, + api::ble_v2::BleMedium::ScanningCallback scan_callback) + : AdaptorInterfaces(system_bus, bluez::advertisement_monitor_path( + std::string{service_uuid})), + devices_(std::move(devices)), + scan_callback_{std::move(scan_callback.advertisement_found_cb)}, + start_scanning_result_callback_( + std::move(scan_callback.start_scanning_result)), + type_(type), + service_uuid_(service_uuid), + tx_power_level_(tx_power_level) { + registerAdaptor(); +} + +void AdvertisementMonitor::DeviceFound(const sdbus::ObjectPath &device) { + devices_->cleanup_lost_peripherals(); + auto peripheral = devices_->add_new_device(device); + std::map service_data; + try { + service_data = peripheral->ServiceData(); + } catch (const sdbus::Error &e) { + DBUS_LOG_PROPERTY_GET_ERROR(peripheral, "ServiceData", e); + return; + } + + struct api::ble_v2::BleAdvertisementData adv_data; + for (const auto &[uuid_str, data] : service_data) { + auto uuid = UuidFromString(uuid_str); + if (!uuid.has_value()) { + NEARBY_LOGS(ERROR) + << __func__ + << ": Could not parse UUID string in ServiceData for peripheral " + << peripheral->getObjectPath(); + continue; + } + + std::vector bytes = data; + adv_data.service_data.emplace(*uuid, + std::string(bytes.begin(), bytes.end())); + } + scan_callback_.advertisement_found_cb(*peripheral, adv_data); +} + +void AdvertisementMonitor::DeviceLost(const sdbus::ObjectPath &device) { + devices_->mark_peripheral_lost(device); +} +} // namespace bluez +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/bluez_advertisement_monitor.h b/internal/platform/implementation/linux/bluez_advertisement_monitor.h new file mode 100644 index 00000000..24e57696 --- /dev/null +++ b/internal/platform/implementation/linux/bluez_advertisement_monitor.h @@ -0,0 +1,95 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef PLATFORM_IMPL_LINUX_BLUEZ_ADVERTISEMENT_MONITOR_H_ +#define PLATFORM_IMPL_LINUX_BLUEZ_ADVERTISEMENT_MONITOR_H_ +#include +#include +#include + +#include "absl/strings/string_view.h" +#include "internal/platform/implementation/ble_v2.h" +#include "internal/platform/implementation/linux/bluetooth_devices.h" +#include "internal/platform/implementation/linux/bluez.h" +#include "internal/platform/implementation/linux/generated/dbus/bluez/advertisement_monitor_server.h" +#include "internal/platform/uuid.h" + +namespace nearby { +namespace linux { +namespace bluez { +class AdvertisementMonitor final + : public sdbus::AdaptorInterfaces { + public: + AdvertisementMonitor(const AdvertisementMonitor&) = delete; + AdvertisementMonitor(AdvertisementMonitor&&) = delete; + AdvertisementMonitor& operator=(const AdvertisementMonitor&) = delete; + AdvertisementMonitor& operator=(AdvertisementMonitor&&) = delete; + + AdvertisementMonitor(sdbus::IConnection& system_bus, Uuid service_uuid, + api::ble_v2::TxPowerLevel tx_power_level, + absl::string_view type, + std::shared_ptr devices, + api::ble_v2::BleMedium::ScanCallback scan_callback); + AdvertisementMonitor(sdbus::IConnection& system_bus, Uuid service_uuid, + api::ble_v2::TxPowerLevel tx_power_level, + absl::string_view type, + std::shared_ptr devices, + api::ble_v2::BleMedium::ScanningCallback scan_callback); + ~AdvertisementMonitor() { unregisterAdaptor(); } + + private: + // Methods + void Release() override {} + void Activate() override { + if (start_scanning_result_callback_ != nullptr) { + start_scanning_result_callback_(absl::OkStatus()); + } + } + + void DeviceFound(const sdbus::ObjectPath& device) override; + void DeviceLost(const sdbus::ObjectPath& device) override; + + // Properties + std::string Type() override { return type_; }; + int16_t RSSILowThreshold() override { return 0; }; + int16_t RSSIHighThreshold() override { + return bluez::TxPowerLevelDbm(tx_power_level_); + } + uint16_t RSSISamplingPeriod() override { + // The Windows implementation uses a sampling interval of 2 seconds. + return 20; + } + std::vector>> Patterns() + override { + std::array service_id_data = service_uuid_.data(); + return {{0, + 0x16, + {static_cast(service_id_data[3] & 0xFF), + static_cast(service_id_data[2] & 0xFF)}}}; + }; + + std::shared_ptr devices_; + api::ble_v2::BleMedium::ScanCallback scan_callback_; + absl::AnyInvocable start_scanning_result_callback_; + + std::string type_; + Uuid service_uuid_; + api::ble_v2::TxPowerLevel tx_power_level_; +}; +} // namespace bluez +} // namespace linux +} // namespace nearby + +#endif diff --git a/internal/platform/implementation/linux/bluez_advertisement_monitor_manager.h b/internal/platform/implementation/linux/bluez_advertisement_monitor_manager.h new file mode 100644 index 00000000..e8ed5d57 --- /dev/null +++ b/internal/platform/implementation/linux/bluez_advertisement_monitor_manager.h @@ -0,0 +1,87 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef PLATFORM_IMPL_LINUX_BLUEZ_ADVERTISEMENT_MONITOR_MANAGER_H_ +#define PLATFORM_IMPL_LINUX_BLUEZ_ADVERTISEMENT_MONITOR_MANAGER_H_ + +#include +#include + +#include "internal/platform/implementation/linux/bluetooth_adapter.h" +#include "internal/platform/implementation/linux/bluez.h" +#include "internal/platform/implementation/linux/dbus.h" +#include "internal/platform/implementation/linux/generated/dbus/bluez/advertisement_monitor_manager_client.h" + +namespace nearby { +namespace linux { +namespace bluez { +class AdvertisementMonitorManager final + : public sdbus::ProxyInterfaces< + org::bluez::AdvertisementMonitorManager1_proxy> { + private: + friend std::unique_ptr + std::make_unique(sdbus::IConnection &, + const BluetoothAdapter &); + AdvertisementMonitorManager(sdbus::IConnection &system_bus, + const BluetoothAdapter &adapter) + : ProxyInterfaces(system_bus, "org.bluez", adapter.GetObjectPath()) { + registerProxy(); + } + + public: + AdvertisementMonitorManager(const AdvertisementMonitorManager &) = delete; + AdvertisementMonitorManager(AdvertisementMonitorManager &&) = delete; + AdvertisementMonitorManager &operator=(const AdvertisementMonitorManager &) = + delete; + AdvertisementMonitorManager &operator=(AdvertisementMonitorManager &&) = + delete; + ~AdvertisementMonitorManager() { unregisterProxy(); } + + static std::unique_ptr + DiscoverAdvertisementMonitorManager(sdbus::IConnection &system_bus, + const BluetoothAdapter &adapter) { + bluez::BluezObjectManager manager(system_bus); + std::map>> + objects; + try { + objects = manager.GetManagedObjects(); + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(&manager, "GetManagedObjects", e); + return nullptr; + } + if (objects.count(adapter.GetObjectPath()) == 0) { + NEARBY_LOGS(ERROR) << __func__ << ": Adapter object no longer exists " + << adapter.GetObjectPath(); + return nullptr; + } + + if (objects[adapter.GetObjectPath()].count( + org::bluez::AdvertisementMonitorManager1_proxy::INTERFACE_NAME) == + 0) { + NEARBY_LOGS(ERROR) + << __func__ << ": Adapter " << adapter.GetObjectPath() + << " doesn't provide " + << org::bluez::AdvertisementMonitorManager1_proxy::INTERFACE_NAME; + return nullptr; + } + + return std::make_unique(system_bus, adapter); + } +}; +} // namespace bluez +} // namespace linux +} // namespace nearby + +#endif diff --git a/internal/platform/implementation/linux/bluez_gatt_characteristic.cc b/internal/platform/implementation/linux/bluez_gatt_characteristic.cc new file mode 100644 index 00000000..e29b2b40 --- /dev/null +++ b/internal/platform/implementation/linux/bluez_gatt_characteristic.cc @@ -0,0 +1,231 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +#include "internal/platform/byte_array.h" +#include "internal/platform/implementation/ble_v2.h" +#include "internal/platform/implementation/linux/bluez_gatt_characteristic.h" +#include "internal/platform/logging.h" + +namespace nearby { +namespace linux { +namespace bluez { +void GattCharacteristic::Update(const nearby::ByteArray &value) { + std::vector bytes(value.size()); + const auto *buf = value.data(); + for (auto i = 0; i < value.size(); i++) bytes[i] = buf[i]; + + absl::MutexLock static_value_lock(&static_value_mutex_); + static_value_ = std::move(bytes); +} + +absl::Status GattCharacteristic::NotifyChanged(bool confirm, + const ByteArray &new_value) { + std::vector bytes(new_value.size()); + const auto *buf = new_value.data(); + for (auto i = 0; i < new_value.size(); i++) bytes[i] = buf[i]; + + { + absl::MutexLock lock(&cached_value_mutex_); + cached_value_ = bytes; + } + + if (confirm) { + auto confirmed = [&]() { + confirmed_mutex_.AssertReaderHeld(); + return confirmed_; + }; + { + absl::MutexLock lock(&confirmed_mutex_); + confirmed_ = false; + } + absl::ReaderMutexLock lock(&confirmed_mutex_, absl::Condition(&confirmed)); + } + + try { + emitPropertiesChangedSignal(GattCharacteristic1_adaptor::INTERFACE_NAME, + {"Value"}); + return absl::OkStatus(); + } catch (const sdbus::Error &e) { + NEARBY_LOGS(ERROR) << __func__ + << ": Error emitting PropertiesChanged signal on " + << getObjectPath() << " with name '" << e.getName() + << "' and message '" << e.getMessage() << "'"; + return absl::UnknownError(e.getMessage()); + } +} + +void GattCharacteristic::ReadValue( + sdbus::Result> &&result, + std::map options) { + { + absl::ReaderMutexLock static_value_lock(&static_value_mutex_); + if (static_value_.has_value()) { + result.returnResults(*static_value_); + + absl::MutexLock cached_value_lock(&cached_value_mutex_); + cached_value_ = *static_value_; + return; + } + } + + uint16_t offset = options["offset"]; + sdbus::ObjectPath device_path = options["device"]; + + auto device = devices_->get_device_by_path(device_path); + if (device == nullptr) { + result.returnError( + sdbus::Error("org.bluez.Error.NotAuthorized", "device does not exist")); + return; + } + auto characteristic = characteristic_; + server_cb_->on_characteristic_read_cb( + *device, characteristic, static_cast(offset), + [result = std::move(result), + this](absl::StatusOr data) { + const auto &status = data.status(); + if (status.ok()) { + auto str = data.value(); + std::vector bytes(str.size()); + for (auto i = 0; i < str.size(); i++) { + bytes[i] = str[i]; + } + result.returnResults(bytes); + + absl::MutexLock lock(&cached_value_mutex_); + cached_value_ = bytes; + } else if (absl::IsPermissionDenied(status)) { + result.returnError(sdbus::Error("org.bluez.Error.NotPermitted", + std::string(status.message()))); + } else if (absl::IsUnauthenticated(status)) { + result.returnError(sdbus::Error("org.bluez.Error.NotAuthorized", + std::string(status.message()))); + } else if (absl::IsOutOfRange(status)) { + result.returnError(sdbus::Error("org.bluez.Error.InvalidOffset", + std::string(status.message()))); + } else if (absl::IsUnimplemented(status)) { + result.returnError(sdbus::Error("org.bluez.Error.NotSupported", + std::string(status.message()))); + } else { + result.returnError(sdbus::Error("org.bluez.Error.Failed", + std::string(status.message()))); + } + }); +} + +void GattCharacteristic::WriteValue( + sdbus::Result<> &&result, std::vector value, + std::map options) { + uint16_t offset = options["offset"]; + sdbus::ObjectPath device_path = options["device"]; + + auto device = devices_->get_device_by_path(device_path); + if (device == nullptr) { + result.returnError( + sdbus::Error("org.bluez.Error.NotAuthorized", "device does not exist")); + return; + } + std::string type = options["type"]; + + std::string data(value.begin(), value.end()); + auto characteristic = characteristic_; + + if (type != "command") { + server_cb_->on_characteristic_write_cb( + *device, characteristic, static_cast(offset), data, + [result = std::move(result)](absl::Status status) { + if (status.ok()) { + result.returnResults(); + } else if (absl::IsPermissionDenied(status)) { + result.returnError(sdbus::Error("org.bluez.Error.NotPermitted", + std::string(status.message()))); + } else if (absl::IsUnauthenticated(status)) { + result.returnError(sdbus::Error("org.bluez.Error.NotAuthorized", + std::string(status.message()))); + } else if (absl::IsOutOfRange(status)) { + result.returnError(sdbus::Error("org.bluez.Error.InvalidOffset", + std::string(status.message()))); + } else if (absl::IsUnimplemented(status)) { + result.returnError(sdbus::Error("org.bluez.Error.NotSupported", + std::string(status.message()))); + } else { + result.returnError(sdbus::Error("org.bluez.Error.Failed", + std::string(status.message()))); + } + }); + } else { + result.returnResults(); + } +} + +void GattCharacteristic::StartNotify() { + if ((characteristic_.property | + api::ble_v2::GattCharacteristic::Property::kNotify) == + api::ble_v2::GattCharacteristic::Property::kNotify) { + server_cb_->characteristic_subscription_cb(characteristic_); + notifying_ = true; + } else { + throw(sdbus::Error("org.bluez.Error.NotSupported")); + } +} + +void GattCharacteristic::StopNotify() { + if ((characteristic_.property | + api::ble_v2::GattCharacteristic::Property::kNotify) == + api::ble_v2::GattCharacteristic::Property::kNotify) { + server_cb_->characteristic_unsubscription_cb(characteristic_); + notifying_ = false; + } else { + throw(sdbus::Error("org.bluez.Error.Failed")); + } +} + +std::vector GattCharacteristic::Flags() { + auto characteristic = characteristic_; + std::vector flags; + + if ((characteristic.permission & + api::ble_v2::GattCharacteristic::Permission::kRead) == + api::ble_v2::GattCharacteristic::Permission::kRead || + (characteristic.property & + api::ble_v2::GattCharacteristic::Property::kRead) == + api::ble_v2::GattCharacteristic::Property::kRead) + flags.push_back("read"); + + if ((characteristic.permission & + api::ble_v2::GattCharacteristic::Permission::kWrite) == + api::ble_v2::GattCharacteristic::Permission::kWrite || + (characteristic.property & + api::ble_v2::GattCharacteristic::Property::kWrite) == + api::ble_v2::GattCharacteristic::Property::kWrite) + flags.push_back("write"); + + if ((characteristic.property & + api::ble_v2::GattCharacteristic::Property::kIndicate) == + api::ble_v2::GattCharacteristic::Property::kIndicate) + flags.push_back("indicate"); + + if ((characteristic.property & + api::ble_v2::GattCharacteristic::Property::kNotify) == + api::ble_v2::GattCharacteristic::Property::kNotify) + flags.push_back("notify"); + + return flags; +} +} // namespace bluez +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/bluez_gatt_characteristic.h b/internal/platform/implementation/linux/bluez_gatt_characteristic.h new file mode 100644 index 00000000..59aa231c --- /dev/null +++ b/internal/platform/implementation/linux/bluez_gatt_characteristic.h @@ -0,0 +1,125 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef PLATFORM_IMPL_LINUX_BLUEZ_GATT_CHARACTERISTIC_H_ +#define PLATFORM_IMPL_LINUX_BLUEZ_GATT_CHARACTERISTIC_H_ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "absl/strings/string_view.h" +#include "absl/synchronization/mutex.h" +#include "internal/platform/implementation/ble_v2.h" +#include "internal/platform/implementation/linux/bluetooth_devices.h" +#include "internal/platform/implementation/linux/bluez.h" +#include "internal/platform/implementation/linux/generated/dbus/bluez/gatt_characteristic_server.h" +#include "internal/platform/logging.h" + +namespace nearby { +namespace linux { +namespace bluez { +class GattCharacteristic final + : public sdbus::AdaptorInterfaces { + public: + GattCharacteristic(const GattCharacteristic &) = delete; + GattCharacteristic(GattCharacteristic &&) = delete; + GattCharacteristic &operator=(const GattCharacteristic &) = delete; + GattCharacteristic &operator=(GattCharacteristic &&) = delete; + + GattCharacteristic( + sdbus::IConnection &system_bus, + const sdbus::ObjectPath &service_object_path, size_t num, + const api::ble_v2::GattCharacteristic &characteristic, + std::shared_ptr server_cb, + std::shared_ptr devices) + : AdaptorInterfaces(system_bus, bluez::gatt_characteristic_path( + service_object_path, num)), + devices_(std::move(devices)), + server_cb_(std::move(server_cb)), + characteristic_(characteristic), + service_object_path_(service_object_path), + notifying_(false), + confirmed_(false) { + registerAdaptor(); + NEARBY_LOGS(VERBOSE) + << __func__ << "Creating a " + << org::bluez::GattCharacteristic1_adaptor::INTERFACE_NAME + << " object at " << getObjectPath(); + } + ~GattCharacteristic() { unregisterAdaptor(); } + + void Update(const nearby::ByteArray &value) + ABSL_LOCKS_EXCLUDED(static_value_mutex_); + absl::Status NotifyChanged(bool confirm, const ByteArray &new_value) + ABSL_LOCKS_EXCLUDED(confirmed_mutex_); + + private: + // Methods + void ReadValue(sdbus::Result> &&result, + std::map options) override + ABSL_LOCKS_EXCLUDED(cached_value_mutex_, static_value_mutex_); + void WriteValue(sdbus::Result<> &&result, std::vector value, + std::map options) override; + void StartNotify() override; + void StopNotify() override; + void Confirm() override ABSL_LOCKS_EXCLUDED(confirmed_mutex_) { + absl::MutexLock lock(&confirmed_mutex_); + confirmed_ = true; + }; + + // Properties + std::string UUID() override { return std::string{characteristic_.uuid}; } + sdbus::ObjectPath Service() override { return service_object_path_; } + bool Notifying() override { return notifying_; } + std::vector Flags() override; + std::vector Value() override + ABSL_LOCKS_EXCLUDED(cached_value_mutex_) { + absl::ReaderMutexLock lock(&cached_value_mutex_); + return cached_value_; + } + + std::shared_ptr devices_; + std::shared_ptr server_cb_; + api::ble_v2::GattCharacteristic characteristic_; + + // Set by `GattServer::UpdateCharacteristic()` + absl::Mutex static_value_mutex_; + std::optional> static_value_ + ABSL_GUARDED_BY(static_value_mutex_); + + sdbus::ObjectPath service_object_path_; + std::atomic_bool notifying_; + absl::Mutex cached_value_mutex_; + std::vector cached_value_ ABSL_GUARDED_BY(cached_value_mutex_); + + absl::Mutex confirmed_mutex_; + bool confirmed_; +}; + +} // namespace bluez +} // namespace linux +} // namespace nearby + +#endif diff --git a/internal/platform/implementation/linux/bluez_gatt_manager.h b/internal/platform/implementation/linux/bluez_gatt_manager.h new file mode 100644 index 00000000..0c6830ca --- /dev/null +++ b/internal/platform/implementation/linux/bluez_gatt_manager.h @@ -0,0 +1,44 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef PLATFORM_IMPL_LINUX_API_BLUEZ_GATT_MANAGER_H_ +#define PLATFORM_IMPL_LINUX_API_BLUEZ_GATT_MANAGER_H_ +#include +#include +#include + +#include "internal/platform/implementation/linux/generated/dbus/bluez/gatt_manager_client.h" +namespace nearby { +namespace linux { +namespace bluez { +class GattManager + : public sdbus::ProxyInterfaces { + public: + GattManager(const GattManager &) = delete; + GattManager(GattManager &&) = delete; + GattManager &operator=(const GattManager &) = delete; + GattManager &operator=(GattManager &&) = delete; + + GattManager(sdbus::IConnection &system_bus, + sdbus::ObjectPath adapter_object_path) + : ProxyInterfaces(system_bus, "org.bluez", + std::move(adapter_object_path)) { + registerProxy(); + } + ~GattManager() { unregisterProxy(); } +}; +} // namespace bluez +} // namespace linux +} // namespace nearby +#endif diff --git a/internal/platform/implementation/linux/bluez_gatt_service.cc b/internal/platform/implementation/linux/bluez_gatt_service.cc new file mode 100644 index 00000000..4ff2ef2d --- /dev/null +++ b/internal/platform/implementation/linux/bluez_gatt_service.cc @@ -0,0 +1,63 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "internal/platform/implementation/linux/bluez_gatt_service.h" +#include "absl/synchronization/mutex.h" +#include "internal/platform/implementation/ble_v2.h" +#include "internal/platform/implementation/linux/bluez_gatt_characteristic.h" +#include "internal/platform/implementation/linux/generated/dbus/bluez/gatt_characteristic_server.h" +#include "internal/platform/uuid.h" + +namespace nearby { +namespace linux { +namespace bluez { +bool GattService::AddCharacteristic( + const Uuid &service_uuid, const Uuid &characteristic_uuid, + api::ble_v2::GattCharacteristic::Permission permission, + api::ble_v2::GattCharacteristic::Property property) { + absl::MutexLock lock(&characterstics_mutex_); + api::ble_v2::GattCharacteristic characteristic{ + characteristic_uuid, service_uuid, permission, property}; + auto count = characteristics_.size(); + std::shared_ptr chr = + std::make_shared( + getObject().getConnection(), getObjectPath(), count, characteristic, + server_cb_, devices_); + try { + chr->emitInterfacesAddedSignal( + {org::bluez::GattCharacteristic1_adaptor::INTERFACE_NAME}); + } catch (const sdbus::Error &e) { + NEARBY_LOGS(ERROR) + << __func__ + << ": error emitting InterfacesAdded signal for object path " + << chr->getObjectPath() << " with name '" << e.getName() + << "' and message '" << e.getMessage() << "'"; + return false; + } + + characteristics_.insert({characteristic_uuid, std::move(chr)}); + return true; +} + +std::shared_ptr GattService::GetCharacteristic( + const Uuid &uuid) { + absl::ReaderMutexLock lock(&characterstics_mutex_); + if (characteristics_.count(uuid) == 0) { + return nullptr; + } + return characteristics_[uuid]; +} +} // namespace bluez +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/bluez_gatt_service.h b/internal/platform/implementation/linux/bluez_gatt_service.h new file mode 100644 index 00000000..5d3edff2 --- /dev/null +++ b/internal/platform/implementation/linux/bluez_gatt_service.h @@ -0,0 +1,110 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef PLATFORM_IMPL_LINUX_BLUEZ_GATT_SERVICE_H_ +#define PLATFORM_IMPL_LINUX_BLUEZ_GATT_SERVICE_H_ + +#include +#include +#include +#include +#include + +#include "absl/container/flat_hash_map.h" +#include "absl/strings/string_view.h" +#include "internal/platform/implementation/ble_v2.h" +#include "internal/platform/implementation/linux/bluez.h" +#include "internal/platform/implementation/linux/bluez_gatt_characteristic.h" +#include "internal/platform/implementation/linux/generated/dbus/bluez/gatt_characteristic_server.h" +#include "internal/platform/implementation/linux/generated/dbus/bluez/gatt_service_server.h" +#include "internal/platform/logging.h" +#include "internal/platform/uuid.h" + +namespace nearby { +namespace linux { +namespace bluez { +class GattService final + : public sdbus::AdaptorInterfaces { + public: + GattService(const GattService &) = delete; + GattService(GattService &&) = delete; + GattService &operator=(const GattService &) = delete; + GattService &operator=(GattService &&) = delete; + + GattService( + sdbus::IConnection &system_bus, size_t num, const Uuid &service_uuid, + std::shared_ptr server_cb, + std::shared_ptr devices) + : AdaptorInterfaces(system_bus, bluez::gatt_service_path(num)), + devices_(std::move(devices)), + server_cb_(std::move(server_cb)), + uuid_(service_uuid), + primary_(true) { + registerAdaptor(); + NEARBY_LOGS(VERBOSE) << __func__ << ": Created a " + << org::bluez::GattService1_adaptor::INTERFACE_NAME + << " object at " << getObjectPath(); + } + + ~GattService() { + absl::MutexLock lock(&characterstics_mutex_); + for (auto &[_uuid, characteristic] : characteristics_) { + NEARBY_LOGS(VERBOSE) << __func__ << ": Removing characteristic " + << characteristic->getObjectPath(); + try { + characteristic->emitInterfacesRemovedSignal( + {org::bluez::GattCharacteristic1_adaptor::INTERFACE_NAME}); + } catch (const sdbus::Error &e) { + NEARBY_LOGS(ERROR) + << __func__ + << ": error emitting InterfacesRemoved signal for object path " + << characteristic->getObjectPath() << " with name '" << e.getName() + << "' and message '" << e.getMessage() << "'"; + } + } + unregisterAdaptor(); + } + + bool AddCharacteristic(const Uuid &service_uuid, + const Uuid &characteristic_uuid, + api::ble_v2::GattCharacteristic::Permission permission, + api::ble_v2::GattCharacteristic::Property property) + ABSL_LOCKS_EXCLUDED(characterstics_mutex_); + std::shared_ptr GetCharacteristic(const Uuid &uuid) + ABSL_LOCKS_EXCLUDED(characterstics_mutex_); + + private: + // Properties + std::string UUID() override { return uuid_; } + bool Primary() override { return primary_; } + sdbus::ObjectPath Device() override { return "/"; } + std::vector Includes() override { return {}; } + + absl::Mutex characterstics_mutex_; + absl::flat_hash_map> + characteristics_ ABSL_GUARDED_BY(characterstics_mutex_); + + std::shared_ptr devices_; + std::shared_ptr server_cb_; + + const std::string uuid_; + const bool primary_; +}; +} // namespace bluez +} // namespace linux +} // namespace nearby + +#endif diff --git a/internal/platform/implementation/linux/bluez_le_advertisement.cc b/internal/platform/implementation/linux/bluez_le_advertisement.cc new file mode 100644 index 00000000..a64244c0 --- /dev/null +++ b/internal/platform/implementation/linux/bluez_le_advertisement.cc @@ -0,0 +1,54 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include "internal/platform/implementation/ble_v2.h" +#include "internal/platform/implementation/linux/bluez.h" +#include "internal/platform/implementation/linux/bluez_le_advertisement.h" +#include "internal/platform/logging.h" +#include "internal/platform/uuid.h" + +namespace nearby { +namespace linux { +namespace bluez { +LEAdvertisement::LEAdvertisement( + sdbus::IConnection& system_bus, sdbus::ObjectPath path, + const api::ble_v2::BleAdvertisementData& advertising_data, + api::ble_v2::AdvertiseParameters advertise_set_parameters) + : AdaptorInterfaces(system_bus, std::move(path)), + is_extended_advertisement_(advertising_data.is_extended_advertisement), + advertise_set_parameters_(advertise_set_parameters) { + for (const auto& [uuid, data] : advertising_data.service_data) { + std::string uuid_string(uuid); + std::vector data_bytes(data.size()); + const auto* bytes = data.data(); + + service_uuids_.push_back(uuid_string); + for (size_t i = 0; i < data.size(); i++) { + data_bytes[i] = bytes[i]; + } + + service_data_.insert({uuid_string, std::move(data_bytes)}); + } + + registerAdaptor(); + + NEARBY_LOGS(VERBOSE) << __func__ + << ": Created a org.bluez.LEAdvertisement1 instance at " + << getObjectPath(); +} +} // namespace bluez +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/bluez_le_advertisement.h b/internal/platform/implementation/linux/bluez_le_advertisement.h new file mode 100644 index 00000000..c17cbc79 --- /dev/null +++ b/internal/platform/implementation/linux/bluez_le_advertisement.h @@ -0,0 +1,112 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef PLATFORM_IMPL_LINUX_API_BLUEZ_BLE_ADVERTISEMENT_H_ +#define PLATFORM_IMPL_LINUX_API_BLUEZ_BLE_ADVERTISEMENT_H_ + +#include +#include +#include +#include +#include + +#include "internal/platform/implementation/ble_v2.h" +#include "internal/platform/implementation/linux/bluetooth_adapter.h" +#include "internal/platform/implementation/linux/bluez.h" +#include "internal/platform/implementation/linux/generated/dbus/bluez/le_advertisement_manager_client.h" +#include "internal/platform/implementation/linux/generated/dbus/bluez/le_advertisement_server.h" +#include "internal/platform/logging.h" + +namespace nearby { +namespace linux { +namespace bluez { +class LEAdvertisement final + : public sdbus::AdaptorInterfaces { + public: + LEAdvertisement(const LEAdvertisement&) = delete; + LEAdvertisement(LEAdvertisement&&) = delete; + LEAdvertisement& operator=(const LEAdvertisement&) = delete; + LEAdvertisement& operator=(LEAdvertisement&&) = delete; + + LEAdvertisement(sdbus::IConnection& system_bus, sdbus::ObjectPath path, + const api::ble_v2::BleAdvertisementData& advertising_data, + api::ble_v2::AdvertiseParameters advertise_set_parameters); + + static std::unique_ptr CreateLEAdvertisement( + sdbus::IConnection& system_bus, + const api::ble_v2::BleAdvertisementData& advertising_data, + api::ble_v2::AdvertiseParameters advertising_parameters) { + static std::atomic adv_count = 0; + auto object_path = bluez::ble_advertisement_path(adv_count++); + return std::make_unique( + system_bus, object_path, advertising_data, advertising_parameters); + } + ~LEAdvertisement() { unregisterAdaptor(); } + + private: + // Methods + void Release() override { + NEARBY_LOGS(INFO) << __func__ + << ": LE Advertisement released: " << getObjectPath(); + } + + // Properties + std::string Type() override { return "broadcast"; } + std::vector ServiceUUIDs() override { return {}; } + std::map ManufacturerData() override { + return {}; + } + std::vector SolicitUUIDs() override { return {}; } + std::map ServiceData() override { + return service_data_; + } + std::vector Includes() override { return {}; } + std::string LocalName() override { return {}; } + uint16_t Duration() override { return 0; } + uint16_t Timeout() override { return 0; } + // Windows seems to hardcode the scan interval to 118.125 milliseconds, so + // lets just replicate that. + uint32_t MinInterval() override { return 118; } + uint32_t MaxInterval() override { return 119; } + int16_t TxPower() override { + return bluez::TxPowerLevelDbm(advertise_set_parameters_.tx_power_level); + }; + + bool is_extended_advertisement_; + std::vector service_uuids_; + std::map service_data_; + api::ble_v2::AdvertiseParameters advertise_set_parameters_; +}; + +class LEAdvertisementManager final + : public sdbus::ProxyInterfaces { + public: + LEAdvertisementManager(sdbus::IConnection& system_bus, + BluetoothAdapter& adapter) + : ProxyInterfaces(system_bus, "org.bluez", adapter.GetObjectPath()) { + registerProxy(); + } + ~LEAdvertisementManager() { unregisterProxy(); } + + LEAdvertisementManager(const LEAdvertisementManager&) = delete; + LEAdvertisementManager(LEAdvertisementManager&&) = delete; + LEAdvertisementManager& operator=(const LEAdvertisementManager&) = delete; + LEAdvertisementManager& operator=(LEAdvertisementManager&&) = delete; +}; +} // namespace bluez +} // namespace linux +} // namespace nearby + +#endif diff --git a/internal/platform/implementation/linux/generated/dbus/bluez/advertisement_monitor_manager_client.h b/internal/platform/implementation/linux/generated/dbus/bluez/advertisement_monitor_manager_client.h new file mode 100644 index 00000000..6e8a86fa --- /dev/null +++ b/internal/platform/implementation/linux/generated/dbus/bluez/advertisement_monitor_manager_client.h @@ -0,0 +1,57 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__advertisement_monitor_manager_client_h__proxy__H__ +#define __sdbuscpp__advertisement_monitor_manager_client_h__proxy__H__ + +#include +#include +#include + +namespace org { +namespace bluez { + +class AdvertisementMonitorManager1_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.bluez.AdvertisementMonitorManager1"; + +protected: + AdvertisementMonitorManager1_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + } + + ~AdvertisementMonitorManager1_proxy() = default; + +public: + void RegisterMonitor(const sdbus::ObjectPath& application) + { + proxy_.callMethod("RegisterMonitor").onInterface(INTERFACE_NAME).withArguments(application); + } + + void UnregisterMonitor(const sdbus::ObjectPath& application) + { + proxy_.callMethod("UnregisterMonitor").onInterface(INTERFACE_NAME).withArguments(application); + } + +public: + std::vector SupportedMonitorTypes() + { + return proxy_.getProperty("SupportedMonitorTypes").onInterface(INTERFACE_NAME); + } + + std::vector SupportedFeatures() + { + return proxy_.getProperty("SupportedFeatures").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}} // namespaces + +#endif diff --git a/internal/platform/implementation/linux/generated/dbus/bluez/advertisement_monitor_server.h b/internal/platform/implementation/linux/generated/dbus/bluez/advertisement_monitor_server.h new file mode 100644 index 00000000..1991ed31 --- /dev/null +++ b/internal/platform/implementation/linux/generated/dbus/bluez/advertisement_monitor_server.h @@ -0,0 +1,57 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__advertisement_monitor_server_h__adaptor__H__ +#define __sdbuscpp__advertisement_monitor_server_h__adaptor__H__ + +#include +#include +#include + +namespace org { +namespace bluez { + +class AdvertisementMonitor1_adaptor +{ +public: + static constexpr const char* INTERFACE_NAME = "org.bluez.AdvertisementMonitor1"; + +protected: + AdvertisementMonitor1_adaptor(sdbus::IObject& object) + : object_(object) + { + object_.registerMethod("Release").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->Release(); }); + object_.registerMethod("Activate").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->Activate(); }); + object_.registerMethod("DeviceFound").onInterface(INTERFACE_NAME).withInputParamNames("device").implementedAs([this](const sdbus::ObjectPath& device){ return this->DeviceFound(device); }); + object_.registerMethod("DeviceLost").onInterface(INTERFACE_NAME).withInputParamNames("device").implementedAs([this](const sdbus::ObjectPath& device){ return this->DeviceLost(device); }); + object_.registerProperty("Type").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Type(); }); + object_.registerProperty("RSSILowThreshold").onInterface(INTERFACE_NAME).withGetter([this](){ return this->RSSILowThreshold(); }); + object_.registerProperty("RSSIHighThreshold").onInterface(INTERFACE_NAME).withGetter([this](){ return this->RSSIHighThreshold(); }); + object_.registerProperty("RSSISamplingPeriod").onInterface(INTERFACE_NAME).withGetter([this](){ return this->RSSISamplingPeriod(); }); + object_.registerProperty("Patterns").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Patterns(); }); + } + + ~AdvertisementMonitor1_adaptor() = default; + +private: + virtual void Release() = 0; + virtual void Activate() = 0; + virtual void DeviceFound(const sdbus::ObjectPath& device) = 0; + virtual void DeviceLost(const sdbus::ObjectPath& device) = 0; + +private: + virtual std::string Type() = 0; + virtual int16_t RSSILowThreshold() = 0; + virtual int16_t RSSIHighThreshold() = 0; + virtual uint16_t RSSISamplingPeriod() = 0; + virtual std::vector>> Patterns() = 0; + +private: + sdbus::IObject& object_; +}; + +}} // namespaces + +#endif diff --git a/internal/platform/implementation/linux/generated/dbus/bluez/gatt_characteristic_client.h b/internal/platform/implementation/linux/generated/dbus/bluez/gatt_characteristic_client.h new file mode 100644 index 00000000..a07c3802 --- /dev/null +++ b/internal/platform/implementation/linux/generated/dbus/bluez/gatt_characteristic_client.h @@ -0,0 +1,89 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__generated_dbus_bluez_gatt_characteristic_client_h__proxy__H__ +#define __sdbuscpp__generated_dbus_bluez_gatt_characteristic_client_h__proxy__H__ + +#include +#include +#include + +namespace org { +namespace bluez { + +class GattCharacteristic1_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.bluez.GattCharacteristic1"; + +protected: + GattCharacteristic1_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + } + + ~GattCharacteristic1_proxy() = default; + +public: + std::vector ReadValue(const std::map& options) + { + std::vector result; + proxy_.callMethod("ReadValue").onInterface(INTERFACE_NAME).withArguments(options).storeResultsTo(result); + return result; + } + + void WriteValue(const std::vector& value, const std::map& options) + { + proxy_.callMethod("WriteValue").onInterface(INTERFACE_NAME).withArguments(value, options); + } + + void StartNotify() + { + proxy_.callMethod("StartNotify").onInterface(INTERFACE_NAME); + } + + void StopNotify() + { + proxy_.callMethod("StopNotify").onInterface(INTERFACE_NAME); + } + + void Confirm() + { + proxy_.callMethod("Confirm").onInterface(INTERFACE_NAME); + } + +public: + std::string UUID() + { + return proxy_.getProperty("UUID").onInterface(INTERFACE_NAME); + } + + sdbus::ObjectPath Service() + { + return proxy_.getProperty("Service").onInterface(INTERFACE_NAME); + } + + std::vector Value() + { + return proxy_.getProperty("Value").onInterface(INTERFACE_NAME); + } + + bool Notifying() + { + return proxy_.getProperty("Notifying").onInterface(INTERFACE_NAME); + } + + std::vector Flags() + { + return proxy_.getProperty("Flags").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}} // namespaces + +#endif diff --git a/internal/platform/implementation/linux/generated/dbus/bluez/gatt_characteristic_server.h b/internal/platform/implementation/linux/generated/dbus/bluez/gatt_characteristic_server.h new file mode 100644 index 00000000..451ac678 --- /dev/null +++ b/internal/platform/implementation/linux/generated/dbus/bluez/gatt_characteristic_server.h @@ -0,0 +1,59 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__generated_dbus_bluez_gatt_characteristic_server_h__adaptor__H__ +#define __sdbuscpp__generated_dbus_bluez_gatt_characteristic_server_h__adaptor__H__ + +#include +#include +#include + +namespace org { +namespace bluez { + +class GattCharacteristic1_adaptor +{ +public: + static constexpr const char* INTERFACE_NAME = "org.bluez.GattCharacteristic1"; + +protected: + GattCharacteristic1_adaptor(sdbus::IObject& object) + : object_(object) + { + object_.registerMethod("ReadValue").onInterface(INTERFACE_NAME).withInputParamNames("options").withOutputParamNames("value").implementedAs([this](sdbus::Result>&& result, std::map options){ this->ReadValue(std::move(result), std::move(options)); }); + object_.registerMethod("WriteValue").onInterface(INTERFACE_NAME).withInputParamNames("value", "options").implementedAs([this](sdbus::Result<>&& result, std::vector value, std::map options){ this->WriteValue(std::move(result), std::move(value), std::move(options)); }); + object_.registerMethod("StartNotify").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->StartNotify(); }); + object_.registerMethod("StopNotify").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->StopNotify(); }); + object_.registerMethod("Confirm").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->Confirm(); }); + object_.registerProperty("UUID").onInterface(INTERFACE_NAME).withGetter([this](){ return this->UUID(); }); + object_.registerProperty("Service").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Service(); }); + object_.registerProperty("Value").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Value(); }); + object_.registerProperty("Notifying").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Notifying(); }); + object_.registerProperty("Flags").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Flags(); }); + } + + ~GattCharacteristic1_adaptor() = default; + +private: + virtual void ReadValue(sdbus::Result>&& result, std::map options) = 0; + virtual void WriteValue(sdbus::Result<>&& result, std::vector value, std::map options) = 0; + virtual void StartNotify() = 0; + virtual void StopNotify() = 0; + virtual void Confirm() = 0; + +private: + virtual std::string UUID() = 0; + virtual sdbus::ObjectPath Service() = 0; + virtual std::vector Value() = 0; + virtual bool Notifying() = 0; + virtual std::vector Flags() = 0; + +private: + sdbus::IObject& object_; +}; + +}} // namespaces + +#endif diff --git a/internal/platform/implementation/linux/generated/dbus/bluez/gatt_manager_client.h b/internal/platform/implementation/linux/generated/dbus/bluez/gatt_manager_client.h new file mode 100644 index 00000000..340ee0af --- /dev/null +++ b/internal/platform/implementation/linux/generated/dbus/bluez/gatt_manager_client.h @@ -0,0 +1,46 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__gatt_manager_client_h__proxy__H__ +#define __sdbuscpp__gatt_manager_client_h__proxy__H__ + +#include +#include +#include + +namespace org { +namespace bluez { + +class GattManager1_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.bluez.GattManager1"; + +protected: + GattManager1_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + } + + ~GattManager1_proxy() = default; + +public: + void RegisterApplication(const sdbus::ObjectPath& application, const std::map& options) + { + proxy_.callMethod("RegisterApplication").onInterface(INTERFACE_NAME).withArguments(application, options); + } + + void UnregisterApplication(const sdbus::ObjectPath& application) + { + proxy_.callMethod("UnregisterApplication").onInterface(INTERFACE_NAME).withArguments(application); + } + +private: + sdbus::IProxy& proxy_; +}; + +}} // namespaces + +#endif diff --git a/internal/platform/implementation/linux/generated/dbus/bluez/gatt_service_server.h b/internal/platform/implementation/linux/generated/dbus/bluez/gatt_service_server.h new file mode 100644 index 00000000..e37253a0 --- /dev/null +++ b/internal/platform/implementation/linux/generated/dbus/bluez/gatt_service_server.h @@ -0,0 +1,45 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__generated_dbus_bluez_gatt_service_server_h__adaptor__H__ +#define __sdbuscpp__generated_dbus_bluez_gatt_service_server_h__adaptor__H__ + +#include +#include +#include + +namespace org { +namespace bluez { + +class GattService1_adaptor +{ +public: + static constexpr const char* INTERFACE_NAME = "org.bluez.GattService1"; + +protected: + GattService1_adaptor(sdbus::IObject& object) + : object_(object) + { + object_.registerProperty("UUID").onInterface(INTERFACE_NAME).withGetter([this](){ return this->UUID(); }); + object_.registerProperty("Primary").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Primary(); }); + object_.registerProperty("Device").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Device(); }); + object_.registerProperty("Includes").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Includes(); }); + } + + ~GattService1_adaptor() = default; + +private: + virtual std::string UUID() = 0; + virtual bool Primary() = 0; + virtual sdbus::ObjectPath Device() = 0; + virtual std::vector Includes() = 0; + +private: + sdbus::IObject& object_; +}; + +}} // namespaces + +#endif diff --git a/internal/platform/implementation/linux/generated/dbus/bluez/le_advertisement_manager_client.h b/internal/platform/implementation/linux/generated/dbus/bluez/le_advertisement_manager_client.h new file mode 100644 index 00000000..eb3125df --- /dev/null +++ b/internal/platform/implementation/linux/generated/dbus/bluez/le_advertisement_manager_client.h @@ -0,0 +1,77 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__generated_dbus_bluez_le_advertisement_manager_client_h__proxy__H__ +#define __sdbuscpp__generated_dbus_bluez_le_advertisement_manager_client_h__proxy__H__ + +#include +#include +#include + +namespace org { +namespace bluez { + +class LEAdvertisingManager1_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.bluez.LEAdvertisingManager1"; + +protected: + LEAdvertisingManager1_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + } + + ~LEAdvertisingManager1_proxy() = default; + +public: + void RegisterAdvertisement(const sdbus::ObjectPath& advertisement, const std::map& options) + { + proxy_.callMethod("RegisterAdvertisement").onInterface(INTERFACE_NAME).withArguments(advertisement, options); + } + + void UnregisterAdvertisement(const sdbus::ObjectPath& service) + { + proxy_.callMethod("UnregisterAdvertisement").onInterface(INTERFACE_NAME).withArguments(service); + } + +public: + uint8_t ActiveInstances() + { + return proxy_.getProperty("ActiveInstances").onInterface(INTERFACE_NAME); + } + + uint8_t SupportedInstances() + { + return proxy_.getProperty("SupportedInstances").onInterface(INTERFACE_NAME); + } + + std::vector SupportedIncludes() + { + return proxy_.getProperty("SupportedIncludes").onInterface(INTERFACE_NAME); + } + + std::vector SupportedSecondaryChannels() + { + return proxy_.getProperty("SupportedSecondaryChannels").onInterface(INTERFACE_NAME); + } + + std::vector SupportedFeatures() + { + return proxy_.getProperty("SupportedFeatures").onInterface(INTERFACE_NAME); + } + + std::map SupportedCapabilities() + { + return proxy_.getProperty("SupportedCapabilities").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}} // namespaces + +#endif diff --git a/internal/platform/implementation/linux/generated/dbus/bluez/le_advertisement_server.h b/internal/platform/implementation/linux/generated/dbus/bluez/le_advertisement_server.h new file mode 100644 index 00000000..89f6c0ef --- /dev/null +++ b/internal/platform/implementation/linux/generated/dbus/bluez/le_advertisement_server.h @@ -0,0 +1,65 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__generated_dbus_bluez_le_advertisement_server_h__adaptor__H__ +#define __sdbuscpp__generated_dbus_bluez_le_advertisement_server_h__adaptor__H__ + +#include +#include +#include + +namespace org { +namespace bluez { + +class LEAdvertisement1_adaptor +{ +public: + static constexpr const char* INTERFACE_NAME = "org.bluez.LEAdvertisement1"; + +protected: + LEAdvertisement1_adaptor(sdbus::IObject& object) + : object_(object) + { + object_.registerMethod("Release").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->Release(); }); + object_.registerProperty("Type").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Type(); }); + object_.registerProperty("ServiceUUIDs").onInterface(INTERFACE_NAME).withGetter([this](){ return this->ServiceUUIDs(); }); + object_.registerProperty("ManufacturerData").onInterface(INTERFACE_NAME).withGetter([this](){ return this->ManufacturerData(); }); + object_.registerProperty("SolicitUUIDs").onInterface(INTERFACE_NAME).withGetter([this](){ return this->SolicitUUIDs(); }); + object_.registerProperty("ServiceData").onInterface(INTERFACE_NAME).withGetter([this](){ return this->ServiceData(); }); + object_.registerProperty("Includes").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Includes(); }); + object_.registerProperty("LocalName").onInterface(INTERFACE_NAME).withGetter([this](){ return this->LocalName(); }); + object_.registerProperty("Duration").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Duration(); }); + object_.registerProperty("Timeout").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Timeout(); }); + object_.registerProperty("MinInterval").onInterface(INTERFACE_NAME).withGetter([this](){ return this->MinInterval(); }); + object_.registerProperty("MaxInterval").onInterface(INTERFACE_NAME).withGetter([this](){ return this->MaxInterval(); }); + object_.registerProperty("TxPower").onInterface(INTERFACE_NAME).withGetter([this](){ return this->TxPower(); }); + } + + ~LEAdvertisement1_adaptor() = default; + +private: + virtual void Release() = 0; + +private: + virtual std::string Type() = 0; + virtual std::vector ServiceUUIDs() = 0; + virtual std::map ManufacturerData() = 0; + virtual std::vector SolicitUUIDs() = 0; + virtual std::map ServiceData() = 0; + virtual std::vector Includes() = 0; + virtual std::string LocalName() = 0; + virtual uint16_t Duration() = 0; + virtual uint16_t Timeout() = 0; + virtual uint32_t MinInterval() = 0; + virtual uint32_t MaxInterval() = 0; + virtual int16_t TxPower() = 0; + +private: + sdbus::IObject& object_; +}; + +}} // namespaces + +#endif diff --git a/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.AdvertisementMonitor1.xml b/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.AdvertisementMonitor1.xml new file mode 100644 index 00000000..c92058ef --- /dev/null +++ b/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.AdvertisementMonitor1.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.AdvertisementMonitorManager1.xml b/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.AdvertisementMonitorManager1.xml new file mode 100644 index 00000000..5b9f2e4c --- /dev/null +++ b/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.AdvertisementMonitorManager1.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.GattCharacteristic1.xml b/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.GattCharacteristic1.xml new file mode 100644 index 00000000..f99de722 --- /dev/null +++ b/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.GattCharacteristic1.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.GattManager1.xml b/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.GattManager1.xml new file mode 100644 index 00000000..e353715b --- /dev/null +++ b/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.GattManager1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.GattService1.xml b/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.GattService1.xml new file mode 100644 index 00000000..da4f8e70 --- /dev/null +++ b/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.GattService1.xml @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.LEAdvertisement1.xml b/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.LEAdvertisement1.xml new file mode 100644 index 00000000..6fc4dcb0 --- /dev/null +++ b/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.LEAdvertisement1.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + diff --git a/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.LEAdvertisementManager1.xml b/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.LEAdvertisementManager1.xml new file mode 100644 index 00000000..36bb0196 --- /dev/null +++ b/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.LEAdvertisementManager1.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/internal/platform/implementation/linux/platform.cc b/internal/platform/implementation/linux/platform.cc index 56648a1c..5895a0a3 100644 --- a/internal/platform/implementation/linux/platform.cc +++ b/internal/platform/implementation/linux/platform.cc @@ -196,13 +196,15 @@ ImplementationPlatform::CreateBluetoothClassicMedium( } std::unique_ptr ImplementationPlatform::CreateBleMedium( - BluetoothAdapter &) { - return std::make_unique(); + BluetoothAdapter &adapter) { + return nullptr; } std::unique_ptr ImplementationPlatform::CreateBleV2Medium(api::BluetoothAdapter &adapter) { - return std::make_unique(); + return std::make_unique( + linux::getSystemBusConnection(), + dynamic_cast(adapter)); } namespace {