• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <cstdint>
17 #include <memory>
18 
19 #include "pw_bluetooth/gatt/error.h"
20 #include "pw_bluetooth/gatt/types.h"
21 #include "pw_bluetooth/internal/raii_ptr.h"
22 #include "pw_bluetooth/result.h"
23 #include "pw_bluetooth/types.h"
24 #include "pw_containers/vector.h"
25 #include "pw_function/function.h"
26 #include "pw_span/span.h"
27 #include "pw_status/status.h"
28 
29 namespace pw::bluetooth::gatt {
30 
31 /// Parameters for registering a local GATT service.
32 struct LocalServiceInfo {
33   /// A unique (within a Server) handle identifying this service.
34   Handle handle;
35 
36   /// Indicates whether this is a primary or secondary service.
37   bool primary;
38 
39   /// The UUID that identifies the type of this service.
40   /// There may be multiple services with the same UUID.
41   Uuid type;
42 
43   /// The characteristics of this service.
44   span<const Characteristic> characteristics;
45 
46   /// Handles of other services that are included by this service.
47   span<const Handle> includes;
48 };
49 
50 /// Interface for serving a local GATT service. This is implemented by the API
51 /// client.
52 class LocalServiceDelegate {
53  public:
54   virtual ~LocalServiceDelegate() = default;
55 
56   /// Called when there is a fatal error related to this service that forces the
57   /// service to close. LocalServiceDelegate methods will no longer be called.
58   /// This invalidates the associated LocalService. It is OK to destroy both
59   /// `LocalServiceDelegate` and the associated `LocalService::Ptr` from within
60   /// this method.
61   virtual void OnError(Error error) = 0;
62 
63   /// This notifies the current configuration of a particular
64   /// characteristic/descriptor for a particular peer. It will be called when
65   /// the peer GATT client changes the configuration.
66   ///
67   /// The Bluetooth stack maintains the state of each peer's configuration
68   /// across reconnections. As such, this method will be called with both
69   /// `notify` and `indicate` set to false for each characteristic when a peer
70   /// disconnects. Also, when a peer reconnects this method will be called again
71   /// with the initial, persisted state of the newly-connected peer's
72   /// configuration. However, clients should not rely on this state being
73   /// persisted indefinitely by the Bluetooth stack.
74   ///
75   /// @param peer_id The PeerId of the GATT client associated with this
76   /// particular CCC.
77   /// @param handle The handle of the characteristic associated with the
78   /// `notify` and `indicate` parameters.
79   /// @param notify True if the client has enabled notifications, false
80   /// otherwise.
81   /// @param indicate True if the client has enabled indications, false
82   /// otherwise.
83   virtual void CharacteristicConfiguration(PeerId peer_id,
84                                            Handle handle,
85                                            bool notify,
86                                            bool indicate) = 0;
87 
88   /// Called when a peer requests to read the value of a characteristic or
89   /// descriptor. It is guaranteed that the peer satisfies the permissions
90   /// associated with this attribute.
91   ///
92   /// @param peer_id The PeerId of the GATT client making the read request.
93   /// @param handle The handle of the requested descriptor/characteristic.
94   /// @param offset The offset at which to start reading the requested value.
95   /// @param result_callback Called with the value of the characteristic on
96   /// success, or an Error on failure. The value will be truncated to fit in the
97   /// MTU if necessary. It is OK to call `result_callback` in `ReadValue`.
98   virtual void ReadValue(PeerId peer_id,
99                          Handle handle,
100                          uint32_t offset,
101                          Function<void(Result<Error, span<const std::byte>>)>&&
102                              result_callback) = 0;
103 
104   /// Called when a peer issues a request to write the value of a characteristic
105   /// or descriptor. It is guaranteed that the peer satisfies the permissions
106   /// associated with this attribute.
107   ///
108   /// @param peer_id The PeerId of the GATT client making the write request.
109   /// @param handle The handle of the requested descriptor/characteristic.
110   /// @param offset The offset at which to start writing the requested value. If
111   /// the offset is 0, any existing value should be overwritten by the new
112   /// value. Otherwise, the existing value between `offset:(offset +
113   /// len(value))` should be changed to `value`.
114   /// @param value The new value for the descriptor/characteristic.
115   /// @param status_callback Called with the result of the write.
116   virtual void WriteValue(PeerId peer_id,
117                           Handle handle,
118                           uint32_t offset,
119                           span<const std::byte> value,
120                           Function<void(Result<Error>)>&& status_callback) = 0;
121 
122   /// Called when the MTU of a peer is updated. Also called for peers that are
123   /// already connected when the server is published.
124   ///
125   /// Notifications and indications must fit in a single packet including both
126   /// the 3-byte notification/indication header and the user-provided payload.
127   /// If these are not used, the MTU can be safely ignored as it is intended for
128   /// use cases where the throughput needs to be optimized.
129   virtual void MtuUpdate(PeerId peer_id, uint16_t mtu) = 0;
130 };
131 
132 /// Interface provided by the backend to interact with a published service.
133 /// LocalService is valid for the lifetime of a published GATT service. It is
134 /// used to control the service and send notifications/indications.
135 class LocalService {
136  public:
137   /// The parameters used to signal a characteristic value change from a
138   /// LocalService to a peer.
139   struct ValueChangedParameters {
140     /// The PeerIds of the peers to signal. The LocalService should respect the
141     /// Characteristic Configuration associated with a peer+handle when deciding
142     /// whether to signal it. If empty, all peers are signalled.
143     span<const PeerId> peer_ids;
144     /// The handle of the characteristic value being signaled.
145     Handle handle;
146     /// The new value for the descriptor/characteristic.
147     span<const std::byte> value;
148   };
149 
150   /// The Result type for a ValueChanged indication or notification message. The
151   /// error can be locally generated for notifications and either locally or
152   /// remotely generated for indications.
153   using ValueChangedResult = Result<Error>;
154 
155   /// The callback type for a ValueChanged indication or notification
156   /// completion.
157   using ValueChangedCallback = Function<void(ValueChangedResult)>;
158 
159   virtual ~LocalService() = default;
160 
161   /// Sends a notification to peers. Notifications should be used instead of
162   /// indications when the service does *not* require peer confirmation of the
163   /// update.
164   ///
165   /// Notifications should not be sent to peers which have not enabled
166   /// notifications on a particular characteristic or that have disconnected
167   /// since - if they are sent, they will not be propagated and the
168   /// `completion_callback` will be called with an error condition. The
169   /// Bluetooth stack will track this configuration for the lifetime of the
170   /// service.
171   ///
172   /// The maximum size of the `parameters.value` field depends on the MTU
173   /// negotiated with the peer. A 3-byte header plus the value contents must fit
174   /// in a packet of MTU bytes.
175   ///
176   /// @param parameters The parameters associated with the changed
177   /// characteristic.
178   /// @param completion_callback Called when the notification has been sent to
179   /// all peers or an error is produced when trying to send the notification to
180   /// any of the peers. This function is called only once when all associated
181   /// work is done, if the implementation wishes to receive a call on a
182   /// per-peer basis, they should send this event with a single PeerId in
183   /// `parameters.peer_ids`. Additional values should not be notified until
184   /// this callback is called.
185   virtual void NotifyValue(const ValueChangedParameters& parameters,
186                            ValueChangedCallback&& completion_callback) = 0;
187 
188   /// Sends an indication to peers. Indications should be used instead of
189   /// notifications when the service *does* require peer confirmation of the
190   /// update.
191   ///
192   /// Indications should not be sent to peers which have not enabled indications
193   /// on a particular characteristic - if they are sent, they will not be
194   /// propagated. The Bluetooth stack will track this configuration for the
195   /// lifetime of the service.
196   ///
197   /// If any of the peers in `parameters.peer_ids` fails to confirm the
198   /// indication within the ATT transaction timeout (30 seconds per
199   /// Bluetooth 5.2 Vol. 4 Part G 3.3.3), the link between the peer and the
200   /// local adapter will be closed.
201   ///
202   /// The maximum size of the `parameters.value` field depends on the MTU
203   /// negotiated with the peer. A 3-byte header plus the value contents must fit
204   /// in a packet of MTU bytes.
205   ///
206   /// @param parameters The parameters associated with the changed
207   /// characteristic.
208   /// @param confirmation When all the peers listed in `parameters.peer_ids`
209   /// have confirmed the indication, `confirmation` is called. If the
210   /// implementation wishes to receive indication confirmations on a per-peer
211   /// basis, they should send this event with a single PeerId in
212   /// `parameters.peer_ids`. Additional values should not be indicated until
213   /// this callback is called.
214   virtual void IndicateValue(const ValueChangedParameters& parameters,
215                              ValueChangedCallback&& confirmation) = 0;
216 
217  private:
218   /// Unpublish the local service. This method is called by the
219   /// ~LocalService::Ptr() when it goes out of scope, the API client should
220   /// never call this method.
221   virtual void UnpublishService() = 0;
222 
223  public:
224   /// Movable LocalService smart pointer. When the LocalService::Ptr object is
225   /// destroyed the service will be unpublished.
226   using Ptr = internal::RaiiPtr<LocalService, &LocalService::UnpublishService>;
227 };
228 
229 /// Interface for a GATT server that serves many GATT services.
230 class Server {
231  public:
232   enum class PublishServiceError {
233     kInternalError = 0,
234 
235     /// The service handle provided was not unique.
236     kInvalidHandle = 1,
237 
238     /// Invalid service UUID provided.
239     kInvalidUuid = 2,
240 
241     /// Invalid service characteristics provided.
242     kInvalidCharacteristics = 3,
243 
244     /// Invalid service includes provided.
245     kInvalidIncludes = 4,
246   };
247 
248   /// The Result passed by PublishService.
249   using PublishServiceResult = Result<PublishServiceError, LocalService::Ptr>;
250 
251   virtual ~Server() = default;
252 
253   /// Publishes the service defined by `info` and implemented by `delegate` so
254   /// that it is available to all remote peers.
255   ///
256   /// The caller must assign distinct handles to the characteristics and
257   /// descriptors listed in `info`. These identifiers will be used in requests
258   /// sent to `delegate`. On success, a `LocalService::Ptr` is returned. When
259   /// the `LocalService::Ptr` is destroyed or an error occurs
260   /// (LocalServiceDelegate.OnError), the service will be unpublished.
261   virtual void PublishService(
262       const LocalServiceInfo& info,
263       LocalServiceDelegate* delegate,
264       Function<void(PublishServiceResult)>&& result_callback) = 0;
265 };
266 
267 }  // namespace pw::bluetooth::gatt
268