| // 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-spec/protocol.h" |
| #include "src/connectivity/bluetooth/core/bt-host/transport/transport.h" |
| |
| namespace bt::gap { |
| |
| LowEnergyInterrogator::LowEnergyInterrogator(PeerCache* cache, fxl::WeakPtr<hci::Transport> hci) |
| : Interrogator(cache, std::move(hci)), weak_ptr_factory_(this) {} |
| |
| void LowEnergyInterrogator::SendCommands(InterrogationRefPtr interrogation) { |
| Peer* peer = peer_cache()->FindById(interrogation->peer_id()); |
| if (!peer) { |
| interrogation->Complete(ToResult(HostError::kFailed)); |
| return; |
| } |
| |
| ZX_ASSERT(peer->le().has_value()); |
| |
| // Always read remote version information as a test of whether the connection was *actually* |
| // successfully established. If the connection failed to be established, the command status of the |
| // Read Remote Version Information command will be "Connection Failed to be Established". See |
| // fxbug.dev/60517 for details. |
| ReadRemoteVersionInformation(interrogation); |
| |
| if (!peer->le()->features().has_value()) { |
| ReadLERemoteFeatures(interrogation); |
| } |
| } |
| |
| void LowEnergyInterrogator::ReadLERemoteFeatures(InterrogationRefPtr interrogation) { |
| auto packet = hci::CommandPacket::New(hci_spec::kLEReadRemoteFeatures, |
| sizeof(hci_spec::LEReadRemoteFeaturesCommandParams)); |
| auto params = packet->mutable_payload<hci_spec::LEReadRemoteFeaturesCommandParams>(); |
| params->connection_handle = htole16(interrogation->handle()); |
| |
| auto cmd_cb = [interrogation, self = weak_ptr_factory_.GetWeakPtr()]( |
| auto id, const hci::EventPacket& event) { |
| if (!self) { |
| return; |
| } |
| |
| if (!interrogation->active()) { |
| return; |
| } |
| |
| if (hci_is_error(event, WARN, "gap-le", "LE read remote features failed")) { |
| interrogation->Complete(event.ToResult()); |
| return; |
| } |
| |
| if (event.event_code() == hci_spec::kCommandStatusEventCode) { |
| return; |
| } |
| |
| ZX_ASSERT(event.event_code() == hci_spec::kLEMetaEventCode); |
| |
| bt_log(DEBUG, "gap-le", "LE read remote features complete (peer: %s)", |
| bt_str(interrogation->peer_id())); |
| |
| const auto* params = |
| event.subevent_params<hci_spec::LEReadRemoteFeaturesCompleteSubeventParams>(); |
| |
| Peer* peer = self->peer_cache()->FindById(interrogation->peer_id()); |
| if (!peer) { |
| interrogation->Complete(ToResult(HostError::kFailed)); |
| return; |
| } |
| |
| peer->MutLe().SetFeatures(hci_spec::LESupportedFeatures{params->le_features}); |
| }; |
| |
| bt_log(TRACE, "gap-le", "sending LE read remote features command (peer id: %s)", |
| bt_str(interrogation->peer_id())); |
| hci()->command_channel()->SendLeAsyncCommand(std::move(packet), std::move(cmd_cb), |
| hci_spec::kLEReadRemoteFeaturesCompleteSubeventCode); |
| } |
| |
| } // namespace bt::gap |