mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-14 22:56:12 -04:00
Signed-off-by: Alexey Polyudov <apolyudov@google.com> Change-Id: I8ca8ef4727e289f3c6ea62ad73008ad718096e5d
296 lines
9.2 KiB
C++
296 lines
9.2 KiB
C++
// Copyright 2020 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 "core/internal/mediums/ble.h"
|
|
|
|
#include "platform/synchronized.h"
|
|
|
|
namespace location {
|
|
namespace nearby {
|
|
namespace connections {
|
|
|
|
template <typename Platform>
|
|
const std::int32_t BLE<Platform>::kMaxAdvertisementLength = 512;
|
|
|
|
template <typename Platform>
|
|
BLE<Platform>::BLE(Ptr<BluetoothRadio<Platform>> bluetooth_radio)
|
|
: lock_(Platform::createLock()),
|
|
bluetooth_radio_(bluetooth_radio),
|
|
bluetooth_adapter_(Platform::createBluetoothAdapter()),
|
|
ble_medium_(Platform::createBLEMedium()),
|
|
scanning_info_(),
|
|
advertising_info_(),
|
|
accepting_connections_info_() {}
|
|
|
|
template <typename Platform>
|
|
BLE<Platform>::~BLE() {
|
|
stopAdvertising();
|
|
stopAcceptingConnections();
|
|
stopScanning();
|
|
}
|
|
|
|
template <typename Platform>
|
|
bool BLE<Platform>::isAvailable() {
|
|
Synchronized s(lock_.get());
|
|
|
|
return !ble_medium_.isNull() && !bluetooth_adapter_.isNull();
|
|
}
|
|
|
|
// TODO(ahlee): Add fastPairData for phase 2 of C++ implementation.
|
|
template <typename Platform>
|
|
bool BLE<Platform>::startAdvertising(const string& service_id,
|
|
ConstPtr<ByteArray> advertisement) {
|
|
Synchronized s(lock_.get());
|
|
|
|
// Avoid leaks.
|
|
ScopedPtr<ConstPtr<ByteArray>> scoped_advertisement(advertisement);
|
|
if (scoped_advertisement.isNull() || service_id.empty()) {
|
|
// TODO(ahlee): logger.atSevere().log("Refusing to start BLE advertising
|
|
// because a null parameter was passed in.");
|
|
return false;
|
|
}
|
|
|
|
if (scoped_advertisement->size() > kMaxAdvertisementLength) {
|
|
// TODO(ahlee): logger.atSevere().log("Refusing to start BLE advertising
|
|
// because the advertisement was too long. Expected at most %d bytes but
|
|
// received %d.", kMaxAdvertisementLength, advertisement->size());
|
|
return false;
|
|
}
|
|
|
|
if (isAdvertising()) {
|
|
// TODO(ahlee): logger.atSevere().log("Failed to BLE advertise because we're
|
|
// already advertising.");
|
|
return false;
|
|
}
|
|
|
|
if (!bluetooth_radio_->isEnabled()) {
|
|
// TODO(ahlee): logger.atSevere().log("Can't start BLE advertising because
|
|
// Bluetooth isn't enabled.");
|
|
return false;
|
|
}
|
|
|
|
if (!isAvailable()) {
|
|
// TODO(ahlee): logger.atSevere().log("Can't start BLE advertising because
|
|
// BLE isn't enabled.");
|
|
return false;
|
|
}
|
|
|
|
if (!ble_medium_->startAdvertising(service_id,
|
|
scoped_advertisement.release())) {
|
|
// TODO(ahlee) logger.atSevere().log("Failed to start BLE advertising");
|
|
return false;
|
|
}
|
|
|
|
advertising_info_ = MakePtr(new AdvertisingInfo(service_id));
|
|
return true;
|
|
}
|
|
|
|
template <typename Platform>
|
|
void BLE<Platform>::stopAdvertising() {
|
|
Synchronized s(lock_.get());
|
|
|
|
if (!isAdvertising()) {
|
|
// TODO(ahlee): logger.atDebug().log("Can't turn off BLE advertising because
|
|
// it never started.");
|
|
return;
|
|
}
|
|
|
|
ble_medium_->stopAdvertising(advertising_info_->service_id);
|
|
// Reset our bundle of advertising state to mark that we're no longer
|
|
// advertising.
|
|
advertising_info_.destroy();
|
|
|
|
// TODO(ahlee): logger.atVerbose().log("Turned BLE advertising off");
|
|
}
|
|
|
|
template <typename Platform>
|
|
bool BLE<Platform>::isAdvertising() {
|
|
Synchronized s(lock_.get());
|
|
|
|
return !advertising_info_.isNull();
|
|
}
|
|
|
|
template <typename Platform>
|
|
bool BLE<Platform>::startScanning(
|
|
const string& service_id,
|
|
Ptr<DiscoveredPeripheralCallback> discovered_peripheral_callback) {
|
|
Synchronized s(lock_.get());
|
|
|
|
// Avoid leaks.
|
|
ScopedPtr<Ptr<DiscoveredPeripheralCallback>>
|
|
scoped_discovered_peripheral_callback(discovered_peripheral_callback);
|
|
if (scoped_discovered_peripheral_callback.isNull() || service_id.empty()) {
|
|
// TODO(ahlee): logger.atSevere().log("Refusing to start BLE scanning
|
|
// because a null parameter was passed in.");
|
|
return false;
|
|
}
|
|
|
|
if (isScanning()) {
|
|
// TODO(ahlee): logger.atSevere().log("Refusing to start BLE scanning
|
|
// because we are already scanning.");
|
|
return false;
|
|
}
|
|
|
|
if (!bluetooth_radio_->isEnabled()) {
|
|
// TODO(ahlee): logger.atSevere().log("Can't start BLE scanning because
|
|
// Bluetooth was never turned on");
|
|
return false;
|
|
}
|
|
|
|
if (!isAvailable()) {
|
|
// TODO(ahlee): logger.atSevere().log("Can't start BLE scanning because
|
|
// BLE isn't available.");
|
|
return false;
|
|
}
|
|
|
|
// Avoid leaks.
|
|
ScopedPtr<Ptr<BLEDiscoveredPeripheralCallback>>
|
|
scoped_ble_discovered_peripheral_callback(
|
|
new BLEDiscoveredPeripheralCallback(
|
|
scoped_discovered_peripheral_callback.release()));
|
|
if (!ble_medium_->startScanning(
|
|
service_id, scoped_ble_discovered_peripheral_callback.get())) {
|
|
// TODO(ahlee): logger.atSevere().log("Failed to start BLE scanning.");
|
|
return false;
|
|
}
|
|
|
|
scanning_info_ = MakePtr(new ScanningInfo(
|
|
service_id, scoped_ble_discovered_peripheral_callback.release()));
|
|
return true;
|
|
}
|
|
|
|
template <typename Platform>
|
|
void BLE<Platform>::stopScanning() {
|
|
Synchronized s(lock_.get());
|
|
|
|
if (!isScanning()) {
|
|
// TODO(ahlee): logger.atDebug().log("Can't turn off BLE scanning because we
|
|
// never started scanning.");
|
|
return;
|
|
}
|
|
|
|
ble_medium_->stopScanning(scanning_info_->service_id);
|
|
// Reset our bundle of scanning state to mark that we're no longer scanning.
|
|
scanning_info_.destroy();
|
|
}
|
|
|
|
template <typename Platform>
|
|
bool BLE<Platform>::isScanning() {
|
|
Synchronized s(lock_.get());
|
|
|
|
return !scanning_info_.isNull();
|
|
}
|
|
|
|
template <typename Platform>
|
|
bool BLE<Platform>::startAcceptingConnections(
|
|
const string& service_id,
|
|
Ptr<AcceptedConnectionCallback> accepted_connection_callback) {
|
|
Synchronized s(lock_.get());
|
|
|
|
// Avoid leaks.
|
|
ScopedPtr<Ptr<AcceptedConnectionCallback>>
|
|
scoped_accepted_connection_callback(accepted_connection_callback);
|
|
if (scoped_accepted_connection_callback.isNull() || service_id.empty()) {
|
|
// TODO(ahlee): logger.atSevere().log("Refusing to start accepting BLE
|
|
// connections because a null parameter was passed in.");
|
|
return false;
|
|
}
|
|
|
|
if (isAcceptingConnections()) {
|
|
// TODO(ahlee): logger.atSevere().log("Refusing to start accepting BLE
|
|
// connections for %s because another BLE server socket is already
|
|
// in-progress.", service_id);
|
|
return false;
|
|
}
|
|
|
|
if (!bluetooth_radio_->isEnabled()) {
|
|
// TODO(ahlee): logger.atSevere().log("Can't start accepting BLE connections
|
|
// for %s because Bluetooth isn't enabled.", serviceId);
|
|
return false;
|
|
}
|
|
|
|
if (!isAvailable()) {
|
|
// TODO(ahlee): logger.atSevere().log("Can't start accepting BLE connections
|
|
// for %s because BLE isn't available.", serviceId);
|
|
return false;
|
|
}
|
|
|
|
// Avoid leaks.
|
|
ScopedPtr<Ptr<BLEAcceptedConnectionCallback>>
|
|
scoped_ble_accepted_connection_callback(new BLEAcceptedConnectionCallback(
|
|
scoped_accepted_connection_callback.release()));
|
|
if (!ble_medium_->startAcceptingConnections(
|
|
service_id, scoped_ble_accepted_connection_callback.get())) {
|
|
return false;
|
|
}
|
|
|
|
accepting_connections_info_ = MakePtr(new AcceptingConnectionsInfo(
|
|
service_id, scoped_ble_accepted_connection_callback.release()));
|
|
return true;
|
|
}
|
|
|
|
template <typename Platform>
|
|
void BLE<Platform>::stopAcceptingConnections() {
|
|
Synchronized s(lock_.get());
|
|
|
|
if (!isAcceptingConnections()) {
|
|
// TODO(ahlee): logger.atDebug().log("Can't stop accepting BLE connections
|
|
// because it was never started.");
|
|
return;
|
|
}
|
|
|
|
ble_medium_->stopAcceptingConnections(
|
|
accepting_connections_info_->service_id);
|
|
// Reset our bundle of accepting connections state to mark that we're no
|
|
// longer accepting connections.
|
|
accepting_connections_info_.destroy();
|
|
}
|
|
|
|
template <typename Platform>
|
|
bool BLE<Platform>::isAcceptingConnections() {
|
|
Synchronized s(lock_.get());
|
|
|
|
return !accepting_connections_info_.isNull();
|
|
}
|
|
|
|
template <typename Platform>
|
|
Ptr<BLESocket> BLE<Platform>::connect(Ptr<BLEPeripheral> ble_peripheral,
|
|
const string& service_id) {
|
|
Synchronized s(lock_.get());
|
|
|
|
if (ble_peripheral.isNull() || service_id.empty()) {
|
|
// TODO(ahlee): logger.atSevere().log("Refusing to create client BLE socket
|
|
// because at least one of blePeripheral or serviceId is null.");
|
|
return Ptr<BLESocket>();
|
|
}
|
|
|
|
if (!bluetooth_radio_->isEnabled()) {
|
|
// TODO(ahlee): logger.atSevere().log("Can't create client BLE socket to %s
|
|
// because Bluetooth isn't enabled.", blePeripheral);
|
|
return Ptr<BLESocket>();
|
|
}
|
|
|
|
if (!isAvailable()) {
|
|
// TODO(ahlee): logger.atSevere().log("Can't create client BLE socket to %s
|
|
// because BLE isn't available.", blePeripheral);
|
|
return Ptr<BLESocket>();
|
|
}
|
|
|
|
return ble_medium_->connect(ble_peripheral, service_id);
|
|
}
|
|
|
|
} // namespace connections
|
|
} // namespace nearby
|
|
} // namespace location
|