• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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