blob: fdccc3b31b1e382100d1925088a2f1d876d0524c [file] [log] [blame]
// 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.
#ifndef SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_HCI_ADVERTISING_HANDLE_MAP_H_
#define SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_HCI_ADVERTISING_HANDLE_MAP_H_
#include "src/connectivity/bluetooth/core/bt-host/hci-spec/protocol.h"
namespace bt::hci {
// When communicating with the controller, we do so in terms of an AdvertisingHandle. This means
// that we frequently need to convert between a DeviceAddress and an AdvertisingHandle.
// AdvertisingHandleMap provides a 1:1 bidirectional mapping between a DeviceAddress and an
// AdvertisingHandle, allocating the next available AdvertisingHandle to new DeviceAddresses.
//
// Users shouldn't rely on any particular ordering of the next available mapping. Any available
// AdvertisingHandle may be used.
//
// TODO(fxbug.dev/78081): implement a bidirectional map that can support looking up key to value as
// well as value to key (two map solution is probably good enough). Makes this clearer, easier to
// maintain, etc.
class AdvertisingHandleMap {
public:
// Instantiate an AdvertisingHandleMap. The capacity parameter specifies the maximum number of
// mappings that this instance will support. Setting the capacity also restricts the range of
// advertising handles AdvertisingHandleMap will return: [0, capacity).
explicit AdvertisingHandleMap(uint8_t capacity = hci_spec::kMaxAdvertisingHandle + 1)
: capacity_(capacity) {}
// Convert a DeviceAddress to an AdvertisingHandle, creating the mapping if it doesn't already
// exist. The conversion may fail if there are already hci_spec::kMaxAdvertisingHandles in the
// container.
std::optional<hci_spec::AdvertisingHandle> MapHandle(const DeviceAddress& address);
// 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> GetHandle(const DeviceAddress& address) const;
// Convert an AdvertisingHandle to a DeviceAddress. The conversion may fail if there is no
// DeviceAddress currently mapping to the provided handle.
std::optional<DeviceAddress> GetAddress(hci_spec::AdvertisingHandle handle) const;
// Remove the mapping between an AdvertisingHandle and the DeviceAddress it maps to. Immediate
// future calls to GetAddress(handle) with the same AdvertisingHandle will fail because the
// mapping no longer exists. The container may reuse the AdvertisingHandle for other
// DeviceAddresses in the future. Immediate future calls to GetHandle(address) will result in a
// new mapping with a new AdvertisingHandle.
//
// If the given handle doesn't map to any DeviceAddress, this function does nothing.
void RemoveHandle(hci_spec::AdvertisingHandle handle);
// Remove the mapping between a DeviceAddress and the AdvertisingHandle it maps to. Immediate
// future calls to GetAddress(handle) with the preivously mapped AdvertisingHandle will fail
// because the mapping no longer exists. The container may reuse the AdvertisingHandle for other
// DeviceAddresses in the future. Immediate future calls to GetHandle(address) will result in a
// new mapping with a new AdvertisingHandle.
void RemoveAddress(const DeviceAddress& address);
// Get the maximum number of mappings the AdvertisingHandleMap will support.
uint8_t capacity() const { return capacity_; }
// Retrieve the advertising handle that was most recently generated. This function is primarily
// used by unit tests so as to avoid hardcoding values or making assumptions about the starting
// point or ordering of advertising handle generation.
std::optional<hci_spec::AdvertisingHandle> LastUsedHandleForTesting() const;
// Get the number of unique mappings in the container
std::size_t Size() const;
// Return true if the container has no mappings, false otherwise
bool Empty() const;
// Remove all mappings in the container
void Clear();
private:
// Although not in the range of valid advertising handles (0x00 to 0xEF), kStartHandle is chosen
// to be 0xFF because adding one to it will overflow to 0, the first valid advertising handle.
constexpr static hci_spec::AdvertisingHandle kStartHandle = 0xFF;
// Tracks the maximum number of elements that can be stored in this container.
//
// NOTE: AdvertisingHandles have a range of [0, capacity_). This value isn't set using default
// member initialization because it is set within the constructor itself.
uint8_t capacity_;
// Generate the next valid, available, and within range AdvertisingHandle. This function may fail
// if there are already hci_spec::kMaxAdvertisingHandles in the container: there are no more valid
// AdvertisingHandles.
std::optional<hci_spec::AdvertisingHandle> NextHandle();
// The last generated advertising handle used as a hint to generate the next handle; defaults to
// kStartHandle if no handles have been generated yet.
hci_spec::AdvertisingHandle last_handle_ = kStartHandle;
std::unordered_map<DeviceAddress, hci_spec::AdvertisingHandle> addr_to_handle_;
std::unordered_map<hci_spec::AdvertisingHandle, DeviceAddress> handle_to_addr_;
};
} // namespace bt::hci
#endif // SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_HCI_ADVERTISING_HANDLE_MAP_H_