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.

272 lines
9.0 KiB

/*
*
* Copyright 2020 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 "iso_manager_impl.h"
#include "common/bind.h"
#include "hci/hci_packets.h"
#include "iso/iso_manager.h"
#include "os/handler.h"
#include "os/log.h"
#include "packet/raw_builder.h"
namespace bluetooth {
namespace iso {
namespace internal {
using bluetooth::hci::IsoBuilder;
IsoManagerImpl::IsoManagerImpl(os::Handler* iso_handler, hci::HciLayer* hci_layer, hci::Controller* controller)
: iso_handler_(iso_handler),
hci_layer_(hci_layer),
hci_le_iso_interface_(hci_layer->GetLeIsoInterface(iso_handler_->BindOn(this, &IsoManagerImpl::OnHciLeEvent))),
controller_(controller) {
hci_layer_->GetIsoQueueEnd()->RegisterDequeue(
iso_handler_, common::Bind(&IsoManagerImpl::OnIncomingPacket, common::Unretained(this)));
iso_enqueue_buffer_ = std::make_unique<os::EnqueueBuffer<IsoBuilder>>(hci_layer_->GetIsoQueueEnd());
}
IsoManagerImpl::~IsoManagerImpl() {
hci_layer_->GetIsoQueueEnd()->UnregisterDequeue();
iso_enqueue_buffer_ = nullptr;
}
void IsoManagerImpl::OnHciLeEvent(hci::LeMetaEventView event) {
hci::SubeventCode code = event.GetSubeventCode();
if (code == hci::SubeventCode::CIS_ESTABLISHED) {
hci::LeCisEstablishedView le_cis_established_view = hci::LeCisEstablishedView::Create(event);
if (!le_cis_established_view.IsValid()) {
LOG_ERROR("Invalid LeCisEstablishedView packet received");
return;
}
cis_established_callback.Invoke(le_cis_established_view.GetConnectionHandle());
return;
} else if (code == hci::SubeventCode::CIS_REQUEST) {
hci::LeCisRequestView le_cis_request_view = hci::LeCisRequestView::Create(event);
if (!le_cis_request_view.IsValid()) {
LOG_ERROR("Invalid LeCisRequestView packet received");
return;
}
hci_le_iso_interface_->EnqueueCommand(
hci::LeAcceptCisRequestBuilder::Create(le_cis_request_view.GetCisConnectionHandle()),
iso_handler_->BindOnce([](hci::CommandStatusView command_status) {
LOG_INFO("command_status=%hhu ", command_status.GetStatus());
}));
return;
}
LOG_ERROR("Unhandled HCI LE ISO event, code %s", hci::SubeventCodeText(code).c_str());
ASSERT_LOG(false, "Unhandled HCI LE ISO event");
}
void IsoManagerImpl::SetCigParameters(
uint8_t cig_id,
uint32_t sdu_interval_m_to_s,
uint32_t sdu_interval_s_to_m,
hci::ClockAccuracy peripherals_clock_accuracy,
hci::Packing packing,
hci::Enable framing,
uint16_t max_transport_latency_m_to_s,
uint16_t max_transport_latency_s_to_m,
const std::vector<hci::CisParametersConfig>& cis_configs,
SetCigParametersCallback command_complete_callback) {
hci_le_iso_interface_->EnqueueCommand(
hci::LeSetCigParametersBuilder::Create(
cig_id,
sdu_interval_m_to_s,
sdu_interval_s_to_m,
peripherals_clock_accuracy,
packing,
framing,
max_transport_latency_m_to_s,
max_transport_latency_s_to_m,
cis_configs),
iso_handler_->BindOnce(
&IsoManagerImpl::SetCigParametersComplete,
common::Unretained(this),
cig_id,
cis_configs,
std::move(command_complete_callback)));
}
void IsoManagerImpl::SetCigParametersComplete(
uint8_t cig_id,
const std::vector<hci::CisParametersConfig>& cis_configs,
SetCigParametersCallback command_complete_callback,
hci::CommandCompleteView command_complete) {
ASSERT(command_complete.IsValid());
hci::LeSetCigParametersCompleteView setCigParamsComplete =
hci::LeSetCigParametersCompleteView::Create(command_complete);
ASSERT(setCigParamsComplete.IsValid());
if (setCigParamsComplete.GetStatus() == hci::ErrorCode::SUCCESS) {
uint8_t cig_id_back_from_ctrl = setCigParamsComplete.GetCigId();
auto conn_handles = setCigParamsComplete.GetConnectionHandle();
ASSERT(cig_id_back_from_ctrl == cig_id);
ASSERT(conn_handles.size() == cis_configs.size());
auto cis_it = cis_configs.begin();
auto handle_it = conn_handles.begin();
std::vector<uint16_t> handles;
while (cis_it != cis_configs.end()) {
iso_connections_.push_back({
.cig_id = cig_id,
.cis_id = cis_it->cis_id_,
.connection_handle = *handle_it,
});
handles.push_back(*handle_it);
cis_it++;
handle_it++;
}
command_complete_callback.Invoke(handles);
}
}
void IsoManagerImpl::SetCigParametersTest(
uint8_t cig_id,
uint32_t sdu_interval_m_to_s,
uint32_t sdu_interval_s_to_m,
uint8_t ft_m_to_s,
uint8_t ft_s_to_m,
uint16_t iso_interval,
hci::ClockAccuracy peripherals_clock_accuracy,
hci::Packing packing,
hci::Enable framing,
uint16_t max_transport_latency_m_to_s,
uint16_t max_transport_latency_s_to_m,
const std::vector<hci::LeCisParametersTestConfig>& cis_test_configs,
SetCigParametersCallback command_complete_callback) {
hci_le_iso_interface_->EnqueueCommand(
hci::LeSetCigParametersTestBuilder::Create(
cig_id,
sdu_interval_m_to_s,
sdu_interval_s_to_m,
ft_m_to_s,
ft_s_to_m,
iso_interval,
peripherals_clock_accuracy,
packing,
framing,
cis_test_configs),
iso_handler_->BindOnce(
&IsoManagerImpl::SetCigParametersTestComplete,
common::Unretained(this),
cig_id,
cis_test_configs,
std::move(command_complete_callback)));
}
void IsoManagerImpl::SetCigParametersTestComplete(
uint8_t cig_id,
const std::vector<hci::LeCisParametersTestConfig>& cis_configs,
SetCigParametersCallback command_complete_callback,
hci::CommandCompleteView command_complete) {
ASSERT(command_complete.IsValid());
hci::LeSetCigParametersTestCompleteView setCigParamsComplete =
hci::LeSetCigParametersTestCompleteView::Create(command_complete);
ASSERT(setCigParamsComplete.IsValid());
if (setCigParamsComplete.GetStatus() == hci::ErrorCode::SUCCESS) {
uint8_t cig_id_back_from_ctrl = setCigParamsComplete.GetCigId();
auto conn_handles = setCigParamsComplete.GetConnectionHandle();
ASSERT(cig_id_back_from_ctrl == cig_id);
ASSERT(conn_handles.size() == cis_configs.size());
auto cis_it = cis_configs.begin();
auto handle_it = conn_handles.begin();
std::vector<uint16_t> handles;
while (cis_it != cis_configs.end()) {
iso_connections_.push_back({
.cig_id = cig_id,
.cis_id = cis_it->cis_id_,
.connection_handle = *handle_it,
});
handles.push_back(*handle_it);
cis_it++;
handle_it++;
}
command_complete_callback.Invoke(handles);
}
}
void IsoManagerImpl::LeCreateCis(std::vector<std::pair<uint16_t, uint16_t>> cis_and_acl_handles) {
std::vector<hci::CreateCisConfig> cis_configs;
for (const auto& handle_pair : cis_and_acl_handles) {
hci::CreateCisConfig config;
config.cis_connection_handle_ = handle_pair.first;
config.acl_connection_handle_ = handle_pair.second;
cis_configs.push_back(config);
}
hci_le_iso_interface_->EnqueueCommand(
hci::LeCreateCisBuilder::Create(cis_configs), iso_handler_->BindOnce([](hci::CommandStatusView command_status) {
LOG_INFO("command_status=%hhu ", command_status.GetStatus());
}));
}
void IsoManagerImpl::RemoveCig(uint8_t cig_id) {
ASSERT(IsKnownCig(cig_id));
hci_le_iso_interface_->EnqueueCommand(
hci::LeRemoveCigBuilder::Create(cig_id),
iso_handler_->BindOnce(&IsoManagerImpl::RemoveCigComplete, common::Unretained(this)));
}
void IsoManagerImpl::RemoveCigComplete(hci::CommandCompleteView command_complete) {
ASSERT(command_complete.IsValid());
hci::LeRemoveCigCompleteView removeCigComplete = hci::LeRemoveCigCompleteView::Create(command_complete);
ASSERT(removeCigComplete.IsValid());
}
void IsoManagerImpl::SendIsoPacket(uint16_t cis_handle, std::vector<uint8_t> packet) {
auto builder = hci::IsoWithoutTimestampBuilder::Create(
cis_handle,
hci::IsoPacketBoundaryFlag::COMPLETE_SDU,
0 /* sequence_number*/,
hci::IsoPacketStatusFlag::VALID,
std::make_unique<bluetooth::packet::RawBuilder>(packet));
LOG_INFO("%c%c", packet[0], packet[1]);
iso_enqueue_buffer_->Enqueue(std::move(builder), iso_handler_);
}
void IsoManagerImpl::OnIncomingPacket() {
std::unique_ptr<hci::IsoView> packet = hci_layer_->GetIsoQueueEnd()->TryDequeue();
iso_data_callback.Invoke(std::move(packet));
}
} // namespace internal
} // namespace iso
} // namespace bluetooth