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 namespace bt::hci {
18
MapHandle(const DeviceAddress & address,bool extended_pdu)19 std::optional<hci_spec::AdvertisingHandle> AdvertisingHandleMap::MapHandle(
20 const DeviceAddress& address, bool extended_pdu) {
21 if (auto it = addr_to_handle_.find({address, extended_pdu});
22 it != addr_to_handle_.end()) {
23 return it->second;
24 }
25
26 if (Size() >= capacity_) {
27 return std::nullopt;
28 }
29
30 std::optional<hci_spec::AdvertisingHandle> handle = NextHandle();
31 PW_CHECK(handle);
32
33 addr_to_handle_[{address, extended_pdu}] = handle.value();
34 handle_to_addr_[handle.value()] = {address, extended_pdu};
35 return handle;
36 }
37
38 // Convert a DeviceAddress to an AdvertisingHandle. The conversion may fail if
39 // there is no AdvertisingHandle currently mapping to the provided device
40 // address.
GetHandle(const DeviceAddress & address,bool extended_pdu) const41 std::optional<hci_spec::AdvertisingHandle> AdvertisingHandleMap::GetHandle(
42 const DeviceAddress& address, bool extended_pdu) const {
43 if (auto it = addr_to_handle_.find({address, extended_pdu});
44 it != addr_to_handle_.end()) {
45 return it->second;
46 }
47
48 return std::nullopt;
49 }
50
GetAddress(hci_spec::AdvertisingHandle handle) const51 std::optional<DeviceAddress> AdvertisingHandleMap::GetAddress(
52 hci_spec::AdvertisingHandle handle) const {
53 if (handle_to_addr_.count(handle) != 0) {
54 const auto& [address, extended] = handle_to_addr_.at(handle);
55 return address;
56 }
57
58 return std::nullopt;
59 }
60
RemoveHandle(hci_spec::AdvertisingHandle handle)61 void AdvertisingHandleMap::RemoveHandle(hci_spec::AdvertisingHandle handle) {
62 if (handle_to_addr_.count(handle) == 0) {
63 return;
64 }
65
66 const auto& [address, extended] = handle_to_addr_[handle];
67 addr_to_handle_.erase({address, extended});
68 handle_to_addr_.erase(handle);
69 }
70
RemoveAddress(const DeviceAddress & address,bool extended)71 void AdvertisingHandleMap::RemoveAddress(const DeviceAddress& address,
72 bool extended) {
73 auto node = addr_to_handle_.extract({address, extended});
74 if (node.empty()) {
75 return;
76 }
77
78 hci_spec::AdvertisingHandle handle = node.mapped();
79 handle_to_addr_.erase(handle);
80 }
81
Size() const82 std::size_t AdvertisingHandleMap::Size() const {
83 PW_CHECK(addr_to_handle_.size() == handle_to_addr_.size());
84 return addr_to_handle_.size();
85 }
86
Empty() const87 bool AdvertisingHandleMap::Empty() const {
88 PW_CHECK(addr_to_handle_.empty() == handle_to_addr_.empty());
89 return addr_to_handle_.empty();
90 }
91
Clear()92 void AdvertisingHandleMap::Clear() {
93 last_handle_ = kStartHandle;
94 addr_to_handle_.clear();
95 handle_to_addr_.clear();
96 }
97
NextHandle()98 std::optional<hci_spec::AdvertisingHandle> AdvertisingHandleMap::NextHandle() {
99 if (Size() >= capacity_) {
100 return std::nullopt;
101 }
102
103 hci_spec::AdvertisingHandle handle = last_handle_;
104 do {
105 handle = static_cast<uint8_t>(handle + 1) % capacity_;
106 } while (handle_to_addr_.count(handle) != 0);
107
108 last_handle_ = handle;
109 return handle;
110 }
111
112 std::optional<hci_spec::AdvertisingHandle>
LastUsedHandleForTesting() const113 AdvertisingHandleMap::LastUsedHandleForTesting() const {
114 if (last_handle_ > hci_spec::kMaxAdvertisingHandle) {
115 return std::nullopt;
116 }
117
118 return last_handle_;
119 }
120 } // namespace bt::hci
121