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