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/advertising_data.h" 19 #include "pw_bluetooth_sapphire/internal/host/common/identifier.h" 20 #include "pw_bluetooth_sapphire/internal/host/common/weak_self.h" 21 #include "pw_bluetooth_sapphire/internal/host/gap/gap.h" 22 #include "pw_bluetooth_sapphire/internal/host/hci-spec/constants.h" 23 #include "pw_bluetooth_sapphire/internal/host/hci/low_energy_advertiser.h" 24 #include "pw_bluetooth_sapphire/internal/host/hci/low_energy_connection.h" 25 26 namespace bt { 27 28 namespace hci { 29 class Connection; 30 class LocalAddressDelegate; 31 class Transport; 32 } // namespace hci 33 34 namespace gap { 35 36 using AdvertisementId = Identifier<uint64_t>; 37 constexpr AdvertisementId kInvalidAdvertisementId(0u); 38 39 class LowEnergyAdvertisingManager; 40 41 // Represents an active advertising instance. Stops the associated advertisement 42 // upon destruction. 43 class AdvertisementInstance final { 44 public: 45 // The default constructor initializes an instance with an invalid ID. 46 AdvertisementInstance(); 47 48 AdvertisementInstance(AdvertisementId advertisement_id, 49 fit::function<void(AdvertisementId)> stop_advertising); 50 AdvertisementInstance(AdvertisementInstance && other)51 AdvertisementInstance(AdvertisementInstance&& other) { Move(&other); } 52 AdvertisementInstance& operator=(AdvertisementInstance&& other) { 53 Move(&other); 54 return *this; 55 } 56 57 ~AdvertisementInstance(); 58 id()59 AdvertisementId id() const { return id_; } 60 61 private: 62 void Move(AdvertisementInstance* other); 63 void Reset(); 64 65 AdvertisementId id_; 66 fit::function<void(AdvertisementId)> stop_advertising_; 67 68 BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(AdvertisementInstance); 69 }; 70 71 // Enum values for determining the advertising interval range. These ranges come 72 // from Core Specification v5.1, Vol 3, Part C, Appendix A (see also the 73 // constants defined in gap.h). 74 enum class AdvertisingInterval { 75 FAST1, 76 FAST2, 77 SLOW, 78 }; 79 80 class LowEnergyAdvertisingManager { 81 public: 82 LowEnergyAdvertisingManager(hci::LowEnergyAdvertiser* advertiser, 83 hci::LocalAddressDelegate* local_addr_delegate); 84 virtual ~LowEnergyAdvertisingManager(); 85 86 // Returns true if the controller is currently advertising. advertising()87 bool advertising() const { return !advertisements_.empty(); } 88 89 // Asynchronously attempts to start advertising a set of |data| with 90 // additional scan response data |scan_rsp|. 91 // 92 // If |connect_callback| is provided, the advertisement will be connectable 93 // and it will be called with the returned advertisement_id and a pointer to 94 // the new connection, at which point the advertisement will have been 95 // stopped. 96 // 97 // Returns false if the parameters represent an invalid advertisement: 98 // * if |anonymous| is true but |callback| is set 99 // 100 // |status_callback| may be called synchronously within this function. 101 // |status_callback| provides one of: 102 // - an |advertisement_id|, which can be used to stop advertising 103 // or disambiguate calls to |callback|, and a success |status|. 104 // - kInvalidAdvertisementId and an error indication in |status|: 105 // * HostError::kInvalidParameters if the advertising parameters 106 // are invalid (e.g. |data| is too large). 107 // * HostError::kNotSupported if another set cannot be advertised 108 // or if the requested parameters are not supported by the hardware. 109 // * HostError::kProtocolError with a HCI error reported from 110 // the controller, otherwise. 111 using ConnectionCallback = 112 fit::function<void(AdvertisementId advertisement_id, 113 std::unique_ptr<hci::LowEnergyConnection> link)>; 114 using AdvertisingStatusCallback = 115 fit::function<void(AdvertisementInstance instance, hci::Result<> status)>; 116 void StartAdvertising(AdvertisingData data, 117 AdvertisingData scan_rsp, 118 ConnectionCallback connect_callback, 119 AdvertisingInterval interval, 120 bool extended_pdu, 121 bool anonymous, 122 bool include_tx_power_level, 123 std::optional<DeviceAddress::Type> address_type, 124 AdvertisingStatusCallback status_callback); 125 126 // Stop advertising the advertisement with the id |advertisement_id| 127 // Returns true if an advertisement was stopped, and false otherwise. 128 // This function is idempotent. 129 bool StopAdvertising(AdvertisementId advertisement_id); 130 131 private: 132 class ActiveAdvertisement; 133 134 // 0 is invalid, so we start at 1. 135 AdvertisementId::value_t next_advertisement_id_ = 1; 136 137 // Active advertisements, indexed by id. 138 // TODO(armansito): Use fbl::HashMap here (fxbug.dev/42143883) or move 139 // ActiveAdvertisement definition here and store by value (it is a small 140 // object). 141 std::unordered_map<AdvertisementId, std::unique_ptr<ActiveAdvertisement>> 142 advertisements_; 143 144 // Used to communicate with the controller. |advertiser_| must outlive this 145 // advertising manager. 146 hci::LowEnergyAdvertiser* advertiser_; // weak 147 148 // Used to obtain the local device address for advertising. Must outlive this 149 // advertising manager. 150 hci::LocalAddressDelegate* local_addr_delegate_; // weak 151 152 // Note: Should remain the last member so it'll be destroyed and 153 // invalidate it's pointers before other members are destroyed. 154 WeakSelf<LowEnergyAdvertisingManager> weak_self_; 155 156 BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(LowEnergyAdvertisingManager); 157 }; 158 159 } // namespace gap 160 } // namespace bt 161