You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1213 lines
51 KiB
1213 lines
51 KiB
/*
|
|
* Copyright 2019 The Android Open Source Project
|
|
*
|
|
* 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
|
|
*
|
|
* http://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 "hci/le_advertising_manager.h"
|
|
|
|
#include <algorithm>
|
|
#include <chrono>
|
|
#include <future>
|
|
#include <map>
|
|
|
|
#include <gmock/gmock.h>
|
|
#include <gtest/gtest.h>
|
|
|
|
#include "common/bind.h"
|
|
#include "hci/acl_manager.h"
|
|
#include "hci/address.h"
|
|
#include "hci/controller.h"
|
|
#include "hci/hci_layer.h"
|
|
#include "os/thread.h"
|
|
#include "packet/raw_builder.h"
|
|
|
|
namespace bluetooth {
|
|
namespace hci {
|
|
namespace {
|
|
|
|
using packet::kLittleEndian;
|
|
using packet::PacketView;
|
|
using packet::RawBuilder;
|
|
|
|
PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet) {
|
|
auto bytes = std::make_shared<std::vector<uint8_t>>();
|
|
BitInserter i(*bytes);
|
|
bytes->reserve(packet->size());
|
|
packet->Serialize(i);
|
|
return packet::PacketView<packet::kLittleEndian>(bytes);
|
|
}
|
|
|
|
class TestController : public Controller {
|
|
public:
|
|
bool IsSupported(OpCode op_code) const override {
|
|
return supported_opcodes_.count(op_code) == 1;
|
|
}
|
|
|
|
void AddSupported(OpCode op_code) {
|
|
supported_opcodes_.insert(op_code);
|
|
}
|
|
|
|
uint8_t GetLeNumberOfSupportedAdverisingSets() const override {
|
|
return num_advertisers;
|
|
}
|
|
|
|
uint16_t GetLeMaximumAdvertisingDataLength() const override {
|
|
return 0x0672;
|
|
}
|
|
|
|
uint8_t num_advertisers{0};
|
|
|
|
protected:
|
|
void Start() override {}
|
|
void Stop() override {}
|
|
void ListDependencies(ModuleList* list) override {}
|
|
|
|
private:
|
|
std::set<OpCode> supported_opcodes_{};
|
|
};
|
|
|
|
class TestHciLayer : public HciLayer {
|
|
public:
|
|
void EnqueueCommand(
|
|
std::unique_ptr<CommandBuilder> command,
|
|
common::ContextualOnceCallback<void(CommandStatusView)> on_status) override {
|
|
auto packet_view = CommandView::Create(GetPacketView(std::move(command)));
|
|
ASSERT_TRUE(packet_view.IsValid());
|
|
std::lock_guard<std::mutex> lock(mutex_);
|
|
command_queue_.push_back(packet_view);
|
|
command_status_callbacks.push_back(std::move(on_status));
|
|
if (command_promise_ != nullptr &&
|
|
(command_op_code_ == OpCode::NONE || command_op_code_ == packet_view.GetOpCode())) {
|
|
if (command_op_code_ == OpCode::LE_MULTI_ADVT && command_sub_ocf_ != SubOcf::SET_ENABLE) {
|
|
return;
|
|
}
|
|
command_promise_->set_value(command_queue_.size());
|
|
command_promise_.reset();
|
|
}
|
|
}
|
|
|
|
void EnqueueCommand(
|
|
std::unique_ptr<CommandBuilder> command,
|
|
common::ContextualOnceCallback<void(CommandCompleteView)> on_complete) override {
|
|
auto packet_view = CommandView::Create(GetPacketView(std::move(command)));
|
|
ASSERT_TRUE(packet_view.IsValid());
|
|
std::lock_guard<std::mutex> lock(mutex_);
|
|
command_queue_.push_back(packet_view);
|
|
command_complete_callbacks.push_back(std::move(on_complete));
|
|
if (command_promise_ != nullptr &&
|
|
(command_op_code_ == OpCode::NONE || command_op_code_ == packet_view.GetOpCode())) {
|
|
if (command_op_code_ == OpCode::LE_MULTI_ADVT) {
|
|
auto sub_view = LeMultiAdvtView::Create(LeAdvertisingCommandView::Create(packet_view));
|
|
ASSERT_TRUE(sub_view.IsValid());
|
|
if (sub_view.GetSubCmd() != command_sub_ocf_) {
|
|
return;
|
|
}
|
|
}
|
|
command_promise_->set_value(command_queue_.size());
|
|
command_promise_.reset();
|
|
}
|
|
}
|
|
|
|
void SetCommandFuture(OpCode op_code = OpCode::NONE) {
|
|
ASSERT_LOG(command_promise_ == nullptr, "Promises, Promises, ... Only one at a time.");
|
|
command_op_code_ = op_code;
|
|
command_promise_ = std::make_unique<std::promise<size_t>>();
|
|
command_future_ = std::make_unique<std::future<size_t>>(command_promise_->get_future());
|
|
}
|
|
|
|
void ResetCommandFuture() {
|
|
if (command_future_ != nullptr) {
|
|
command_future_.reset();
|
|
command_promise_.reset();
|
|
}
|
|
}
|
|
|
|
void SetSubCommandFuture(SubOcf sub_ocf) {
|
|
ASSERT_LOG(command_promise_ == nullptr, "Promises promises ... Only one at a time");
|
|
command_op_code_ = OpCode::LE_MULTI_ADVT;
|
|
command_sub_ocf_ = sub_ocf;
|
|
command_promise_ = std::make_unique<std::promise<size_t>>();
|
|
command_future_ = std::make_unique<std::future<size_t>>(command_promise_->get_future());
|
|
}
|
|
|
|
ConnectionManagementCommandView GetCommand(OpCode op_code) {
|
|
if (!command_queue_.empty()) {
|
|
std::lock_guard<std::mutex> lock(mutex_);
|
|
if (command_future_ != nullptr) {
|
|
command_future_.reset();
|
|
command_promise_.reset();
|
|
}
|
|
} else if (command_future_ != nullptr) {
|
|
auto result = command_future_->wait_for(std::chrono::milliseconds(1000));
|
|
EXPECT_NE(std::future_status::timeout, result);
|
|
}
|
|
ASSERT_LOG(
|
|
!command_queue_.empty(), "Expecting command %s but command queue was empty", OpCodeText(op_code).c_str());
|
|
std::lock_guard<std::mutex> lock(mutex_);
|
|
CommandView command_packet_view = CommandView::Create(command_queue_.front());
|
|
command_queue_.pop_front();
|
|
auto command = ConnectionManagementCommandView::Create(AclCommandView::Create(command_packet_view));
|
|
EXPECT_TRUE(command.IsValid());
|
|
EXPECT_EQ(command.GetOpCode(), op_code);
|
|
|
|
return command;
|
|
}
|
|
|
|
void RegisterEventHandler(EventCode event_code, common::ContextualCallback<void(EventView)> event_handler) override {
|
|
registered_events_[event_code] = event_handler;
|
|
}
|
|
|
|
void RegisterLeEventHandler(SubeventCode subevent_code,
|
|
common::ContextualCallback<void(LeMetaEventView)> event_handler) override {
|
|
registered_le_events_[subevent_code] = event_handler;
|
|
}
|
|
|
|
void IncomingEvent(std::unique_ptr<EventBuilder> event_builder) {
|
|
auto packet = GetPacketView(std::move(event_builder));
|
|
EventView event = EventView::Create(packet);
|
|
ASSERT_TRUE(event.IsValid());
|
|
EventCode event_code = event.GetEventCode();
|
|
ASSERT_NE(registered_events_.find(event_code), registered_events_.end()) << EventCodeText(event_code);
|
|
registered_events_[event_code].Invoke(event);
|
|
}
|
|
|
|
void IncomingLeMetaEvent(std::unique_ptr<LeMetaEventBuilder> event_builder) {
|
|
auto packet = GetPacketView(std::move(event_builder));
|
|
EventView event = EventView::Create(packet);
|
|
LeMetaEventView meta_event_view = LeMetaEventView::Create(event);
|
|
ASSERT_TRUE(meta_event_view.IsValid());
|
|
SubeventCode subevent_code = meta_event_view.GetSubeventCode();
|
|
ASSERT_NE(registered_le_events_.find(subevent_code), registered_le_events_.end())
|
|
<< SubeventCodeText(subevent_code);
|
|
registered_le_events_[subevent_code].Invoke(meta_event_view);
|
|
}
|
|
|
|
void CommandCompleteCallback(EventView event) {
|
|
CommandCompleteView complete_view = CommandCompleteView::Create(event);
|
|
ASSERT_TRUE(complete_view.IsValid());
|
|
std::move(command_complete_callbacks.front()).Invoke(complete_view);
|
|
command_complete_callbacks.pop_front();
|
|
}
|
|
|
|
void CommandStatusCallback(EventView event) {
|
|
CommandStatusView status_view = CommandStatusView::Create(event);
|
|
ASSERT_TRUE(status_view.IsValid());
|
|
std::move(command_status_callbacks.front()).Invoke(status_view);
|
|
command_status_callbacks.pop_front();
|
|
}
|
|
|
|
void ListDependencies(ModuleList* list) override {}
|
|
void Start() override {
|
|
RegisterEventHandler(EventCode::COMMAND_COMPLETE,
|
|
GetHandler()->BindOn(this, &TestHciLayer::CommandCompleteCallback));
|
|
RegisterEventHandler(EventCode::COMMAND_STATUS, GetHandler()->BindOn(this, &TestHciLayer::CommandStatusCallback));
|
|
}
|
|
void Stop() override {}
|
|
|
|
private:
|
|
std::map<EventCode, common::ContextualCallback<void(EventView)>> registered_events_;
|
|
std::map<SubeventCode, common::ContextualCallback<void(LeMetaEventView)>> registered_le_events_;
|
|
std::list<common::ContextualOnceCallback<void(CommandCompleteView)>> command_complete_callbacks;
|
|
std::list<common::ContextualOnceCallback<void(CommandStatusView)>> command_status_callbacks;
|
|
|
|
std::list<CommandView> command_queue_;
|
|
mutable std::mutex mutex_;
|
|
std::unique_ptr<std::promise<size_t>> command_promise_{};
|
|
std::unique_ptr<std::future<size_t>> command_future_{};
|
|
OpCode command_op_code_;
|
|
SubOcf command_sub_ocf_;
|
|
};
|
|
|
|
class TestLeAddressManager : public LeAddressManager {
|
|
public:
|
|
TestLeAddressManager(
|
|
common::Callback<void(std::unique_ptr<CommandBuilder>)> enqueue_command,
|
|
os::Handler* handler,
|
|
Address public_address,
|
|
uint8_t connect_list_size,
|
|
uint8_t resolving_list_size)
|
|
: LeAddressManager(enqueue_command, handler, public_address, connect_list_size, resolving_list_size) {}
|
|
|
|
AddressPolicy Register(LeAddressManagerCallback* callback) override {
|
|
return AddressPolicy::USE_STATIC_ADDRESS;
|
|
}
|
|
|
|
void Unregister(LeAddressManagerCallback* callback) override {}
|
|
|
|
AddressWithType GetAnotherAddress() override {
|
|
hci::Address address;
|
|
Address::FromString("05:04:03:02:01:00", address);
|
|
auto random_address = AddressWithType(address, AddressType::RANDOM_DEVICE_ADDRESS);
|
|
return random_address;
|
|
}
|
|
};
|
|
|
|
class TestAclManager : public AclManager {
|
|
public:
|
|
LeAddressManager* GetLeAddressManager() override {
|
|
return test_le_address_manager_;
|
|
}
|
|
|
|
protected:
|
|
void Start() override {
|
|
thread_ = new os::Thread("thread", os::Thread::Priority::NORMAL);
|
|
handler_ = new os::Handler(thread_);
|
|
Address address({0x01, 0x02, 0x03, 0x04, 0x05, 0x06});
|
|
test_le_address_manager_ = new TestLeAddressManager(
|
|
common::Bind(&TestAclManager::enqueue_command, common::Unretained(this)), handler_, address, 0x3F, 0x3F);
|
|
}
|
|
|
|
void Stop() override {
|
|
delete test_le_address_manager_;
|
|
handler_->Clear();
|
|
delete handler_;
|
|
delete thread_;
|
|
}
|
|
|
|
void ListDependencies(ModuleList* list) override {}
|
|
|
|
void SetRandomAddress(Address address) {}
|
|
|
|
void enqueue_command(std::unique_ptr<CommandBuilder> command_packet){};
|
|
|
|
os::Thread* thread_;
|
|
os::Handler* handler_;
|
|
TestLeAddressManager* test_le_address_manager_;
|
|
};
|
|
|
|
class LeAdvertisingManagerTest : public ::testing::Test {
|
|
protected:
|
|
void SetUp() override {
|
|
test_hci_layer_ = new TestHciLayer; // Ownership is transferred to registry
|
|
test_controller_ = new TestController;
|
|
test_acl_manager_ = new TestAclManager;
|
|
test_controller_->AddSupported(param_opcode_);
|
|
fake_registry_.InjectTestModule(&HciLayer::Factory, test_hci_layer_);
|
|
fake_registry_.InjectTestModule(&Controller::Factory, test_controller_);
|
|
fake_registry_.InjectTestModule(&AclManager::Factory, test_acl_manager_);
|
|
client_handler_ = fake_registry_.GetTestModuleHandler(&HciLayer::Factory);
|
|
ASSERT_NE(client_handler_, nullptr);
|
|
test_controller_->num_advertisers = 1;
|
|
le_advertising_manager_ = fake_registry_.Start<LeAdvertisingManager>(&thread_);
|
|
le_advertising_manager_->RegisterAdvertisingCallback(&mock_advertising_callback_);
|
|
}
|
|
|
|
void TearDown() override {
|
|
fake_registry_.SynchronizeModuleHandler(&LeAdvertisingManager::Factory, std::chrono::milliseconds(20));
|
|
fake_registry_.StopAll();
|
|
}
|
|
|
|
TestModuleRegistry fake_registry_;
|
|
TestHciLayer* test_hci_layer_ = nullptr;
|
|
TestController* test_controller_ = nullptr;
|
|
TestAclManager* test_acl_manager_ = nullptr;
|
|
os::Thread& thread_ = fake_registry_.GetTestThread();
|
|
LeAdvertisingManager* le_advertising_manager_ = nullptr;
|
|
os::Handler* client_handler_ = nullptr;
|
|
|
|
const common::Callback<void(Address, AddressType)> scan_callback =
|
|
common::Bind(&LeAdvertisingManagerTest::on_scan, common::Unretained(this));
|
|
const common::Callback<void(ErrorCode, uint8_t, uint8_t)> set_terminated_callback =
|
|
common::Bind(&LeAdvertisingManagerTest::on_set_terminated, common::Unretained(this));
|
|
|
|
std::future<Address> GetOnScanPromise() {
|
|
ASSERT_LOG(address_promise_ == nullptr, "Promises promises ... Only one at a time");
|
|
address_promise_ = std::make_unique<std::promise<Address>>();
|
|
return address_promise_->get_future();
|
|
}
|
|
void on_scan(Address address, AddressType address_type) {
|
|
if (address_promise_ == nullptr) {
|
|
return;
|
|
}
|
|
address_promise_->set_value(address);
|
|
address_promise_.reset();
|
|
}
|
|
|
|
std::future<ErrorCode> GetSetTerminatedPromise() {
|
|
ASSERT_LOG(set_terminated_promise_ == nullptr, "Promises promises ... Only one at a time");
|
|
set_terminated_promise_ = std::make_unique<std::promise<ErrorCode>>();
|
|
return set_terminated_promise_->get_future();
|
|
}
|
|
void on_set_terminated(ErrorCode error_code, uint8_t, uint8_t) {
|
|
if (set_terminated_promise_ != nullptr) {
|
|
return;
|
|
}
|
|
set_terminated_promise_->set_value(error_code);
|
|
set_terminated_promise_.reset();
|
|
}
|
|
|
|
void sync_client_handler() {
|
|
std::promise<void> promise;
|
|
auto future = promise.get_future();
|
|
client_handler_->Call(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
|
|
auto future_status = future.wait_for(std::chrono::seconds(1));
|
|
ASSERT_EQ(future_status, std::future_status::ready);
|
|
}
|
|
|
|
std::unique_ptr<std::promise<Address>> address_promise_{};
|
|
std::unique_ptr<std::promise<ErrorCode>> set_terminated_promise_{};
|
|
|
|
OpCode param_opcode_{OpCode::LE_SET_ADVERTISING_PARAMETERS};
|
|
|
|
class MockAdvertisingCallback : public AdvertisingCallback {
|
|
public:
|
|
MOCK_METHOD4(
|
|
OnAdvertisingSetStarted, void(int reg_id, uint8_t advertiser_id, int8_t tx_power, AdvertisingStatus status));
|
|
MOCK_METHOD3(OnAdvertisingEnabled, void(uint8_t advertiser_id, bool enable, uint8_t status));
|
|
MOCK_METHOD2(OnAdvertisingDataSet, void(uint8_t advertiser_id, uint8_t status));
|
|
MOCK_METHOD2(OnScanResponseDataSet, void(uint8_t advertiser_id, uint8_t status));
|
|
MOCK_METHOD3(OnAdvertisingParametersUpdated, void(uint8_t advertiser_id, int8_t tx_power, uint8_t status));
|
|
MOCK_METHOD2(OnPeriodicAdvertisingParametersUpdated, void(uint8_t advertiser_id, uint8_t status));
|
|
MOCK_METHOD2(OnPeriodicAdvertisingDataSet, void(uint8_t advertiser_id, uint8_t status));
|
|
MOCK_METHOD3(OnPeriodicAdvertisingEnabled, void(uint8_t advertiser_id, bool enable, uint8_t status));
|
|
} mock_advertising_callback_;
|
|
};
|
|
|
|
class LeAdvertisingAPITest : public LeAdvertisingManagerTest {
|
|
protected:
|
|
void SetUp() override {
|
|
LeAdvertisingManagerTest::SetUp();
|
|
|
|
// start advertising set
|
|
ExtendedAdvertisingConfig advertising_config{};
|
|
advertising_config.advertising_type = AdvertisingType::ADV_IND;
|
|
advertising_config.own_address_type = OwnAddressType::PUBLIC_DEVICE_ADDRESS;
|
|
std::vector<GapData> gap_data{};
|
|
GapData data_item{};
|
|
data_item.data_type_ = GapDataType::FLAGS;
|
|
data_item.data_ = {0x34};
|
|
gap_data.push_back(data_item);
|
|
data_item.data_type_ = GapDataType::COMPLETE_LOCAL_NAME;
|
|
data_item.data_ = {'r', 'a', 'n', 'd', 'o', 'm', ' ', 'd', 'e', 'v', 'i', 'c', 'e'};
|
|
gap_data.push_back(data_item);
|
|
advertising_config.advertisement = gap_data;
|
|
advertising_config.scan_response = gap_data;
|
|
|
|
test_hci_layer_->SetCommandFuture();
|
|
advertiser_id_ = le_advertising_manager_->ExtendedCreateAdvertiser(
|
|
0x00, advertising_config, scan_callback, set_terminated_callback, 0, 0, client_handler_);
|
|
ASSERT_NE(LeAdvertisingManager::kInvalidId, advertiser_id_);
|
|
EXPECT_CALL(
|
|
mock_advertising_callback_,
|
|
OnAdvertisingSetStarted(0x00, advertiser_id_, 0x00, AdvertisingCallback::AdvertisingStatus::SUCCESS));
|
|
std::vector<OpCode> adv_opcodes = {
|
|
OpCode::LE_READ_ADVERTISING_PHYSICAL_CHANNEL_TX_POWER,
|
|
OpCode::LE_SET_ADVERTISING_PARAMETERS,
|
|
OpCode::LE_SET_SCAN_RESPONSE_DATA,
|
|
OpCode::LE_SET_ADVERTISING_DATA,
|
|
OpCode::LE_SET_ADVERTISING_ENABLE,
|
|
};
|
|
std::vector<uint8_t> success_vector{static_cast<uint8_t>(ErrorCode::SUCCESS)};
|
|
for (size_t i = 0; i < adv_opcodes.size(); i++) {
|
|
auto packet_view = test_hci_layer_->GetCommand(adv_opcodes[i]);
|
|
CommandView command_packet_view = CommandView::Create(packet_view);
|
|
if (adv_opcodes[i] == OpCode::LE_READ_ADVERTISING_PHYSICAL_CHANNEL_TX_POWER) {
|
|
test_hci_layer_->IncomingEvent(
|
|
LeReadAdvertisingPhysicalChannelTxPowerCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS, 0x00));
|
|
} else {
|
|
test_hci_layer_->IncomingEvent(
|
|
CommandCompleteBuilder::Create(uint8_t{1}, adv_opcodes[i], std::make_unique<RawBuilder>(success_vector)));
|
|
}
|
|
test_hci_layer_->SetCommandFuture();
|
|
}
|
|
sync_client_handler();
|
|
test_hci_layer_->ResetCommandFuture();
|
|
}
|
|
|
|
AdvertiserId advertiser_id_;
|
|
};
|
|
|
|
class LeAndroidHciAdvertisingManagerTest : public LeAdvertisingManagerTest {
|
|
protected:
|
|
void SetUp() override {
|
|
param_opcode_ = OpCode::LE_MULTI_ADVT;
|
|
LeAdvertisingManagerTest::SetUp();
|
|
test_controller_->num_advertisers = 3;
|
|
}
|
|
};
|
|
|
|
class LeAndroidHciAdvertisingAPITest : public LeAndroidHciAdvertisingManagerTest {
|
|
protected:
|
|
void SetUp() override {
|
|
LeAndroidHciAdvertisingManagerTest::SetUp();
|
|
|
|
ExtendedAdvertisingConfig advertising_config{};
|
|
advertising_config.advertising_type = AdvertisingType::ADV_IND;
|
|
advertising_config.own_address_type = OwnAddressType::PUBLIC_DEVICE_ADDRESS;
|
|
std::vector<GapData> gap_data{};
|
|
GapData data_item{};
|
|
data_item.data_type_ = GapDataType::FLAGS;
|
|
data_item.data_ = {0x34};
|
|
gap_data.push_back(data_item);
|
|
data_item.data_type_ = GapDataType::COMPLETE_LOCAL_NAME;
|
|
data_item.data_ = {'r', 'a', 'n', 'd', 'o', 'm', ' ', 'd', 'e', 'v', 'i', 'c', 'e'};
|
|
gap_data.push_back(data_item);
|
|
advertising_config.advertisement = gap_data;
|
|
advertising_config.scan_response = gap_data;
|
|
|
|
test_hci_layer_->SetSubCommandFuture(SubOcf::SET_PARAM);
|
|
advertiser_id_ = le_advertising_manager_->ExtendedCreateAdvertiser(
|
|
0x00, advertising_config, scan_callback, set_terminated_callback, 0, 0, client_handler_);
|
|
ASSERT_NE(LeAdvertisingManager::kInvalidId, advertiser_id_);
|
|
std::vector<SubOcf> sub_ocf = {
|
|
SubOcf::SET_PARAM,
|
|
SubOcf::SET_DATA,
|
|
SubOcf::SET_SCAN_RESP,
|
|
SubOcf::SET_RANDOM_ADDR,
|
|
SubOcf::SET_ENABLE,
|
|
};
|
|
EXPECT_CALL(
|
|
mock_advertising_callback_,
|
|
OnAdvertisingSetStarted(0, advertiser_id_, 0, AdvertisingCallback::AdvertisingStatus::SUCCESS));
|
|
for (size_t i = 0; i < sub_ocf.size(); i++) {
|
|
auto packet = test_hci_layer_->GetCommand(OpCode::LE_MULTI_ADVT);
|
|
auto sub_packet = LeMultiAdvtView::Create(LeAdvertisingCommandView::Create(packet));
|
|
ASSERT_TRUE(sub_packet.IsValid());
|
|
test_hci_layer_->IncomingEvent(LeMultiAdvtCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS, sub_ocf[i]));
|
|
if ((i + 1) < sub_ocf.size()) {
|
|
test_hci_layer_->SetSubCommandFuture(sub_ocf[i + 1]);
|
|
}
|
|
}
|
|
sync_client_handler();
|
|
}
|
|
|
|
AdvertiserId advertiser_id_;
|
|
};
|
|
|
|
class LeExtendedAdvertisingManagerTest : public LeAdvertisingManagerTest {
|
|
protected:
|
|
void SetUp() override {
|
|
param_opcode_ = OpCode::LE_SET_EXTENDED_ADVERTISING_PARAMETERS;
|
|
LeAdvertisingManagerTest::SetUp();
|
|
test_controller_->num_advertisers = 5;
|
|
}
|
|
};
|
|
|
|
class LeExtendedAdvertisingAPITest : public LeExtendedAdvertisingManagerTest {
|
|
protected:
|
|
void SetUp() override {
|
|
LeExtendedAdvertisingManagerTest::SetUp();
|
|
|
|
// start advertising set
|
|
ExtendedAdvertisingConfig advertising_config{};
|
|
advertising_config.advertising_type = AdvertisingType::ADV_IND;
|
|
advertising_config.own_address_type = OwnAddressType::PUBLIC_DEVICE_ADDRESS;
|
|
std::vector<GapData> gap_data{};
|
|
GapData data_item{};
|
|
data_item.data_type_ = GapDataType::FLAGS;
|
|
data_item.data_ = {0x34};
|
|
gap_data.push_back(data_item);
|
|
data_item.data_type_ = GapDataType::COMPLETE_LOCAL_NAME;
|
|
data_item.data_ = {'r', 'a', 'n', 'd', 'o', 'm', ' ', 'd', 'e', 'v', 'i', 'c', 'e'};
|
|
gap_data.push_back(data_item);
|
|
advertising_config.advertisement = gap_data;
|
|
advertising_config.scan_response = gap_data;
|
|
advertising_config.channel_map = 1;
|
|
advertising_config.sid = 0x01;
|
|
|
|
test_hci_layer_->SetCommandFuture();
|
|
advertiser_id_ = le_advertising_manager_->ExtendedCreateAdvertiser(
|
|
0x00, advertising_config, scan_callback, set_terminated_callback, 0, 0, client_handler_);
|
|
ASSERT_NE(LeAdvertisingManager::kInvalidId, advertiser_id_);
|
|
EXPECT_CALL(
|
|
mock_advertising_callback_,
|
|
OnAdvertisingSetStarted(0x00, advertiser_id_, -23, AdvertisingCallback::AdvertisingStatus::SUCCESS));
|
|
std::vector<OpCode> adv_opcodes = {
|
|
OpCode::LE_SET_EXTENDED_ADVERTISING_PARAMETERS,
|
|
OpCode::LE_SET_EXTENDED_ADVERTISING_SCAN_RESPONSE,
|
|
OpCode::LE_SET_EXTENDED_ADVERTISING_DATA,
|
|
OpCode::LE_SET_EXTENDED_ADVERTISING_ENABLE,
|
|
};
|
|
std::vector<uint8_t> success_vector{static_cast<uint8_t>(ErrorCode::SUCCESS)};
|
|
for (size_t i = 0; i < adv_opcodes.size(); i++) {
|
|
auto packet_view = test_hci_layer_->GetCommand(adv_opcodes[i]);
|
|
CommandView command_packet_view = CommandView::Create(packet_view);
|
|
auto command = ConnectionManagementCommandView::Create(AclCommandView::Create(command_packet_view));
|
|
if (adv_opcodes[i] == OpCode::LE_SET_EXTENDED_ADVERTISING_PARAMETERS) {
|
|
test_hci_layer_->IncomingEvent(LeSetExtendedAdvertisingParametersCompleteBuilder::Create(
|
|
uint8_t{1}, ErrorCode::SUCCESS, static_cast<uint8_t>(-23)));
|
|
} else {
|
|
test_hci_layer_->IncomingEvent(
|
|
CommandCompleteBuilder::Create(uint8_t{1}, adv_opcodes[i], std::make_unique<RawBuilder>(success_vector)));
|
|
}
|
|
test_hci_layer_->SetCommandFuture();
|
|
}
|
|
sync_client_handler();
|
|
test_hci_layer_->ResetCommandFuture();
|
|
}
|
|
|
|
AdvertiserId advertiser_id_;
|
|
};
|
|
|
|
TEST_F(LeAdvertisingManagerTest, startup_teardown) {}
|
|
|
|
TEST_F(LeAndroidHciAdvertisingManagerTest, startup_teardown) {}
|
|
|
|
TEST_F(LeExtendedAdvertisingManagerTest, startup_teardown) {}
|
|
|
|
TEST_F(LeAdvertisingManagerTest, create_advertiser_test) {
|
|
ExtendedAdvertisingConfig advertising_config{};
|
|
advertising_config.advertising_type = AdvertisingType::ADV_IND;
|
|
advertising_config.own_address_type = OwnAddressType::PUBLIC_DEVICE_ADDRESS;
|
|
std::vector<GapData> gap_data{};
|
|
GapData data_item{};
|
|
data_item.data_type_ = GapDataType::FLAGS;
|
|
data_item.data_ = {0x34};
|
|
gap_data.push_back(data_item);
|
|
data_item.data_type_ = GapDataType::COMPLETE_LOCAL_NAME;
|
|
data_item.data_ = {'r', 'a', 'n', 'd', 'o', 'm', ' ', 'd', 'e', 'v', 'i', 'c', 'e'};
|
|
gap_data.push_back(data_item);
|
|
advertising_config.advertisement = gap_data;
|
|
advertising_config.scan_response = gap_data;
|
|
|
|
test_hci_layer_->SetCommandFuture();
|
|
auto id = le_advertising_manager_->ExtendedCreateAdvertiser(
|
|
0x00, advertising_config, scan_callback, set_terminated_callback, 0, 0, client_handler_);
|
|
ASSERT_NE(LeAdvertisingManager::kInvalidId, id);
|
|
std::vector<OpCode> adv_opcodes = {
|
|
OpCode::LE_READ_ADVERTISING_PHYSICAL_CHANNEL_TX_POWER,
|
|
OpCode::LE_SET_ADVERTISING_PARAMETERS,
|
|
OpCode::LE_SET_SCAN_RESPONSE_DATA,
|
|
OpCode::LE_SET_ADVERTISING_DATA,
|
|
OpCode::LE_SET_ADVERTISING_ENABLE,
|
|
};
|
|
EXPECT_CALL(
|
|
mock_advertising_callback_,
|
|
OnAdvertisingSetStarted(0x00, id, 0x00, AdvertisingCallback::AdvertisingStatus::SUCCESS));
|
|
std::vector<uint8_t> success_vector{static_cast<uint8_t>(ErrorCode::SUCCESS)};
|
|
for (size_t i = 0; i < adv_opcodes.size(); i++) {
|
|
auto packet_view = test_hci_layer_->GetCommand(adv_opcodes[i]);
|
|
CommandView command_packet_view = CommandView::Create(packet_view);
|
|
auto command = ConnectionManagementCommandView::Create(AclCommandView::Create(command_packet_view));
|
|
if (adv_opcodes[i] == OpCode::LE_READ_ADVERTISING_PHYSICAL_CHANNEL_TX_POWER) {
|
|
test_hci_layer_->IncomingEvent(
|
|
LeReadAdvertisingPhysicalChannelTxPowerCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS, 0x00));
|
|
} else {
|
|
test_hci_layer_->IncomingEvent(
|
|
CommandCompleteBuilder::Create(uint8_t{1}, adv_opcodes[i], std::make_unique<RawBuilder>(success_vector)));
|
|
}
|
|
test_hci_layer_->SetCommandFuture();
|
|
}
|
|
sync_client_handler();
|
|
|
|
// Disable the advertiser
|
|
le_advertising_manager_->RemoveAdvertiser(id);
|
|
test_hci_layer_->GetCommand(OpCode::LE_SET_ADVERTISING_ENABLE);
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(LeAndroidHciAdvertisingManagerTest, create_advertiser_test) {
|
|
ExtendedAdvertisingConfig advertising_config{};
|
|
advertising_config.advertising_type = AdvertisingType::ADV_IND;
|
|
advertising_config.own_address_type = OwnAddressType::PUBLIC_DEVICE_ADDRESS;
|
|
std::vector<GapData> gap_data{};
|
|
GapData data_item{};
|
|
data_item.data_type_ = GapDataType::FLAGS;
|
|
data_item.data_ = {0x34};
|
|
gap_data.push_back(data_item);
|
|
data_item.data_type_ = GapDataType::COMPLETE_LOCAL_NAME;
|
|
data_item.data_ = {'r', 'a', 'n', 'd', 'o', 'm', ' ', 'd', 'e', 'v', 'i', 'c', 'e'};
|
|
gap_data.push_back(data_item);
|
|
advertising_config.advertisement = gap_data;
|
|
advertising_config.scan_response = gap_data;
|
|
|
|
test_hci_layer_->SetSubCommandFuture(SubOcf::SET_PARAM);
|
|
auto id = le_advertising_manager_->ExtendedCreateAdvertiser(
|
|
0x00, advertising_config, scan_callback, set_terminated_callback, 0, 0, client_handler_);
|
|
ASSERT_NE(LeAdvertisingManager::kInvalidId, id);
|
|
std::vector<SubOcf> sub_ocf = {
|
|
SubOcf::SET_PARAM, SubOcf::SET_DATA, SubOcf::SET_SCAN_RESP, SubOcf::SET_RANDOM_ADDR, SubOcf::SET_ENABLE,
|
|
};
|
|
EXPECT_CALL(
|
|
mock_advertising_callback_, OnAdvertisingSetStarted(0, id, 0, AdvertisingCallback::AdvertisingStatus::SUCCESS));
|
|
for (size_t i = 0; i < sub_ocf.size(); i++) {
|
|
auto packet = test_hci_layer_->GetCommand(OpCode::LE_MULTI_ADVT);
|
|
auto sub_packet = LeMultiAdvtView::Create(LeAdvertisingCommandView::Create(packet));
|
|
ASSERT_TRUE(sub_packet.IsValid());
|
|
test_hci_layer_->IncomingEvent(LeMultiAdvtCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS, sub_ocf[i]));
|
|
if ((i + 1) < sub_ocf.size()) {
|
|
test_hci_layer_->SetSubCommandFuture(sub_ocf[i + 1]);
|
|
}
|
|
}
|
|
sync_client_handler();
|
|
|
|
// Disable the advertiser
|
|
test_hci_layer_->SetSubCommandFuture(SubOcf::SET_ENABLE);
|
|
le_advertising_manager_->RemoveAdvertiser(id);
|
|
test_hci_layer_->GetCommand(OpCode::LE_MULTI_ADVT);
|
|
test_hci_layer_->IncomingEvent(LeMultiAdvtSetEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(LeExtendedAdvertisingManagerTest, create_advertiser_test) {
|
|
ExtendedAdvertisingConfig advertising_config{};
|
|
advertising_config.advertising_type = AdvertisingType::ADV_IND;
|
|
advertising_config.own_address_type = OwnAddressType::PUBLIC_DEVICE_ADDRESS;
|
|
std::vector<GapData> gap_data{};
|
|
GapData data_item{};
|
|
data_item.data_type_ = GapDataType::FLAGS;
|
|
data_item.data_ = {0x34};
|
|
gap_data.push_back(data_item);
|
|
data_item.data_type_ = GapDataType::COMPLETE_LOCAL_NAME;
|
|
data_item.data_ = {'r', 'a', 'n', 'd', 'o', 'm', ' ', 'd', 'e', 'v', 'i', 'c', 'e'};
|
|
gap_data.push_back(data_item);
|
|
advertising_config.advertisement = gap_data;
|
|
advertising_config.scan_response = gap_data;
|
|
advertising_config.channel_map = 1;
|
|
advertising_config.sid = 0x01;
|
|
|
|
test_hci_layer_->SetCommandFuture();
|
|
auto id = le_advertising_manager_->ExtendedCreateAdvertiser(
|
|
0x00, advertising_config, scan_callback, set_terminated_callback, 0, 0, client_handler_);
|
|
ASSERT_NE(LeAdvertisingManager::kInvalidId, id);
|
|
EXPECT_CALL(
|
|
mock_advertising_callback_,
|
|
OnAdvertisingSetStarted(0x00, id, -23, AdvertisingCallback::AdvertisingStatus::SUCCESS));
|
|
std::vector<OpCode> adv_opcodes = {
|
|
OpCode::LE_SET_EXTENDED_ADVERTISING_PARAMETERS,
|
|
OpCode::LE_SET_EXTENDED_ADVERTISING_SCAN_RESPONSE,
|
|
OpCode::LE_SET_EXTENDED_ADVERTISING_DATA,
|
|
OpCode::LE_SET_EXTENDED_ADVERTISING_ENABLE,
|
|
};
|
|
std::vector<uint8_t> success_vector{static_cast<uint8_t>(ErrorCode::SUCCESS)};
|
|
for (size_t i = 0; i < adv_opcodes.size(); i++) {
|
|
auto packet_view = test_hci_layer_->GetCommand(adv_opcodes[i]);
|
|
CommandView command_packet_view = CommandView::Create(packet_view);
|
|
auto command = ConnectionManagementCommandView::Create(AclCommandView::Create(command_packet_view));
|
|
if (adv_opcodes[i] == OpCode::LE_SET_EXTENDED_ADVERTISING_PARAMETERS) {
|
|
test_hci_layer_->IncomingEvent(LeSetExtendedAdvertisingParametersCompleteBuilder::Create(
|
|
uint8_t{1}, ErrorCode::SUCCESS, static_cast<uint8_t>(-23)));
|
|
} else {
|
|
test_hci_layer_->IncomingEvent(
|
|
CommandCompleteBuilder::Create(uint8_t{1}, adv_opcodes[i], std::make_unique<RawBuilder>(success_vector)));
|
|
}
|
|
test_hci_layer_->SetCommandFuture();
|
|
}
|
|
sync_client_handler();
|
|
|
|
// Remove the advertiser
|
|
le_advertising_manager_->RemoveAdvertiser(id);
|
|
test_hci_layer_->GetCommand(OpCode::LE_SET_EXTENDED_ADVERTISING_ENABLE);
|
|
test_hci_layer_->SetCommandFuture();
|
|
test_hci_layer_->GetCommand(OpCode::LE_SET_PERIODIC_ADVERTISING_ENABLE);
|
|
test_hci_layer_->SetCommandFuture();
|
|
test_hci_layer_->GetCommand(OpCode::LE_REMOVE_ADVERTISING_SET);
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(LeAdvertisingAPITest, startup_teardown) {}
|
|
|
|
TEST_F(LeAndroidHciAdvertisingAPITest, startup_teardown) {}
|
|
|
|
TEST_F(LeExtendedAdvertisingAPITest, startup_teardown) {}
|
|
|
|
TEST_F(LeAdvertisingAPITest, set_parameter) {
|
|
ExtendedAdvertisingConfig advertising_config{};
|
|
advertising_config.advertising_type = AdvertisingType::ADV_IND;
|
|
advertising_config.own_address_type = OwnAddressType::PUBLIC_DEVICE_ADDRESS;
|
|
std::vector<GapData> gap_data{};
|
|
GapData data_item{};
|
|
data_item.data_type_ = GapDataType::COMPLETE_LOCAL_NAME;
|
|
data_item.data_ = {'r', 'a', 'n', 'd', 'o', 'm', ' ', 'd', 'e', 'v', 'i', 'c', 'e'};
|
|
gap_data.push_back(data_item);
|
|
advertising_config.advertisement = gap_data;
|
|
advertising_config.channel_map = 1;
|
|
test_hci_layer_->SetCommandFuture();
|
|
le_advertising_manager_->SetParameters(advertiser_id_, advertising_config);
|
|
test_hci_layer_->GetCommand(OpCode::LE_SET_ADVERTISING_PARAMETERS);
|
|
EXPECT_CALL(
|
|
mock_advertising_callback_,
|
|
OnAdvertisingParametersUpdated(advertiser_id_, 0x00, AdvertisingCallback::AdvertisingStatus::SUCCESS));
|
|
test_hci_layer_->IncomingEvent(LeSetAdvertisingParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(LeAndroidHciAdvertisingAPITest, set_parameter) {
|
|
ExtendedAdvertisingConfig advertising_config{};
|
|
advertising_config.advertising_type = AdvertisingType::ADV_IND;
|
|
advertising_config.own_address_type = OwnAddressType::PUBLIC_DEVICE_ADDRESS;
|
|
std::vector<GapData> gap_data{};
|
|
GapData data_item{};
|
|
data_item.data_type_ = GapDataType::COMPLETE_LOCAL_NAME;
|
|
data_item.data_ = {'r', 'a', 'n', 'd', 'o', 'm', ' ', 'd', 'e', 'v', 'i', 'c', 'e'};
|
|
gap_data.push_back(data_item);
|
|
advertising_config.advertisement = gap_data;
|
|
advertising_config.channel_map = 1;
|
|
test_hci_layer_->SetSubCommandFuture(SubOcf::SET_PARAM);
|
|
le_advertising_manager_->SetParameters(advertiser_id_, advertising_config);
|
|
test_hci_layer_->GetCommand(OpCode::LE_MULTI_ADVT);
|
|
EXPECT_CALL(
|
|
mock_advertising_callback_,
|
|
OnAdvertisingParametersUpdated(advertiser_id_, 0x00, AdvertisingCallback::AdvertisingStatus::SUCCESS));
|
|
test_hci_layer_->IncomingEvent(LeMultiAdvtCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS, SubOcf::SET_PARAM));
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(LeExtendedAdvertisingAPITest, set_parameter) {
|
|
ExtendedAdvertisingConfig advertising_config{};
|
|
advertising_config.advertising_type = AdvertisingType::ADV_IND;
|
|
advertising_config.own_address_type = OwnAddressType::PUBLIC_DEVICE_ADDRESS;
|
|
std::vector<GapData> gap_data{};
|
|
GapData data_item{};
|
|
data_item.data_type_ = GapDataType::COMPLETE_LOCAL_NAME;
|
|
data_item.data_ = {'r', 'a', 'n', 'd', 'o', 'm', ' ', 'd', 'e', 'v', 'i', 'c', 'e'};
|
|
gap_data.push_back(data_item);
|
|
advertising_config.advertisement = gap_data;
|
|
advertising_config.channel_map = 1;
|
|
advertising_config.sid = 0x01;
|
|
advertising_config.tx_power = 0x08;
|
|
test_hci_layer_->SetCommandFuture();
|
|
le_advertising_manager_->SetParameters(advertiser_id_, advertising_config);
|
|
test_hci_layer_->GetCommand(OpCode::LE_SET_EXTENDED_ADVERTISING_PARAMETERS);
|
|
EXPECT_CALL(
|
|
mock_advertising_callback_,
|
|
OnAdvertisingParametersUpdated(advertiser_id_, 0x08, AdvertisingCallback::AdvertisingStatus::SUCCESS));
|
|
test_hci_layer_->IncomingEvent(
|
|
LeSetExtendedAdvertisingParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS, 0x08));
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(LeAdvertisingAPITest, set_data_test) {
|
|
// Set advertising data
|
|
std::vector<GapData> advertising_data{};
|
|
GapData data_item{};
|
|
data_item.data_type_ = GapDataType::TX_POWER_LEVEL;
|
|
data_item.data_ = {0x00};
|
|
advertising_data.push_back(data_item);
|
|
test_hci_layer_->SetCommandFuture();
|
|
le_advertising_manager_->SetData(advertiser_id_, false, advertising_data);
|
|
test_hci_layer_->GetCommand(OpCode::LE_SET_ADVERTISING_DATA);
|
|
EXPECT_CALL(
|
|
mock_advertising_callback_,
|
|
OnAdvertisingDataSet(advertiser_id_, AdvertisingCallback::AdvertisingStatus::SUCCESS));
|
|
test_hci_layer_->IncomingEvent(LeSetAdvertisingDataCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
|
|
sync_client_handler();
|
|
|
|
// Set scan response data
|
|
std::vector<GapData> response_data{};
|
|
GapData data_item2{};
|
|
data_item2.data_type_ = GapDataType::COMPLETE_LOCAL_NAME;
|
|
data_item2.data_ = {'t', 'e', 's', 't', ' ', 'd', 'e', 'v', 'i', 'c', 'e'};
|
|
response_data.push_back(data_item2);
|
|
test_hci_layer_->SetCommandFuture();
|
|
le_advertising_manager_->SetData(advertiser_id_, true, response_data);
|
|
test_hci_layer_->GetCommand(OpCode::LE_SET_SCAN_RESPONSE_DATA);
|
|
EXPECT_CALL(
|
|
mock_advertising_callback_,
|
|
OnScanResponseDataSet(advertiser_id_, AdvertisingCallback::AdvertisingStatus::SUCCESS));
|
|
test_hci_layer_->IncomingEvent(LeSetScanResponseDataCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(LeExtendedAdvertisingAPITest, set_data_test) {
|
|
// Set advertising data
|
|
std::vector<GapData> advertising_data{};
|
|
GapData data_item{};
|
|
data_item.data_type_ = GapDataType::TX_POWER_LEVEL;
|
|
data_item.data_ = {0x00};
|
|
advertising_data.push_back(data_item);
|
|
test_hci_layer_->SetCommandFuture();
|
|
le_advertising_manager_->SetData(advertiser_id_, false, advertising_data);
|
|
test_hci_layer_->GetCommand(OpCode::LE_SET_EXTENDED_ADVERTISING_DATA);
|
|
EXPECT_CALL(
|
|
mock_advertising_callback_,
|
|
OnAdvertisingDataSet(advertiser_id_, AdvertisingCallback::AdvertisingStatus::SUCCESS));
|
|
test_hci_layer_->IncomingEvent(LeSetExtendedAdvertisingDataCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
|
|
sync_client_handler();
|
|
|
|
// Set scan response data
|
|
std::vector<GapData> response_data{};
|
|
GapData data_item2{};
|
|
data_item2.data_type_ = GapDataType::COMPLETE_LOCAL_NAME;
|
|
data_item2.data_ = {'t', 'e', 's', 't', ' ', 'd', 'e', 'v', 'i', 'c', 'e'};
|
|
response_data.push_back(data_item2);
|
|
test_hci_layer_->SetCommandFuture();
|
|
le_advertising_manager_->SetData(advertiser_id_, true, response_data);
|
|
test_hci_layer_->GetCommand(OpCode::LE_SET_EXTENDED_ADVERTISING_SCAN_RESPONSE);
|
|
EXPECT_CALL(
|
|
mock_advertising_callback_,
|
|
OnScanResponseDataSet(advertiser_id_, AdvertisingCallback::AdvertisingStatus::SUCCESS));
|
|
test_hci_layer_->IncomingEvent(
|
|
LeSetExtendedAdvertisingScanResponseCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(LeAndroidHciAdvertisingAPITest, set_data_test) {
|
|
// Set advertising data
|
|
std::vector<GapData> advertising_data{};
|
|
GapData data_item{};
|
|
data_item.data_type_ = GapDataType::TX_POWER_LEVEL;
|
|
data_item.data_ = {0x00};
|
|
advertising_data.push_back(data_item);
|
|
test_hci_layer_->SetSubCommandFuture(SubOcf::SET_DATA);
|
|
le_advertising_manager_->SetData(advertiser_id_, false, advertising_data);
|
|
test_hci_layer_->GetCommand(OpCode::LE_MULTI_ADVT);
|
|
EXPECT_CALL(
|
|
mock_advertising_callback_,
|
|
OnAdvertisingDataSet(advertiser_id_, AdvertisingCallback::AdvertisingStatus::SUCCESS));
|
|
test_hci_layer_->IncomingEvent(LeMultiAdvtCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS, SubOcf::SET_DATA));
|
|
sync_client_handler();
|
|
|
|
// Set scan response data
|
|
std::vector<GapData> response_data{};
|
|
GapData data_item2{};
|
|
data_item2.data_type_ = GapDataType::COMPLETE_LOCAL_NAME;
|
|
data_item2.data_ = {'t', 'e', 's', 't', ' ', 'd', 'e', 'v', 'i', 'c', 'e'};
|
|
response_data.push_back(data_item2);
|
|
test_hci_layer_->SetSubCommandFuture(SubOcf::SET_SCAN_RESP);
|
|
le_advertising_manager_->SetData(advertiser_id_, true, response_data);
|
|
test_hci_layer_->GetCommand(OpCode::LE_MULTI_ADVT);
|
|
EXPECT_CALL(
|
|
mock_advertising_callback_,
|
|
OnScanResponseDataSet(advertiser_id_, AdvertisingCallback::AdvertisingStatus::SUCCESS));
|
|
test_hci_layer_->IncomingEvent(
|
|
LeMultiAdvtCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS, SubOcf::SET_SCAN_RESP));
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(LeExtendedAdvertisingAPITest, set_data_fragments_test) {
|
|
// Set advertising data
|
|
std::vector<GapData> advertising_data{};
|
|
for (uint8_t i = 0; i < 3; i++) {
|
|
GapData data_item{};
|
|
data_item.data_.push_back(0xda);
|
|
data_item.data_type_ = GapDataType::SERVICE_DATA_128_BIT_UUIDS;
|
|
uint8_t uuid[16] = {0xf0, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, i};
|
|
std::copy_n(uuid, 16, std::back_inserter(data_item.data_));
|
|
uint8_t service_data[200];
|
|
std::copy_n(service_data, 200, std::back_inserter(data_item.data_));
|
|
advertising_data.push_back(data_item);
|
|
}
|
|
le_advertising_manager_->SetData(advertiser_id_, false, advertising_data);
|
|
|
|
// First fragment
|
|
test_hci_layer_->SetCommandFuture();
|
|
test_hci_layer_->GetCommand(OpCode::LE_SET_EXTENDED_ADVERTISING_DATA);
|
|
|
|
// Intermediate fragment
|
|
test_hci_layer_->SetCommandFuture();
|
|
test_hci_layer_->GetCommand(OpCode::LE_SET_EXTENDED_ADVERTISING_DATA);
|
|
|
|
// Last fragment
|
|
test_hci_layer_->SetCommandFuture();
|
|
test_hci_layer_->GetCommand(OpCode::LE_SET_EXTENDED_ADVERTISING_DATA);
|
|
|
|
EXPECT_CALL(
|
|
mock_advertising_callback_,
|
|
OnAdvertisingDataSet(advertiser_id_, AdvertisingCallback::AdvertisingStatus::SUCCESS));
|
|
test_hci_layer_->IncomingEvent(LeSetExtendedAdvertisingDataCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
|
|
test_hci_layer_->IncomingEvent(LeSetExtendedAdvertisingDataCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
|
|
test_hci_layer_->IncomingEvent(LeSetExtendedAdvertisingDataCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
|
|
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(LeExtendedAdvertisingAPITest, set_scan_response_fragments_test) {
|
|
// Set advertising data
|
|
std::vector<GapData> advertising_data{};
|
|
for (uint8_t i = 0; i < 3; i++) {
|
|
GapData data_item{};
|
|
data_item.data_.push_back(0xfa);
|
|
data_item.data_type_ = GapDataType::SERVICE_DATA_128_BIT_UUIDS;
|
|
uint8_t uuid[16] = {0xf0, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, i};
|
|
std::copy_n(uuid, 16, std::back_inserter(data_item.data_));
|
|
uint8_t service_data[232];
|
|
std::copy_n(service_data, 232, std::back_inserter(data_item.data_));
|
|
advertising_data.push_back(data_item);
|
|
}
|
|
le_advertising_manager_->SetData(advertiser_id_, true, advertising_data);
|
|
|
|
// First fragment
|
|
test_hci_layer_->SetCommandFuture();
|
|
test_hci_layer_->GetCommand(OpCode::LE_SET_EXTENDED_ADVERTISING_SCAN_RESPONSE);
|
|
|
|
// Intermediate fragment
|
|
test_hci_layer_->SetCommandFuture();
|
|
test_hci_layer_->GetCommand(OpCode::LE_SET_EXTENDED_ADVERTISING_SCAN_RESPONSE);
|
|
|
|
// Last fragment
|
|
test_hci_layer_->SetCommandFuture();
|
|
test_hci_layer_->GetCommand(OpCode::LE_SET_EXTENDED_ADVERTISING_SCAN_RESPONSE);
|
|
|
|
EXPECT_CALL(
|
|
mock_advertising_callback_,
|
|
OnScanResponseDataSet(advertiser_id_, AdvertisingCallback::AdvertisingStatus::SUCCESS));
|
|
test_hci_layer_->IncomingEvent(
|
|
LeSetExtendedAdvertisingScanResponseCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
|
|
test_hci_layer_->IncomingEvent(
|
|
LeSetExtendedAdvertisingScanResponseCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
|
|
test_hci_layer_->IncomingEvent(
|
|
LeSetExtendedAdvertisingScanResponseCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
|
|
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(LeExtendedAdvertisingAPITest, set_data_with_invalid_ad_structure) {
|
|
// Set advertising data with AD structure that length greater than 251
|
|
std::vector<GapData> advertising_data{};
|
|
GapData data_item{};
|
|
data_item.data_.push_back(0xfb);
|
|
data_item.data_type_ = GapDataType::SERVICE_DATA_128_BIT_UUIDS;
|
|
uint8_t uuid[16] = {0xf0, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00};
|
|
std::copy_n(uuid, 16, std::back_inserter(data_item.data_));
|
|
uint8_t service_data[233];
|
|
std::copy_n(service_data, 233, std::back_inserter(data_item.data_));
|
|
advertising_data.push_back(data_item);
|
|
|
|
EXPECT_CALL(
|
|
mock_advertising_callback_,
|
|
OnAdvertisingDataSet(advertiser_id_, AdvertisingCallback::AdvertisingStatus::INTERNAL_ERROR));
|
|
|
|
le_advertising_manager_->SetData(advertiser_id_, false, advertising_data);
|
|
|
|
EXPECT_CALL(
|
|
mock_advertising_callback_,
|
|
OnScanResponseDataSet(advertiser_id_, AdvertisingCallback::AdvertisingStatus::INTERNAL_ERROR));
|
|
le_advertising_manager_->SetData(advertiser_id_, true, advertising_data);
|
|
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(LeExtendedAdvertisingAPITest, set_data_with_invalid_length) {
|
|
// Set advertising data with data that greater than le_maximum_advertising_data_length_
|
|
std::vector<GapData> advertising_data{};
|
|
for (uint8_t i = 0; i < 10; i++) {
|
|
GapData data_item{};
|
|
data_item.data_.push_back(0xfb);
|
|
data_item.data_type_ = GapDataType::SERVICE_DATA_128_BIT_UUIDS;
|
|
uint8_t uuid[16] = {0xf0, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, i};
|
|
std::copy_n(uuid, 16, std::back_inserter(data_item.data_));
|
|
uint8_t service_data[200];
|
|
std::copy_n(service_data, 200, std::back_inserter(data_item.data_));
|
|
advertising_data.push_back(data_item);
|
|
}
|
|
|
|
EXPECT_CALL(
|
|
mock_advertising_callback_,
|
|
OnAdvertisingDataSet(advertiser_id_, AdvertisingCallback::AdvertisingStatus::DATA_TOO_LARGE));
|
|
le_advertising_manager_->SetData(advertiser_id_, false, advertising_data);
|
|
|
|
EXPECT_CALL(
|
|
mock_advertising_callback_,
|
|
OnScanResponseDataSet(advertiser_id_, AdvertisingCallback::AdvertisingStatus::DATA_TOO_LARGE));
|
|
le_advertising_manager_->SetData(advertiser_id_, true, advertising_data);
|
|
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(LeAdvertisingAPITest, disable_enable_advertiser_test) {
|
|
// disable advertiser
|
|
test_hci_layer_->SetCommandFuture();
|
|
le_advertising_manager_->EnableAdvertiser(advertiser_id_, false, 0x00, 0x00);
|
|
test_hci_layer_->GetCommand(OpCode::LE_SET_ADVERTISING_ENABLE);
|
|
EXPECT_CALL(
|
|
mock_advertising_callback_,
|
|
OnAdvertisingEnabled(advertiser_id_, false, AdvertisingCallback::AdvertisingStatus::SUCCESS));
|
|
test_hci_layer_->IncomingEvent(LeSetAdvertisingEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
|
|
sync_client_handler();
|
|
|
|
// enable advertiser
|
|
test_hci_layer_->SetCommandFuture();
|
|
le_advertising_manager_->EnableAdvertiser(advertiser_id_, true, 0x00, 0x00);
|
|
test_hci_layer_->GetCommand(OpCode::LE_SET_ADVERTISING_ENABLE);
|
|
EXPECT_CALL(
|
|
mock_advertising_callback_,
|
|
OnAdvertisingEnabled(advertiser_id_, true, AdvertisingCallback::AdvertisingStatus::SUCCESS));
|
|
test_hci_layer_->IncomingEvent(LeSetAdvertisingEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(LeAndroidHciAdvertisingAPITest, disable_enable_advertiser_test) {
|
|
// disable advertiser
|
|
test_hci_layer_->SetSubCommandFuture(SubOcf::SET_ENABLE);
|
|
le_advertising_manager_->EnableAdvertiser(advertiser_id_, false, 0x00, 0x00);
|
|
test_hci_layer_->GetCommand(OpCode::LE_MULTI_ADVT);
|
|
EXPECT_CALL(
|
|
mock_advertising_callback_,
|
|
OnAdvertisingEnabled(advertiser_id_, false, AdvertisingCallback::AdvertisingStatus::SUCCESS));
|
|
test_hci_layer_->IncomingEvent(
|
|
LeMultiAdvtCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS, SubOcf::SET_ENABLE));
|
|
sync_client_handler();
|
|
|
|
// enable advertiser
|
|
test_hci_layer_->SetSubCommandFuture(SubOcf::SET_ENABLE);
|
|
le_advertising_manager_->EnableAdvertiser(advertiser_id_, true, 0x00, 0x00);
|
|
test_hci_layer_->GetCommand(OpCode::LE_MULTI_ADVT);
|
|
EXPECT_CALL(
|
|
mock_advertising_callback_,
|
|
OnAdvertisingEnabled(advertiser_id_, true, AdvertisingCallback::AdvertisingStatus::SUCCESS));
|
|
test_hci_layer_->IncomingEvent(
|
|
LeMultiAdvtCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS, SubOcf::SET_ENABLE));
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(LeExtendedAdvertisingAPITest, disable_enable_advertiser_test) {
|
|
// disable advertiser
|
|
test_hci_layer_->SetCommandFuture();
|
|
le_advertising_manager_->EnableAdvertiser(advertiser_id_, false, 0x00, 0x00);
|
|
test_hci_layer_->GetCommand(OpCode::LE_SET_EXTENDED_ADVERTISING_ENABLE);
|
|
EXPECT_CALL(
|
|
mock_advertising_callback_,
|
|
OnAdvertisingEnabled(advertiser_id_, false, AdvertisingCallback::AdvertisingStatus::SUCCESS));
|
|
test_hci_layer_->IncomingEvent(LeSetExtendedAdvertisingEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
|
|
sync_client_handler();
|
|
|
|
// enable advertiser
|
|
test_hci_layer_->SetCommandFuture();
|
|
le_advertising_manager_->EnableAdvertiser(advertiser_id_, true, 0x00, 0x00);
|
|
test_hci_layer_->GetCommand(OpCode::LE_SET_EXTENDED_ADVERTISING_ENABLE);
|
|
EXPECT_CALL(
|
|
mock_advertising_callback_,
|
|
OnAdvertisingEnabled(advertiser_id_, true, AdvertisingCallback::AdvertisingStatus::SUCCESS));
|
|
test_hci_layer_->IncomingEvent(LeSetExtendedAdvertisingEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(LeExtendedAdvertisingAPITest, set_periodic_parameter) {
|
|
PeriodicAdvertisingParameters advertising_config{};
|
|
advertising_config.max_interval = 0x1000;
|
|
advertising_config.min_interval = 0x0006;
|
|
test_hci_layer_->SetCommandFuture();
|
|
le_advertising_manager_->SetPeriodicParameters(advertiser_id_, advertising_config);
|
|
test_hci_layer_->GetCommand(OpCode::LE_SET_PERIODIC_ADVERTISING_PARAM);
|
|
EXPECT_CALL(
|
|
mock_advertising_callback_,
|
|
OnPeriodicAdvertisingParametersUpdated(advertiser_id_, AdvertisingCallback::AdvertisingStatus::SUCCESS));
|
|
test_hci_layer_->IncomingEvent(LeSetPeriodicAdvertisingParamCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(LeExtendedAdvertisingAPITest, set_periodic_data_test) {
|
|
// Set advertising data
|
|
std::vector<GapData> advertising_data{};
|
|
GapData data_item{};
|
|
data_item.data_type_ = GapDataType::TX_POWER_LEVEL;
|
|
data_item.data_ = {0x00};
|
|
advertising_data.push_back(data_item);
|
|
test_hci_layer_->SetCommandFuture();
|
|
le_advertising_manager_->SetPeriodicData(advertiser_id_, advertising_data);
|
|
test_hci_layer_->GetCommand(OpCode::LE_SET_PERIODIC_ADVERTISING_DATA);
|
|
EXPECT_CALL(
|
|
mock_advertising_callback_,
|
|
OnPeriodicAdvertisingDataSet(advertiser_id_, AdvertisingCallback::AdvertisingStatus::SUCCESS));
|
|
test_hci_layer_->IncomingEvent(LeSetPeriodicAdvertisingDataCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(LeExtendedAdvertisingAPITest, set_periodic_data_fragments_test) {
|
|
// Set advertising data
|
|
std::vector<GapData> advertising_data{};
|
|
for (uint8_t i = 0; i < 3; i++) {
|
|
GapData data_item{};
|
|
data_item.data_.push_back(0xfa);
|
|
data_item.data_type_ = GapDataType::SERVICE_DATA_128_BIT_UUIDS;
|
|
uint8_t uuid[16] = {0xf0, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, i};
|
|
std::copy_n(uuid, 16, std::back_inserter(data_item.data_));
|
|
uint8_t service_data[232];
|
|
std::copy_n(service_data, 232, std::back_inserter(data_item.data_));
|
|
advertising_data.push_back(data_item);
|
|
}
|
|
le_advertising_manager_->SetPeriodicData(advertiser_id_, advertising_data);
|
|
|
|
// First fragment
|
|
test_hci_layer_->SetCommandFuture();
|
|
test_hci_layer_->GetCommand(OpCode::LE_SET_PERIODIC_ADVERTISING_DATA);
|
|
|
|
// Intermediate fragment
|
|
test_hci_layer_->SetCommandFuture();
|
|
test_hci_layer_->GetCommand(OpCode::LE_SET_PERIODIC_ADVERTISING_DATA);
|
|
|
|
// Last fragment
|
|
test_hci_layer_->SetCommandFuture();
|
|
test_hci_layer_->GetCommand(OpCode::LE_SET_PERIODIC_ADVERTISING_DATA);
|
|
|
|
EXPECT_CALL(
|
|
mock_advertising_callback_,
|
|
OnPeriodicAdvertisingDataSet(advertiser_id_, AdvertisingCallback::AdvertisingStatus::SUCCESS));
|
|
test_hci_layer_->IncomingEvent(LeSetPeriodicAdvertisingDataCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
|
|
test_hci_layer_->IncomingEvent(LeSetPeriodicAdvertisingDataCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
|
|
test_hci_layer_->IncomingEvent(LeSetPeriodicAdvertisingDataCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
|
|
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(LeExtendedAdvertisingAPITest, set_perodic_data_with_invalid_ad_structure) {
|
|
// Set advertising data with AD structure that length greater than 251
|
|
std::vector<GapData> advertising_data{};
|
|
GapData data_item{};
|
|
data_item.data_.push_back(0xfb);
|
|
data_item.data_type_ = GapDataType::SERVICE_DATA_128_BIT_UUIDS;
|
|
uint8_t uuid[16] = {0xf0, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00};
|
|
std::copy_n(uuid, 16, std::back_inserter(data_item.data_));
|
|
uint8_t service_data[233];
|
|
std::copy_n(service_data, 233, std::back_inserter(data_item.data_));
|
|
advertising_data.push_back(data_item);
|
|
|
|
EXPECT_CALL(
|
|
mock_advertising_callback_,
|
|
OnPeriodicAdvertisingDataSet(advertiser_id_, AdvertisingCallback::AdvertisingStatus::INTERNAL_ERROR));
|
|
|
|
le_advertising_manager_->SetPeriodicData(advertiser_id_, advertising_data);
|
|
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(LeExtendedAdvertisingAPITest, set_perodic_data_with_invalid_length) {
|
|
// Set advertising data with data that greater than le_maximum_advertising_data_length_
|
|
std::vector<GapData> advertising_data{};
|
|
for (uint8_t i = 0; i < 10; i++) {
|
|
GapData data_item{};
|
|
data_item.data_.push_back(0xfb);
|
|
data_item.data_type_ = GapDataType::SERVICE_DATA_128_BIT_UUIDS;
|
|
uint8_t uuid[16] = {0xf0, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, i};
|
|
std::copy_n(uuid, 16, std::back_inserter(data_item.data_));
|
|
uint8_t service_data[200];
|
|
std::copy_n(service_data, 200, std::back_inserter(data_item.data_));
|
|
advertising_data.push_back(data_item);
|
|
}
|
|
|
|
EXPECT_CALL(
|
|
mock_advertising_callback_,
|
|
OnPeriodicAdvertisingDataSet(advertiser_id_, AdvertisingCallback::AdvertisingStatus::DATA_TOO_LARGE));
|
|
le_advertising_manager_->SetPeriodicData(advertiser_id_, advertising_data);
|
|
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(LeExtendedAdvertisingAPITest, disable_enable_periodic_advertiser_test) {
|
|
// disable advertiser
|
|
test_hci_layer_->SetCommandFuture();
|
|
le_advertising_manager_->EnablePeriodicAdvertising(advertiser_id_, false);
|
|
test_hci_layer_->GetCommand(OpCode::LE_SET_PERIODIC_ADVERTISING_ENABLE);
|
|
EXPECT_CALL(
|
|
mock_advertising_callback_,
|
|
OnPeriodicAdvertisingEnabled(advertiser_id_, false, AdvertisingCallback::AdvertisingStatus::SUCCESS));
|
|
test_hci_layer_->IncomingEvent(LeSetPeriodicAdvertisingEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
|
|
sync_client_handler();
|
|
|
|
// enable advertiser
|
|
test_hci_layer_->SetCommandFuture();
|
|
le_advertising_manager_->EnablePeriodicAdvertising(advertiser_id_, true);
|
|
test_hci_layer_->GetCommand(OpCode::LE_SET_PERIODIC_ADVERTISING_ENABLE);
|
|
EXPECT_CALL(
|
|
mock_advertising_callback_,
|
|
OnPeriodicAdvertisingEnabled(advertiser_id_, true, AdvertisingCallback::AdvertisingStatus::SUCCESS));
|
|
test_hci_layer_->IncomingEvent(LeSetPeriodicAdvertisingEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
|
|
sync_client_handler();
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace hci
|
|
} // namespace bluetooth
|