xref: /aosp_15_r20/external/pigweed/pw_bluetooth/public/pw_bluetooth/low_energy/central.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2022 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 #pragma once
15 
16 #include <memory>
17 #include <optional>
18 
19 #include "pw_bluetooth/internal/raii_ptr.h"
20 #include "pw_bluetooth/low_energy/advertising_data.h"
21 #include "pw_bluetooth/low_energy/connection.h"
22 #include "pw_bluetooth/result.h"
23 #include "pw_bluetooth/types.h"
24 #include "pw_chrono/system_clock.h"
25 #include "pw_containers/vector.h"
26 #include "pw_function/function.h"
27 
28 namespace pw::bluetooth::low_energy {
29 
30 /// Represents the LE central role. Used to scan and connect to peripherals.
31 class Central {
32  public:
33   /// Represents an ongoing LE scan.
34   class ScanHandle {
35    public:
36     /// Possible errors that can cause a scan to stop prematurely.
37     enum class ScanError : uint8_t { kCanceled = 0 };
38 
39     virtual ~ScanHandle() = 0;
40 
41     /// Set a callback that will be called if the scan is stopped due to an
42     /// error in the BLE stack.
43     virtual void SetErrorCallback(Function<void(ScanError)>&& callback) = 0;
44 
45    private:
46     /// Stop the current scan. This method is called by the ~ScanHandle::Ptr()
47     /// when it goes out of scope, the API client should never call this method.
48     virtual void StopScan() = 0;
49 
50    public:
51     /// Movable ScanHandle smart pointer. The controller will continue scanning
52     /// until the ScanHandle::Ptr is destroyed.
53     using Ptr = internal::RaiiPtr<ScanHandle, &ScanHandle::StopScan>;
54   };
55 
56   /// Filter parameters for use during a scan. A discovered peer only matches
57   /// the filter if it satisfies all of the present filter parameters.
58   struct ScanFilter {
59     /// Filter based on advertised service UUID.
60     std::optional<Uuid> service_uuid;
61 
62     /// Filter based on service data containing the given UUID.
63     std::optional<Uuid> service_data_uuid;
64 
65     /// Filter based on a manufacturer identifier present in the manufacturer
66     /// data. If this filter parameter is set, then the advertising payload must
67     /// contain manufacturer specific data with the provided company identifier
68     /// to satisfy this filter. Manufacturer identifiers can be found at
69     /// https://www.bluetooth.com/specifications/assigned-numbers/company-identifiers/
70     std::optional<uint16_t> manufacturer_id;
71 
72     /// Filter based on whether or not a device is connectable. For example, a
73     /// client that is only interested in peripherals that it can connect to can
74     /// set this to true. Similarly a client can scan only for broadcasters by
75     /// setting this to false.
76     std::optional<bool> connectable;
77 
78     /// Filter results based on a portion of the advertised device name.
79     /// Substring matches are allowed.
80     /// The name length must be at most pw::bluetooth::kMaxDeviceNameLength.
81     std::optional<std::string_view> name;
82 
83     /// Filter results based on the path loss of the radio wave. A device that
84     /// matches this filter must satisfy the following:
85     ///   1. Radio transmission power level and received signal strength must be
86     ///      available for the path loss calculation.
87     ///   2. The calculated path loss value must be less than, or equal to,
88     ///      `max_path_loss`.
89     ///
90     /// @note This field is calculated using the RSSI and TX Power information
91     /// obtained from advertising and scan response data during a scan
92     /// procedure. It should NOT be confused with information for an active
93     /// connection obtained using the "Path Loss Reporting" feature.
94     std::optional<uint8_t> max_path_loss;
95   };
96 
97   /// Parameters used during a scan.
98   struct ScanOptions {
99     /// List of filters for use during a scan. A peripheral that satisfies any
100     /// of these filters will be reported. At least 1 filter must be specified.
101     /// While not recommended, clients that require that all peripherals be
102     /// reported can specify an empty filter.
103     Vector<ScanFilter> filters;
104 
105     /// The time interval between scans.
106     /// - Time = N * 0.625ms
107     /// - Range: 0x0004 (2.5ms) - 10.24ms (0x4000)
108     /// - Default: 10ms
109     uint16_t interval = 0x0010;
110 
111     /// The duration of the scan. The window must be less than or equal to the
112     /// interval.
113     /// - Time = N * 0.625ms
114     /// - Range: 0x0004 (2.5ms) - 10.24ms (0x4000)
115     /// - Default: 10ms
116     uint16_t window = 0x0010;
117   };
118 
119   /// Information obtained from advertising and scan response data broadcast by
120   /// a peer.
121   struct ScanData {
122     /// The radio transmit power level.
123     /// @note This field should NOT be confused with the "connection TX Power
124     /// Level" of a peer that is currently connected to the system obtained via
125     /// the "Transmit Power reporting" feature.
126     std::optional<uint8_t> tx_power;
127 
128     /// The appearance of the device.
129     std::optional<Appearance> appearance;
130 
131     Vector<Uuid> service_uuids;
132 
133     Vector<ServiceData> service_data;
134 
135     Vector<ManufacturerData> manufacturer_data;
136 
137     /// String representing a URI to be advertised, as defined in IETF STD 66:
138     /// https://tools.ietf.org/html/std66. Each entry should be a UTF-8 string
139     /// including the scheme. For more information, see
140     /// https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml for
141     /// allowed schemes;
142     /// @note Bluetooth advertising compresses schemas over the air to save
143     /// space. See
144     /// https://www.bluetooth.com/specifications/assigned-numbers/uri-scheme-name-string-mapping.
145     Vector<std::string_view> uris;
146 
147     /// The time when this scan data was received.
148     chrono::SystemClock::time_point timestamp;
149   };
150 
151   struct ScanResult {
152     /// ScanResult is non-copyable because strings are only valid in the result
153     /// callback.
154     ScanResult(const ScanResult&) = delete;
155     ScanResult& operator=(const ScanResult&) = delete;
156 
157     /// Uniquely identifies this peer on the current system.
158     PeerId peer_id;
159 
160     /// Whether or not this peer is connectable. Non-connectable peers are
161     /// typically in the LE broadcaster role.
162     bool connectable;
163 
164     /// The last observed signal strength of this peer. This field is only
165     /// present for a peer that is broadcasting. The RSSI can be stale if the
166     /// peer has not been advertising.
167     ///
168     /// @note This field should NOT be confused with the "connection RSSI" of a
169     /// peer that is currently connected to the system.
170     std::optional<uint8_t> rssi;
171 
172     /// Information from advertising and scan response data broadcast by this
173     /// peer. This contains the advertising data last received from the peer.
174     ScanData scan_data;
175 
176     /// The name of this peer. The name is often obtained during a scan
177     /// procedure and can get updated during the name discovery procedure
178     /// following a connection.
179     ///
180     /// This field is present if the name is known.
181     std::optional<std::string_view> name;
182 
183     /// Timestamp of when the information in this `ScanResult` was last updated.
184     chrono::SystemClock::time_point last_updated;
185   };
186 
187   /// Possible errors returned by `Connect`.
188   enum class ConnectError : uint8_t {
189     /// The peer ID is unknown.
190     kUnknownPeer,
191 
192     /// The `ConnectionOptions` were invalid.
193     kInvalidOptions,
194 
195     /// A connection to the peer already exists.
196     kAlreadyExists,
197 
198     /// A connection could not be established.
199     kCouldNotBeEstablished,
200   };
201 
202   enum class StartScanError : uint8_t {
203     /// A scan is already in progress. Only 1 scan may be active at a time.
204     kScanInProgress,
205     /// Some of the scan options are invalid.
206     kInvalidParameters,
207     /// An internal error occurred and a scan could not be started.
208     kInternal,
209   };
210 
211   /// The Result type returned by Connect() via the passed callback.
212   using ConnectResult = Result<ConnectError, Connection::Ptr>;
213 
214   virtual ~Central() = default;
215 
216   /// Connect to the peer with the given identifier.
217   ///
218   /// The requested `Connection` represents the client's interest in the LE
219   /// connection to the peer. Destroying the `Connection` will disconnect from
220   /// the peer. Only 1 connection per peer may exist at a time.
221   ///
222   /// The `Connection` will be closed by the system if the connection to the
223   /// peer is lost or an error occurs, as indicated by `Connection.OnError`.
224   ///
225   /// @param peer_id Identifier of the peer to initiate a connection to.
226   /// @param options Options used to configure the connection.
227   /// @param callback Called when a connection is successfully established, or
228   /// an error occurs.
229   ///
230   /// Possible errors are documented in `ConnectError`.
231   virtual void Connect(PeerId peer_id,
232                        ConnectionOptions options,
233                        Function<void(ConnectResult)>&& callback) = 0;
234 
235   /// Scans for nearby LE peripherals and broadcasters. The lifetime of the scan
236   /// session is tied to the returned `ScanHandle` object. Once a scan is
237   /// started, `scan_result_callback` will be called with scan results. Only 1
238   /// scan may be active at a time. It is OK to destroy the `ScanHandle::Ptr`
239   /// object in `scan_result_callback` to stop scanning (no more results will be
240   /// returned).
241   ///
242   /// @param options Options used to configure the scan session.
243   /// @param scan_result_callback If scanning starts successfully,called for LE
244   /// peers that satisfy the filters indicated in `options`. The initial calls
245   /// may report recently discovered peers. Subsequent calls will be made only
246   /// when peers have been scanned or updated since the last call.
247   /// @param scan_started_callback Called with a `ScanHandle` object if the scan
248   /// successfully starts, or a `ScanError` otherwise.
249   virtual void Scan(ScanOptions options,
250                     Function<void(ScanResult)>&& scan_result_callback,
251                     Function<void(Result<StartScanError, ScanHandle::Ptr>)>&&
252                         scan_started_callback) = 0;
253 };
254 
255 }  // namespace pw::bluetooth::low_energy
256