diff options
Diffstat (limited to 'pw_bluetooth/public/pw_bluetooth/low_energy/central.h')
-rw-r--r-- | pw_bluetooth/public/pw_bluetooth/low_energy/central.h | 255 |
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 |