1 // Copyright 2023 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 #include "pw_bluetooth_sapphire/internal/host/hci/advertising_handle_map.h"
16
17 #include <pw_assert/check.h>
18
19 namespace bt::hci {
20
MapHandle(const DeviceAddress & address,bool extended_pdu)21 std::optional<hci_spec::AdvertisingHandle> AdvertisingHandleMap::MapHandle(
22 const DeviceAddress& address, bool extended_pdu) {
23 if (auto it = addr_to_handle_.find({address, extended_pdu});
24 it != addr_to_handle_.end()) {
25 return it->second;
26 }
27
28 if (Size() >= capacity_) {
29 return std::nullopt;
30 }
31
32 std::optional<hci_spec::AdvertisingHandle> handle = NextHandle();
33 PW_CHECK(handle);
34
35 addr_to_handle_[{address, extended_pdu}] = handle.value();
36 handle_to_addr_[handle.value()] = {address, extended_pdu};
37 return handle;
38 }
39
40 // Convert a DeviceAddress to an AdvertisingHandle. The conversion may fail if
41 // there is no AdvertisingHandle currently mapping to the provided device
42 // address.
GetHandle(const DeviceAddress & address,bool extended_pdu) const43 std::optional<hci_spec::AdvertisingHandle> AdvertisingHandleMap::GetHandle(
44 const DeviceAddress& address, bool extended_pdu) const {
45 if (auto it = addr_to_handle_.find({address, extended_pdu});
46 it != addr_to_handle_.end()) {
47 return it->second;
48 }
49
50 return std::nullopt;
51 }
52
GetAddress(hci_spec::AdvertisingHandle handle) const53 std::optional<DeviceAddress> AdvertisingHandleMap::GetAddress(
54 hci_spec::AdvertisingHandle handle) const {
55 if (handle_to_addr_.count(handle) != 0) {
56 const auto& [address, extended] = handle_to_addr_.at(handle);
57 return address;
58 }
59
60 return std::nullopt;
61 }
62
RemoveHandle(hci_spec::AdvertisingHandle handle)63 void AdvertisingHandleMap::RemoveHandle(hci_spec::AdvertisingHandle handle) {
64 if (handle_to_addr_.count(handle) == 0) {
65 return;
66 }
67
68 const auto& [address, extended] = handle_to_addr_[handle];
69 addr_to_handle_.erase({address, extended});
70 handle_to_addr_.erase(handle);
71 }
72
RemoveAddress(const DeviceAddress & address,bool extended)73 void AdvertisingHandleMap::RemoveAddress(const DeviceAddress& address,
74 bool extended) {
75 auto node = addr_to_handle_.extract({address, extended});
76 if (node.empty()) {
77 return;
78 }
79
80 hci_spec::AdvertisingHandle handle = node.mapped();
81 handle_to_addr_.erase(handle);
82 }
83
Size() const84 std::size_t AdvertisingHandleMap::Size() const {
85 PW_CHECK(addr_to_handle_.size() == handle_to_addr_.size());
86 return addr_to_handle_.size();
87 }
88
Empty() const89 bool AdvertisingHandleMap::Empty() const {
90 PW_CHECK(addr_to_handle_.empty() == handle_to_addr_.empty());
91 return addr_to_handle_.empty();
92 }
93
Clear()94 void AdvertisingHandleMap::Clear() {
95 last_handle_ = kStartHandle;
96 addr_to_handle_.clear();
97 handle_to_addr_.clear();
98 }
99
NextHandle()100 std::optional<hci_spec::AdvertisingHandle> AdvertisingHandleMap::NextHandle() {
101 if (Size() >= capacity_) {
102 return std::nullopt;
103 }
104
105 hci_spec::AdvertisingHandle handle = last_handle_;
106 do {
107 handle = static_cast<uint8_t>(handle + 1) % capacity_;
108 } while (handle_to_addr_.count(handle) != 0);
109
110 last_handle_ = handle;
111 return handle;
112 }
113
114 std::optional<hci_spec::AdvertisingHandle>
LastUsedHandleForTesting() const115 AdvertisingHandleMap::LastUsedHandleForTesting() const {
116 if (last_handle_ > hci_spec::kMaxAdvertisingHandle) {
117 return std::nullopt;
118 }
119
120 return last_handle_;
121 }
122 } // namespace bt::hci
123