1 // Copyright 2023 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 15 #pragma once 16 #include <lib/fit/function.h> 17 18 #include "pw_bluetooth_sapphire/internal/host/common/uuid.h" 19 #include "pw_bluetooth_sapphire/internal/host/gatt/gatt_defs.h" 20 #include "pw_bluetooth_sapphire/internal/host/gatt/local_service_manager.h" 21 #include "pw_bluetooth_sapphire/internal/host/gatt/persisted_data.h" 22 #include "pw_bluetooth_sapphire/internal/host/gatt/remote_service.h" 23 #include "pw_bluetooth_sapphire/internal/host/gatt/server.h" 24 #include "pw_bluetooth_sapphire/internal/host/gatt/types.h" 25 26 namespace bt { 27 28 namespace l2cap { 29 class Channel; 30 } // namespace l2cap 31 32 namespace gatt { 33 34 // This is the root object of the GATT layer. This object owns: 35 // 36 // * A single local attribute database 37 // * All client and server data bearers 38 // * L2CAP ATT fixed channels 39 class GATT : public WeakSelf<GATT> { 40 public: 41 using RemoteServiceWatcherId = uint64_t; 42 using PeerMtuListenerId = uint64_t; 43 44 // Constructs a production GATT object. 45 static std::unique_ptr<GATT> Create(); 46 47 GATT(); 48 virtual ~GATT() = default; 49 50 // Registers the given connection with the GATT profile without initiating 51 // service discovery. Once a connection is registered with GATT, the peer can 52 // access local services and clients can call the "Remote Service" methods 53 // below using |peer_id|. 54 // 55 // |peer_id|: The identifier for the peer device that the link belongs to. 56 // This is used to identify the peer while handling certain events. 57 // |client|: The GATT client specific to this connection. This can be a 58 // production |Client| or a 59 // |FakeClient| for testing. 60 // |server_factory|: Factory method for a GATT server that operates on this 61 // connection. This can 62 // be a production |Server| or a |MockServer| for testing. 63 // Note: the server handles GATT server procedures, but 64 // importantly does *not* store any GATT server state 65 // itself. 66 virtual void AddConnection(PeerId peer_id, 67 std::unique_ptr<Client> client, 68 Server::FactoryFunction server_factory) = 0; 69 70 // Unregisters the GATT profile connection to the peer with Id |peer_id|. 71 virtual void RemoveConnection(PeerId peer_id) = 0; 72 73 // |PeerMtuListener| will be notified when any MTU negotiation completes 74 // without an unrecoverable error. The PeerId is the peer using that MTU, and 75 // the uint16_t is the MTU. 76 using PeerMtuListener = fit::function<void(PeerId, uint16_t)>; 77 virtual PeerMtuListenerId RegisterPeerMtuListener( 78 PeerMtuListener listener) = 0; 79 80 // Unregisters the PeerMtuListener associated with |listener_id|. Returns true 81 // if a listener was successfully unregistered, or false if |listener_id| was 82 // not associated with an active listener. 83 virtual bool UnregisterPeerMtuListener(PeerMtuListenerId listener_id) = 0; 84 85 // ============== 86 // Local Services 87 // ============== 88 // 89 // The methods below are for managing local GATT services that are available 90 // to data bearers in the server role. 91 92 // Registers the GATT service hierarchy represented by |service| with the 93 // local attribute database. Once successfully registered, the service will 94 // be available to remote clients. 95 // 96 // Objects under |service| must have unique identifiers to aid in value 97 // request handling. These identifiers will be passed to |read_handler| and 98 // |write_handler|. 99 // 100 // The provided handlers will be called to handle remote initiated 101 // transactions targeting the service. 102 // 103 // This method returns an opaque identifier on successful registration, 104 // which can be used by the caller to refer to the service in the future. This 105 // ID will be returned via |callback|. 106 // 107 // Returns |kInvalidId| on failure. Registration can fail if the attribute 108 // database has run out of handles or if the hierarchy contains 109 // characteristics or descriptors with repeated IDs. 110 using ServiceIdCallback = fit::function<void(IdType)>; 111 virtual void RegisterService(ServicePtr service, 112 ServiceIdCallback callback, 113 ReadHandler read_handler, 114 WriteHandler write_handler, 115 ClientConfigCallback ccc_callback) = 0; 116 117 // Unregisters the GATT service hierarchy identified by |service_id|. Has no 118 // effect if |service_id| is not a registered id. 119 virtual void UnregisterService(IdType service_id) = 0; 120 121 // Sends a characteristic handle-value notification|indication to a peer that 122 // has configured the characteristic for notifications|indications. Does 123 // nothing if the given peer has not configured the characteristic. 124 // 125 // |service_id|: The GATT service that the characteristic belongs to. 126 // |chrc_id|: The GATT characteristic that will be notified. 127 // |peer_id|: ID of the peer that the notification/indication will be sent to. 128 // |value|: The attribute value that will be included in the notification. 129 // |indicate_cb|: If nullptr, a notification will be sent. Otherwise, an 130 // indication will be attempted, and |indicate_cb| will be resolved when 131 // the indication is acknowledged by the peer or fails (e.g. if the peer is 132 // not connected, not configured for indications, or fails to confirm the 133 // indication within the ATT timeout of 30s (v5.3, Vol. 3, Part F 3.3.3)). 134 // 135 // TODO(fxbug.dev/42161294): Revise this API to involve fewer lookups. 136 virtual void SendUpdate(IdType service_id, 137 IdType chrc_id, 138 PeerId peer_id, 139 ::std::vector<uint8_t> value, 140 IndicationCallback indicate_cb) = 0; 141 142 // Like SendUpdate, but instead of updating a particular peer, sends a 143 // notification|indication to all connected peers that have configured 144 // notifications|indications. |indicate_cb|: If nullptr, notifications will be 145 // sent. Otherwise, indications will be sent, and 146 // |indicate_cb| will be resolved after all of the indications are 147 // successfully confirmed, or when any of the 148 // connected+configured-for-indications peers fail to confirm the indication 149 // within the ATT timeout of 30s (v5.3, Vol. 3, Part F 3.3.3)). 150 virtual void UpdateConnectedPeers(IdType service_id, 151 IdType chrc_id, 152 ::std::vector<uint8_t> value, 153 IndicationCallback indicate_cb) = 0; 154 155 // Sets a callback to run when certain local GATT database changes occur. 156 // These changes are to those database attributes which need to be persisted 157 // accross reconnects by bonded peers. This is used by the GAP adapter to 158 // store these changes in the peer cache. This should only be called by the 159 // GAP adapter. 160 virtual void SetPersistServiceChangedCCCCallback( 161 PersistServiceChangedCCCCallback callback) = 0; 162 163 // Sets a callback to run when a peer connects. This used to set those 164 // database attributes which need to be persisted accross reconnects by bonded 165 // peers by reading them from the peer cache. This should only be called by 166 // the GAP adapter. 167 virtual void SetRetrieveServiceChangedCCCCallback( 168 RetrieveServiceChangedCCCCallback callback) = 0; 169 170 // =============== 171 // Remote Services 172 // =============== 173 // 174 // The methods below are for interacting with remote GATT services. These 175 // methods operate asynchronously. 176 177 // Initialize remote services (e.g. exchange MTU, perform service discovery) 178 // for the peer with the given |peer_id|. If |services_to_discover| is 179 // non-empty, only discover services with the given UUIDs. 180 virtual void InitializeClient(PeerId peer_id, 181 std::vector<UUID> services_to_discover) = 0; 182 183 // Register a handler that will be notified when remote services are added, 184 // modified, or removed on the peer |peer_id|. Returns an ID that can be used 185 // to unregister the handler. 186 virtual RemoteServiceWatcherId RegisterRemoteServiceWatcherForPeer( 187 PeerId peer_id, RemoteServiceWatcher watcher) = 0; 188 189 // Remove the remote service watcher with ID |watcher_id|. Returns true if the 190 // handler existed and was successfully removed. 191 virtual bool UnregisterRemoteServiceWatcher( 192 RemoteServiceWatcherId watcher_id) = 0; 193 194 // Returns the list of remote services that were found on the device with 195 // |peer_id|. If |peer_id| was registered but InitializeClient() has not been 196 // called yet, this request will be buffered until remote services have been 197 // discovered. If the connection is removed without discovery services, 198 // |callback| will be called with an error status. 199 virtual void ListServices(PeerId peer_id, 200 std::vector<UUID> uuids, 201 ServiceListCallback callback) = 0; 202 203 // Connects the RemoteService with the given identifier found on the device 204 // with |peer_id|. A pointer to the service will be returned if it exists, or 205 // nullptr will be returned otherwise. 206 virtual RemoteService::WeakPtr FindService(PeerId peer_id, 207 IdType service_id) = 0; 208 209 private: 210 BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(GATT); 211 }; 212 213 } // namespace gatt 214 } // namespace bt 215