Add async operations to ble_v2

PiperOrigin-RevId: 472611661
This commit is contained in:
Hai Shang
2022-09-06 19:08:22 -07:00
committed by Copybara-Service
parent 851f5ec0dd
commit da54ba3422
11 changed files with 341 additions and 8 deletions
+35 -2
View File
@@ -38,6 +38,15 @@ bool BleV2Medium::StartAdvertising(
bool BleV2Medium::StopAdvertising() { return impl_->StopAdvertising(); }
std::unique_ptr<api::ble_v2::BleMedium::AdvertisingSession>
BleV2Medium::StartAdvertising(
const api::ble_v2::BleAdvertisementData& advertising_data,
api::ble_v2::AdvertiseParameters advertise_set_parameters,
api::ble_v2::BleMedium::AdvertisingCallback callback) {
return impl_->StartAdvertising(advertising_data, advertise_set_parameters,
callback);
}
bool BleV2Medium::StartScanning(const Uuid& service_uuid,
TxPowerLevel tx_power_level,
ScanCallback callback) {
@@ -48,7 +57,7 @@ bool BleV2Medium::StartScanning(const Uuid& service_uuid,
}
bool success = impl_->StartScanning(
service_uuid, tx_power_level,
{
api::ble_v2::BleMedium::ScanCallback{
.advertisement_found_cb =
[this](api::ble_v2::BlePeripheral& peripheral,
BleAdvertisementData advertisement_data) {
@@ -84,7 +93,9 @@ bool BleV2Medium::StartScanning(const Uuid& service_uuid,
bool BleV2Medium::StopScanning() {
MutexLock lock(&mutex_);
if (!scanning_enabled_) return true;
if (!scanning_enabled_) {
return true;
}
scanning_enabled_ = false;
peripherals_.clear();
scan_callback_ = {};
@@ -92,6 +103,28 @@ bool BleV2Medium::StopScanning() {
return impl_->StopScanning();
}
std::unique_ptr<api::ble_v2::BleMedium::ScanningSession>
BleV2Medium::StartScanning(const Uuid& service_uuid,
api::ble_v2::TxPowerLevel tx_power_level,
api::ble_v2::BleMedium::ScanningCallback callback) {
NEARBY_LOG(INFO, "platform mutex: %p", &mutex_);
return impl_->StartScanning(
service_uuid, tx_power_level,
api::ble_v2::BleMedium::ScanningCallback{
.start_scanning_result =
[this, callback](api::ble_v2::BleOperationStatus status) {
{
MutexLock lock(&mutex_);
if (status == api::ble_v2::BleOperationStatus::kSucceeded) {
scanning_enabled_ = true;
}
}
callback.start_scanning_result(status);
},
.advertisement_found_cb = callback.advertisement_found_cb,
});
}
std::unique_ptr<GattServer> BleV2Medium::StartGattServer(
ServerGattConnectionCallback callback) {
{
+13 -3
View File
@@ -168,7 +168,9 @@ class GattServer final {
return impl_->UpdateCharacteristic(characteristic, value);
}
void Stop() { if (impl_) return impl_->Stop(); }
void Stop() {
if (impl_) return impl_->Stop();
}
// Returns true if a gatt_server is usable. If this method returns false,
// it is not safe to call any other method.
@@ -193,8 +195,7 @@ class GattClient final {
: impl_(std::move(client_gatt_connection)) {}
bool DiscoverServiceAndCharacteristics(
const Uuid& service_uuid,
const std::vector<Uuid>& characteristic_uuids) {
const Uuid& service_uuid, const std::vector<Uuid>& characteristic_uuids) {
return impl_->DiscoverServiceAndCharacteristics(service_uuid,
characteristic_uuids);
}
@@ -269,12 +270,21 @@ class BleV2Medium final {
api::ble_v2::AdvertiseParameters advertise_parameters);
bool StopAdvertising();
std::unique_ptr<api::ble_v2::BleMedium::AdvertisingSession> StartAdvertising(
const api::ble_v2::BleAdvertisementData& advertising_data,
api::ble_v2::AdvertiseParameters advertise_set_parameters,
api::ble_v2::BleMedium::AdvertisingCallback callback);
// Returns true once the BLE scan has been initiated.
bool StartScanning(const Uuid& service_uuid,
api::ble_v2::TxPowerLevel tx_power_level,
ScanCallback callback);
bool StopScanning();
std::unique_ptr<api::ble_v2::BleMedium::ScanningSession> StartScanning(
const Uuid& service_uuid, api::ble_v2::TxPowerLevel tx_power_level,
api::ble_v2::BleMedium::ScanningCallback callback);
// Starts Gatt Server for waiting to client connection.
std::unique_ptr<GattServer> StartGattServer(
ServerGattConnectionCallback callback);
+135
View File
@@ -14,6 +14,7 @@
#include "internal/platform/ble_v2.h"
#include <functional>
#include <memory>
#include <string>
#include <utility>
@@ -23,6 +24,7 @@
#include "gtest/gtest.h"
#include "internal/platform/bluetooth_adapter.h"
#include "internal/platform/count_down_latch.h"
#include "internal/platform/implementation/ble_v2.h"
#include "internal/platform/medium_environment.h"
namespace location {
@@ -333,6 +335,139 @@ TEST_F(BleV2MediumTest, CanStartScanningAndAdvertising) {
env_.Stop();
}
TEST_F(BleV2MediumTest, StartThenStopAsyncScanning) {
env_.Start();
BluetoothAdapter adapter_a;
BleV2Medium ble_a(adapter_a);
Uuid service_uuid(1234, 5678);
CountDownLatch found_latch_a(1);
std::function<void(api::ble_v2::BlePeripheral&, BleAdvertisementData)>
advertisement_found_cb_a =
[&found_latch_a](api::ble_v2::BlePeripheral& peripheral,
BleAdvertisementData advertisement_data) -> void {
found_latch_a.CountDown();
};
std::unique_ptr<api::ble_v2::BleMedium::ScanningSession> scanning_session_a =
ble_a.StartScanning(
service_uuid, kTxPowerLevel,
api::ble_v2::BleMedium::ScanningCallback{
.advertisement_found_cb = advertisement_found_cb_a,
});
EXPECT_TRUE(env_.GetBleV2MediumStatus(*ble_a.GetImpl()).value().is_scanning);
api::ble_v2::BleOperationStatus stop_result =
scanning_session_a->stop_scanning();
EXPECT_EQ(stop_result, api::ble_v2::BleOperationStatus::kSucceeded);
EXPECT_FALSE(env_.GetBleV2MediumStatus(*ble_a.GetImpl()).value().is_scanning);
env_.Stop();
}
TEST_F(BleV2MediumTest, CanStartMultipleAsyncScanning) {
env_.Start();
BluetoothAdapter adapter_a;
BluetoothAdapter adapter_b;
BleV2Medium ble_a(adapter_a);
BleV2Medium ble_b(adapter_b);
Uuid service_uuid(1234, 5678);
CountDownLatch found_latch_a(1);
CountDownLatch found_latch_b(1);
std::function<void(api::ble_v2::BlePeripheral&, BleAdvertisementData)>
advertisement_found_cb_a =
[&found_latch_a](api::ble_v2::BlePeripheral& peripheral,
BleAdvertisementData advertisement_data) -> void {
found_latch_a.CountDown();
};
std::function<void(api::ble_v2::BlePeripheral&, BleAdvertisementData)>
advertisement_found_cb_b =
[&found_latch_b](api::ble_v2::BlePeripheral& peripheral,
BleAdvertisementData advertisement_data) -> void {
found_latch_b.CountDown();
};
std::unique_ptr<api::ble_v2::BleMedium::ScanningSession> scanning_session_a =
ble_a.StartScanning(
service_uuid, kTxPowerLevel,
api::ble_v2::BleMedium::ScanningCallback{
.advertisement_found_cb = advertisement_found_cb_a,
});
std::unique_ptr<api::ble_v2::BleMedium::ScanningSession> scanning_session_b =
ble_b.StartScanning(
service_uuid, kTxPowerLevel,
api::ble_v2::BleMedium::ScanningCallback{
.advertisement_found_cb = advertisement_found_cb_b,
});
EXPECT_TRUE(env_.GetBleV2MediumStatus(*ble_a.GetImpl()).value().is_scanning);
EXPECT_TRUE(env_.GetBleV2MediumStatus(*ble_b.GetImpl()).value().is_scanning);
api::ble_v2::BleOperationStatus stop_result_a =
scanning_session_a->stop_scanning();
EXPECT_EQ(stop_result_a, api::ble_v2::BleOperationStatus::kSucceeded);
api::ble_v2::BleOperationStatus stop_result_b =
scanning_session_b->stop_scanning();
EXPECT_EQ(stop_result_b, api::ble_v2::BleOperationStatus::kSucceeded);
EXPECT_FALSE(env_.GetBleV2MediumStatus(*ble_a.GetImpl()).value().is_scanning);
EXPECT_FALSE(env_.GetBleV2MediumStatus(*ble_b.GetImpl()).value().is_scanning);
env_.Stop();
}
TEST_F(BleV2MediumTest, CanStartAsyncScanningAndAdvertising) {
env_.Start();
BluetoothAdapter adapter_a;
BluetoothAdapter adapter_b;
BleV2Medium ble_a(adapter_a);
BleV2Medium ble_b(adapter_b);
Uuid service_uuid(1234, 5678);
ByteArray advertisement_bytes{std::string(kAdvertisementString)};
ByteArray advertisement_header_bytes{std::string(kAdvertisementHeaderString)};
CountDownLatch found_latch(1);
std::function<void(api::ble_v2::BlePeripheral&, BleAdvertisementData)>
advertisement_found_cb =
[&found_latch](api::ble_v2::BlePeripheral& peripheral,
BleAdvertisementData advertisement_data) -> void {
found_latch.CountDown();
};
std::unique_ptr<api::ble_v2::BleMedium::ScanningSession> scanning_session =
ble_a.StartScanning(service_uuid, kTxPowerLevel,
api::ble_v2::BleMedium::ScanningCallback{
.advertisement_found_cb = advertisement_found_cb,
});
// Succeed to start regular advertisement.
BleAdvertisementData advertising_data;
advertising_data.is_extended_advertisement = false;
advertising_data.service_data = {{service_uuid, advertisement_header_bytes}};
EXPECT_TRUE(ble_b.StartAdvertising(
advertising_data,
{.tx_power_level = kTxPowerLevel, .is_connectable = true}));
EXPECT_TRUE(env_.GetBleV2MediumStatus(*ble_a.GetImpl()).value().is_scanning);
EXPECT_TRUE(
env_.GetBleV2MediumStatus(*ble_b.GetImpl()).value().is_advertising);
EXPECT_TRUE(found_latch.Await(kWaitDuration).result());
api::ble_v2::BleOperationStatus stop_scanning_result =
scanning_session->stop_scanning();
EXPECT_EQ(stop_scanning_result, api::ble_v2::BleOperationStatus::kSucceeded);
EXPECT_TRUE(ble_b.StopAdvertising());
EXPECT_FALSE(env_.GetBleV2MediumStatus(*ble_a.GetImpl()).value().is_scanning);
EXPECT_FALSE(
env_.GetBleV2MediumStatus(*ble_b.GetImpl()).value().is_advertising);
env_.UnregisterBleV2Medium(*ble_a.GetImpl());
env_.UnregisterBleV2Medium(*ble_b.GetImpl());
EXPECT_EQ(env_.GetBleV2MediumStatus(*ble_a.GetImpl()), absl::nullopt);
EXPECT_EQ(env_.GetBleV2MediumStatus(*ble_b.GetImpl()), absl::nullopt);
env_.Stop();
}
TEST_F(BleV2MediumTest, CanStartGattServer) {
env_.Start();
BluetoothAdapter adapter;
+45 -1
View File
@@ -26,13 +26,13 @@
#include "absl/container/flat_hash_map.h"
#include "absl/strings/string_view.h"
#include "internal/platform/uuid.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/cancellation_flag.h"
#include "internal/platform/exception.h"
#include "internal/platform/input_stream.h"
#include "internal/platform/listeners.h"
#include "internal/platform/output_stream.h"
#include "internal/platform/uuid.h"
namespace location {
namespace nearby {
@@ -48,6 +48,12 @@ enum class TxPowerLevel {
kHigh = 4,
};
enum class BleOperationStatus {
kUnknown = 0,
kSucceeded = 1,
kFailed = 2,
};
// https://developer.android.com/reference/android/bluetooth/le/AdvertisingSetParameters.Builder
//
// The preferences for Advertising.
@@ -298,6 +304,23 @@ class BleMedium {
const BleAdvertisementData& advertising_data,
AdvertiseParameters advertise_set_parameters) = 0;
struct AdvertisingCallback {
std::function<void(BleOperationStatus)> start_advertising_result;
};
struct AdvertisingSession {
std::function<BleOperationStatus()> stop_advertising;
};
// Async interface for StartAdertising.
// Result status will be passed to start_advertising_result callback.
// To stop advertising, invoke the stop_advertising callback in
// AdvertisingSession.
virtual std::unique_ptr<AdvertisingSession> StartAdvertising(
const BleAdvertisementData& advertising_data,
AdvertiseParameters advertise_set_parameters,
AdvertisingCallback callback) = 0;
// https://developer.android.com/reference/android/bluetooth/le/BluetoothLeAdvertiser.html#stopAdvertising(android.bluetooth.le.AdvertiseCallback)
//
// Stops advertising.
@@ -342,6 +365,27 @@ class BleMedium {
// Stops scanning.
virtual bool StopScanning() = 0;
struct ScanningSession {
std::function<BleOperationStatus()> stop_scanning;
};
struct ScanningCallback {
std::function<void(BleOperationStatus)> start_scanning_result =
DefaultCallback<BleOperationStatus>();
std::function<void(BlePeripheral& peripheral,
BleAdvertisementData advertisement_data)>
advertisement_found_cb =
DefaultCallback<BlePeripheral&, BleAdvertisementData>();
};
// Async interface for StartScanning.
// Result status will be passed to start_advertising_result callback.
// To stop advertising, invoke the stop_advertising callback in
// AdvertisingSession.
virtual std::unique_ptr<ScanningSession> StartScanning(
const Uuid& service_uuid, TxPowerLevel tx_power_level,
ScanningCallback callback) = 0;
// https://developer.android.com/reference/android/bluetooth/BluetoothManager#openGattServer(android.content.Context,%20android.bluetooth.BluetoothGattServerCallback)
//
// Starts a GATT server. Returns a nullptr upon error.
@@ -35,6 +35,7 @@ namespace g3 {
namespace {
using ::location::nearby::api::ble_v2::BleAdvertisementData;
using ::location::nearby::api::ble_v2::BleOperationStatus;
using ::location::nearby::api::ble_v2::TxPowerLevel;
std::string TxPowerLevelToName(TxPowerLevel power_mode) {
@@ -242,6 +243,30 @@ bool BleV2Medium::StopAdvertising() {
return true;
}
std::unique_ptr<BleV2Medium::AdvertisingSession> BleV2Medium::StartAdvertising(
const api::ble_v2::BleAdvertisementData& advertising_data,
api::ble_v2::AdvertiseParameters advertise_parameters,
BleV2Medium::AdvertisingCallback callback) {
NEARBY_LOGS(INFO)
<< "G3 Ble StartAdvertising: advertising_data.is_extended_advertisement="
<< advertising_data.is_extended_advertisement
<< ", advertising_data.service_data size="
<< advertising_data.service_data.size() << ", tx_power_level="
<< TxPowerLevelToName(advertise_parameters.tx_power_level)
<< ", is_connectable=" << advertise_parameters.is_connectable;
if (advertising_data.is_extended_advertisement &&
!is_support_extended_advertisement_) {
NEARBY_LOGS(INFO)
<< "G3 Ble StartAdvertising does not support extended advertisement";
return nullptr;
}
absl::MutexLock lock(&mutex_);
MediumEnvironment::Instance().UpdateBleV2MediumForAdvertising(
/*enabled=*/true, *this, adapter_->GetPeripheralV2(), advertising_data);
return std::make_unique<AdvertisingSession>(AdvertisingSession{});
}
bool BleV2Medium::StartScanning(const Uuid& service_uuid,
TxPowerLevel tx_power_level,
ScanCallback callback) {
@@ -263,6 +288,29 @@ bool BleV2Medium::StopScanning() {
return true;
}
std::unique_ptr<BleV2Medium::ScanningSession> BleV2Medium::StartScanning(
const Uuid& service_uuid, TxPowerLevel tx_power_level,
BleV2Medium::ScanningCallback callback) {
{
NEARBY_LOGS(INFO) << "G3 Ble StartScanning";
absl::MutexLock lock(&mutex_);
MediumEnvironment::Instance().UpdateBleV2MediumForScanning(
/*enabled=*/true, service_uuid,
{.advertisement_found_cb = callback.advertisement_found_cb}, *this);
}
callback.start_scanning_result(api::ble_v2::BleOperationStatus::kSucceeded);
return std::make_unique<ScanningSession>(ScanningSession{
.stop_scanning =
[this]() {
if (StopScanning())
return BleOperationStatus::kSucceeded;
else
return BleOperationStatus::kFailed;
},
});
}
std::unique_ptr<api::ble_v2::GattServer> BleV2Medium::StartGattServer(
api::ble_v2::ServerGattConnectionCallback callback) {
return std::make_unique<GattServer>();
@@ -161,11 +161,19 @@ class BleV2Medium : public api::ble_v2::BleMedium {
ABSL_LOCKS_EXCLUDED(mutex_);
bool StopAdvertising() override ABSL_LOCKS_EXCLUDED(mutex_);
std::unique_ptr<AdvertisingSession> StartAdvertising(
const api::ble_v2::BleAdvertisementData& advertising_data,
api::ble_v2::AdvertiseParameters advertise_parameters,
AdvertisingCallback callback) override ABSL_LOCKS_EXCLUDED(mutex_);
bool StartScanning(const Uuid& service_uuid,
api::ble_v2::TxPowerLevel tx_power_level,
ScanCallback callback) override
ABSL_LOCKS_EXCLUDED(mutex_);
bool StopScanning() override ABSL_LOCKS_EXCLUDED(mutex_);
std::unique_ptr<ScanningSession> StartScanning(
const Uuid& service_uuid, api::ble_v2::TxPowerLevel tx_power_level,
ScanningCallback callback) override ABSL_LOCKS_EXCLUDED(mutex_);
std::unique_ptr<api::ble_v2::GattServer> StartGattServer(
api::ble_v2::ServerGattConnectionCallback callback) override
ABSL_LOCKS_EXCLUDED(mutex_);
@@ -71,7 +71,7 @@ static const TxPowerLevel kTxPowerLevel = TxPowerLevel::kHigh;
- (void)testStartandStopScanning {
Uuid service_uuid(1234, 5678);
XCTAssertTrue(_ble->StartScanning(service_uuid, kTxPowerLevel, {}));
XCTAssertTrue(_ble->StartScanning(service_uuid, kTxPowerLevel, BleMedium::ScanCallback{}));
[NSThread sleepForTimeInterval:0.1];
@@ -121,9 +121,16 @@ class BleMedium : public api::ble_v2::BleMedium {
bool StartAdvertising(const api::ble_v2::BleAdvertisementData &advertising_data,
api::ble_v2::AdvertiseParameters advertise_set_parameters) override;
bool StopAdvertising() override;
std::unique_ptr<AdvertisingSession> StartAdvertising(
const api::ble_v2::BleAdvertisementData &advertising_data,
api::ble_v2::AdvertiseParameters advertise_parameters, AdvertisingCallback callback) override;
bool StartScanning(const Uuid &service_uuid, api::ble_v2::TxPowerLevel tx_power_level,
api::ble_v2::BleMedium::ScanCallback scan_callback) override;
bool StopScanning() override;
std::unique_ptr<ScanningSession> StartScanning(const Uuid &service_uuid,
api::ble_v2::TxPowerLevel tx_power_level,
ScanningCallback callback) override;
std::unique_ptr<api::ble_v2::GattServer> StartGattServer(
api::ble_v2::ServerGattConnectionCallback callback) override;
std::unique_ptr<api::ble_v2::GattClient> ConnectToGattServer(
+14 -1
View File
@@ -357,7 +357,13 @@ bool BleMedium::StopAdvertising() {
peripheral_ = nil;
return true;
}
std::unique_ptr<BleMedium::AdvertisingSession> BleMedium::StartAdvertising(
const api::ble_v2::BleAdvertisementData& advertising_data,
api::ble_v2::AdvertiseParameters advertise_parameters,
BleMedium::AdvertisingCallback callback) {
// TODO(hais): add real impl for iOs StartAdvertising
return std::make_unique<AdvertisingSession>(AdvertisingSession{});
}
bool BleMedium::StartScanning(const Uuid& service_uuid, TxPowerLevel tx_power_level,
ScanCallback scan_callback) {
if (!central_) {
@@ -386,6 +392,13 @@ bool BleMedium::StopScanning() {
return true;
}
std::unique_ptr<BleMedium::ScanningSession> BleMedium::StartScanning(
const Uuid& service_uuid, TxPowerLevel tx_power_level,
BleMedium::ScanningCallback callback) {
// TODO(hais): add real impl for windows StartScanning.
return std::make_unique<ScanningSession>(ScanningSession{});
}
std::unique_ptr<api::ble_v2::GattServer> BleMedium::StartGattServer(
api::ble_v2::ServerGattConnectionCallback callback) {
if (!peripheral_) {
@@ -33,6 +33,7 @@ namespace {
using ::location::nearby::api::ble_v2::AdvertiseParameters;
using ::location::nearby::api::ble_v2::BleAdvertisementData;
using ::location::nearby::api::ble_v2::BleOperationStatus;
using ::location::nearby::api::ble_v2::BleServerSocket;
using ::location::nearby::api::ble_v2::BleSocket;
using ::location::nearby::api::ble_v2::GattClient;
@@ -184,6 +185,23 @@ bool BleV2Medium::StopAdvertising() {
return true;
}
std::unique_ptr<BleV2Medium::AdvertisingSession> BleV2Medium::StartAdvertising(
const api::ble_v2::BleAdvertisementData& advertising_data,
api::ble_v2::AdvertiseParameters advertise_parameters,
BleV2Medium::AdvertisingCallback callback) {
NEARBY_LOGS(INFO) << "Windows Ble StartAdvertising: "
"advertising_data.is_extended_advertisement="
<< advertising_data.is_extended_advertisement
<< ", advertising_data.service_data size="
<< advertising_data.service_data.size()
<< ", tx_power_level="
<< TxPowerLevelToName(advertise_parameters.tx_power_level)
<< ", is_connectable="
<< advertise_parameters.is_connectable;
// TODO(hais): add real impl for windows StartAdvertising.
return std::make_unique<AdvertisingSession>(AdvertisingSession{});
}
bool BleV2Medium::StartScanning(const Uuid& service_uuid,
TxPowerLevel tx_power_level,
ScanCallback callback) {
@@ -246,6 +264,15 @@ bool BleV2Medium::StopScanning() {
return true;
}
std::unique_ptr<BleV2Medium::ScanningSession> BleV2Medium::StartScanning(
const Uuid& service_uuid, TxPowerLevel tx_power_level,
BleV2Medium::ScanningCallback callback) {
NEARBY_LOGS(INFO) << "Windows Ble StartScanning";
// TODO(hais): add real impl for windows StartAdvertising.
return std::make_unique<ScanningSession>(ScanningSession{});
}
std::unique_ptr<api::ble_v2::GattServer> BleV2Medium::StartGattServer(
ServerGattConnectionCallback callback) {
return nullptr;
@@ -50,11 +50,19 @@ class BleV2Medium : public api::ble_v2::BleMedium {
ABSL_LOCKS_EXCLUDED(mutex_);
bool StopAdvertising() override ABSL_LOCKS_EXCLUDED(mutex_);
std::unique_ptr<AdvertisingSession> StartAdvertising(
const api::ble_v2::BleAdvertisementData& advertising_data,
api::ble_v2::AdvertiseParameters advertise_set_parameters,
AdvertisingCallback callback) override ABSL_LOCKS_EXCLUDED(mutex_);
bool StartScanning(const Uuid& service_uuid,
api::ble_v2::TxPowerLevel tx_power_level,
ScanCallback callback) override
ABSL_LOCKS_EXCLUDED(mutex_);
bool StopScanning() override ABSL_LOCKS_EXCLUDED(mutex_);
std::unique_ptr<ScanningSession> StartScanning(
const Uuid& service_uuid, api::ble_v2::TxPowerLevel tx_power_level,
ScanningCallback callback) override ABSL_LOCKS_EXCLUDED(mutex_);
std::unique_ptr<api::ble_v2::GattServer> StartGattServer(
api::ble_v2::ServerGattConnectionCallback callback) override
ABSL_LOCKS_EXCLUDED(mutex_);