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
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
|