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 <unordered_set> 19 20 #include "pw_bluetooth_sapphire/internal/host/att/att.h" 21 #include "pw_bluetooth_sapphire/internal/host/common/byte_buffer.h" 22 #include "pw_bluetooth_sapphire/internal/host/gatt/local_service_manager.h" 23 #include "pw_bluetooth_sapphire/internal/host/gatt/persisted_data.h" 24 25 namespace bt::gatt { 26 constexpr IdType kServiceChangedChrcId = 0u; 27 constexpr IdType kServerSupportedFeaturesChrcId = 1u; 28 29 // Callback to send an indication. Used to inject the GATT object's 30 // update-sending ability without requiring this service to carry a reference to 31 // GATT or Server. 32 // |chrc_id|: the service-defined ID of the characteristic to indicate 33 // |svc_id|: the gatt::GATT-defined ID of the service containing |chrc_id|. 34 // For example, to indicate a new service to a peer via the Service Changed 35 // chrc, one would invoke this with svc_id = the GenericAttributeService's 36 // service_id_, chrc_id = kServiceChangedChrcId, peer_id of the peer, and value 37 // = the att::Handle range of the new service. 38 using SendIndicationCallback = fit::function<void( 39 IdType svc_id, IdType chrc_id, PeerId peer_id, BufferView value)>; 40 41 // Implements the "Generic Attribute Profile Service" containing the "Service 42 // Changed" characteristic that is "...used to indicate to connected devices 43 // that services have changed (Vol 3, Part G, 7)." 44 class GenericAttributeService final { 45 public: 46 // Registers this service and makes this service the callee of the Service 47 // Changed callback. GATT remote clients must still request that they be sent 48 // indications for the Service Changed characteristic. Holds the 49 // LocalServiceManager pointer for this object's lifetime. Do not register 50 // multiple instances of this service in a single bt-host. 51 GenericAttributeService(LocalServiceManager::WeakPtr local_service_manager, 52 SendIndicationCallback send_indication_callback); 53 ~GenericAttributeService(); 54 55 // This callback is called when a client changes the CCC for the service 56 // changed characteristic to inform the upper layers of the stack to persist 57 // this value. SetPersistServiceChangedCCCCallback(PersistServiceChangedCCCCallback callback)58 void SetPersistServiceChangedCCCCallback( 59 PersistServiceChangedCCCCallback callback) { 60 persist_service_changed_ccc_callback_ = std::move(callback); 61 } 62 63 // Set the service changed indication subscription for a given peer. 64 void SetServiceChangedIndicationSubscription(PeerId peer_id, bool indicate); 65 service_id()66 inline IdType service_id() const { return service_id_; } 67 68 private: 69 void Register(); 70 71 // Send indications to subscribed clients when a service has changed. 72 void OnServiceChanged(IdType service_id, att::Handle start, att::Handle end); 73 74 // Data store against which to register and unregister this service. It must 75 // outlive this instance. 76 LocalServiceManager::WeakPtr local_service_manager_; 77 const SendIndicationCallback send_indication_callback_; 78 79 // Peers that have subscribed to indications. 80 std::unordered_set<PeerId> subscribed_peers_; 81 82 // Local service ID; hidden because registration is tied to instance lifetime. 83 IdType service_id_ = kInvalidId; 84 85 // Callback to inform uper stack layers to persist service changed CCC. 86 PersistServiceChangedCCCCallback persist_service_changed_ccc_callback_; 87 }; 88 89 } // namespace bt::gatt 90