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 <string> 17 #include <vector> 18 19 #include "pw_bluetooth_sapphire/internal/host/common/advertising_data.h" 20 #include "pw_bluetooth_sapphire/internal/host/common/uuid.h" 21 22 namespace bt::hci { 23 24 // A DiscoveryFilter allows clients of discovery procedures to filter results 25 // based on certain parameters, such as service UUIDs that might be present in 26 // EIR or advertising data, or based on available proximity information, to name 27 // a few. 28 class DiscoveryFilter final { 29 public: 30 DiscoveryFilter() = default; 31 32 // Sets this filter up for the "General Discovery" procedure. 33 void SetGeneralDiscoveryFlags(); 34 35 // Discovery filter based on the "Flags" bit field in LE Advertising Data. If 36 // |require_all| is true, then The filter is considered satisifed if ALL of 37 // the bits set in |flags_bitfield| are present in the advertisement. 38 // Otherwise, the filter is considered satisfied as long as one of the bits 39 // set in |flags_bitfield| is present. 40 void set_flags(uint8_t flags_bitfield, bool require_all = false) { 41 flags_ = flags_bitfield; 42 all_flags_required_ = require_all; 43 } 44 45 // Discovery filter based on whether or not a device is connectable. set_connectable(bool connectable)46 void set_connectable(bool connectable) { connectable_ = connectable; } connectable()47 std::optional<bool> connectable() const { return connectable_; } 48 49 // Sets the service UUIDs that should be present in a scan result. A scan 50 // result satisfies this filter if it provides at least one of the provided 51 // UUIDs. 52 // 53 // Passing an empty value for |service_uuids| effectively disables this 54 // filter. set_service_uuids(const std::vector<UUID> & service_uuids)55 void set_service_uuids(const std::vector<UUID>& service_uuids) { 56 service_uuids_ = service_uuids; 57 } service_uuids()58 const std::vector<UUID>& service_uuids() const { return service_uuids_; } 59 60 // Filter on service data UUIDs. 61 // 62 // Passing an empty value for |service_data_uuids| effectively disables this 63 // filter. set_service_data_uuids(const std::vector<UUID> & service_data_uuids)64 void set_service_data_uuids(const std::vector<UUID>& service_data_uuids) { 65 service_data_uuids_ = service_data_uuids; 66 } service_data_uuids()67 const std::vector<UUID>& service_data_uuids() const { 68 return service_data_uuids_; 69 } 70 71 // Sets a string to be matched against the device name. A scan result 72 // satisfies this filter if part of the complete or shortened device name 73 // fields matches |name_substring|. 74 // 75 // Passing an empty value for |name_substring| effectively disables this 76 // filter. set_name_substring(const std::string & name_substring)77 void set_name_substring(const std::string& name_substring) { 78 name_substring_ = name_substring; 79 } name_substring()80 const std::string& name_substring() const { return name_substring_; } 81 82 // Sets a device to be filtered by the pathloss (in dBm) of the radio wave. 83 // This value is calculated using the received signal strength (measured 84 // locally) and the transmission power of the signal (as reported by the 85 // remote): 86 // 87 // Path Loss = RSSI - Tx Power 88 // 89 // If this filter parameter has been set and the pathloss value calculated for 90 // a device greater than the provided |pathloss| value, then the scan result 91 // will fail to satisfy this filter. 92 // 93 // If this filter parameter has been set and the pathloss value cannot be 94 // calculated because the remote device did not report its transmission power, 95 // then the device will fail to satisfy this filter UNLESS an RSSI filter 96 // parameter has been set via SetRSSI() that is satisfied by the scan result. set_pathloss(int8_t pathloss)97 void set_pathloss(int8_t pathloss) { pathloss_ = pathloss; } pathloss()98 std::optional<int8_t> pathloss() const { return pathloss_; } 99 100 // Sets a device to be filtered by RSSI. While this can produce inaccurate 101 // results when used alone to approximate proximity, it can still be useful 102 // when the scan results do not provide the remote device's Transmission 103 // Power. 104 // 105 // A remote device is considered to satisfy this filter parameter if the RSSI 106 // of the received transmission is greater than or equal to |rssi|, except if 107 // a path loss filter was provided via SetPathLoss() which the remote device 108 // failed to satisfy (see comments on SetPathLoss()). set_rssi(int8_t rssi)109 void set_rssi(int8_t rssi) { rssi_ = rssi; } rssi()110 std::optional<int8_t> rssi() const { return rssi_; } 111 112 // Sets a device to be filtered by manufacturer specific data. A scan result 113 // satisfies this filter if it advertises manufacturer specific data 114 // containing |manufacturer_code|. set_manufacturer_code(uint16_t manufacturer_code)115 void set_manufacturer_code(uint16_t manufacturer_code) { 116 manufacturer_code_ = manufacturer_code; 117 } manufacturer_code()118 std::optional<uint16_t> manufacturer_code() const { 119 return manufacturer_code_; 120 } 121 122 // Sets a device to be filtered by service data UUIDs it requests peers 123 // support (solicitation). 124 // 125 // Passing an empty value for |solicitation_uuids| effectively disables this 126 // filter. set_solicitation_uuids(const std::vector<UUID> & solicitation_uuids)127 void set_solicitation_uuids(const std::vector<UUID>& solicitation_uuids) { 128 solicitation_uuids_ = solicitation_uuids; 129 } solicitation_uuids()130 const std::vector<UUID>& solicitation_uuids() const { 131 return solicitation_uuids_; 132 } 133 134 // Returns true, if the given LE scan result satisfies this filter. Otherwise 135 // returns false. |advertising_data| should include scan response data, if 136 // any. 137 bool MatchLowEnergyResult( 138 const std::optional<std::reference_wrapper<const AdvertisingData>> 139 advertising_data, 140 bool connectable, 141 int8_t rssi) const; 142 143 // Clears all the fields of this filter. 144 void Reset(); 145 146 private: 147 std::vector<UUID> service_uuids_; 148 std::vector<UUID> service_data_uuids_; 149 std::vector<UUID> solicitation_uuids_; 150 std::string name_substring_; 151 std::optional<bool> connectable_; 152 std::optional<uint16_t> manufacturer_code_; 153 std::optional<int8_t> pathloss_; 154 std::optional<int8_t> rssi_; 155 156 std::optional<uint8_t> flags_; 157 bool all_flags_required_; 158 }; 159 } // namespace bt::hci 160