Add an initial BLE v2 implementation.

This commit is contained in:
Vibhav Pant
2023-09-08 16:53:49 +05:30
parent 2425473981
commit 54d31abedf
32 changed files with 2442 additions and 28 deletions
+15 -1
View File
@@ -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 = [
@@ -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<api::ble_v2::GattCharacteristic>
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<bluez::GattService>(
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<bluez::GattCharacteristic> 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<bluez::GattCharacteristic> 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
@@ -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 <memory>
#include <sdbus-c++/IConnection.h>
#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<BluetoothDevices> 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<api::ble_v2::ServerGattConnectionCallback>(
std::move(server_cb))) {}
~GattServer() override = default;
api::ble_v2::BlePeripheral& GetBlePeripheral() override {
return local_peripheral_;
}
absl::optional<api::ble_v2::GattCharacteristic> 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<BluetoothDevices> devices_;
BluetoothAdapter adapter_;
LocalBlePeripheral local_peripheral_;
std::shared_ptr<api::ble_v2::ServerGattConnectionCallback> server_cb_;
absl::Mutex services_mutex_;
absl::flat_hash_map<Uuid, std::unique_ptr<bluez::GattService>> services_
ABSL_GUARDED_BY(services_mutex_);
};
} // namespace linux
} // namespace nearby
#endif
@@ -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 <algorithm>
#include <cassert>
#include <sdbus-c++/IProxy.h>
#include <sdbus-c++/Types.h>
#include <absl/functional/any_invocable.h>
#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<BluetoothDevices>(
system_bus_, adapter_.GetObjectPath(), observers_)),
adv_monitor_manager_(
bluez::AdvertisementMonitorManager::
DiscoverAdvertisementMonitorManager(system_bus, adapter_)),
adv_manager_(
std::make_unique<bluez::LEAdvertisementManager>(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<api::ble_v2::BleMedium::AdvertisingSession>
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<sdbus::IProxy> proxy =
sdbus::createProxy(system_bus_, "org.bluez", adapter_.GetObjectPath());
proxy->finishRegistration();
std::shared_ptr<AdvertisingCallback> shared_cb =
std::make_shared<AdvertisingCallback>(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<std::string, sdbus::Variant>{})
.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<absl::Status()> 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>(
api::ble_v2::BleMedium::AdvertisingSession{std::move(stop_adv)});
}
std::unique_ptr<api::ble_v2::GattServer> BleV2Medium::StartGattServer(
api::ble_v2::ServerGattConnectionCallback callback) {
return std::make_unique<GattServer>(system_bus_, adapter_, devices_,
std::move(callback));
}
bool BleV2Medium::StartLEDiscovery() {
std::map<std::string, sdbus::Variant> 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<bluez::AdvertisementMonitor>(
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<api::ble_v2::BleMedium::ScanningSession>
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<bluez::AdvertisementMonitor>(
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>(
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
@@ -15,41 +15,57 @@
#ifndef PLATFORM_IMPL_LINUX_API_BLE_V2_MEDIUM_H_
#define PLATFORM_IMPL_LINUX_API_BLE_V2_MEDIUM_H_
#include <memory>
#include <sdbus-c++/IConnection.h>
#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<AdvertisingSession> 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<ScanningSession> StartScanning(
const Uuid &service_uuid, api::ble_v2::TxPowerLevel tx_power_level,
ScanningCallback callback) override {
return nullptr;
};
ScanningCallback callback) override;
std::unique_ptr<api::ble_v2::GattServer> StartGattServer(
api::ble_v2::ServerGattConnectionCallback callback) override {
return nullptr;
}
api::ble_v2::ServerGattConnectionCallback callback) override;
std::unique_ptr<api::ble_v2::GattClient> ConnectToGattServer(
api::ble_v2::BlePeripheral &peripheral,
@@ -60,7 +76,7 @@ class BleV2Medium : public api::ble_v2::BleMedium {
std::unique_ptr<api::ble_v2::BleServerSocket> OpenServerSocket(
const std::string &service_id) override {
return nullptr;
return std::make_unique<BleV2ServerSocket>();
}
std::unique_ptr<api::ble_v2::BleSocket> 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<std::string> 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<api::BluetoothClassicMedium::Observer> observers_ = {};
std::shared_ptr<BluetoothDevices> devices_;
std::unique_ptr<bluez::AdvertisementMonitorManager> adv_monitor_manager_;
absl::Mutex active_adv_monitors_mutex_;
absl::flat_hash_map<Uuid, std::unique_ptr<bluez::AdvertisementMonitor>>
active_adv_monitors_ ABSL_GUARDED_BY(active_adv_monitors_mutex_);
// Used by the synchronous variant of StartScanning
std::optional<Uuid> cur_monitored_service_uuid_;
std::unique_ptr<bluez::LEAdvertisementManager> adv_manager_;
absl::Mutex cur_adv_mutex_;
std::unique_ptr<bluez::LEAdvertisement> cur_adv_
ABSL_GUARDED_BY(cur_adv_mutex_);
absl::Mutex advs_mutex_;
std::list<std::unique_ptr<bluez::LEAdvertisement>> advs_
ABSL_GUARDED_BY(advs_mutex_);
};
} // namespace linux
} // namespace nearby
@@ -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<api::ble_v2::BleSocket> 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
@@ -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<BluetoothDevices> 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<BluetoothDevices> 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<std::string, sdbus::Variant> 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<uint8_t> 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
@@ -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 <sdbus-c++/AdaptorInterfaces.h>
#include <sdbus-c++/IConnection.h>
#include <sdbus-c++/StandardInterfaces.h>
#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<org::bluez::AdvertisementMonitor1_adaptor,
sdbus::ManagedObject_adaptor> {
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<BluetoothDevices> 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<BluetoothDevices> 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<sdbus::Struct<uint8_t, uint8_t, std::vector<uint8_t>>> Patterns()
override {
std::array<char, 16> service_id_data = service_uuid_.data();
return {{0,
0x16,
{static_cast<uint8_t>(service_id_data[3] & 0xFF),
static_cast<uint8_t>(service_id_data[2] & 0xFF)}}};
};
std::shared_ptr<BluetoothDevices> devices_;
api::ble_v2::BleMedium::ScanCallback scan_callback_;
absl::AnyInvocable<void(absl::Status)> start_scanning_result_callback_;
std::string type_;
Uuid service_uuid_;
api::ble_v2::TxPowerLevel tx_power_level_;
};
} // namespace bluez
} // namespace linux
} // namespace nearby
#endif
@@ -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 <sdbus-c++/IConnection.h>
#include <sdbus-c++/ProxyInterfaces.h>
#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<AdvertisementMonitorManager>
std::make_unique<AdvertisementMonitorManager>(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<AdvertisementMonitorManager>
DiscoverAdvertisementMonitorManager(sdbus::IConnection &system_bus,
const BluetoothAdapter &adapter) {
bluez::BluezObjectManager manager(system_bus);
std::map<sdbus::ObjectPath,
std::map<std::string, std::map<std::string, sdbus::Variant>>>
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<AdvertisementMonitorManager>(system_bus, adapter);
}
};
} // namespace bluez
} // namespace linux
} // namespace nearby
#endif
@@ -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 <sdbus-c++/Error.h>
#include <sdbus-c++/MethodResult.h>
#include <sdbus-c++/Types.h>
#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<uint8_t> 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<uint8_t> 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<std::vector<uint8_t>> &&result,
std::map<std::string, sdbus::Variant> 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<int>(offset),
[result = std::move(result),
this](absl::StatusOr<absl::string_view> data) {
const auto &status = data.status();
if (status.ok()) {
auto str = data.value();
std::vector<uint8_t> 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<uint8_t> value,
std::map<std::string, sdbus::Variant> 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<int>(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<std::string> GattCharacteristic::Flags() {
auto characteristic = characteristic_;
std::vector<std::string> 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
@@ -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 <atomic>
#include <map>
#include <optional>
#include <string>
#include <vector>
#include <sdbus-c++/AdaptorInterfaces.h>
#include <sdbus-c++/IConnection.h>
#include <sdbus-c++/MethodResult.h>
#include <sdbus-c++/StandardInterfaces.h>
#include <sdbus-c++/Types.h>
#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<org::bluez::GattCharacteristic1_adaptor,
sdbus::Properties_adaptor,
sdbus::ManagedObject_adaptor> {
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<api::ble_v2::ServerGattConnectionCallback> server_cb,
std::shared_ptr<BluetoothDevices> 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<std::vector<uint8_t>> &&result,
std::map<std::string, sdbus::Variant> options) override
ABSL_LOCKS_EXCLUDED(cached_value_mutex_, static_value_mutex_);
void WriteValue(sdbus::Result<> &&result, std::vector<uint8_t> value,
std::map<std::string, sdbus::Variant> 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<std::string> Flags() override;
std::vector<uint8_t> Value() override
ABSL_LOCKS_EXCLUDED(cached_value_mutex_) {
absl::ReaderMutexLock lock(&cached_value_mutex_);
return cached_value_;
}
std::shared_ptr<BluetoothDevices> devices_;
std::shared_ptr<api::ble_v2::ServerGattConnectionCallback> server_cb_;
api::ble_v2::GattCharacteristic characteristic_;
// Set by `GattServer::UpdateCharacteristic()`
absl::Mutex static_value_mutex_;
std::optional<std::vector<uint8_t>> static_value_
ABSL_GUARDED_BY(static_value_mutex_);
sdbus::ObjectPath service_object_path_;
std::atomic_bool notifying_;
absl::Mutex cached_value_mutex_;
std::vector<uint8_t> cached_value_ ABSL_GUARDED_BY(cached_value_mutex_);
absl::Mutex confirmed_mutex_;
bool confirmed_;
};
} // namespace bluez
} // namespace linux
} // namespace nearby
#endif
@@ -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 <sdbus-c++/IConnection.h>
#include <sdbus-c++/ProxyInterfaces.h>
#include <sdbus-c++/Types.h>
#include "internal/platform/implementation/linux/generated/dbus/bluez/gatt_manager_client.h"
namespace nearby {
namespace linux {
namespace bluez {
class GattManager
: public sdbus::ProxyInterfaces<org::bluez::GattManager1_proxy> {
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
@@ -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<GattCharacteristic> chr =
std::make_shared<GattCharacteristic>(
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<GattCharacteristic> 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
@@ -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 <sdbus-c++/AdaptorInterfaces.h>
#include <sdbus-c++/IConnection.h>
#include <sdbus-c++/IObject.h>
#include <sdbus-c++/StandardInterfaces.h>
#include <sdbus-c++/Types.h>
#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<org::bluez::GattService1_adaptor,
sdbus::ManagedObject_adaptor,
sdbus::Properties_adaptor> {
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<api::ble_v2::ServerGattConnectionCallback> server_cb,
std::shared_ptr<BluetoothDevices> 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<GattCharacteristic> 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<sdbus::ObjectPath> Includes() override { return {}; }
absl::Mutex characterstics_mutex_;
absl::flat_hash_map<Uuid, std::shared_ptr<GattCharacteristic>>
characteristics_ ABSL_GUARDED_BY(characterstics_mutex_);
std::shared_ptr<BluetoothDevices> devices_;
std::shared_ptr<api::ble_v2::ServerGattConnectionCallback> server_cb_;
const std::string uuid_;
const bool primary_;
};
} // namespace bluez
} // namespace linux
} // namespace nearby
#endif
@@ -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 <vector>
#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<uint8_t> 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
@@ -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 <sdbus-c++/AdaptorInterfaces.h>
#include <sdbus-c++/IConnection.h>
#include <sdbus-c++/ProxyInterfaces.h>
#include <sdbus-c++/StandardInterfaces.h>
#include <sdbus-c++/Types.h>
#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<org::bluez::LEAdvertisement1_adaptor,
sdbus::ObjectManager_adaptor> {
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<LEAdvertisement> CreateLEAdvertisement(
sdbus::IConnection& system_bus,
const api::ble_v2::BleAdvertisementData& advertising_data,
api::ble_v2::AdvertiseParameters advertising_parameters) {
static std::atomic<size_t> adv_count = 0;
auto object_path = bluez::ble_advertisement_path(adv_count++);
return std::make_unique<LEAdvertisement>(
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<std::string> ServiceUUIDs() override { return {}; }
std::map<std::string, sdbus::Variant> ManufacturerData() override {
return {};
}
std::vector<std::string> SolicitUUIDs() override { return {}; }
std::map<std::string, sdbus::Variant> ServiceData() override {
return service_data_;
}
std::vector<std::string> 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<std::string> service_uuids_;
std::map<std::string, sdbus::Variant> service_data_;
api::ble_v2::AdvertiseParameters advertise_set_parameters_;
};
class LEAdvertisementManager final
: public sdbus::ProxyInterfaces<org::bluez::LEAdvertisingManager1_proxy> {
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
@@ -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 <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
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<std::string> SupportedMonitorTypes()
{
return proxy_.getProperty("SupportedMonitorTypes").onInterface(INTERFACE_NAME);
}
std::vector<std::string> SupportedFeatures()
{
return proxy_.getProperty("SupportedFeatures").onInterface(INTERFACE_NAME);
}
private:
sdbus::IProxy& proxy_;
};
}} // namespaces
#endif
@@ -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 <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
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<sdbus::Struct<uint8_t, uint8_t, std::vector<uint8_t>>> Patterns() = 0;
private:
sdbus::IObject& object_;
};
}} // namespaces
#endif
@@ -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 <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
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<uint8_t> ReadValue(const std::map<std::string, sdbus::Variant>& options)
{
std::vector<uint8_t> result;
proxy_.callMethod("ReadValue").onInterface(INTERFACE_NAME).withArguments(options).storeResultsTo(result);
return result;
}
void WriteValue(const std::vector<uint8_t>& value, const std::map<std::string, sdbus::Variant>& 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<uint8_t> Value()
{
return proxy_.getProperty("Value").onInterface(INTERFACE_NAME);
}
bool Notifying()
{
return proxy_.getProperty("Notifying").onInterface(INTERFACE_NAME);
}
std::vector<std::string> Flags()
{
return proxy_.getProperty("Flags").onInterface(INTERFACE_NAME);
}
private:
sdbus::IProxy& proxy_;
};
}} // namespaces
#endif
@@ -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 <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
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<std::vector<uint8_t>>&& result, std::map<std::string, sdbus::Variant> 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<uint8_t> value, std::map<std::string, sdbus::Variant> 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<std::vector<uint8_t>>&& result, std::map<std::string, sdbus::Variant> options) = 0;
virtual void WriteValue(sdbus::Result<>&& result, std::vector<uint8_t> value, std::map<std::string, sdbus::Variant> 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<uint8_t> Value() = 0;
virtual bool Notifying() = 0;
virtual std::vector<std::string> Flags() = 0;
private:
sdbus::IObject& object_;
};
}} // namespaces
#endif
@@ -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 <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
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<std::string, sdbus::Variant>& 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
@@ -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 <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
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<sdbus::ObjectPath> Includes() = 0;
private:
sdbus::IObject& object_;
};
}} // namespaces
#endif
@@ -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 <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
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<std::string, sdbus::Variant>& 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<std::string> SupportedIncludes()
{
return proxy_.getProperty("SupportedIncludes").onInterface(INTERFACE_NAME);
}
std::vector<std::string> SupportedSecondaryChannels()
{
return proxy_.getProperty("SupportedSecondaryChannels").onInterface(INTERFACE_NAME);
}
std::vector<std::string> SupportedFeatures()
{
return proxy_.getProperty("SupportedFeatures").onInterface(INTERFACE_NAME);
}
std::map<std::string, sdbus::Variant> SupportedCapabilities()
{
return proxy_.getProperty("SupportedCapabilities").onInterface(INTERFACE_NAME);
}
private:
sdbus::IProxy& proxy_;
};
}} // namespaces
#endif
@@ -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 <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
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<std::string> ServiceUUIDs() = 0;
virtual std::map<std::string, sdbus::Variant> ManufacturerData() = 0;
virtual std::vector<std::string> SolicitUUIDs() = 0;
virtual std::map<std::string, sdbus::Variant> ServiceData() = 0;
virtual std::vector<std::string> 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
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.bluez.AdvertisementMonitor1">
<method name="Release">
</method>
<method name="Activate">
</method>
<method name="DeviceFound">
<arg type='o' name="device" direction="in"/>
</method>
<method name="DeviceLost">
<arg type='o' name="device" direction="in"/>
</method>
<property name="Type" type="s" access="read">
</property>
<property name="RSSILowThreshold" type="n" access="read">
</property>
<property name="RSSIHighThreshold" type="n" access="read">
</property>
<property name="RSSISamplingPeriod" type="q" access="read">
</property>
<property name="Patterns" type="a(yyay)" access="read">
</property>
</interface>
</node>
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.bluez.AdvertisementMonitorManager1">
<method name="RegisterMonitor">
<arg name="application" type="o" direction="in" />
</method>
<method name="UnregisterMonitor">
<arg name="application" type="o" direction="in" />
</method>
<property name="SupportedMonitorTypes" type="as" access="read" />
<property name="SupportedFeatures" type="as" access="read" />
</interface>
</node>
@@ -0,0 +1,28 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.bluez.GattCharacteristic1">
<method name="ReadValue">
<annotation name="org.freedesktop.DBus.Method.Async" value="server" />
<arg name="options" type="a{sv}" direction="in"/>
<arg name="value" type="ay" direction="out"/>
</method>
<method name="WriteValue">
<annotation name="org.freedesktop.DBus.Method.Async" value="server" />
<arg name="value" type="ay" direction="in"/>
<arg name="options" type="a{sv}" direction="in"/>
</method>
<method name="StartNotify">
</method>
<method name="StopNotify">
</method>
<method name="Confirm">
</method>
<property name="UUID" type="s" access="read"></property>
<property name="Service" type="o" access="read"></property>
<property name="Value" type="ay" access="read"></property>
<property name="Notifying" type="b" access="read"></property>
<property name="Flags" type="as" access="read"></property>
</interface>
</node>
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.bluez.GattManager1">
<method name="RegisterApplication">
<arg name="application" type="o" direction="in" />
<arg name="options" type="a{sv}" direction="in" />
</method>
<method name="UnregisterApplication">
<arg name="application" type="o" direction="in" />
</method>
</interface>
</node>
@@ -0,0 +1,10 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.bluez.GattService1">
<property name="UUID" type="s" access="read"></property>
<property name="Primary" type="b" access="read"></property>
<property name="Device" type="o" access="read"></property>
<property name="Includes" type="ao" access="read"></property>
</interface>
</node>
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE node PUBLIC
"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.bluez.LEAdvertisement1">
<method name="Release"/>
<property name="Type" type="s" access="read"/>
<property name="ServiceUUIDs" type="as" access="read"/>
<property name="ManufacturerData" type="a{sv}" access="read"/>
<property name="SolicitUUIDs" type="as" access="read"/>
<property name="ServiceData" type="a{sv}" access="read"/>
<property name="Includes" type="as" access="read"/>
<property name="LocalName" type="s" access="read"/>
<property name="Duration" type="q" access="read"/>
<property name="Timeout" type="q" access="read"/>
<property name="MinInterval" type="u" access="read"/>
<property name="MaxInterval" type="u" access="read"/>
<property name="TxPower" type="n" access="read"/>
</interface>
</node>
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.bluez.LEAdvertisingManager1">
<method name="RegisterAdvertisement">
<arg name="advertisement" type="o" direction="in" />
<arg name="options" type="a{sv}" direction="in" />
</method>
<method name="UnregisterAdvertisement">
<arg name="service" type="o" direction="in" />
</method>
<property name="ActiveInstances" type="y" access="read" />
<property name="SupportedInstances" type="y" access="read" />
<property name="SupportedIncludes" type="as" access="read" />
<property name="SupportedSecondaryChannels" type="as" access="read" />
<property name="SupportedFeatures" type="as" access="read" />
<property name="SupportedCapabilities" type="a{sv}" access="read" />
</interface>
</node>
@@ -196,13 +196,15 @@ ImplementationPlatform::CreateBluetoothClassicMedium(
}
std::unique_ptr<BleMedium> ImplementationPlatform::CreateBleMedium(
BluetoothAdapter &) {
return std::make_unique<linux::BleMedium>();
BluetoothAdapter &adapter) {
return nullptr;
}
std::unique_ptr<api::ble_v2::BleMedium>
ImplementationPlatform::CreateBleV2Medium(api::BluetoothAdapter &adapter) {
return std::make_unique<linux::BleV2Medium>();
return std::make_unique<linux::BleV2Medium>(
linux::getSystemBusConnection(),
dynamic_cast<linux::BluetoothAdapter &>(adapter));
}
namespace {