mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-16 07:36:10 -04:00
[BLE Refactor] Implements GattClient for sender's device to fetch Gatt advertisement.
PiperOrigin-RevId: 448400837
This commit is contained in:
committed by
Copybara-Service
parent
73c0ce9c76
commit
080e964a4c
@@ -77,6 +77,8 @@ bool BleV2::IsAvailable() const {
|
||||
}
|
||||
|
||||
// TODO(edwinwu): Break down the function.
|
||||
// TODO(b/229927044): Use bool: is_fast_advertisement, not
|
||||
// fast_advertisement_service_uuid.
|
||||
bool BleV2::StartAdvertising(
|
||||
const std::string& service_id, const ByteArray& advertisement_bytes,
|
||||
PowerLevel power_level,
|
||||
@@ -273,6 +275,7 @@ bool BleV2::IsAdvertising(const std::string& service_id) const {
|
||||
return IsAdvertisingLocked(service_id);
|
||||
}
|
||||
|
||||
// TODO(b/229927044): Remove param: fast_advertisement_service_uuid.
|
||||
bool BleV2::StartScanning(const std::string& service_id, PowerLevel power_level,
|
||||
DiscoveredPeripheralCallback callback,
|
||||
const std::string& fast_advertisement_service_uuid) {
|
||||
@@ -314,13 +317,27 @@ bool BleV2::StartScanning(const std::string& service_id, PowerLevel power_level,
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if scan has been activated, if yes, no need to notify client
|
||||
// to scan again.
|
||||
if (!scanned_service_ids_.empty()) {
|
||||
scanned_service_ids_.insert(service_id);
|
||||
NEARBY_LOGS(INFO) << "Turned on BLE scanning with service id=" << service_id
|
||||
<< " without start client scanning";
|
||||
return true;
|
||||
}
|
||||
|
||||
scanned_service_ids_.insert(service_id);
|
||||
// TODO(b/213835576): We should re-start scanning once the power level is
|
||||
// changed.
|
||||
std::vector<std::string> service_uuids{
|
||||
std::string(mediums::bleutils::kCopresenceServiceUuid)};
|
||||
std::vector<std::string> scanning_service_uuids;
|
||||
if (!fast_advertisement_service_uuid.empty()) {
|
||||
scanning_service_uuids.push_back(fast_advertisement_service_uuid);
|
||||
} else {
|
||||
scanning_service_uuids.push_back(
|
||||
std::string(mediums::bleutils::kCopresenceServiceUuid));
|
||||
}
|
||||
if (!medium_.StartScanning(
|
||||
service_uuids, PowerLevelToPowerMode(power_level),
|
||||
scanning_service_uuids, PowerLevelToPowerMode(power_level),
|
||||
{
|
||||
.advertisement_found_cb =
|
||||
[this](BleV2Peripheral peripheral,
|
||||
@@ -428,18 +445,8 @@ bool BleV2::StartAdvertisementGattServerLocked(
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_ptr<GattServer> gatt_server = medium_.StartGattServer({
|
||||
.characteristic_subscription_cb =
|
||||
[](const ServerGattConnection& connection,
|
||||
const GattCharacteristic& characteristic) {
|
||||
// TODO(b/213835576): Impl or remove.
|
||||
},
|
||||
.characteristic_unsubscription_cb =
|
||||
[](const ServerGattConnection& connection,
|
||||
const GattCharacteristic& characteristic) {
|
||||
// TODO(b/213835576): Impl or remove.
|
||||
},
|
||||
});
|
||||
std::unique_ptr<GattServer> gatt_server =
|
||||
medium_.StartGattServer(/*ServerGattConnectionCallback=*/{});
|
||||
if (!gatt_server || !gatt_server->IsValid()) {
|
||||
NEARBY_LOGS(INFO) << "Unable to start an advertisement GATT server.";
|
||||
return false;
|
||||
@@ -508,7 +515,63 @@ void BleV2::ProcessFetchGattAdvertisementsRequest(
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO(edwinwu): Attempt to connect and read some GATT characteristics.
|
||||
// Connect to a GATT server, reads advertisement data, and then disconnect
|
||||
// from the GATT server.
|
||||
bool read_success = true;
|
||||
std::unique_ptr<GattClient> gatt_client = medium_.ConnectToGattServer(
|
||||
std::move(peripheral), PowerLevelToPowerMode(PowerLevel::kHighPower),
|
||||
/*ClientGattConnectionCallback=*/{});
|
||||
if (!gatt_client || !gatt_client->IsValid()) {
|
||||
advertisement_read_result.RecordLastReadStatus(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Always use kCopresenceServiceUuid for service uuid.
|
||||
std::string service_uuid =
|
||||
std::string(mediums::bleutils::kCopresenceServiceUuid);
|
||||
if (!gatt_client->DiscoverService(service_uuid)) {
|
||||
NEARBY_LOGS(WARNING) << "GATT client can't discover service.";
|
||||
advertisement_read_result.RecordLastReadStatus(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Read all advertisements from all slots that we haven't read from yet.
|
||||
for (int slot = 0; slot < num_slots; ++slot) {
|
||||
// Make sure we haven't already read this advertisement before.
|
||||
if (advertisement_read_result.HasAdvertisement(slot)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Make sure the characteristic even exists for this slot number. If
|
||||
// the characteristic doesn't exist, we shouldn't count the fetch as a
|
||||
// failure because there's nothing we could've done about a
|
||||
// non-existed characteristic.
|
||||
auto gatt_characteristic = gatt_client->GetCharacteristic(
|
||||
std::string(mediums::bleutils::kCopresenceServiceUuid),
|
||||
mediums::bleutils::GenerateAdvertisementUuid(slot));
|
||||
if (!gatt_characteristic.has_value()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Read advertisement data from the characteristic associated with this
|
||||
// slot.
|
||||
auto characteristic_byte =
|
||||
gatt_client->ReadCharacteristic(gatt_characteristic.value());
|
||||
if (characteristic_byte.has_value()) {
|
||||
advertisement_read_result.AddAdvertisement(slot, *characteristic_byte);
|
||||
NEARBY_LOGS(VERBOSE) << "Successfully read advertisement at slot="
|
||||
<< slot;
|
||||
} else {
|
||||
NEARBY_LOGS(WARNING) << "Can't read advertisement for slot=" << slot;
|
||||
read_success = false;
|
||||
}
|
||||
// Whether or not we succeeded with this slot, we should try reading the
|
||||
// other slots to get as many advertisements as possible before
|
||||
// returning a success or failure.
|
||||
}
|
||||
gatt_client->Disconnect();
|
||||
|
||||
advertisement_read_result.RecordLastReadStatus(read_success);
|
||||
}
|
||||
|
||||
bool BleV2::StopAdvertisementGattServerLocked() {
|
||||
|
||||
@@ -42,8 +42,6 @@ namespace connections {
|
||||
// (BLE) medium.
|
||||
class BleV2 final {
|
||||
public:
|
||||
using ServerGattConnectionCallback =
|
||||
BleV2Medium::ServerGattConnectionCallback;
|
||||
using DiscoveredPeripheralCallback = mediums::DiscoveredPeripheralCallback;
|
||||
|
||||
static constexpr absl::Duration kPeripheralLostTimeout = absl::Seconds(3);
|
||||
|
||||
@@ -28,11 +28,11 @@ namespace connections {
|
||||
namespace {
|
||||
|
||||
constexpr absl::Duration kWaitDuration = absl::Milliseconds(1000);
|
||||
constexpr absl::string_view kServiceIDA{
|
||||
"com.google.location.nearby.apps.test.a"};
|
||||
constexpr absl::string_view kServiceIDB{
|
||||
"com.google.location.nearby.apps.test.b"};
|
||||
constexpr absl::string_view kAdvertisementString{"\x0a\x0b\x0c\x0d"};
|
||||
constexpr absl::string_view kServiceIDA =
|
||||
"com.google.location.nearby.apps.test.a";
|
||||
constexpr absl::string_view kServiceIDB =
|
||||
"com.google.location.nearby.apps.test.b";
|
||||
constexpr absl::string_view kAdvertisementString = "\x0a\x0b\x0c\x0d";
|
||||
constexpr absl::string_view kFastAdvertisementServiceUuid =
|
||||
"0000FE2C-0000-1000-8000-00805F9B34FB";
|
||||
|
||||
@@ -47,8 +47,8 @@ TEST_F(BleV2Test, CanConstructValidObject) {
|
||||
env_.Start();
|
||||
BluetoothRadio radio_a;
|
||||
BluetoothRadio radio_b;
|
||||
BleV2 ble_a{radio_a};
|
||||
BleV2 ble_b{radio_b};
|
||||
BleV2 ble_a(radio_a);
|
||||
BleV2 ble_b(radio_b);
|
||||
|
||||
EXPECT_TRUE(ble_a.IsMediumValid());
|
||||
EXPECT_TRUE(ble_a.IsAvailable());
|
||||
@@ -58,58 +58,15 @@ TEST_F(BleV2Test, CanConstructValidObject) {
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(BleV2Test, CanStartAdvertising) {
|
||||
env_.Start();
|
||||
BluetoothRadio radio;
|
||||
BleV2 ble{radio};
|
||||
radio.Enable();
|
||||
ByteArray advertisement_bytes{std::string(kAdvertisementString)};
|
||||
|
||||
EXPECT_TRUE(ble.StartAdvertising(std::string(kServiceIDA),
|
||||
advertisement_bytes, PowerLevel::kHighPower,
|
||||
/*fast_advertisement_service_uuid=*/""));
|
||||
// Can't advertise twice for the same service_id.
|
||||
EXPECT_FALSE(ble.StartAdvertising(std::string(kServiceIDA),
|
||||
advertisement_bytes, PowerLevel::kHighPower,
|
||||
/*fast_advertisement_service_uuid=*/""));
|
||||
EXPECT_TRUE(ble.StopAdvertising(std::string(kServiceIDA)));
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(BleV2Test, CanStartScanning) {
|
||||
env_.Start();
|
||||
BluetoothRadio radio;
|
||||
BleV2 ble{radio};
|
||||
radio.Enable();
|
||||
|
||||
EXPECT_TRUE(ble.StartScanning(
|
||||
std::string(kServiceIDA), PowerLevel::kHighPower,
|
||||
mediums::DiscoveredPeripheralCallback{
|
||||
.peripheral_discovered_cb =
|
||||
[](BleV2Peripheral peripheral, const std::string& service_id,
|
||||
const ByteArray& advertisement_bytes,
|
||||
bool fast_advertisement) {
|
||||
// nothing to do for now
|
||||
},
|
||||
.peripheral_lost_cb =
|
||||
[](BleV2Peripheral peripheral, const std::string& service_id) {
|
||||
// nothing to do for now
|
||||
},
|
||||
},
|
||||
/*fast_advertisement_service_uuid=*/""));
|
||||
EXPECT_TRUE(ble.StopScanning(std::string(kServiceIDA)));
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(BleV2Test, CanStartFastAdvertising) {
|
||||
env_.Start();
|
||||
BluetoothRadio radio_a;
|
||||
BluetoothRadio radio_b;
|
||||
BleV2 ble_a{radio_a};
|
||||
BleV2 ble_b{radio_b};
|
||||
BleV2 ble_a(radio_a);
|
||||
BleV2 ble_b(radio_b);
|
||||
radio_a.Enable();
|
||||
radio_b.Enable();
|
||||
ByteArray advertisement_bytes{std::string(kAdvertisementString)};
|
||||
ByteArray advertisement_bytes((std::string(kAdvertisementString)));
|
||||
CountDownLatch found_latch(1);
|
||||
|
||||
ble_b.StartScanning(
|
||||
@@ -123,10 +80,6 @@ TEST_F(BleV2Test, CanStartFastAdvertising) {
|
||||
EXPECT_TRUE(fast_advertisement);
|
||||
found_latch.CountDown();
|
||||
},
|
||||
.peripheral_lost_cb =
|
||||
[](BleV2Peripheral peripheral, const std::string& service_id) {
|
||||
// nothing to do for now
|
||||
},
|
||||
},
|
||||
std::string(kFastAdvertisementServiceUuid));
|
||||
|
||||
@@ -143,11 +96,11 @@ TEST_F(BleV2Test, CanStartFastScanning) {
|
||||
env_.Start();
|
||||
BluetoothRadio radio_a;
|
||||
BluetoothRadio radio_b;
|
||||
BleV2 ble_a{radio_a};
|
||||
BleV2 ble_b{radio_b};
|
||||
BleV2 ble_a(radio_a);
|
||||
BleV2 ble_b(radio_b);
|
||||
radio_a.Enable();
|
||||
radio_b.Enable();
|
||||
ByteArray advertisement_bytes{std::string(kAdvertisementString)};
|
||||
ByteArray advertisement_bytes((std::string(kAdvertisementString)));
|
||||
CountDownLatch found_latch(1);
|
||||
|
||||
ble_b.StartAdvertising(std::string(kServiceIDA), advertisement_bytes,
|
||||
@@ -165,10 +118,6 @@ TEST_F(BleV2Test, CanStartFastScanning) {
|
||||
EXPECT_TRUE(fast_advertisement);
|
||||
found_latch.CountDown();
|
||||
},
|
||||
.peripheral_lost_cb =
|
||||
[](BleV2Peripheral peripheral, const std::string& service_id) {
|
||||
// nothing to do for now
|
||||
},
|
||||
},
|
||||
std::string(kFastAdvertisementServiceUuid)));
|
||||
|
||||
@@ -178,10 +127,79 @@ TEST_F(BleV2Test, CanStartFastScanning) {
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(BleV2Test, CanStartAdvertising) {
|
||||
env_.Start();
|
||||
BluetoothRadio radio_a;
|
||||
BluetoothRadio radio_b;
|
||||
BleV2 ble_a(radio_a);
|
||||
BleV2 ble_b(radio_b);
|
||||
radio_a.Enable();
|
||||
radio_b.Enable();
|
||||
ByteArray advertisement_bytes((std::string(kAdvertisementString)));
|
||||
CountDownLatch found_latch(1);
|
||||
|
||||
ble_b.StartScanning(
|
||||
std::string(kServiceIDA), PowerLevel::kHighPower,
|
||||
mediums::DiscoveredPeripheralCallback{
|
||||
.peripheral_discovered_cb =
|
||||
[&found_latch](BleV2Peripheral peripheral,
|
||||
const std::string& service_id,
|
||||
const ByteArray& advertisement_bytes,
|
||||
bool fast_advertisement) {
|
||||
EXPECT_FALSE(fast_advertisement);
|
||||
found_latch.CountDown();
|
||||
},
|
||||
},
|
||||
/*fast_advertisement_service_uuid=*/"");
|
||||
|
||||
EXPECT_TRUE(ble_a.StartAdvertising(
|
||||
std::string(kServiceIDA), advertisement_bytes, PowerLevel::kHighPower,
|
||||
/*fast_advertisement_service_uuid=*/""));
|
||||
EXPECT_TRUE(found_latch.Await(kWaitDuration).result());
|
||||
EXPECT_TRUE(ble_a.StopAdvertising(std::string(kServiceIDA)));
|
||||
ble_b.StopScanning(std::string(kServiceIDA));
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(BleV2Test, CanStartScanning) {
|
||||
env_.Start();
|
||||
BluetoothRadio radio_a;
|
||||
BluetoothRadio radio_b;
|
||||
BleV2 ble_a(radio_a);
|
||||
BleV2 ble_b(radio_b);
|
||||
radio_a.Enable();
|
||||
radio_b.Enable();
|
||||
ByteArray advertisement_bytes((std::string(kAdvertisementString)));
|
||||
CountDownLatch found_latch(1);
|
||||
|
||||
ble_b.StartAdvertising(std::string(kServiceIDA), advertisement_bytes,
|
||||
PowerLevel::kHighPower,
|
||||
/*fast_advertisement_service_uuid=*/"");
|
||||
|
||||
EXPECT_TRUE(ble_a.StartScanning(
|
||||
std::string(kServiceIDA), PowerLevel::kHighPower,
|
||||
mediums::DiscoveredPeripheralCallback{
|
||||
.peripheral_discovered_cb =
|
||||
[&found_latch](BleV2Peripheral peripheral,
|
||||
const std::string& service_id,
|
||||
const ByteArray& advertisement_bytes,
|
||||
bool fast_advertisement) {
|
||||
EXPECT_FALSE(fast_advertisement);
|
||||
found_latch.CountDown();
|
||||
},
|
||||
},
|
||||
/*fast_advertisement_service_uuid=*/""));
|
||||
|
||||
EXPECT_TRUE(found_latch.Await(kWaitDuration).result());
|
||||
ble_b.StopAdvertising(std::string(kServiceIDA));
|
||||
EXPECT_TRUE(ble_a.StopScanning(std::string(kServiceIDA)));
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(BleV2Test, CanStartStopMultipleScanningWithDifferentServiceIds) {
|
||||
env_.Start();
|
||||
BluetoothRadio radio;
|
||||
BleV2 ble{radio};
|
||||
BleV2 ble(radio);
|
||||
radio.Enable();
|
||||
|
||||
EXPECT_TRUE(ble.StartScanning(std::string(kServiceIDA),
|
||||
@@ -207,12 +225,12 @@ TEST_F(BleV2Test, DestructWorksForStartAdvertisingAndScanningWithoutStop) {
|
||||
env_.Start();
|
||||
BluetoothRadio radio_a;
|
||||
BluetoothRadio radio_b;
|
||||
BleV2 ble_a{radio_a};
|
||||
BleV2 ble_b{radio_b};
|
||||
BleV2 ble_a(radio_a);
|
||||
BleV2 ble_b(radio_b);
|
||||
|
||||
radio_a.Enable();
|
||||
radio_b.Enable();
|
||||
ByteArray advertisement_bytes{std::string(kAdvertisementString)};
|
||||
ByteArray advertisement_bytes((std::string(kAdvertisementString)));
|
||||
|
||||
// Device A starts advertising with service IDA and IDB.
|
||||
EXPECT_TRUE(ble_a.StartAdvertising(
|
||||
@@ -234,15 +252,15 @@ TEST_F(BleV2Test, DestructWorksForStartAdvertisingAndScanningWithoutStop) {
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(BleV2Test, StartScanningDiscoverAndLostPeripheral) {
|
||||
TEST_F(BleV2Test, StartFastScanningDiscoverAndLostPeripheral) {
|
||||
env_.Start();
|
||||
BluetoothRadio radio_a;
|
||||
BluetoothRadio radio_b;
|
||||
BleV2 ble_a{radio_a};
|
||||
BleV2 ble_b{radio_b};
|
||||
BleV2 ble_a(radio_a);
|
||||
BleV2 ble_b(radio_b);
|
||||
radio_a.Enable();
|
||||
radio_b.Enable();
|
||||
ByteArray advertisement_bytes{std::string(kAdvertisementString)};
|
||||
ByteArray advertisement_bytes((std::string(kAdvertisementString)));
|
||||
CountDownLatch found_latch(1);
|
||||
CountDownLatch lost_latch(1);
|
||||
|
||||
@@ -273,7 +291,7 @@ TEST_F(BleV2Test, StartScanningDiscoverAndLostPeripheral) {
|
||||
|
||||
ble_b.StopAdvertising(std::string(kServiceIDA));
|
||||
|
||||
// Wait for a while (2 times delay) to let the alaram occur twice and
|
||||
// Wait for a while (2 times delay) to let the alarm occur twice and
|
||||
// `ProcessLostGattAdvertisements` twice to lost periperal.
|
||||
SystemClock::Sleep(BleV2::kPeripheralLostTimeout * 2);
|
||||
|
||||
@@ -283,15 +301,16 @@ TEST_F(BleV2Test, StartScanningDiscoverAndLostPeripheral) {
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(BleV2Test, StartScanningDiscoverButNoPeripheralLostAfterStopScanning) {
|
||||
TEST_F(BleV2Test,
|
||||
StartFastScanningDiscoverButNoPeripheralLostAfterStopScanning) {
|
||||
env_.Start();
|
||||
BluetoothRadio radio_a;
|
||||
BluetoothRadio radio_b;
|
||||
BleV2 ble_a{radio_a};
|
||||
BleV2 ble_b{radio_b};
|
||||
BleV2 ble_a(radio_a);
|
||||
BleV2 ble_b(radio_b);
|
||||
radio_a.Enable();
|
||||
radio_b.Enable();
|
||||
ByteArray advertisement_bytes{std::string(kAdvertisementString)};
|
||||
ByteArray advertisement_bytes((std::string(kAdvertisementString)));
|
||||
CountDownLatch found_latch(1);
|
||||
CountDownLatch lost_latch(1);
|
||||
|
||||
@@ -330,6 +349,101 @@ TEST_F(BleV2Test, StartScanningDiscoverButNoPeripheralLostAfterStopScanning) {
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(BleV2Test, StartScanningDiscoverAndLostPeripheral) {
|
||||
env_.Start();
|
||||
BluetoothRadio radio_a;
|
||||
BluetoothRadio radio_b;
|
||||
BleV2 ble_a(radio_a);
|
||||
BleV2 ble_b(radio_b);
|
||||
radio_a.Enable();
|
||||
radio_b.Enable();
|
||||
ByteArray advertisement_bytes((std::string(kAdvertisementString)));
|
||||
CountDownLatch found_latch(1);
|
||||
CountDownLatch lost_latch(1);
|
||||
|
||||
ble_b.StartAdvertising(std::string(kServiceIDA), advertisement_bytes,
|
||||
PowerLevel::kHighPower,
|
||||
/*fast_advertisement_service_uuid=*/"");
|
||||
|
||||
ble_a.StartScanning(
|
||||
std::string(kServiceIDA), PowerLevel::kHighPower,
|
||||
mediums::DiscoveredPeripheralCallback{
|
||||
.peripheral_discovered_cb =
|
||||
[&found_latch](BleV2Peripheral peripheral,
|
||||
const std::string& service_id,
|
||||
const ByteArray& advertisement_bytes,
|
||||
bool fast_advertisement) {
|
||||
EXPECT_FALSE(fast_advertisement);
|
||||
found_latch.CountDown();
|
||||
},
|
||||
.peripheral_lost_cb =
|
||||
[&lost_latch](BleV2Peripheral peripheral,
|
||||
const std::string& service_id) {
|
||||
lost_latch.CountDown();
|
||||
},
|
||||
},
|
||||
/*fast_advertisement_service_uuid=*/"");
|
||||
|
||||
EXPECT_TRUE(found_latch.Await(kWaitDuration).result());
|
||||
|
||||
ble_b.StopAdvertising(std::string(kServiceIDA));
|
||||
|
||||
// Wait for a while (2 times delay) to let the alarm occur twice and
|
||||
// `ProcessLostGattAdvertisements` twice to lost periperal.
|
||||
SystemClock::Sleep(BleV2::kPeripheralLostTimeout * 2);
|
||||
|
||||
EXPECT_TRUE(lost_latch.Await(kWaitDuration).result());
|
||||
|
||||
ble_a.StopScanning(std::string(kServiceIDA));
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(BleV2Test, StartScanningDiscoverButNoPeripheralLostAfterStopScanning) {
|
||||
env_.Start();
|
||||
BluetoothRadio radio_a;
|
||||
BluetoothRadio radio_b;
|
||||
BleV2 ble_a(radio_a);
|
||||
BleV2 ble_b(radio_b);
|
||||
radio_a.Enable();
|
||||
radio_b.Enable();
|
||||
ByteArray advertisement_bytes((std::string(kAdvertisementString)));
|
||||
CountDownLatch found_latch(1);
|
||||
CountDownLatch lost_latch(1);
|
||||
|
||||
ble_b.StartAdvertising(std::string(kServiceIDA), advertisement_bytes,
|
||||
PowerLevel::kHighPower, "");
|
||||
|
||||
ble_a.StartScanning(
|
||||
std::string(kServiceIDA), PowerLevel::kHighPower,
|
||||
mediums::DiscoveredPeripheralCallback{
|
||||
.peripheral_discovered_cb =
|
||||
[&found_latch](BleV2Peripheral peripheral,
|
||||
const std::string& service_id,
|
||||
const ByteArray& advertisement_bytes,
|
||||
bool fast_advertisement) {
|
||||
EXPECT_FALSE(fast_advertisement);
|
||||
found_latch.CountDown();
|
||||
},
|
||||
.peripheral_lost_cb =
|
||||
[&lost_latch](BleV2Peripheral peripheral,
|
||||
const std::string& service_id) {
|
||||
lost_latch.CountDown();
|
||||
},
|
||||
},
|
||||
/*fast_advertisement_service_uuid=*/"");
|
||||
|
||||
EXPECT_TRUE(found_latch.Await(kWaitDuration).result());
|
||||
|
||||
ble_b.StopAdvertising(std::string(kServiceIDA));
|
||||
ble_a.StopScanning(std::string(kServiceIDA));
|
||||
|
||||
// Don't receive lost peripheral callback because we have stopped scanning and
|
||||
// cancelled the alarm.
|
||||
EXPECT_FALSE(lost_latch.Await(kWaitDuration).result());
|
||||
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace connections
|
||||
} // namespace nearby
|
||||
|
||||
@@ -340,6 +340,7 @@ cc_library(
|
||||
"//internal/platform/implementation:platform",
|
||||
"@com_google_absl//absl/container:flat_hash_map",
|
||||
"@com_google_absl//absl/strings",
|
||||
"@com_google_absl//absl/types:optional",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "internal/platform/ble_v2.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "internal/platform/bluetooth_adapter.h"
|
||||
@@ -102,25 +103,41 @@ std::unique_ptr<GattServer> BleV2Medium::StartGattServer(
|
||||
std::unique_ptr<api::ble_v2::GattServer> api_gatt_server =
|
||||
impl_->StartGattServer({
|
||||
.characteristic_subscription_cb =
|
||||
[this](api::ble_v2::ServerGattConnection& connection,
|
||||
const GattCharacteristic& characteristic) {
|
||||
[this](const GattCharacteristic& characteristic) {
|
||||
MutexLock lock(&mutex_);
|
||||
ServerGattConnection server_gatt_connection(&connection);
|
||||
server_gatt_connection_callback_.characteristic_subscription_cb(
|
||||
server_gatt_connection, characteristic);
|
||||
characteristic);
|
||||
},
|
||||
.characteristic_unsubscription_cb =
|
||||
[this](api::ble_v2::ServerGattConnection& connection,
|
||||
const GattCharacteristic& characteristic) {
|
||||
[this](const GattCharacteristic& characteristic) {
|
||||
MutexLock lock(&mutex_);
|
||||
ServerGattConnection server_gatt_connection(&connection);
|
||||
server_gatt_connection_callback_
|
||||
.characteristic_unsubscription_cb(server_gatt_connection,
|
||||
characteristic);
|
||||
.characteristic_unsubscription_cb(characteristic);
|
||||
},
|
||||
});
|
||||
return std::make_unique<GattServer>(std::move(api_gatt_server));
|
||||
}
|
||||
|
||||
std::unique_ptr<GattClient> BleV2Medium::ConnectToGattServer(
|
||||
BleV2Peripheral peripheral, PowerMode power_mode,
|
||||
ClientGattConnectionCallback callback) {
|
||||
{
|
||||
MutexLock lock(&mutex_);
|
||||
client_gatt_connection_callback_ = std::move(callback);
|
||||
}
|
||||
|
||||
std::unique_ptr<api::ble_v2::GattClient> api_gatt_client =
|
||||
impl_->ConnectToGattServer(
|
||||
peripheral.GetImpl(), power_mode,
|
||||
{
|
||||
.disconnected_cb =
|
||||
[this]() {
|
||||
MutexLock lock(&mutex_);
|
||||
client_gatt_connection_callback_.disconnected_cb();
|
||||
},
|
||||
});
|
||||
return std::make_unique<GattClient>(std::move(api_gatt_client));
|
||||
}
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
+66
-31
@@ -16,9 +16,11 @@
|
||||
#define PLATFORM_PUBLIC_BLE_V2_H_
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "internal/platform/bluetooth_adapter.h"
|
||||
#include "internal/platform/byte_array.h"
|
||||
#include "internal/platform/implementation/ble_v2.h"
|
||||
@@ -27,38 +29,18 @@
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
// Opaque wrapper over a ServerGattConnection.
|
||||
class ServerGattConnection final {
|
||||
public:
|
||||
ServerGattConnection() = default;
|
||||
explicit ServerGattConnection(
|
||||
api::ble_v2::ServerGattConnection* server_gatt_connection)
|
||||
: impl_(server_gatt_connection) {}
|
||||
|
||||
bool SendCharacteristic(const api::ble_v2::GattCharacteristic& characteristic,
|
||||
const ByteArray& value) {
|
||||
return impl_->SendCharacteristic(characteristic, value);
|
||||
}
|
||||
|
||||
api::ble_v2::ServerGattConnection* GetImpl() { return impl_; }
|
||||
|
||||
bool IsValid() const { return impl_ != nullptr; }
|
||||
|
||||
private:
|
||||
api::ble_v2::ServerGattConnection* impl_ = nullptr;
|
||||
};
|
||||
|
||||
// Opaque wrapper over a GattServer.
|
||||
// Move only, disallow copy.
|
||||
//
|
||||
// Note that some of the methods return absl::optional instead
|
||||
// of std::optional, because iOS platform is still in C++14.
|
||||
class GattServer final {
|
||||
public:
|
||||
GattServer() = default;
|
||||
explicit GattServer(std::unique_ptr<api::ble_v2::GattServer> gatt_server)
|
||||
: impl_(std::move(gatt_server)) {}
|
||||
GattServer(GattServer&&) = default;
|
||||
GattServer& operator=(GattServer&&) = default;
|
||||
~GattServer() { Stop(); }
|
||||
|
||||
// NOLINTNEXTLINE(google3-legacy-absl-backports)
|
||||
absl::optional<api::ble_v2::GattCharacteristic> CreateCharacteristic(
|
||||
const std::string& service_uuid, const std::string& characteristic_uuid,
|
||||
const std::vector<api::ble_v2::GattCharacteristic::Permission>&
|
||||
@@ -89,6 +71,47 @@ class GattServer final {
|
||||
std::unique_ptr<api::ble_v2::GattServer> impl_;
|
||||
};
|
||||
|
||||
// Opaque wrapper for a GattClient.
|
||||
//
|
||||
// Note that some of the methods return absl::optional instead
|
||||
// of std::optional, because iOS platform is still in C++14.
|
||||
class GattClient final {
|
||||
public:
|
||||
explicit GattClient(
|
||||
std::unique_ptr<api::ble_v2::GattClient> client_gatt_connection)
|
||||
: impl_(std::move(client_gatt_connection)) {}
|
||||
|
||||
bool DiscoverService(const std::string& service_uuid) {
|
||||
return impl_->DiscoverService(service_uuid);
|
||||
}
|
||||
|
||||
// TODO(edwinwu): Change std::string to Uuid.
|
||||
// NOLINTNEXTLINE(google3-legacy-absl-backports)
|
||||
absl::optional<api::ble_v2::GattCharacteristic> GetCharacteristic(
|
||||
const std::string& service_uuid, const std::string& characteristic_uuid) {
|
||||
return impl_->GetCharacteristic(service_uuid, characteristic_uuid);
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(google3-legacy-absl-backports)
|
||||
absl::optional<ByteArray> ReadCharacteristic(
|
||||
api::ble_v2::GattCharacteristic& characteristic) {
|
||||
return impl_->ReadCharacteristic(characteristic);
|
||||
}
|
||||
|
||||
void Disconnect() { impl_->Disconnect(); }
|
||||
|
||||
// Returns true if a client_gatt_connection is usable. If this method returns
|
||||
// false, it is not safe to call any other method.
|
||||
bool IsValid() const { return impl_ != nullptr; }
|
||||
|
||||
// Returns reference to platform implementation.
|
||||
// This is used to communicate with platform code, and for debugging purposes.
|
||||
api::ble_v2::GattClient* GetImpl() { return impl_.get(); }
|
||||
|
||||
private:
|
||||
std::unique_ptr<api::ble_v2::GattClient> impl_;
|
||||
};
|
||||
|
||||
// Container of operations that can be performed over the BLE medium.
|
||||
class BleV2Medium final {
|
||||
public:
|
||||
@@ -107,16 +130,19 @@ class BleV2Medium final {
|
||||
advertisement_found_cb = location::nearby::DefaultCallback<
|
||||
BleV2Peripheral, const api::ble_v2::BleAdvertisementData&>();
|
||||
};
|
||||
|
||||
struct ServerGattConnectionCallback {
|
||||
std::function<void(ServerGattConnection& connection,
|
||||
const api::ble_v2::GattCharacteristic& characteristic)>
|
||||
std::function<void(const api::ble_v2::GattCharacteristic& characteristic)>
|
||||
characteristic_subscription_cb = location::nearby::DefaultCallback<
|
||||
ServerGattConnection&, const api::ble_v2::GattCharacteristic&>();
|
||||
std::function<void(ServerGattConnection& connection,
|
||||
const api::ble_v2::GattCharacteristic& characteristic)>
|
||||
const api::ble_v2::GattCharacteristic&>();
|
||||
std::function<void(const api::ble_v2::GattCharacteristic& characteristic)>
|
||||
characteristic_unsubscription_cb = location::nearby::DefaultCallback<
|
||||
ServerGattConnection&, const api::ble_v2::GattCharacteristic&>();
|
||||
const api::ble_v2::GattCharacteristic&>();
|
||||
};
|
||||
// TODO(b/231318879): Remove this wrapper callback and use impl callback if
|
||||
// there is only disconnect function here in the end.
|
||||
struct ClientGattConnectionCallback {
|
||||
std::function<void()> disconnected_cb =
|
||||
location::nearby::DefaultCallback<>();
|
||||
};
|
||||
|
||||
explicit BleV2Medium(BluetoothAdapter& adapter)
|
||||
@@ -136,9 +162,16 @@ class BleV2Medium final {
|
||||
api::ble_v2::PowerMode power_mode, ScanCallback callback);
|
||||
bool StopScanning();
|
||||
|
||||
// Starts Gatt Server for waiting to client connection.
|
||||
std::unique_ptr<GattServer> StartGattServer(
|
||||
ServerGattConnectionCallback callback);
|
||||
|
||||
// Returns a new GattClient connection to a gatt server.
|
||||
// There is only one instance of GattServer can run at a time.
|
||||
std::unique_ptr<GattClient> ConnectToGattServer(
|
||||
BleV2Peripheral peripheral, api::ble_v2::PowerMode power_mode,
|
||||
ClientGattConnectionCallback callback);
|
||||
|
||||
bool IsValid() const { return impl_ != nullptr; }
|
||||
|
||||
api::ble_v2::BleMedium* GetImpl() const { return impl_.get(); }
|
||||
@@ -149,6 +182,8 @@ class BleV2Medium final {
|
||||
BluetoothAdapter& adapter_;
|
||||
ServerGattConnectionCallback server_gatt_connection_callback_
|
||||
ABSL_GUARDED_BY(mutex_);
|
||||
ClientGattConnectionCallback client_gatt_connection_callback_
|
||||
ABSL_GUARDED_BY(mutex_);
|
||||
absl::flat_hash_set<api::ble_v2::BlePeripheral*> peripherals_
|
||||
ABSL_GUARDED_BY(mutex_);
|
||||
ScanCallback scan_callback_ ABSL_GUARDED_BY(mutex_);
|
||||
|
||||
@@ -17,7 +17,11 @@
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "protobuf-matchers/protocol-buffer-matchers.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "internal/platform/bluetooth_adapter.h"
|
||||
#include "internal/platform/count_down_latch.h"
|
||||
#include "internal/platform/medium_environment.h"
|
||||
|
||||
namespace location {
|
||||
@@ -27,12 +31,27 @@ namespace {
|
||||
using ::location::nearby::api::ble_v2::BleAdvertisementData;
|
||||
using ::location::nearby::api::ble_v2::GattCharacteristic;
|
||||
using ::location::nearby::api::ble_v2::PowerMode;
|
||||
using ::testing::Optional;
|
||||
|
||||
constexpr absl::string_view kAdvertisementString{"\x0a\x0b\x0c\x0d"};
|
||||
constexpr absl::string_view kCopresenceServiceUuid{"F3FE"};
|
||||
constexpr absl::string_view kFastAdvertisementServiceUuid{"FAST"};
|
||||
constexpr absl::Duration kWaitDuration = absl::Milliseconds(1000);
|
||||
constexpr absl::string_view kAdvertisementString = "\x0a\x0b\x0c\x0d";
|
||||
constexpr absl::string_view kCopresenceServiceUuid = "F3FE";
|
||||
constexpr absl::string_view kFastAdvertisementServiceUuid = "FE2C";
|
||||
constexpr PowerMode kPowerMode(PowerMode::kHigh);
|
||||
|
||||
// A stub BlePeripheral implementation.
|
||||
class BlePeripheralStub : public api::ble_v2::BlePeripheral {
|
||||
public:
|
||||
explicit BlePeripheralStub(absl::string_view mac_address) {
|
||||
mac_address_ = mac_address;
|
||||
}
|
||||
|
||||
std::string GetAddress() const override { return mac_address_; }
|
||||
|
||||
private:
|
||||
std::string mac_address_;
|
||||
};
|
||||
|
||||
class BleV2MediumTest : public testing::Test {
|
||||
protected:
|
||||
BleV2MediumTest() { env_.Stop(); }
|
||||
@@ -42,10 +61,10 @@ class BleV2MediumTest : public testing::Test {
|
||||
|
||||
TEST_F(BleV2MediumTest, ConstructorDestructorWorks) {
|
||||
env_.Start();
|
||||
BluetoothAdapter adapter_a_;
|
||||
BluetoothAdapter adapter_b_;
|
||||
BleV2Medium ble_a{adapter_a_};
|
||||
BleV2Medium ble_b{adapter_b_};
|
||||
BluetoothAdapter adapter_a;
|
||||
BluetoothAdapter adapter_b;
|
||||
BleV2Medium ble_a(adapter_a);
|
||||
BleV2Medium ble_b(adapter_b);
|
||||
|
||||
// Make sure we can create functional mediums.
|
||||
ASSERT_TRUE(ble_a.IsValid());
|
||||
@@ -56,75 +75,162 @@ TEST_F(BleV2MediumTest, ConstructorDestructorWorks) {
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(BleV2MediumTest, CanStartFastAdvertising) {
|
||||
TEST_F(BleV2MediumTest, CanStartFastScanningAndFastAdvertising) {
|
||||
env_.Start();
|
||||
BluetoothAdapter adapter_;
|
||||
BleV2Medium ble{adapter_};
|
||||
ByteArray advertisement_bytes{std::string(kAdvertisementString)};
|
||||
std::string fast_advertisement_service_uuid(kFastAdvertisementServiceUuid);
|
||||
BluetoothAdapter adapter_a;
|
||||
BluetoothAdapter adapter_b;
|
||||
BleV2Medium ble_a(adapter_a);
|
||||
BleV2Medium ble_b(adapter_b);
|
||||
CountDownLatch found_latch(1);
|
||||
|
||||
BleAdvertisementData advertising_data;
|
||||
advertising_data.is_connectable = true;
|
||||
advertising_data.tx_power_level =
|
||||
BleAdvertisementData::kUnspecifiedTxPowerLevel;
|
||||
advertising_data.service_uuids.insert(fast_advertisement_service_uuid);
|
||||
EXPECT_TRUE(ble_a.StartScanning(
|
||||
{std::string(kFastAdvertisementServiceUuid)}, kPowerMode,
|
||||
{
|
||||
.advertisement_found_cb =
|
||||
[&found_latch](BleV2Peripheral peripheral,
|
||||
const BleAdvertisementData& advertisement_data) {
|
||||
found_latch.CountDown();
|
||||
},
|
||||
}));
|
||||
|
||||
// Assemble fast advertising and scan response data.
|
||||
BleAdvertisementData advertising_data;
|
||||
advertising_data.service_uuids.insert(
|
||||
std::string(kFastAdvertisementServiceUuid));
|
||||
BleAdvertisementData scan_response_data;
|
||||
scan_response_data.is_connectable = true;
|
||||
scan_response_data.tx_power_level =
|
||||
BleAdvertisementData::kUnspecifiedTxPowerLevel;
|
||||
scan_response_data.service_data.insert(
|
||||
{fast_advertisement_service_uuid, advertisement_bytes});
|
||||
{std::string(kFastAdvertisementServiceUuid),
|
||||
ByteArray(std::string(kAdvertisementString))});
|
||||
|
||||
EXPECT_TRUE(
|
||||
ble.StartAdvertising(advertising_data, scan_response_data, kPowerMode));
|
||||
|
||||
EXPECT_TRUE(ble.StopAdvertising());
|
||||
ble_b.StartAdvertising(advertising_data, scan_response_data, kPowerMode));
|
||||
EXPECT_TRUE(found_latch.Await(kWaitDuration).result());
|
||||
EXPECT_TRUE(ble_a.StopScanning());
|
||||
EXPECT_TRUE(ble_b.StopAdvertising());
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(BleV2MediumTest, CanStartAdvertising) {
|
||||
TEST_F(BleV2MediumTest, CanStartScanningAndAdvertising) {
|
||||
env_.Start();
|
||||
BluetoothAdapter adapter_;
|
||||
BleV2Medium ble{adapter_};
|
||||
ByteArray advertisement_header_bytes{std::string(kAdvertisementString)};
|
||||
std::string fast_advertisement_service_uuid(kFastAdvertisementServiceUuid);
|
||||
BluetoothAdapter adapter_a;
|
||||
BluetoothAdapter adapter_b;
|
||||
BleV2Medium ble_a(adapter_a);
|
||||
BleV2Medium ble_b(adapter_b);
|
||||
CountDownLatch found_latch(1);
|
||||
|
||||
EXPECT_TRUE(ble_a.StartScanning(
|
||||
{std::string(kCopresenceServiceUuid)}, kPowerMode,
|
||||
{
|
||||
.advertisement_found_cb =
|
||||
[&found_latch](BleV2Peripheral peripheral,
|
||||
const BleAdvertisementData& advertisement_data) {
|
||||
found_latch.CountDown();
|
||||
},
|
||||
}));
|
||||
|
||||
// Assemble regular advertising and scan response data.
|
||||
BleAdvertisementData advertising_data;
|
||||
advertising_data.is_connectable = true;
|
||||
advertising_data.tx_power_level =
|
||||
BleAdvertisementData::kUnspecifiedTxPowerLevel;
|
||||
|
||||
BleAdvertisementData advertising_data = {};
|
||||
BleAdvertisementData scan_response_data;
|
||||
scan_response_data.is_connectable = true;
|
||||
scan_response_data.tx_power_level =
|
||||
BleAdvertisementData::kUnspecifiedTxPowerLevel;
|
||||
scan_response_data.service_uuids.insert(fast_advertisement_service_uuid);
|
||||
scan_response_data.service_uuids.insert(std::string(kCopresenceServiceUuid));
|
||||
scan_response_data.service_data.insert(
|
||||
{fast_advertisement_service_uuid, advertisement_header_bytes});
|
||||
{std::string(kCopresenceServiceUuid),
|
||||
ByteArray(std::string(kAdvertisementString))});
|
||||
|
||||
EXPECT_TRUE(
|
||||
ble.StartAdvertising(advertising_data, scan_response_data, kPowerMode));
|
||||
ble_b.StartAdvertising(advertising_data, scan_response_data, kPowerMode));
|
||||
EXPECT_TRUE(found_latch.Await(kWaitDuration).result());
|
||||
EXPECT_TRUE(ble_a.StopScanning());
|
||||
EXPECT_TRUE(ble_b.StopAdvertising());
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
EXPECT_TRUE(ble.StopAdvertising());
|
||||
TEST_F(BleV2MediumTest,
|
||||
CanStartFastAdvertisingButRegularScanningFailToFoundAdvertisement) {
|
||||
env_.Start();
|
||||
BluetoothAdapter adapter_a;
|
||||
BluetoothAdapter adapter_b;
|
||||
BleV2Medium ble_a(adapter_a);
|
||||
BleV2Medium ble_b(adapter_b);
|
||||
CountDownLatch found_latch(1);
|
||||
|
||||
EXPECT_TRUE(ble_a.StartScanning(
|
||||
{std::string(kCopresenceServiceUuid)}, kPowerMode,
|
||||
{
|
||||
.advertisement_found_cb =
|
||||
[&found_latch](BleV2Peripheral peripheral,
|
||||
const BleAdvertisementData& advertisement_data) {
|
||||
found_latch.CountDown();
|
||||
},
|
||||
}));
|
||||
|
||||
// Assemble fast advertising and scan response data.
|
||||
BleAdvertisementData advertising_data;
|
||||
advertising_data.service_uuids.insert(
|
||||
std::string(kFastAdvertisementServiceUuid));
|
||||
BleAdvertisementData scan_response_data;
|
||||
scan_response_data.service_data.insert(
|
||||
{std::string(kFastAdvertisementServiceUuid),
|
||||
ByteArray(std::string(kAdvertisementString))});
|
||||
|
||||
EXPECT_TRUE(
|
||||
ble_b.StartAdvertising(advertising_data, scan_response_data, kPowerMode));
|
||||
// Fail to found the advertiement.
|
||||
EXPECT_FALSE(found_latch.Await(kWaitDuration).result());
|
||||
EXPECT_TRUE(ble_a.StopScanning());
|
||||
EXPECT_TRUE(ble_b.StopAdvertising());
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(BleV2MediumTest,
|
||||
CanStartAdvertisingButFastScanningFailToFoundAdvertisement) {
|
||||
env_.Start();
|
||||
BluetoothAdapter adapter_a;
|
||||
BluetoothAdapter adapter_b;
|
||||
BleV2Medium ble_a(adapter_a);
|
||||
BleV2Medium ble_b(adapter_b);
|
||||
CountDownLatch found_latch(1);
|
||||
|
||||
EXPECT_TRUE(ble_a.StartScanning(
|
||||
{std::string(kFastAdvertisementServiceUuid)}, kPowerMode,
|
||||
{
|
||||
.advertisement_found_cb =
|
||||
[&found_latch](BleV2Peripheral peripheral,
|
||||
const BleAdvertisementData& advertisement_data) {
|
||||
found_latch.CountDown();
|
||||
},
|
||||
}));
|
||||
|
||||
// Assemble regular advertising and scan response data.
|
||||
BleAdvertisementData advertising_data = {};
|
||||
BleAdvertisementData scan_response_data;
|
||||
scan_response_data.service_uuids.insert(std::string(kCopresenceServiceUuid));
|
||||
scan_response_data.service_data.insert(
|
||||
{std::string(kCopresenceServiceUuid),
|
||||
ByteArray(std::string(kAdvertisementString))});
|
||||
|
||||
EXPECT_TRUE(
|
||||
ble_b.StartAdvertising(advertising_data, scan_response_data, kPowerMode));
|
||||
// Fail to found the advertiement.
|
||||
EXPECT_FALSE(found_latch.Await(kWaitDuration).result());
|
||||
EXPECT_TRUE(ble_a.StopScanning());
|
||||
EXPECT_TRUE(ble_b.StopAdvertising());
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(BleV2MediumTest, CanStartGattServer) {
|
||||
env_.Start();
|
||||
BluetoothAdapter adapter_;
|
||||
BleV2Medium ble{adapter_};
|
||||
BluetoothAdapter adapter;
|
||||
BleV2Medium ble{adapter};
|
||||
std::string characteristic_uuid = "characteristic_uuid";
|
||||
|
||||
std::unique_ptr<GattServer> gatt_server = ble.StartGattServer({});
|
||||
std::unique_ptr<GattServer> gatt_server =
|
||||
ble.StartGattServer(/*ServerGattConnectionCallback=*/{});
|
||||
|
||||
ASSERT_NE(gatt_server, nullptr);
|
||||
|
||||
std::vector<GattCharacteristic::Permission> permissions{
|
||||
std::vector<GattCharacteristic::Permission> permissions = {
|
||||
GattCharacteristic::Permission::kRead};
|
||||
std::vector<GattCharacteristic::Property> properties{
|
||||
std::vector<GattCharacteristic::Property> properties = {
|
||||
GattCharacteristic::Property::kRead};
|
||||
absl::optional<GattCharacteristic> gatt_characteristic =
|
||||
gatt_server->CreateCharacteristic(std::string(kCopresenceServiceUuid),
|
||||
@@ -143,21 +249,61 @@ TEST_F(BleV2MediumTest, CanStartGattServer) {
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(BleV2MediumTest, CanStartScanning) {
|
||||
TEST_F(BleV2MediumTest, GattClientConnectToGattServerWorks) {
|
||||
env_.Start();
|
||||
BluetoothAdapter adapter_;
|
||||
BleV2Medium ble{adapter_};
|
||||
BluetoothAdapter adapter_a;
|
||||
BluetoothAdapter adapter_b;
|
||||
BleV2Medium ble_a(adapter_a);
|
||||
BleV2Medium ble_b(adapter_b);
|
||||
std::string characteristic_uuid = "characteristic_uuid";
|
||||
|
||||
EXPECT_TRUE(ble.StartScanning(
|
||||
{std::string(kCopresenceServiceUuid)}, kPowerMode,
|
||||
{
|
||||
.advertisement_found_cb =
|
||||
[](BleV2Peripheral peripheral,
|
||||
BleAdvertisementData advertisement_data) {
|
||||
// nothing to do for now
|
||||
},
|
||||
}));
|
||||
EXPECT_TRUE(ble.StopScanning());
|
||||
// Start GattServer
|
||||
std::unique_ptr<GattServer> gatt_server =
|
||||
ble_a.StartGattServer(/*ServerGattConnectionCallback=*/{});
|
||||
|
||||
ASSERT_NE(gatt_server, nullptr);
|
||||
|
||||
std::vector<GattCharacteristic::Permission> permissions = {
|
||||
GattCharacteristic::Permission::kRead};
|
||||
std::vector<GattCharacteristic::Property> properties = {
|
||||
GattCharacteristic::Property::kRead};
|
||||
// Add characteristic and its value.
|
||||
// NOLINTNEXTLINE(google3-legacy-absl-backports)
|
||||
absl::optional<GattCharacteristic> server_characteristic =
|
||||
gatt_server->CreateCharacteristic(std::string(kCopresenceServiceUuid),
|
||||
characteristic_uuid, permissions,
|
||||
properties);
|
||||
ASSERT_TRUE(server_characteristic.has_value());
|
||||
ByteArray server_value("any");
|
||||
EXPECT_TRUE(
|
||||
gatt_server->UpdateCharacteristic(*server_characteristic, server_value));
|
||||
|
||||
// Start GattClient
|
||||
auto ble_peripheral =
|
||||
std::make_unique<BlePeripheralStub>(/*mac_address=*/"ABCD");
|
||||
std::unique_ptr<GattClient> gatt_client = ble_b.ConnectToGattServer(
|
||||
BleV2Peripheral(ble_peripheral.get()), kPowerMode,
|
||||
/*ClientGattConnectionCallback=*/{});
|
||||
|
||||
ASSERT_NE(gatt_client, nullptr);
|
||||
|
||||
// Discover service.
|
||||
EXPECT_TRUE(
|
||||
gatt_client->DiscoverService(std::string(kCopresenceServiceUuid)));
|
||||
|
||||
// Discover characteristic.
|
||||
// NOLINTNEXTLINE(google3-legacy-absl-backports)
|
||||
absl::optional<GattCharacteristic> client_characteristic =
|
||||
gatt_client->GetCharacteristic(std::string(kCopresenceServiceUuid),
|
||||
characteristic_uuid);
|
||||
ASSERT_TRUE(client_characteristic.has_value());
|
||||
|
||||
// Can read the characteristic value.
|
||||
EXPECT_THAT(gatt_client->ReadCharacteristic(*client_characteristic),
|
||||
Optional(server_value));
|
||||
|
||||
gatt_client->Disconnect();
|
||||
gatt_server->Stop();
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#define PLATFORM_API_BLE_V2_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
@@ -25,7 +26,6 @@
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "absl/container/flat_hash_set.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/types/optional.h"
|
||||
#include "internal/platform/byte_array.h"
|
||||
#include "internal/platform/exception.h"
|
||||
#include "internal/platform/input_stream.h"
|
||||
@@ -111,35 +111,32 @@ struct GattCharacteristic {
|
||||
};
|
||||
|
||||
std::string uuid;
|
||||
std::string servie_uuid;
|
||||
std::string service_uuid;
|
||||
|
||||
// Hashable
|
||||
template <typename H>
|
||||
friend H AbslHashValue(H h, const GattCharacteristic& s) {
|
||||
return H::combine(std::move(h), s.uuid, s.servie_uuid);
|
||||
return H::combine(std::move(h), s.uuid, s.service_uuid);
|
||||
}
|
||||
bool operator==(const GattCharacteristic& rhs) const {
|
||||
return this->uuid == rhs.uuid && this->servie_uuid == rhs.servie_uuid;
|
||||
return this->uuid == rhs.uuid && this->service_uuid == rhs.service_uuid;
|
||||
}
|
||||
};
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothGatt
|
||||
//
|
||||
// Representation of a client GATT connection to a remote GATT server.
|
||||
class ClientGattConnection {
|
||||
class GattClient {
|
||||
public:
|
||||
virtual ~ClientGattConnection() = default;
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#getDevice()
|
||||
virtual BlePeripheral& GetPeripheral() = 0;
|
||||
virtual ~GattClient() = default;
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#discoverServices()
|
||||
//
|
||||
// Discovers all available services and characteristics on this connection.
|
||||
// Discovers available service and characteristics on this connection.
|
||||
// Returns whether or not discovery finished successfully.
|
||||
//
|
||||
// This function should block until discovery has finished.
|
||||
virtual bool DiscoverServices() = 0;
|
||||
virtual bool DiscoverService(const std::string& service_uuid) = 0;
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#getService(java.util.UUID)
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothGattService.html#getCharacteristic(java.util.UUID)
|
||||
@@ -172,49 +169,6 @@ class ClientGattConnection {
|
||||
virtual void Disconnect() = 0;
|
||||
};
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothGattServer
|
||||
//
|
||||
// Representation of a server GATT connection to a remote GATT client.
|
||||
class ServerGattConnection {
|
||||
public:
|
||||
virtual ~ServerGattConnection() = default;
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothGattCharacteristic.html#setValue(byte[])
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothGattServer.html#notifyCharacteristicChanged(android.bluetooth.BluetoothDevice,%20android.bluetooth.BluetoothGattCharacteristic,%20boolean)
|
||||
//
|
||||
// Sends a notification (via indication) to the client that a characteristic
|
||||
// has changed with the given value. Returns whether or not it was
|
||||
// successful.
|
||||
//
|
||||
// The value sent does not have to reflect the locally stored characteristic
|
||||
// value. To update the local value, call GattServer::UpdateCharacteristic.
|
||||
virtual bool SendCharacteristic(const GattCharacteristic& characteristic,
|
||||
const ByteArray& value) = 0;
|
||||
};
|
||||
|
||||
// Callback for asynchronous events on the client side of a GATT connection.
|
||||
struct ClientGattConnectionCallback {
|
||||
public:
|
||||
// Called when the client is disconnected from the GATT server.
|
||||
std::function<void(ClientGattConnection& connection)> disconnected_cb =
|
||||
DefaultCallback<ClientGattConnection&>();
|
||||
};
|
||||
|
||||
// Callback for asynchronous events on the server side of a GATT connection.
|
||||
struct ServerGattConnectionCallback {
|
||||
// Called when a remote peripheral connected to us and subscribed to one of
|
||||
// our characteristics.
|
||||
std::function<void(ServerGattConnection& connection,
|
||||
const GattCharacteristic& characteristic)>
|
||||
characteristic_subscription_cb;
|
||||
|
||||
// Called when a remote peripheral unsubscribed from one of our
|
||||
// characteristics.
|
||||
std::function<void(ServerGattConnection& connection,
|
||||
const GattCharacteristic& characteristic)>
|
||||
characteristic_unsubscription_cb;
|
||||
};
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothGattServer
|
||||
//
|
||||
// Representation of a BLE GATT server.
|
||||
@@ -251,6 +205,26 @@ class GattServer {
|
||||
virtual void Stop() = 0;
|
||||
};
|
||||
|
||||
// Callback for asynchronous events on the client side of a GATT connection.
|
||||
struct ClientGattConnectionCallback {
|
||||
public:
|
||||
// Called when the client is disconnected from the GATT server.
|
||||
std::function<void()> disconnected_cb = DefaultCallback<>();
|
||||
};
|
||||
|
||||
// Callback for asynchronous events on the server side of a GATT connection.
|
||||
struct ServerGattConnectionCallback {
|
||||
// Called when a remote peripheral connected to us and subscribed to one of
|
||||
// our characteristics.
|
||||
std::function<void(const GattCharacteristic& characteristic)>
|
||||
characteristic_subscription_cb;
|
||||
|
||||
// Called when a remote peripheral unsubscribed from one of our
|
||||
// characteristics.
|
||||
std::function<void(const GattCharacteristic& characteristic)>
|
||||
characteristic_unsubscription_cb;
|
||||
};
|
||||
|
||||
class BleSocket {
|
||||
public:
|
||||
virtual ~BleSocket() {}
|
||||
@@ -295,8 +269,6 @@ class ServerBleSocketLifeCycleCallback : public BleSocketLifeCycleCallback {
|
||||
// for all BLE and GATT related operations.
|
||||
class BleMedium {
|
||||
public:
|
||||
using Mtu = uint32_t;
|
||||
|
||||
virtual ~BleMedium() = default;
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/le/BluetoothLeAdvertiser.html#startAdvertising(android.bluetooth.le.AdvertiseSettings,%20android.bluetooth.le.AdvertiseData,%20android.bluetooth.le.AdvertiseData,%20android.bluetooth.le.AdvertiseCallback)
|
||||
@@ -375,16 +347,13 @@ class BleMedium {
|
||||
// Connects to a GATT server and negotiates the specified connection
|
||||
// parameters. Returns nullptr upon error.
|
||||
//
|
||||
// Both connection interval and MTU can be negotiated on a best-effort
|
||||
// basis.
|
||||
//
|
||||
// Power mode should be interpreted in the following way:
|
||||
// HIGH:
|
||||
// - Connection interval = ~11.25ms - 15ms
|
||||
// LOW:
|
||||
// - Connection interval = ~100ms - 125ms
|
||||
virtual std::unique_ptr<ClientGattConnection> ConnectToGattServer(
|
||||
BlePeripheral& peripheral, Mtu mtu, PowerMode power_mode,
|
||||
virtual std::unique_ptr<GattClient> ConnectToGattServer(
|
||||
BlePeripheral& peripheral, PowerMode power_mode,
|
||||
ClientGattConnectionCallback callback) = 0;
|
||||
|
||||
// Establishes a BLE socket to the specified remote peripheral. Returns
|
||||
|
||||
@@ -16,12 +16,13 @@
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/strings/escaping.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "internal/platform/implementation/ble_v2.h"
|
||||
#include "internal/platform/implementation/shared/count_down_latch.h"
|
||||
#include "internal/platform/logging.h"
|
||||
#include "internal/platform/medium_environment.h"
|
||||
|
||||
@@ -34,9 +35,7 @@ namespace {
|
||||
using ::location::nearby::api::ble_v2::BleAdvertisementData;
|
||||
using ::location::nearby::api::ble_v2::BleSocket;
|
||||
using ::location::nearby::api::ble_v2::BleSocketLifeCycleCallback;
|
||||
using ::location::nearby::api::ble_v2::ClientGattConnection;
|
||||
using ::location::nearby::api::ble_v2::PowerMode;
|
||||
using ::location::nearby::api::ble_v2::ServerGattConnectionCallback;
|
||||
|
||||
std::string PowerModeToName(PowerMode power_mode) {
|
||||
switch (power_mode) {
|
||||
@@ -96,7 +95,6 @@ bool BleV2Medium::StartAdvertising(
|
||||
bool BleV2Medium::StopAdvertising() {
|
||||
NEARBY_LOGS(INFO) << "G3 Ble StopAdvertising";
|
||||
absl::MutexLock lock(&mutex_);
|
||||
advertisement_byte_ = {};
|
||||
|
||||
BleAdvertisementData empty_advertisement_data = {};
|
||||
MediumEnvironment::Instance().UpdateBleV2MediumForAdvertising(
|
||||
@@ -111,7 +109,7 @@ bool BleV2Medium::StartScanning(const std::vector<std::string>& service_uuids,
|
||||
absl::MutexLock lock(&mutex_);
|
||||
|
||||
MediumEnvironment::Instance().UpdateBleV2MediumForScanning(
|
||||
true, std::move(callback), *this);
|
||||
/*enabled=*/true, service_uuids.front(), std::move(callback), *this);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -119,12 +117,14 @@ bool BleV2Medium::StopScanning() {
|
||||
NEARBY_LOGS(INFO) << "G3 Ble StopScanning";
|
||||
absl::MutexLock lock(&mutex_);
|
||||
|
||||
MediumEnvironment::Instance().UpdateBleV2MediumForScanning(false, {}, *this);
|
||||
MediumEnvironment::Instance().UpdateBleV2MediumForScanning(
|
||||
/*enabled=*/false,
|
||||
/*service_uuid=*/{}, /*callback=*/{}, *this);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<api::ble_v2::GattServer> BleV2Medium::StartGattServer(
|
||||
ServerGattConnectionCallback callback) {
|
||||
api::ble_v2::ServerGattConnectionCallback callback) {
|
||||
return std::make_unique<GattServer>();
|
||||
}
|
||||
|
||||
@@ -135,10 +135,10 @@ bool BleV2Medium::StartListeningForIncomingBleSockets(
|
||||
|
||||
void BleV2Medium::StopListeningForIncomingBleSockets() {}
|
||||
|
||||
std::unique_ptr<ClientGattConnection> BleV2Medium::ConnectToGattServer(
|
||||
api::ble_v2::BlePeripheral& peripheral, Mtu mtu, PowerMode power_mode,
|
||||
std::unique_ptr<api::ble_v2::GattClient> BleV2Medium::ConnectToGattServer(
|
||||
api::ble_v2::BlePeripheral& peripheral, PowerMode power_mode,
|
||||
api::ble_v2::ClientGattConnectionCallback callback) {
|
||||
return nullptr;
|
||||
return std::make_unique<GattClient>();
|
||||
}
|
||||
|
||||
std::unique_ptr<BleSocket> BleV2Medium::EstablishBleSocket(
|
||||
@@ -147,6 +147,102 @@ std::unique_ptr<BleSocket> BleV2Medium::EstablishBleSocket(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::optional<api::ble_v2::GattCharacteristic>
|
||||
BleV2Medium::GattServer::CreateCharacteristic(
|
||||
absl::string_view service_uuid, absl::string_view characteristic_uuid,
|
||||
const std::vector<api::ble_v2::GattCharacteristic::Permission>& permissions,
|
||||
const std::vector<api::ble_v2::GattCharacteristic::Property>& properties) {
|
||||
api::ble_v2::GattCharacteristic characteristic = {
|
||||
.uuid = std::string(characteristic_uuid),
|
||||
.service_uuid = std::string(service_uuid)};
|
||||
return characteristic;
|
||||
}
|
||||
|
||||
bool BleV2Medium::GattServer::UpdateCharacteristic(
|
||||
const api::ble_v2::GattCharacteristic& characteristic,
|
||||
const location::nearby::ByteArray& value) {
|
||||
NEARBY_LOGS(INFO)
|
||||
<< "G3 Ble GattServer UpdateCharacteristic, characteristic=("
|
||||
<< characteristic.service_uuid << "," << characteristic.uuid
|
||||
<< "), value = " << absl::BytesToHexString(value.data());
|
||||
MediumEnvironment::Instance().InsertBleV2MediumGattCharacteristics(
|
||||
characteristic, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
void BleV2Medium::GattServer::Stop() {
|
||||
NEARBY_LOGS(INFO) << "G3 Ble GattServer Stop";
|
||||
MediumEnvironment::Instance().ClearBleV2MediumGattCharacteristics();
|
||||
}
|
||||
|
||||
bool BleV2Medium::GattClient::DiscoverService(const std::string& service_uuid) {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
NEARBY_LOGS(INFO) << "G3 Ble GattClient DiscoverService, service_uuid"
|
||||
<< service_uuid;
|
||||
if (!is_connection_alive_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Search if the service exists.
|
||||
return MediumEnvironment::Instance().ContainsBleV2MediumGattCharacteristics(
|
||||
service_uuid, "");
|
||||
}
|
||||
|
||||
std::optional<api::ble_v2::GattCharacteristic>
|
||||
BleV2Medium::GattClient::GetCharacteristic(
|
||||
absl::string_view service_uuid, absl::string_view characteristic_uuid) {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
NEARBY_LOGS(INFO) << "G3 Ble GattClient GetCharacteristic, service_uuid="
|
||||
<< service_uuid
|
||||
<< ", characteristic_uuid=" << characteristic_uuid;
|
||||
if (!is_connection_alive_) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Search gatt_characteristic by uuid and if found return the
|
||||
// gatt_characteristic.
|
||||
api::ble_v2::GattCharacteristic characteristic = {};
|
||||
if (MediumEnvironment::Instance().ContainsBleV2MediumGattCharacteristics(
|
||||
service_uuid, characteristic_uuid)) {
|
||||
characteristic = {.uuid = std::string(characteristic_uuid),
|
||||
.service_uuid = std::string(service_uuid)};
|
||||
}
|
||||
NEARBY_LOGS(INFO)
|
||||
<< "G3 Ble GattClient GetCharacteristic, found characteristic=("
|
||||
<< characteristic.service_uuid << "," << characteristic.uuid << ")";
|
||||
|
||||
return characteristic;
|
||||
}
|
||||
|
||||
std::optional<ByteArray> BleV2Medium::GattClient::ReadCharacteristic(
|
||||
const api::ble_v2::GattCharacteristic& characteristic) {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
if (!is_connection_alive_) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
ByteArray value =
|
||||
MediumEnvironment::Instance().ReadBleV2MediumGattCharacteristics(
|
||||
characteristic);
|
||||
NEARBY_LOGS(INFO) << "G3 Ble ReadCharacteristic, characteristic=("
|
||||
<< characteristic.service_uuid << "," << characteristic.uuid
|
||||
<< "), value = " << absl::BytesToHexString(value.data());
|
||||
return std::move(value);
|
||||
}
|
||||
|
||||
bool BleV2Medium::GattClient::WriteCharacteristic(
|
||||
const api::ble_v2::GattCharacteristic& characteristic,
|
||||
const ByteArray& value) {
|
||||
// No op.
|
||||
return false;
|
||||
}
|
||||
|
||||
void BleV2Medium::GattClient::Disconnect() {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
NEARBY_LOGS(INFO) << "G3 Ble GattClient Disconnect";
|
||||
is_connection_alive_ = false;
|
||||
}
|
||||
|
||||
} // namespace g3
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
@@ -55,9 +55,8 @@ class BleV2Medium : public api::ble_v2::BleMedium {
|
||||
ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
void StopListeningForIncomingBleSockets() override
|
||||
ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
std::unique_ptr<api::ble_v2::ClientGattConnection> ConnectToGattServer(
|
||||
api::ble_v2::BlePeripheral& peripheral, Mtu mtu,
|
||||
api::ble_v2::PowerMode power_mode,
|
||||
std::unique_ptr<api::ble_v2::GattClient> ConnectToGattServer(
|
||||
api::ble_v2::BlePeripheral& peripheral, api::ble_v2::PowerMode power_mode,
|
||||
api::ble_v2::ClientGattConnectionCallback callback) override
|
||||
ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
std::unique_ptr<api::ble_v2::BleSocket> EstablishBleSocket(
|
||||
@@ -68,6 +67,7 @@ class BleV2Medium : public api::ble_v2::BleMedium {
|
||||
BluetoothAdapter& GetAdapter() { return *adapter_; }
|
||||
|
||||
private:
|
||||
// A concrete implemenation for GattServer.
|
||||
class GattServer : public api::ble_v2::GattServer {
|
||||
public:
|
||||
std::optional<api::ble_v2::GattCharacteristic> CreateCharacteristic(
|
||||
@@ -75,28 +75,44 @@ class BleV2Medium : public api::ble_v2::BleMedium {
|
||||
const std::vector<api::ble_v2::GattCharacteristic::Permission>&
|
||||
permissions,
|
||||
const std::vector<api::ble_v2::GattCharacteristic::Property>&
|
||||
properties) override {
|
||||
api::ble_v2::GattCharacteristic characteristic = {
|
||||
.uuid = std::string(characteristic_uuid),
|
||||
.servie_uuid = std::string(service_uuid)};
|
||||
return characteristic;
|
||||
}
|
||||
properties) override;
|
||||
|
||||
bool UpdateCharacteristic(
|
||||
const api::ble_v2::GattCharacteristic& characteristic,
|
||||
const location::nearby::ByteArray& value) override {
|
||||
// No action for now.
|
||||
return true;
|
||||
}
|
||||
const location::nearby::ByteArray& value) override;
|
||||
|
||||
void Stop() override {
|
||||
// No action for now.
|
||||
}
|
||||
void Stop() override;
|
||||
};
|
||||
|
||||
// A concrete implemenation for GattClient.
|
||||
class GattClient : public api::ble_v2::GattClient {
|
||||
public:
|
||||
bool DiscoverService(const std::string& service_uuid) override;
|
||||
|
||||
std::optional<api::ble_v2::GattCharacteristic> GetCharacteristic(
|
||||
absl::string_view service_uuid,
|
||||
absl::string_view characteristic_uuid) override;
|
||||
|
||||
std::optional<ByteArray> ReadCharacteristic(
|
||||
const api::ble_v2::GattCharacteristic& characteristic) override;
|
||||
|
||||
bool WriteCharacteristic(
|
||||
const api::ble_v2::GattCharacteristic& characteristic,
|
||||
const ByteArray& value) override;
|
||||
|
||||
void Disconnect() override;
|
||||
|
||||
private:
|
||||
absl::Mutex mutex_;
|
||||
|
||||
// A flag to indicate the gatt connection alive or not. If it is
|
||||
// disconnected/*false*/, the instance needs to be created again to bring it
|
||||
// alive.
|
||||
bool is_connection_alive_ ABSL_GUARDED_BY(mutex_) = true;
|
||||
};
|
||||
|
||||
absl::Mutex mutex_;
|
||||
BluetoothAdapter* adapter_; // Our device adapter; read-only.
|
||||
ByteArray advertisement_byte_ ABSL_GUARDED_BY(mutex_);
|
||||
};
|
||||
|
||||
} // namespace g3
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace {
|
||||
using ::location::nearby::api::ble_v2::BleAdvertisementData;
|
||||
using ::location::nearby::api::ble_v2::BleSocket;
|
||||
using ::location::nearby::api::ble_v2::BleSocketLifeCycleCallback;
|
||||
using ::location::nearby::api::ble_v2::ClientGattConnection;
|
||||
using ::location::nearby::api::ble_v2::GattClient;
|
||||
using ::location::nearby::api::ble_v2::PowerMode;
|
||||
using ::location::nearby::api::ble_v2::ServerGattConnectionCallback;
|
||||
using ::winrt::Windows::Devices::Bluetooth::BluetoothError;
|
||||
@@ -289,8 +289,8 @@ bool BleV2Medium::StartListeningForIncomingBleSockets(
|
||||
|
||||
void BleV2Medium::StopListeningForIncomingBleSockets() {}
|
||||
|
||||
std::unique_ptr<ClientGattConnection> BleV2Medium::ConnectToGattServer(
|
||||
api::ble_v2::BlePeripheral& peripheral, Mtu mtu, PowerMode power_mode,
|
||||
std::unique_ptr<GattClient> BleV2Medium::ConnectToGattServer(
|
||||
api::ble_v2::BlePeripheral& peripheral, PowerMode power_mode,
|
||||
api::ble_v2::ClientGattConnectionCallback callback) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -66,9 +66,8 @@ class BleV2Medium : public api::ble_v2::BleMedium {
|
||||
ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
void StopListeningForIncomingBleSockets() override
|
||||
ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
std::unique_ptr<api::ble_v2::ClientGattConnection> ConnectToGattServer(
|
||||
api::ble_v2::BlePeripheral& peripheral, Mtu mtu,
|
||||
api::ble_v2::PowerMode power_mode,
|
||||
std::unique_ptr<api::ble_v2::GattClient> ConnectToGattServer(
|
||||
api::ble_v2::BlePeripheral& peripheral, api::ble_v2::PowerMode power_mode,
|
||||
api::ble_v2::ClientGattConnectionCallback callback) override
|
||||
ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
std::unique_ptr<api::ble_v2::BleSocket> EstablishBleSocket(
|
||||
|
||||
@@ -539,6 +539,9 @@ void MediumEnvironment::UpdateBleV2MediumForAdvertising(
|
||||
BleV2MediumContext& remote_context = medium_info.second;
|
||||
// Do not send notification to the same medium.
|
||||
if (remote_medium == &medium) continue;
|
||||
if (!context.advertisement_data.service_uuids.contains(
|
||||
remote_context.scanning_service_uuid))
|
||||
continue;
|
||||
NEARBY_LOGS(INFO)
|
||||
<< "G3 UpdateBleV2MediumForAdvertising, found other medium="
|
||||
<< remote_medium << ", remote_medium_context=" << &remote_context
|
||||
@@ -552,10 +555,12 @@ void MediumEnvironment::UpdateBleV2MediumForAdvertising(
|
||||
}
|
||||
|
||||
void MediumEnvironment::UpdateBleV2MediumForScanning(
|
||||
bool enabled, BleScanCallback callback, api::ble_v2::BleMedium& medium) {
|
||||
bool enabled, const std::string& scanning_service_uuid,
|
||||
BleScanCallback callback, api::ble_v2::BleMedium& medium) {
|
||||
if (!enabled_) return;
|
||||
RunOnMediumEnvironmentThread(
|
||||
[this, &medium, callback = std::move(callback), enabled]() {
|
||||
[this, &medium, scanning_service_uuid = scanning_service_uuid,
|
||||
callback = std::move(callback), enabled]() {
|
||||
auto it = ble_v2_mediums_.find(&medium);
|
||||
if (it == ble_v2_mediums_.end()) {
|
||||
NEARBY_LOGS(INFO)
|
||||
@@ -565,6 +570,7 @@ void MediumEnvironment::UpdateBleV2MediumForScanning(
|
||||
}
|
||||
BleV2MediumContext& context = it->second;
|
||||
context.scan_callback = std::move(callback);
|
||||
context.scanning_service_uuid = scanning_service_uuid;
|
||||
NEARBY_LOGS(INFO) << "G3 UpdateBleV2MediumForScanning: this=" << this
|
||||
<< ", medium=" << &medium
|
||||
<< ", medium_context=" << &context
|
||||
@@ -577,10 +583,14 @@ void MediumEnvironment::UpdateBleV2MediumForScanning(
|
||||
// medium.
|
||||
if (remote_medium == &medium || !remote_context.advertising)
|
||||
continue;
|
||||
if (!remote_context.advertisement_data.service_uuids.contains(
|
||||
context.scanning_service_uuid))
|
||||
continue;
|
||||
NEARBY_LOGS(INFO)
|
||||
<< "G3 UpdateBleV2MediumForScanning, found other medium="
|
||||
<< remote_medium
|
||||
<< ", remote_medium_context=" << &remote_context
|
||||
<< ", scanning_service_uuid=" << scanning_service_uuid
|
||||
<< ". Ready to call OnBleV2PeripheralStateChanged.";
|
||||
OnBleV2PeripheralStateChanged(enabled, context,
|
||||
remote_context.advertisement_data,
|
||||
@@ -590,6 +600,68 @@ void MediumEnvironment::UpdateBleV2MediumForScanning(
|
||||
});
|
||||
}
|
||||
|
||||
void MediumEnvironment::InsertBleV2MediumGattCharacteristics(
|
||||
const api::ble_v2::GattCharacteristic& characteristic,
|
||||
const ByteArray& gatt_advertisement_byte) {
|
||||
if (!enabled_) return;
|
||||
CountDownLatch latch(1);
|
||||
RunOnMediumEnvironmentThread(
|
||||
[this, &latch, &characteristic, &gatt_advertisement_byte]() {
|
||||
gatt_advertisement_bytes_[characteristic] = gatt_advertisement_byte;
|
||||
latch.CountDown();
|
||||
});
|
||||
latch.Await();
|
||||
}
|
||||
|
||||
bool MediumEnvironment::ContainsBleV2MediumGattCharacteristics(
|
||||
absl::string_view service_uuid, absl::string_view characteristic_uuid) {
|
||||
if (!enabled_) return false;
|
||||
bool found_characteristic = false;
|
||||
CountDownLatch latch(1);
|
||||
RunOnMediumEnvironmentThread([this, &latch, &service_uuid,
|
||||
&characteristic_uuid, &found_characteristic]() {
|
||||
for (const auto& item : gatt_advertisement_bytes_) {
|
||||
if (service_uuid == item.first.service_uuid) {
|
||||
if (characteristic_uuid.empty()) {
|
||||
// Found the service uuid and no need to search characteristic
|
||||
// uuid.
|
||||
found_characteristic = true;
|
||||
break;
|
||||
}
|
||||
if (characteristic_uuid == item.first.uuid) {
|
||||
found_characteristic = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
latch.CountDown();
|
||||
});
|
||||
latch.Await();
|
||||
return found_characteristic;
|
||||
}
|
||||
|
||||
ByteArray MediumEnvironment::ReadBleV2MediumGattCharacteristics(
|
||||
const api::ble_v2::GattCharacteristic& characteristic) {
|
||||
if (!enabled_) return {};
|
||||
ByteArray gatt_advertisement_byte = {};
|
||||
CountDownLatch latch(1);
|
||||
RunOnMediumEnvironmentThread(
|
||||
[this, &latch, &characteristic, &gatt_advertisement_byte]() {
|
||||
auto it = gatt_advertisement_bytes_.find(characteristic);
|
||||
if (it != gatt_advertisement_bytes_.end()) {
|
||||
gatt_advertisement_byte = it->second;
|
||||
}
|
||||
latch.CountDown();
|
||||
});
|
||||
latch.Await();
|
||||
return gatt_advertisement_byte;
|
||||
}
|
||||
|
||||
void MediumEnvironment::ClearBleV2MediumGattCharacteristics() {
|
||||
if (!enabled_) return;
|
||||
RunOnMediumEnvironmentThread([this]() { gatt_advertisement_bytes_.clear(); });
|
||||
}
|
||||
|
||||
void MediumEnvironment::UnregisterBleV2Medium(api::ble_v2::BleMedium& medium) {
|
||||
if (!enabled_) return;
|
||||
RunOnMediumEnvironmentThread([this, &medium]() {
|
||||
|
||||
@@ -230,9 +230,31 @@ class MediumEnvironment {
|
||||
// This should be called when discoverable state changes.
|
||||
// The `callback` argument should be non-empty if `enabled` is true or empty
|
||||
// if `enabled` is false.
|
||||
void UpdateBleV2MediumForScanning(bool enabled, BleScanCallback callback,
|
||||
void UpdateBleV2MediumForScanning(bool enabled,
|
||||
const std::string& scanning_service_uuid,
|
||||
BleScanCallback callback,
|
||||
api::ble_v2::BleMedium& medium);
|
||||
|
||||
// Inserts the BLE GATT characteristic and its value BleAdvertisement byte
|
||||
// array.
|
||||
void InsertBleV2MediumGattCharacteristics(
|
||||
const api::ble_v2::GattCharacteristic& characteristic,
|
||||
const ByteArray& gatt_advertisement_byte);
|
||||
|
||||
// Check if `service_uuid` and `characteristic_uuid` exists in the map.
|
||||
//
|
||||
// `characteristic_uuid` can be empty and to check `service_uuid` only.
|
||||
bool ContainsBleV2MediumGattCharacteristics(
|
||||
absl::string_view service_uuid, absl::string_view characteristic_uuid);
|
||||
|
||||
// Reads the BLE GATT characteristic value. If the GATT characteristic is not
|
||||
// existed, return empty byte array.
|
||||
ByteArray ReadBleV2MediumGattCharacteristics(
|
||||
const api::ble_v2::GattCharacteristic& characteristic);
|
||||
|
||||
// Clears the map `gatt_advertisement_bytes_`.
|
||||
void ClearBleV2MediumGattCharacteristics();
|
||||
|
||||
// Removes medium-related info. This should correspond to device power off.
|
||||
void UnregisterBleV2Medium(api::ble_v2::BleMedium& mediumum);
|
||||
|
||||
@@ -311,6 +333,7 @@ class MediumEnvironment {
|
||||
BleScanCallback scan_callback = {};
|
||||
api::ble_v2::BlePeripheral* ble_peripheral = nullptr;
|
||||
api::ble_v2::BleAdvertisementData advertisement_data;
|
||||
std::string scanning_service_uuid = {};
|
||||
bool advertising = false;
|
||||
};
|
||||
|
||||
@@ -377,6 +400,9 @@ class MediumEnvironment {
|
||||
absl::flat_hash_map<api::BleMedium*, BleMediumContext> ble_mediums_;
|
||||
absl::flat_hash_map<api::ble_v2::BleMedium*, BleV2MediumContext>
|
||||
ble_v2_mediums_;
|
||||
absl::flat_hash_map<api::ble_v2::GattCharacteristic,
|
||||
location::nearby::ByteArray>
|
||||
gatt_advertisement_bytes_;
|
||||
|
||||
#ifndef NO_WEBRTC
|
||||
// Maps peer id to callback for receiving signaling messages.
|
||||
|
||||
Reference in New Issue
Block a user