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