aboutsummaryrefslogtreecommitdiff
path: root/pw_bluetooth/public/pw_bluetooth/low_energy/central.h
diff options
context:
space:
mode:
Diffstat (limited to 'pw_bluetooth/public/pw_bluetooth/low_energy/central.h')
-rw-r--r--pw_bluetooth/public/pw_bluetooth/low_energy/central.h255
1 files changed, 255 insertions, 0 deletions
diff --git a/pw_bluetooth/public/pw_bluetooth/low_energy/central.h b/pw_bluetooth/public/pw_bluetooth/low_energy/central.h
new file mode 100644
index 000000000..391e691c8
--- /dev/null
+++ b/pw_bluetooth/public/pw_bluetooth/low_energy/central.h
@@ -0,0 +1,255 @@
+// Copyright 2022 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+#pragma once
+
+#include <memory>
+#include <optional>
+
+#include "pw_bluetooth/internal/raii_ptr.h"
+#include "pw_bluetooth/low_energy/advertising_data.h"
+#include "pw_bluetooth/low_energy/connection.h"
+#include "pw_bluetooth/result.h"
+#include "pw_bluetooth/types.h"
+#include "pw_chrono/system_clock.h"
+#include "pw_containers/vector.h"
+#include "pw_function/function.h"
+
+namespace pw::bluetooth::low_energy {
+
+/// Represents the LE central role. Used to scan and connect to peripherals.
+class Central {
+ public:
+ /// Represents an ongoing LE scan.
+ class ScanHandle {
+ public:
+ /// Possible errors that can cause a scan to stop prematurely.
+ enum class ScanError : uint8_t { kCanceled = 0 };
+
+ virtual ~ScanHandle() = 0;
+
+ /// Set a callback that will be called if the scan is stopped due to an
+ /// error in the BLE stack.
+ virtual void SetErrorCallback(Function<void(ScanError)>&& callback) = 0;
+
+ private:
+ /// Stop the current scan. This method is called by the ~ScanHandle::Ptr()
+ /// when it goes out of scope, the API client should never call this method.
+ virtual void StopScan() = 0;
+
+ public:
+ /// Movable ScanHandle smart pointer. The controller will continue scanning
+ /// until the ScanHandle::Ptr is destroyed.
+ using Ptr = internal::RaiiPtr<ScanHandle, &ScanHandle::StopScan>;
+ };
+
+ /// Filter parameters for use during a scan. A discovered peer only matches
+ /// the filter if it satisfies all of the present filter parameters.
+ struct ScanFilter {
+ /// Filter based on advertised service UUID.
+ std::optional<Uuid> service_uuid;
+
+ /// Filter based on service data containing the given UUID.
+ std::optional<Uuid> service_data_uuid;
+
+ /// Filter based on a manufacturer identifier present in the manufacturer
+ /// data. If this filter parameter is set, then the advertising payload must
+ /// contain manufacturer specific data with the provided company identifier
+ /// to satisfy this filter. Manufacturer identifiers can be found at
+ /// https://www.bluetooth.com/specifications/assigned-numbers/company-identifiers/
+ std::optional<uint16_t> manufacturer_id;
+
+ /// Filter based on whether or not a device is connectable. For example, a
+ /// client that is only interested in peripherals that it can connect to can
+ /// set this to true. Similarly a client can scan only for broadcasters by
+ /// setting this to false.
+ std::optional<bool> connectable;
+
+ /// Filter results based on a portion of the advertised device name.
+ /// Substring matches are allowed.
+ /// The name length must be at most pw::bluetooth::kMaxDeviceNameLength.
+ std::optional<std::string_view> name;
+
+ /// Filter results based on the path loss of the radio wave. A device that
+ /// matches this filter must satisfy the following:
+ /// 1. Radio transmission power level and received signal strength must be
+ /// available for the path loss calculation.
+ /// 2. The calculated path loss value must be less than, or equal to,
+ /// `max_path_loss`.
+ ///
+ /// @note This field is calculated using the RSSI and TX Power information
+ /// obtained from advertising and scan response data during a scan
+ /// procedure. It should NOT be confused with information for an active
+ /// connection obtained using the "Path Loss Reporting" feature.
+ std::optional<uint8_t> max_path_loss;
+ };
+
+ /// Parameters used during a scan.
+ struct ScanOptions {
+ /// List of filters for use during a scan. A peripheral that satisfies any
+ /// of these filters will be reported. At least 1 filter must be specified.
+ /// While not recommended, clients that require that all peripherals be
+ /// reported can specify an empty filter.
+ Vector<ScanFilter> filters;
+
+ /// The time interval between scans.
+ /// - Time = N * 0.625ms
+ /// - Range: 0x0004 (2.5ms) - 10.24ms (0x4000)
+ /// - Default: 10ms
+ uint16_t interval = 0x0010;
+
+ /// The duration of the scan. The window must be less than or equal to the
+ /// interval.
+ /// - Time = N * 0.625ms
+ /// - Range: 0x0004 (2.5ms) - 10.24ms (0x4000)
+ /// - Default: 10ms
+ uint16_t window = 0x0010;
+ };
+
+ /// Information obtained from advertising and scan response data broadcast by
+ /// a peer.
+ struct ScanData {
+ /// The radio transmit power level.
+ /// @note This field should NOT be confused with the "connection TX Power
+ /// Level" of a peer that is currently connected to the system obtained via
+ /// the "Transmit Power reporting" feature.
+ std::optional<uint8_t> tx_power;
+
+ /// The appearance of the device.
+ std::optional<Appearance> appearance;
+
+ Vector<Uuid> service_uuids;
+
+ Vector<ServiceData> service_data;
+
+ Vector<ManufacturerData> manufacturer_data;
+
+ /// String representing a URI to be advertised, as defined in IETF STD 66:
+ /// https://tools.ietf.org/html/std66. Each entry should be a UTF-8 string
+ /// including the scheme. For more information, see
+ /// https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml for
+ /// allowed schemes;
+ /// @note Bluetooth advertising compresses schemas over the air to save
+ /// space. See
+ /// https://www.bluetooth.com/specifications/assigned-numbers/uri-scheme-name-string-mapping.
+ Vector<std::string_view> uris;
+
+ /// The time when this scan data was received.
+ chrono::SystemClock::time_point timestamp;
+ };
+
+ struct ScanResult {
+ /// ScanResult is non-copyable because strings are only valid in the result
+ /// callback.
+ ScanResult(const ScanResult&) = delete;
+ ScanResult& operator=(const ScanResult&) = delete;
+
+ /// Uniquely identifies this peer on the current system.
+ PeerId peer_id;
+
+ /// Whether or not this peer is connectable. Non-connectable peers are
+ /// typically in the LE broadcaster role.
+ bool connectable;
+
+ /// The last observed signal strength of this peer. This field is only
+ /// present for a peer that is broadcasting. The RSSI can be stale if the
+ /// peer has not been advertising.
+ ///
+ /// @note This field should NOT be confused with the "connection RSSI" of a
+ /// peer that is currently connected to the system.
+ std::optional<uint8_t> rssi;
+
+ /// Information from advertising and scan response data broadcast by this
+ /// peer. This contains the advertising data last received from the peer.
+ ScanData scan_data;
+
+ /// The name of this peer. The name is often obtained during a scan
+ /// procedure and can get updated during the name discovery procedure
+ /// following a connection.
+ ///
+ /// This field is present if the name is known.
+ std::optional<std::string_view> name;
+
+ /// Timestamp of when the information in this `ScanResult` was last updated.
+ chrono::SystemClock::time_point last_updated;
+ };
+
+ /// Possible errors returned by `Connect`.
+ enum class ConnectError : uint8_t {
+ /// The peer ID is unknown.
+ kUnknownPeer,
+
+ /// The `ConnectionOptions` were invalid.
+ kInvalidOptions,
+
+ /// A connection to the peer already exists.
+ kAlreadyExists,
+
+ /// A connection could not be established.
+ kCouldNotBeEstablished,
+ };
+
+ enum class StartScanError : uint8_t {
+ /// A scan is already in progress. Only 1 scan may be active at a time.
+ kScanInProgress,
+ /// Some of the scan options are invalid.
+ kInvalidParameters,
+ /// An internal error occurred and a scan could not be started.
+ kInternal,
+ };
+
+ /// The Result type returned by Connect() via the passed callback.
+ using ConnectResult = Result<ConnectError, Connection::Ptr>;
+
+ virtual ~Central() = default;
+
+ /// Connect to the peer with the given identifier.
+ ///
+ /// The requested `Connection` represents the client's interest in the LE
+ /// connection to the peer. Destroying the `Connection` will disconnect from
+ /// the peer. Only 1 connection per peer may exist at a time.
+ ///
+ /// The `Connection` will be closed by the system if the connection to the
+ /// peer is lost or an error occurs, as indicated by `Connection.OnError`.
+ ///
+ /// @param peer_id Identifier of the peer to initiate a connection to.
+ /// @param options Options used to configure the connection.
+ /// @param callback Called when a connection is successfully established, or
+ /// an error occurs.
+ ///
+ /// Possible errors are documented in `ConnectError`.
+ virtual void Connect(PeerId peer_id,
+ ConnectionOptions options,
+ Function<void(ConnectResult)>&& callback) = 0;
+
+ /// Scans for nearby LE peripherals and broadcasters. The lifetime of the scan
+ /// session is tied to the returned `ScanHandle` object. Once a scan is
+ /// started, `scan_result_callback` will be called with scan results. Only 1
+ /// scan may be active at a time. It is OK to destroy the `ScanHandle::Ptr`
+ /// object in `scan_result_callback` to stop scanning (no more results will be
+ /// returned).
+ ///
+ /// @param options Options used to configure the scan session.
+ /// @param scan_result_callback If scanning starts successfully,called for LE
+ /// peers that satisfy the filters indicated in `options`. The initial calls
+ /// may report recently discovered peers. Subsequent calls will be made only
+ /// when peers have been scanned or updated since the last call.
+ /// @param scan_started_callback Called with a `ScanHandle` object if the scan
+ /// successfully starts, or a `ScanError` otherwise.
+ virtual void Scan(ScanOptions options,
+ Function<void(ScanResult)>&& scan_result_callback,
+ Function<void(Result<StartScanError, ScanHandle::Ptr>)>&&
+ scan_started_callback) = 0;
+};
+
+} // namespace pw::bluetooth::low_energy