Files
nearby/cpp/core/internal/mediums/ble.cc
T
Alexey Polyudov c3a89bb894 Generate OSS-ready HEAD from master
Signed-off-by: Alexey Polyudov <apolyudov@google.com>
Change-Id: I8ca8ef4727e289f3c6ea62ad73008ad718096e5d
2020-05-04 13:14:50 -07:00

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