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