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