blob: b19c9b82d67f24de2eb841b9fa16446e28c06932 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/connectivity/bluetooth/core/bt-host/gap/low_energy_interrogator.h"
#include "src/connectivity/bluetooth/core/bt-host/gap/peer.h"
#include "src/connectivity/bluetooth/core/bt-host/hci/hci.h"
#include "src/connectivity/bluetooth/core/bt-host/hci/transport.h"
namespace bt::gap {
LowEnergyInterrogator::LowEnergyInterrogator(PeerCache* cache, fxl::RefPtr<hci::Transport> hci,
async_dispatcher_t* dispatcher)
: Interrogator(cache, std::move(hci), dispatcher), weak_ptr_factory_(this) {}
void LowEnergyInterrogator::SendCommands(InterrogationRefPtr interrogation) {
Peer* peer = peer_cache()->FindById(interrogation->peer_id());
if (!peer) {
interrogation->Complete(hci::Status(HostError::kFailed));
return;
}
ZX_ASSERT(peer->le().has_value());
if (!peer->version().has_value()) {
ReadRemoteVersionInformation(interrogation);
}
if (!peer->le()->features().has_value()) {
ReadLERemoteFeatures(interrogation);
}
}
void LowEnergyInterrogator::ReadLERemoteFeatures(InterrogationRefPtr interrogation) {
auto packet = hci::CommandPacket::New(hci::kLEReadRemoteFeatures,
sizeof(hci::LEReadRemoteFeaturesCommandParams));
auto params = packet->mutable_payload<hci::LEReadRemoteFeaturesCommandParams>();
params->connection_handle = htole16(interrogation->handle());
auto cmd_cb = [interrogation, self = weak_ptr_factory_.GetWeakPtr()](
auto id, const hci::EventPacket& event) {
if (!interrogation->active()) {
return;
}
if (hci_is_error(event, WARN, "gap-le", "LE read remote features failed")) {
interrogation->Complete(event.ToStatus());
return;
}
if (event.event_code() == hci::kCommandStatusEventCode) {
return;
}
ZX_ASSERT(event.event_code() == hci::kLEMetaEventCode);
bt_log(SPEW, "gap-le", "LE read remote features complete (peer id: %s)",
bt_str(interrogation->peer_id()));
const auto* params = event.le_event_params<hci::LEReadRemoteFeaturesCompleteSubeventParams>();
Peer* peer = self->peer_cache()->FindById(interrogation->peer_id());
if (!peer) {
interrogation->Complete(hci::Status(HostError::kFailed));
return;
}
peer->MutLe().SetFeatures(hci::LESupportedFeatures{params->le_features});
};
bt_log(SPEW, "gap-le", "sending LE read remote features command (peer id: %s)",
bt_str(interrogation->peer_id()));
hci()->command_channel()->SendLeAsyncCommand(std::move(packet), dispatcher(), std::move(cmd_cb),
hci::kLEReadRemoteFeaturesCompleteSubeventCode);
}
} // namespace bt::gap