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 <map> 19 #include <queue> 20 #include <unordered_map> 21 22 #include "pw_bluetooth_sapphire/internal/host/att/error.h" 23 #include "pw_bluetooth_sapphire/internal/host/common/macros.h" 24 #include "pw_bluetooth_sapphire/internal/host/gatt/client.h" 25 #include "pw_bluetooth_sapphire/internal/host/gatt/gatt_defs.h" 26 27 namespace bt::gatt { 28 29 class Client; 30 31 // Used by a RemoteService to represent one of its characteristics. This object 32 // maintains information about a characteristic (such as its descriptors, known 33 // permissions, etc) and is responsible for routing notifications to subscribed 34 // clients. 35 // 36 // Instances are created and owned by a RemoteService. 37 // 38 // ID SCHEME: 39 // 40 // The ID that gets assigned to a RemoteCharacteristic is its value_handle 41 // The ID that gets assigned to a Descriptor is its handle. Looking up a 42 // descriptor by id from the service is logarithmic in the number of 43 // descriptors. 44 class RemoteCharacteristic final { 45 public: 46 using ValueCallback = 47 fit::function<void(const ByteBuffer&, bool maybe_truncated)>; 48 using NotifyStatusCallback = 49 fit::function<void(att::Result<>, IdType handler_id)>; 50 51 // We use an ordered map so that the Descriptors are exposed to the world in 52 // order 53 using DescriptorMap = std::map<DescriptorHandle, DescriptorData>; 54 55 RemoteCharacteristic(Client::WeakPtr client, const CharacteristicData& info); 56 ~RemoteCharacteristic(); 57 58 // The properties for this characteristic. properties()59 Properties properties() const { return info_.properties; } 60 61 // The extended properties for this characteristic. extended_properties()62 std::optional<ExtendedProperties> extended_properties() const { 63 return info_.extended_properties; 64 } 65 66 // ATT declaration data for this characteristic. info()67 const CharacteristicData& info() const { return info_; } 68 69 // Descriptors of this characteristic. descriptors()70 const DescriptorMap& descriptors() const { return descriptors_; } 71 72 private: 73 friend class RemoteService; 74 75 // The following private methods can only be called by a RemoteService. 76 77 // `service_changed` indicates whether destruction will occur due to a Service 78 // Changed notification, in which case this characteristic may no longer exist 79 // or may have been changed. set_service_changed(bool service_changed)80 void set_service_changed(bool service_changed) { 81 service_changed_ = service_changed; 82 } 83 84 // Updates the CharacteristicData |info_| with the Extended Properties that 85 // are read from the descriptors discovered in |DiscoverDescriptors|. 86 void UpdateDataWithExtendedProperties(ExtendedProperties ext_props); 87 88 // Discovers the descriptors of this characteristic and reports the status in 89 // |callback|. 90 // 91 // NOTE: The owning RemoteService is responsible for ensuring that this object 92 // outlives the discovery procedure. 93 void DiscoverDescriptors(att::Handle range_end, 94 att::ResultFunction<> callback); 95 96 // (See RemoteService::EnableNotifications in remote_service.h). 97 void EnableNotifications(ValueCallback value_callback, 98 NotifyStatusCallback status_callback); 99 bool DisableNotifications(IdType handler_id); 100 101 // Sends a request to disable notifications and indications. Called by 102 // DisableNotifications and destructor. 103 void DisableNotificationsInternal(); 104 105 // Resolves all pending notification subscription requests. Called by 106 // EnableNotifications(). 107 void ResolvePendingNotifyRequests(att::Result<> status); 108 109 // Called when a notification is received for this characteristic. 110 void HandleNotification(const ByteBuffer& value, bool maybe_truncated); 111 112 CharacteristicData info_; 113 DescriptorMap descriptors_; 114 bool discovery_error_; 115 116 // If true, this characteristic was in a service that has been changed. Values 117 // should not be read/written after a service is changed. 118 bool service_changed_ = false; 119 120 // Handle of the Client Characteristic Configuration descriptor, or 0 if none. 121 att::Handle ccc_handle_; 122 123 // Handle of the Characteristic Extended Properties descriptor, or 0 if none. 124 att::Handle ext_prop_handle_; 125 126 // Represents a pending request to subscribe to notifications or indications. 127 struct PendingNotifyRequest { 128 PendingNotifyRequest(ValueCallback value_callback, 129 NotifyStatusCallback status_callback); 130 131 PendingNotifyRequest() = default; 132 PendingNotifyRequest(PendingNotifyRequest&&) = default; 133 134 ValueCallback value_callback; 135 NotifyStatusCallback status_callback; 136 }; 137 std::queue<PendingNotifyRequest> pending_notify_reqs_; 138 139 // Active notification handlers. 140 std::unordered_map<IdType, ValueCallback> notify_handlers_; 141 // Set to true while handlers in notify_handlers_ are being notified. 142 bool notifying_handlers_ = false; 143 std::vector<IdType> handlers_pending_disable_; 144 145 // The next available notification handler ID. 146 size_t next_notify_handler_id_; 147 148 // The GATT client bearer used for ATT requests. 149 Client::WeakPtr client_; 150 151 WeakSelf<RemoteCharacteristic> weak_self_; 152 153 BT_DISALLOW_COPY_ASSIGN_AND_MOVE(RemoteCharacteristic); 154 }; 155 156 } // namespace bt::gatt 157