blob: 04ec360c372494643a33ae51ee422815dc3b2178 [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 <cstdint>
#include <memory>
#include "pw_bluetooth/gatt/error.h"
#include "pw_bluetooth/gatt/types.h"
#include "pw_bluetooth/result.h"
#include "pw_bluetooth/types.h"
#include "pw_containers/vector.h"
#include "pw_function/function.h"
#include "pw_span/span.h"
#include "pw_status/status.h"
namespace pw::bluetooth::gatt {
// Parameters for registering a local GATT service.
struct LocalServiceInfo {
// Indicates whether this is a primary or secondary service.
bool primary;
// The UUID that identifies the type of this service.
// There may be multiple services with the same UUID.
Uuid type;
// The characteristics of this service.
Vector<Characteristic> characteristics;
// Handles of other services that are included by this service.
Vector<Handle> includes;
};
// Interface for serving a local GATT service. This is implemented by the API
// client.
class LocalServiceDelegate {
public:
virtual ~LocalServiceDelegate() = default;
// Called when there is a fatal error related to this service that forces the
// service to close. LocalServiceDelegate methods will no longer be called.
// This invalidates the associated LocalService. It is OK to destroy both
// LocalServiceDelegate and the associated LocalService from within this
// method.
virtual void OnError(Error error) = 0;
// This notifies the current configuration of a particular
// characteristic/descriptor for a particular peer. It will be called when the
// peer GATT client changes the configuration.
//
// The Bluetooth stack maintains the state of each peer's configuration across
// reconnections. As such, this method will also be called when a peer
// connects for each characteristic with the initial, persisted state of the
// newly-connected peer's configuration. However, clients should not rely on
// this state being persisted indefinitely by the Bluetooth stack.
//
// Parameters:
// `peer_id` - The PeerId of the GATT client associated with this particular
// CCC.
// `handle` - The handle of the characteristic associated with the `notify`
// and `indicate` parameters.
// `notify` - True if the client has enabled notifications, false otherwise.
// `indicate` - True if the client has enabled indications, false otherwise.
virtual void CharacteristicConfiguration(PeerId peer_id,
Handle handle,
bool notify,
bool indicate) = 0;
// Called when a peer requests to read the value of a characteristic or
// descriptor. It is guaranteed that the peer satisfies the permssions
// associated with this attribute.
//
// Parameters:
// `peer_id` - The PeerId of the GATT client making the read request.
// `handle` - The handle of the requested descriptor/characteristic.
// `offset` - The offset at which to start reading the requested value.
// `result_callback` - Called with the value of the characteristic on success,
// or an Error on failure. The value will be truncated to fit in the MTU
// if necessary. It is OK to call `result_callback` in `ReadValue`.
virtual void ReadValue(
PeerId peer_id,
Handle handle,
uint32_t offset,
Function<void(Result<Error, span<const std::byte>>)> result_callback) = 0;
// Called when a peer issues a request to write the value of a characteristic
// or descriptor. It is guaranteed that the peer satisfies the permissions
// associated with this attribute.
//
// Parameters:
// `peer_id` - The PeerId of the GATT client making the write request.
// `handle` - The handle of the requested descriptor/characteristic.
// `offset` - The offset at which to start writing the requested value. If the
// offset is 0, any existing value should be overwritten by the new value.
// Otherwise, the existing value between offset:(offset + len(value))
// should be changed to `value`.
// `value` - The new value for the descriptor/characteristic.
// `status_callback` - Called with the result of the write.
virtual void WriteValue(PeerId peer_id,
Handle handle,
uint32_t offset,
span<const std::byte> value,
Function<void(Result<Error>)> status_callback) = 0;
// Called when the MTU of a peer is updated. Also called for peers that are
// already connected when the server is published. This method is safe to
// ignore if you do not care about the MTU. It is intended for use cases where
// throughput needs to be optimized.
virtual void MtuUpdate(PeerId peer_id, uint16_t mtu) = 0;
};
// LocalService is valid for the lifetime of a published GATT service. It is
// used to control the service and send notifications/indications.
class LocalService {
public:
// The parameters used to signal a characteristic value change from a
// LocalService to a peer.
struct ValueChangedParameters {
// The PeerIds of the peers to signal. The LocalService should respect the
// Characteristic Configuration associated with a peer+handle when deciding
// whether to signal it. If empty, all peers are signalled.
Vector<PeerId> peer_ids;
// The handle of the characteristic value being signaled.
Handle handle;
// The new value for the descriptor/characteristic.
span<const std::byte> value;
};
virtual ~LocalService() = default;
// Returns the unique handle assigned to this service.
virtual Handle GetHandle() = 0;
// Sends a notification to peers. Notifications should be used instead of
// indications when the service does *not* require peer confirmation of the
// update.
//
// Notifications should not be sent to peers which have not enabled
// notifications on a particular characteristic - if they are sent, they will
// not be propagated. The Bluetooth stack will track this configuration for
// the lifetime of the service.
//
// Parameters:
// `parameters` - The parameters associated with the changed characteristic.
// `completion_callback` - Called when the notification has been sent.
// Additional values should not be notified until this callback is called.
virtual void NotifyValue(const ValueChangedParameters& parameters,
Closure completion_callback) = 0;
// Sends an indication to peers. Indications should be used instead of
// notifications when the service *does* require peer confirmation of the
// update.
//
// Indications should not be sent to peers which have not enabled indications
// on a particular characteristic - if they are sent, they will not be
// propagated. The Bluetooth stack will track this configuration for the
// lifetime of the service.
//
// If any of the peers in `update.peer_ids` fails to confirm the indication
// within the ATT transaction timeout (30 seconds per Bluetooth 5.2 Vol. 4
// Part G 3.3.3), the link between the peer and the local adapter will be
// closed.
//
// Parameters:
// `parameters` - The parameters associated with the changed characteristic.
// `confirmation` - When all the peers listed in `parameters.peer_ids` have
// confirmed the indication, `confirmation` is called. If the
// implementation wishes to receive indication confirmations on a per-peer
// basis, they should send this event with a single PeerId in
// `parameters.peer_ids`. Additional values should not be indicated until
// this callback is called.
virtual void IndicateValue(const ValueChangedParameters& parameters,
Function<void(Result<Error>)> confirmation) = 0;
};
// Interface for a GATT server that serves many GATT services.
class Server {
public:
enum class PublishServiceError {
kInternalError = 0,
/// Invalid service UUID provided.
kInvalidUuid = 1,
// Invalid service characteristics provided.
kInvalidCharacteristics = 2,
// Invalid service includes provided.
kInvalidIncludes = 3,
};
virtual ~Server() = default;
// Publishes the service defined by `info` and implemented by `delegate` so
// that it is available to all remote peers.
//
// The caller must assign distinct handles to the characteristics and
// descriptors listed in `info`. These identifiers will be used in requests
// sent to `delegate`. On success, a `LocalService` is returned. When the
// `LocalService` is destroyed or an error occurs
// (LocalServiceDelegate.OnError), the service will be unpublished.
virtual void PublishService(
LocalServiceInfo info,
LocalServiceDelegate* delegate,
Function<
void(Result<PublishServiceError, std::unique_ptr<LocalService>>)>&&
result_callback) = 0;
};
} // namespace pw::bluetooth::gatt