blob: 2ce553e7dde96b1931067e2301de1aacfbb045a8 [file] [log] [blame]
// 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/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 Scan {
public:
enum class ScanError : uint8_t { kCanceled = 0 };
virtual ~Scan() = 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;
};
// 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 becuase 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,
};
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`.
//
// Parameters:
// `id` - Identifier of the peer to initiate a connection to.
// `options` - Options used to configure the connection.
// `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(Result<ConnectError, std::unique_ptr<Connection>>)>&&
callback) = 0;
// Scans for nearby LE peripherals and broadcasters. The lifetime of the scan
// session is tied to the returned `Scan` 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 `Scan` object in
// `scan_result_callback` to stop scanning (no more results will be returned).
//
// Parameters:
// `options` - Options used to configure the scan session.
// `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.
// `scan_started_callback` - Called with a `Scan` 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, std::unique_ptr<Scan>>)>&&
scan_started_callback) = 0;
};
} // namespace pw::bluetooth::low_energy