• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <unordered_map>
17 
18 #include "pw_bluetooth_sapphire/internal/host/att/attribute.h"
19 #include "pw_bluetooth_sapphire/internal/host/att/database.h"
20 #include "pw_bluetooth_sapphire/internal/host/common/macros.h"
21 #include "pw_bluetooth_sapphire/internal/host/common/weak_self.h"
22 #include "pw_bluetooth_sapphire/internal/host/gatt/gatt_defs.h"
23 #include "pw_bluetooth_sapphire/internal/host/gatt/types.h"
24 
25 namespace bt::gatt {
26 
27 // Called to read the value of a dynamic characteristic or characteristic
28 // descriptor.
29 //   - |peer_id|: The PeerId of the peer making the request.
30 //   - |service_id|: Identifies the service that the object belongs to.
31 //   - |id|: Identifies the object to be read. This is a user assigned
32 //           identifier provided while registering the service.
33 //   - |offset|: The offset into the value that is being read.
34 //   - |responder|: Should be called to respond to the read request with a
35 //                  characteristic or descriptor value, or an ATT error code.
36 using ReadHandler = fit::function<void(PeerId peer_id,
37                                        IdType service_id,
38                                        IdType id,
39                                        uint16_t offset,
40                                        ReadResponder responder)>;
41 
42 // Called to write the value of a dynamic characteristic or characteristic
43 // descriptor.
44 //   - |peer_id|: The PeerId of the peer making the request.
45 //   - |service_id|: Identifies the service that the object belongs to.
46 //   - |id|: Identifies the object to be written. This is a user assigned
47 //           identifier provided while registering the service.
48 //   - |offset|: The offset into the value that is being written.
49 //   - |responder|: Should be called to respond to the write request with
50 //                  success or an ATT error code. This can be a null callback
51 //                  if the client has initiated a "Write Without Response"
52 //                  procedure, in which case a response is not required.
53 using WriteHandler = fit::function<void(PeerId peer_id,
54                                         IdType service_id,
55                                         IdType id,
56                                         uint16_t offset,
57                                         const ByteBuffer& value,
58                                         WriteResponder responder)>;
59 
60 // Called when the peer device with the given |peer_id| has enabled or disabled
61 // notifications/indications on the characteristic with id |chrc_id|.
62 using ClientConfigCallback = fit::function<void(IdType service_id,
63                                                 IdType chrc_id,
64                                                 PeerId peer_id,
65                                                 bool notify,
66                                                 bool indicate)>;
67 
68 // Called with the ID and range of attributes handles spanned (inclusive) by a
69 // service that was added or removed.
70 using ServiceChangedCallback =
71     fit::function<void(IdType service_id, att::Handle start, att::Handle end)>;
72 
73 // LocalServiceManager allows clients to implement GATT services. This
74 // internally maintains an attribute database and provides hooks for clients to
75 // respond to read and write requests, send notifications/indications,
76 // add/remove services, etc.
77 class LocalServiceManager final : public WeakSelf<LocalServiceManager> {
78  public:
79   LocalServiceManager();
80   // Even though this is a noop, cannot be defaulted due to forward declaration
81   // of ServiceData.
82   ~LocalServiceManager();
83 
84   // Registers the GATT service hierarchy represented by |service| with the
85   // local attribute database. Once successfully registered, the service will be
86   // available for discovery and other ATT protocol requests.
87   //
88   // This method returns an opaque identifier on successful registration, which
89   // can be used by the caller to refer to the service in the future.
90   //
91   // Returns |kInvalidId| on failure. Registration can fail if the attribute
92   // database has run out of handles or if the hierarchy contains
93   // characteristics or descriptors with repeated IDs. Objects under |service|
94   // must have unique identifiers to aid in value request handling.
95   IdType RegisterService(ServicePtr service,
96                          ReadHandler read_handler,
97                          WriteHandler write_handler,
98                          ClientConfigCallback ccc_callback);
99 
100   // Unregisters the GATT service hierarchy identified by |service_id|. Returns
101   // false if |service_id| is unrecognized.
102   bool UnregisterService(IdType service_id);
103 
104   // Returns the client characteristic configuration for the given |peer_id| and
105   // the characteristic identified by |service_id| and |chrc_id|. Returns false
106   // if |service_id| is unknown or no configurations exist for |chrc_id|.
107   struct ClientCharacteristicConfig {
108     att::Handle handle;
109     bool notify;
110     bool indicate;
111   };
112   bool GetCharacteristicConfig(IdType service_id,
113                                IdType chrc_id,
114                                PeerId peer_id,
115                                ClientCharacteristicConfig* out_config);
116 
117   // Erase any client characteristic configuration associated to a specific
118   // client and invoke its ClientConfigCallback to signal that notifications and
119   // indications are now disabled.
120   void DisconnectClient(PeerId peer_id);
121 
set_service_changed_callback(ServiceChangedCallback callback)122   void set_service_changed_callback(ServiceChangedCallback callback) {
123     service_changed_callback_ = std::move(callback);
124   }
125 
database()126   inline att::Database::WeakPtr database() { return db_->GetWeakPtr(); }
127 
128  private:
129   class ServiceData;
130 
131   std::unique_ptr<att::Database> db_;
132   IdType next_service_id_;
133 
134   // Mapping from service instance ids to ServiceData.
135   std::unordered_map<IdType, std::unique_ptr<ServiceData>> services_;
136 
137   ServiceChangedCallback service_changed_callback_;
138 
139   BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(LocalServiceManager);
140 };
141 
142 }  // namespace bt::gatt
143