| // Copyright 2021 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/public/pw_bluetooth_sapphire/internal/host/hci/advertising_handle_map.h" |
| |
| namespace bt::hci { |
| |
| std::optional<hci_spec::AdvertisingHandle> AdvertisingHandleMap::MapHandle( |
| const DeviceAddress& address, bool extended_pdu) { |
| if (auto it = addr_to_handle_.find({address, extended_pdu}); |
| it != addr_to_handle_.end()) { |
| return it->second; |
| } |
| |
| if (Size() >= capacity_) { |
| return std::nullopt; |
| } |
| |
| std::optional<hci_spec::AdvertisingHandle> handle = NextHandle(); |
| BT_ASSERT(handle); |
| |
| addr_to_handle_[{address, extended_pdu}] = handle.value(); |
| handle_to_addr_[handle.value()] = {address, extended_pdu}; |
| return handle; |
| } |
| |
| // Convert a DeviceAddress to an AdvertisingHandle. The conversion may fail if |
| // there is no AdvertisingHandle currently mapping to the provided device |
| // address. |
| std::optional<hci_spec::AdvertisingHandle> AdvertisingHandleMap::GetHandle( |
| const DeviceAddress& address, bool extended_pdu) const { |
| if (auto it = addr_to_handle_.find({address, extended_pdu}); |
| it != addr_to_handle_.end()) { |
| return it->second; |
| } |
| |
| return std::nullopt; |
| } |
| |
| std::optional<DeviceAddress> AdvertisingHandleMap::GetAddress( |
| hci_spec::AdvertisingHandle handle) const { |
| if (handle_to_addr_.count(handle) != 0) { |
| const auto& [address, extended] = handle_to_addr_.at(handle); |
| return address; |
| } |
| |
| return std::nullopt; |
| } |
| |
| void AdvertisingHandleMap::RemoveHandle(hci_spec::AdvertisingHandle handle) { |
| if (handle_to_addr_.count(handle) == 0) { |
| return; |
| } |
| |
| const auto& [address, extended] = handle_to_addr_[handle]; |
| addr_to_handle_.erase({address, extended}); |
| handle_to_addr_.erase(handle); |
| } |
| |
| void AdvertisingHandleMap::RemoveAddress(const DeviceAddress& address, |
| bool extended) { |
| auto node = addr_to_handle_.extract({address, extended}); |
| if (node.empty()) { |
| return; |
| } |
| |
| hci_spec::AdvertisingHandle handle = node.mapped(); |
| handle_to_addr_.erase(handle); |
| } |
| |
| std::size_t AdvertisingHandleMap::Size() const { |
| BT_ASSERT(addr_to_handle_.size() == handle_to_addr_.size()); |
| return addr_to_handle_.size(); |
| } |
| |
| bool AdvertisingHandleMap::Empty() const { |
| BT_ASSERT(addr_to_handle_.empty() == handle_to_addr_.empty()); |
| return addr_to_handle_.empty(); |
| } |
| |
| void AdvertisingHandleMap::Clear() { |
| last_handle_ = kStartHandle; |
| addr_to_handle_.clear(); |
| handle_to_addr_.clear(); |
| } |
| |
| std::optional<hci_spec::AdvertisingHandle> AdvertisingHandleMap::NextHandle() { |
| if (Size() >= capacity_) { |
| return std::nullopt; |
| } |
| |
| hci_spec::AdvertisingHandle handle = last_handle_; |
| do { |
| handle = static_cast<uint8_t>(handle + 1) % capacity_; |
| } while (handle_to_addr_.count(handle) != 0); |
| |
| last_handle_ = handle; |
| return handle; |
| } |
| |
| std::optional<hci_spec::AdvertisingHandle> |
| AdvertisingHandleMap::LastUsedHandleForTesting() const { |
| if (last_handle_ > hci_spec::kMaxAdvertisingHandle) { |
| return std::nullopt; |
| } |
| |
| return last_handle_; |
| } |
| } // namespace bt::hci |