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 #pragma once
16 #include <cpp-string/string_printf.h>
17 
18 #include <cinttypes>
19 #include <cstdint>
20 #include <string>
21 
22 #include "pw_bluetooth_sapphire/internal/host/common/assert.h"
23 #include "pw_bluetooth_sapphire/internal/host/common/log.h"
24 #include "pw_bluetooth_sapphire/internal/host/hci-spec/constants.h"
25 
26 namespace bt::hci_spec {
27 
28 // Remote devices and local controllers have a feature set defined by the
29 // Link Manager Protocol.
30 // LMP features are organized into "pages", each containing a bit-mask of
31 // supported controller features. See Core Spec v5.0, Vol 2, Part C, Section 3.3
32 // "Feature Mask Definition".
33 // Three of these pages (the standard page plus two "extended feature" pages)
34 // are defined by the spec.
35 
36 // See LMPFeature in hci_constants.h for the list of feature bits.
37 class LMPFeatureSet {
38  public:
39   // Creates a feature set with no pages set.
LMPFeatureSet()40   LMPFeatureSet() : valid_pages_{false}, last_page_number_(0) {}
41 
42   // The maximum extended page that we support
43   constexpr static uint8_t kMaxLastPageNumber = 2;
44   constexpr static uint8_t kMaxPages = kMaxLastPageNumber + 1;
45 
46   // Returns true if |bit| is set in the LMP Features.
47   // |page| is the page that this bit resides on.
48   // Page 0 is the standard features.
HasBit(size_t page,LMPFeature bit)49   inline bool HasBit(size_t page, LMPFeature bit) const {
50     return HasPage(page) && (features_[page] & static_cast<uint64_t>(bit));
51   }
52 
53   // Sets |page| features to |features|
SetPage(size_t page,uint64_t features)54   inline void SetPage(size_t page, uint64_t features) {
55     PW_CHECK(page < kMaxPages);
56     features_[page] = features;
57     valid_pages_[page] = true;
58   }
59 
60   // Returns true if the feature page |page| has been set.
HasPage(size_t page)61   inline bool HasPage(size_t page) const {
62     return (page < kMaxPages) && valid_pages_[page];
63   }
64 
ToString()65   inline std::string ToString() const {
66     std::string str;
67     for (size_t i = 0; i <= last_page_number_; i++)
68       if (HasPage(i))
69         str += bt_lib_cpp_string::StringPrintf(
70             "[P%zu: 0x%016" PRIx64 "]", i, features_[i]);
71     return str;
72   }
73 
set_last_page_number(uint8_t page)74   inline void set_last_page_number(uint8_t page) {
75     if (page > kMaxLastPageNumber) {
76       bt_log(TRACE,
77              "hci",
78              "attempt to set lmp last page number to %u, capping at %u",
79              page,
80              kMaxLastPageNumber);
81       last_page_number_ = kMaxLastPageNumber;
82     } else {
83       last_page_number_ = page;
84     }
85   }
86 
last_page_number()87   inline uint8_t last_page_number() const { return last_page_number_; }
88 
89  private:
90   uint64_t features_[kMaxPages];
91   bool valid_pages_[kMaxPages];
92   uint8_t last_page_number_;
93 };
94 
95 }  // namespace bt::hci_spec
96