Skip to content
Snippets Groups Projects
Commit 022e7d62 authored by Myles Watson's avatar Myles Watson
Browse files

HCI: Add classic interface definitions

Test: bluetooth_test_gd --gtest_filter=*Hci*
Change-Id: I4206c818084302341d4e99f2cce8aad1c12ce4ae
parent 09894a4e
No related branches found
No related tags found
No related merge requests found
......@@ -105,6 +105,7 @@ cc_library {
"module.cc",
":BluetoothCommonSources",
":BluetoothHalSources",
":BluetoothHciSources",
":BluetoothPacketSources",
],
generated_headers: [
......
filegroup {
name: "BluetoothHciSources",
srcs: [
"hci_layer.cc",
],
}
filegroup {
name: "BluetoothHciTestSources",
srcs: [
"acl_builder_test.cc",
"hci_layer_test.cc",
],
}
/*
* 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/hci_layer.h"
#include "packet/packet_builder.h"
namespace {
using bluetooth::hci::CommandCompleteView;
using bluetooth::hci::CommandPacketBuilder;
using bluetooth::hci::CommandStatusView;
using bluetooth::hci::EventPacketView;
using bluetooth::os::Handler;
class EventHandler {
public:
EventHandler() : event_handler(), handler(nullptr) {}
EventHandler(std::function<void(EventPacketView)> on_event, Handler* on_event_handler)
: event_handler(on_event), handler(on_event_handler) {}
std::function<void(EventPacketView)> event_handler;
Handler* handler;
};
class CommandQueueEntry {
public:
CommandQueueEntry(std::unique_ptr<CommandPacketBuilder> command_packet,
std::function<void(CommandStatusView)> on_status_function,
std::function<void(CommandCompleteView)> on_complete_function, Handler* handler)
: command(std::move(command_packet)), on_status(on_status_function), on_complete(on_complete_function),
caller_handler(handler) {}
std::unique_ptr<CommandPacketBuilder> command;
std::function<void(CommandStatusView)> on_status;
std::function<void(CommandCompleteView)> on_complete;
Handler* caller_handler;
};
} // namespace
namespace bluetooth {
namespace hci {
using common::Address;
using common::BidiQueue;
using common::BidiQueueEnd;
using os::Handler;
struct HciLayer::impl : public hal::HciHalCallbacks {
impl(HciLayer& module) : hal_(nullptr), module_(module) {
RegisterEventHandler(EventCode::COMMAND_COMPLETE, [this](EventPacketView event) { CommandCompleteCallback(event); },
module_.GetHandler());
RegisterEventHandler(EventCode::COMMAND_STATUS, [this](EventPacketView event) { CommandStatusCallback(event); },
module_.GetHandler());
}
void Start(hal::HciHal* hal) {
hal_ = hal;
hal_->registerIncomingPacketCallback(this);
send_acl_ = [this](std::unique_ptr<hci::BasePacketBuilder> packet) {
std::vector<uint8_t> bytes;
BitInserter bi(bytes);
packet->Serialize(bi);
hal_->sendAclData(bytes);
};
send_sco_ = [this](std::unique_ptr<hci::BasePacketBuilder> packet) {
std::vector<uint8_t> bytes;
BitInserter bi(bytes);
packet->Serialize(bi);
hal_->sendScoData(bytes);
};
auto queue_end = acl_queue_.GetDownEnd();
Handler* handler = module_.GetHandler();
queue_end->RegisterDequeue(handler, [queue_end, this]() { send_acl_(queue_end->TryDequeue()); });
}
void Stop() {
acl_queue_.GetDownEnd()->UnregisterDequeue();
hal_ = nullptr;
}
void CommandStatusCallback(EventPacketView event) {
CommandStatusView status_view = CommandStatusView::Create(event);
ASSERT(status_view.IsValid());
if (command_queue_.size() == 0) {
ASSERT_LOG(status_view.GetCommandOpCode() == OpCode::NONE, "Unexpected status event with OpCode 0x%02hx",
status_view.GetCommandOpCode());
return;
}
// TODO: Check whether this is the CommandOpCode we're looking for.
auto caller_handler = command_queue_.front().caller_handler;
auto on_status = command_queue_.front().on_status;
caller_handler->Post([on_status, status_view]() { on_status(status_view); });
command_queue_.pop();
}
void CommandCompleteCallback(EventPacketView event) {
CommandCompleteView complete_view = CommandCompleteView::Create(event);
ASSERT(complete_view.IsValid());
if (command_queue_.size() == 0) {
ASSERT_LOG(complete_view.GetCommandOpCode() == OpCode::NONE,
"Unexpected command complete event with OpCode 0x%02hx", complete_view.GetCommandOpCode());
return;
}
// TODO: Check whether this is the CommandOpCode we're looking for.
auto caller_handler = command_queue_.front().caller_handler;
auto on_complete = command_queue_.front().on_complete;
caller_handler->Post([on_complete, complete_view]() { on_complete(complete_view); });
command_queue_.pop();
}
void hciEventReceived(hal::HciPacket event_bytes) override {
auto packet = packet::PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>(event_bytes));
EventPacketView event = EventPacketView::Create(packet);
ASSERT(event.IsValid());
EventCode event_code = event.GetEventCode();
Handler* hci_handler = module_.GetHandler();
hci_handler->Post([this, event, event_code]() {
ASSERT_LOG(event_handlers_.find(event_code) != event_handlers_.end(), "Unhandled event of type 0x%02hhx",
event.GetEventCode());
auto& registered_handler = event_handlers_[event_code].event_handler;
event_handlers_[event_code].handler->Post([event, registered_handler]() { registered_handler(event); });
});
// TODO: Credits
}
void aclDataReceived(hal::HciPacket data_bytes) override {
module_.GetHandler()->Post([this, data_bytes]() {
auto queue_end = acl_queue_.GetDownEnd();
Handler* hci_handler = module_.GetHandler();
queue_end->RegisterEnqueue(hci_handler, [queue_end, data_bytes]() {
auto packet = packet::PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>(data_bytes));
AclPacketView acl2 = AclPacketView::Create(packet);
queue_end->UnregisterEnqueue();
return std::make_unique<AclPacketView>(acl2);
});
});
}
void scoDataReceived(hal::HciPacket data_bytes) override {
auto packet = packet::PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>(data_bytes));
ScoPacketView sco = ScoPacketView::Create(packet);
}
void EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command, std::function<void(CommandStatusView)> on_status,
std::function<void(CommandCompleteView)> on_complete, Handler* handler) {
command_queue_.emplace(std::move(command), on_status, on_complete, handler);
if (command_queue_.size() == 1) {
std::vector<uint8_t> bytes;
BitInserter bi(bytes);
command_queue_.front().command->Serialize(bi);
hal_->sendHciCommand(bytes);
}
}
BidiQueueEnd<AclPacketBuilder, AclPacketView>* GetAclQueueEnd() {
return acl_queue_.GetUpEnd();
}
void RegisterEventHandler(EventCode event_code, std::function<void(EventPacketView)> event_handler,
Handler* handler) {
ASSERT_LOG(event_handlers_.count(event_code) == 0, "Can not register a second handler for event_code %02hhx",
event_code);
EventHandler to_save(event_handler, handler);
event_handlers_[event_code] = to_save;
}
void UnregisterEventHandler(EventCode event_code) {
event_handlers_.erase(event_code);
}
// The HAL
hal::HciHal* hal_;
// A reference to the HciLayer module
HciLayer& module_;
// Conversion functions for sending bytes from Builders
std::function<void(std::unique_ptr<hci::BasePacketBuilder>)> send_acl_;
std::function<void(std::unique_ptr<hci::BasePacketBuilder>)> send_sco_;
// Command Handling
std::queue<CommandQueueEntry> command_queue_;
std::map<EventCode, EventHandler> event_handlers_;
OpCode waiting_command_;
// Acl packets
BidiQueue<AclPacketView, AclPacketBuilder> acl_queue_{3 /* TODO: Set queue depth */};
};
HciLayer::HciLayer() : impl_(std::make_unique<impl>(*this)) {}
HciLayer::~HciLayer() {
impl_.reset();
}
void HciLayer::EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command,
std::function<void(CommandStatusView)> on_status,
std::function<void(CommandCompleteView)> on_complete, Handler* handler) {
impl_->EnqueueCommand(std::move(command), on_status, on_complete, handler);
}
common::BidiQueueEnd<AclPacketBuilder, AclPacketView>* HciLayer::GetAclQueueEnd() {
return impl_->GetAclQueueEnd();
}
void HciLayer::RegisterEventHandler(EventCode event_code, std::function<void(EventPacketView)> event_handler,
Handler* handler) {
impl_->RegisterEventHandler(event_code, event_handler, handler);
}
void HciLayer::UnregisterEventHandler(EventCode event_code) {
impl_->UnregisterEventHandler(event_code);
}
const ModuleFactory HciLayer::Factory = ModuleFactory([]() { return new HciLayer(); });
void HciLayer::ListDependencies(ModuleList* list) {
list->add<hal::HciHal>();
}
void HciLayer::Start() {
impl_->Start(GetDependency<hal::HciHal>());
}
void HciLayer::Stop() {
impl_->Stop();
}
} // namespace hci
} // namespace bluetooth
/*
* 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.
*/
#pragma once
#include <map>
#include "common/address.h"
#include "common/bidi_queue.h"
#include "common/class_of_device.h"
#include "hal/hci_hal.h"
#include "hci/hci_packets.h"
#include "module.h"
#include "os/utils.h"
namespace bluetooth {
namespace hci {
class HciLayer : public Module {
public:
HciLayer();
virtual ~HciLayer();
DISALLOW_COPY_AND_ASSIGN(HciLayer);
virtual void EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command,
std::function<void(CommandStatusView)> on_status,
std::function<void(CommandCompleteView)> on_complete, os::Handler* handler);
virtual common::BidiQueueEnd<AclPacketBuilder, AclPacketView>* GetAclQueueEnd();
virtual void RegisterEventHandler(EventCode event_code, std::function<void(EventPacketView)> event_handler,
os::Handler* handler);
virtual void UnregisterEventHandler(EventCode event_code);
static const ModuleFactory Factory;
void ListDependencies(ModuleList* list) override;
void Start() override;
void Stop() override;
private:
struct impl;
std::unique_ptr<impl> impl_;
};
} // namespace hci
} // namespace bluetooth
/*
* 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/hci_layer.h"
#include <gtest/gtest.h>
#include <list>
#include <memory>
#include "hal/hci_hal.h"
#include "hci/hci_packets.h"
#include "module.h"
#include "os/log.h"
#include "os/thread.h"
#include "packet/bit_inserter.h"
#include "packet/raw_builder.h"
using bluetooth::os::Thread;
using bluetooth::packet::BitInserter;
using bluetooth::packet::RawBuilder;
using std::vector;
namespace {
vector<uint8_t> information_request = {
0xfe, 0x2e, 0x0a, 0x00, 0x06, 0x00, 0x01, 0x00, 0x0a, 0x02, 0x02, 0x00, 0x02, 0x00,
};
// 0x00, 0x01, 0x02, 0x03, ...
vector<uint8_t> counting_bytes;
// 0xFF, 0xFE, 0xFD, 0xFC, ...
vector<uint8_t> counting_down_bytes;
const size_t count_size = 0x8;
} // namespace
namespace bluetooth {
namespace hci {
class TestHciHal : public hal::HciHal {
public:
TestHciHal() : hal::HciHal() {}
virtual void registerIncomingPacketCallback(hal::HciHalCallbacks* callback) {
callbacks = callback;
}
virtual void sendHciCommand(hal::HciPacket command) {
outgoing_commands_.push_back(std::move(command));
}
virtual void sendAclData(hal::HciPacket data) {
outgoing_acl_.push_front(std::move(data));
}
virtual void sendScoData(hal::HciPacket data) {
outgoing_sco_.push_front(std::move(data));
}
hal::HciHalCallbacks* callbacks = nullptr;
PacketView<kLittleEndian> GetPacketView(hal::HciPacket data) {
auto shared = std::make_shared<std::vector<uint8_t>>(data);
return PacketView<kLittleEndian>(shared);
}
PacketView<kLittleEndian> GetSentCommand() {
while (outgoing_commands_.size() == 0)
;
auto packetview = GetPacketView(std::move(outgoing_commands_.front()));
outgoing_commands_.pop_front();
return packetview;
}
PacketView<kLittleEndian> GetSentAcl() {
while (outgoing_acl_.size() == 0)
;
auto packetview = GetPacketView(std::move(outgoing_acl_.front()));
outgoing_acl_.pop_front();
return packetview;
}
void Start() {}
void Stop() {}
void ListDependencies(ModuleList*) {}
static const ModuleFactory Factory;
private:
std::list<hal::HciPacket> outgoing_commands_;
std::list<hal::HciPacket> outgoing_acl_;
std::list<hal::HciPacket> outgoing_sco_;
};
const ModuleFactory TestHciHal::Factory = ModuleFactory([]() { return new TestHciHal(); });
class DependsOnHci : public Module {
public:
DependsOnHci() : Module() {}
void SendHciCommand(std::unique_ptr<CommandPacketBuilder> command) {
hci_->EnqueueCommand(std::move(command), [this](CommandStatusView status) { incoming_events_.push_back(status); },
[this](CommandCompleteView complete) { incoming_events_.push_back(complete); }, GetHandler());
}
void SendAclData(std::unique_ptr<AclPacketBuilder> acl) {
AclPacketBuilder* raw_acl_pointer = acl.release();
auto queue_end = hci_->GetAclQueueEnd();
queue_end->RegisterEnqueue(GetHandler(), [queue_end, raw_acl_pointer]() -> std::unique_ptr<AclPacketBuilder> {
queue_end->UnregisterEnqueue();
return std::unique_ptr<AclPacketBuilder>(raw_acl_pointer);
});
}
EventPacketView GetReceivedEvent() {
while (incoming_events_.size() == 0)
;
EventPacketView packetview = incoming_events_.front();
incoming_events_.pop_front();
return packetview;
}
AclPacketView GetReceivedAcl() {
auto queue_end = hci_->GetAclQueueEnd();
std::unique_ptr<AclPacketView> incoming_acl_ptr;
while (incoming_acl_ptr == nullptr) {
incoming_acl_ptr = queue_end->TryDequeue();
}
AclPacketView packetview = *incoming_acl_ptr;
return packetview;
}
void Start() {
hci_ = GetDependency<HciLayer>();
hci_->RegisterEventHandler(EventCode::CONNECTION_COMPLETE,
[this](EventPacketView event) { incoming_events_.push_back(event); }, GetHandler());
}
void Stop() {}
void ListDependencies(ModuleList* list) {
list->add<HciLayer>();
}
static const ModuleFactory Factory;
private:
HciLayer* hci_ = nullptr;
std::list<EventPacketView> incoming_events_;
};
const ModuleFactory DependsOnHci::Factory = ModuleFactory([]() { return new DependsOnHci(); });
class HciTest : public ::testing::Test {
public:
void SetUp() override {
counting_bytes.reserve(count_size);
counting_down_bytes.reserve(count_size);
for (size_t i = 0; i < count_size; i++) {
counting_bytes.push_back(i);
counting_down_bytes.push_back(~i);
}
thread_ = new Thread("test_thread", Thread::Priority::NORMAL);
hal = new TestHciHal();
fake_registry_.inject_test_module(&hal::HciHal::Factory, hal, thread_);
fake_registry_.Start<DependsOnHci>(thread_);
hci = fake_registry_.get_module_under_test<HciLayer>();
upper = fake_registry_.get_module_under_test<DependsOnHci>();
ASSERT(fake_registry_.IsStarted<HciLayer>());
}
void TearDown() override {
fake_registry_.StopAll();
delete thread_;
}
std::vector<uint8_t> GetPacketBytes(std::unique_ptr<packet::BasePacketBuilder> packet) {
std::vector<uint8_t> bytes;
BitInserter i(bytes);
bytes.reserve(packet->size());
packet->Serialize(i);
return bytes;
}
DependsOnHci* upper = nullptr;
TestHciHal* hal = nullptr;
HciLayer* hci = nullptr;
ModuleRegistry fake_registry_;
Thread* thread_ = nullptr;
};
TEST_F(HciTest, initAndClose) {}
TEST_F(HciTest, createConnectionTest) {
// Send CreateConnection to the controller
common::Address bd_addr;
ASSERT_TRUE(common::Address::FromString("A1:A2:A3:A4:A5:A6", bd_addr));
uint16_t packet_type = 0x1234;
PageScanRepetitionMode page_scan_repetition_mode = PageScanRepetitionMode::R0;
uint16_t clock_offset = 0x3456;
ClockOffsetValid clock_offset_valid = ClockOffsetValid::VALID;
CreateConnectionRoleSwitch allow_role_switch = CreateConnectionRoleSwitch::ALLOW_ROLE_SWITCH;
upper->SendHciCommand(CreateConnectionBuilder::Create(bd_addr, packet_type, page_scan_repetition_mode, clock_offset,
clock_offset_valid, allow_role_switch));
// Check the command
auto sent_command = hal->GetSentCommand();
ASSERT_LT(0, sent_command.size());
CreateConnectionView view =
CreateConnectionView::Create(ConnectionManagementCommandView::Create(CommandPacketView::Create(sent_command)));
ASSERT_TRUE(view.IsValid());
ASSERT_EQ(bd_addr, view.GetBdAddr());
ASSERT_EQ(packet_type, view.GetPacketType());
ASSERT_EQ(page_scan_repetition_mode, view.GetPageScanRepetitionMode());
ASSERT_EQ(clock_offset, view.GetClockOffset());
ASSERT_EQ(clock_offset_valid, view.GetClockOffsetValid());
ASSERT_EQ(allow_role_switch, view.GetAllowRoleSwitch());
// Send a ConnectionComplete to the host
ErrorCode status = ErrorCode::SUCCESS;
uint16_t handle = 0x123;
LinkType link_type = LinkType::ACL;
Enable encryption_enabled = Enable::DISABLED;
hal->callbacks->hciEventReceived(
GetPacketBytes(ConnectionCompleteBuilder::Create(status, handle, bd_addr, link_type, encryption_enabled)));
// Verify the event
auto event = upper->GetReceivedEvent();
ASSERT_TRUE(event.IsValid());
ASSERT_EQ(EventCode::CONNECTION_COMPLETE, event.GetEventCode());
ConnectionCompleteView connection_complete_view = ConnectionCompleteView::Create(event);
ASSERT_TRUE(connection_complete_view.IsValid());
ASSERT_EQ(status, connection_complete_view.GetStatus());
ASSERT_EQ(handle, connection_complete_view.GetConnectionHandle());
ASSERT_EQ(link_type, connection_complete_view.GetLinkType());
ASSERT_EQ(encryption_enabled, connection_complete_view.GetEncryptionEnabled());
// Send an ACL packet from the remote
PacketBoundaryFlag packet_boundary_flag = PacketBoundaryFlag::COMPLETE_PDU;
BroadcastFlag broadcast_flag = BroadcastFlag::POINT_TO_POINT;
auto acl_payload = std::make_unique<RawBuilder>();
acl_payload->AddAddress(bd_addr);
acl_payload->AddOctets2(handle);
hal->callbacks->aclDataReceived(
GetPacketBytes(AclPacketBuilder::Create(handle, packet_boundary_flag, broadcast_flag, std::move(acl_payload))));
// Verify the ACL packet
auto acl_view = upper->GetReceivedAcl();
ASSERT_TRUE(acl_view.IsValid());
ASSERT_EQ(sizeof(bd_addr) + sizeof(handle), acl_view.GetPayload().size());
auto itr = acl_view.GetPayload().begin();
ASSERT_EQ(bd_addr, itr.extract<Address>());
ASSERT_EQ(handle, itr.extract<uint16_t>());
// Send an ACL packet from DependsOnHci
PacketBoundaryFlag packet_boundary_flag2 = PacketBoundaryFlag::COMPLETE_PDU;
BroadcastFlag broadcast_flag2 = BroadcastFlag::POINT_TO_POINT;
auto acl_payload2 = std::make_unique<RawBuilder>();
acl_payload2->AddOctets2(handle);
acl_payload2->AddAddress(bd_addr);
upper->SendAclData(AclPacketBuilder::Create(handle, packet_boundary_flag2, broadcast_flag2, std::move(acl_payload2)));
// Verify the ACL packet
auto sent_acl = hal->GetSentAcl();
ASSERT_LT(0, sent_acl.size());
AclPacketView sent_acl_view = AclPacketView::Create(sent_acl);
ASSERT_TRUE(sent_acl_view.IsValid());
ASSERT_EQ(sizeof(bd_addr) + sizeof(handle), sent_acl_view.GetPayload().size());
auto sent_itr = sent_acl_view.GetPayload().begin();
ASSERT_EQ(handle, sent_itr.extract<uint16_t>());
ASSERT_EQ(bd_addr, sent_itr.extract<Address>());
}
} // namespace hci
} // namespace bluetooth
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment