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 "pw_bluetooth_sapphire/internal/host/hci/advertising_handle_map.h" 17 #include "pw_bluetooth_sapphire/internal/host/hci/low_energy_advertiser.h" 18 19 namespace bt::hci { 20 21 class Transport; 22 class SequentialCommandRunner; 23 24 // AndroidExtendedLowEnergyAdvertiser implements chip-based multiple adverting 25 // via Android's vendor extensions. AndroidExtendedLowEnergyAdvertiser 26 // implements a LowEnergyAdvertiser but uses the Android vendor HCI extension 27 // commands to interface with the controller instead of standard Bluetooth Core 28 // Specification 5.0+. This enables power efficient multiple advertising for 29 // chipsets using pre-5.0 versions of Bluetooth. 30 // 31 // For more information, see 32 // https://source.android.com/devices/bluetooth/hci_requirements 33 class AndroidExtendedLowEnergyAdvertiser final : public LowEnergyAdvertiser { 34 public: 35 // Create an AndroidExtendedLowEnergyAdvertiser. The maximum number of 36 // advertisements the controller can support (obtained via 37 // hci_spec::vendor::android::LEGetVendorCapabilities) should be passed to the 38 // constructor via the max_advertisements parameter. 39 explicit AndroidExtendedLowEnergyAdvertiser(hci::Transport::WeakPtr hci, 40 uint8_t max_advertisements); 41 ~AndroidExtendedLowEnergyAdvertiser() override; 42 43 // LowEnergyAdvertiser overrides: AllowsRandomAddressChange()44 bool AllowsRandomAddressChange() const override { return !IsAdvertising(); } 45 46 // Attempt to start advertising. See LowEnergyAdvertiser::StartAdvertising for 47 // full documentation. 48 // 49 // The number of advertising sets that can be supported is not fixed and the 50 // Controller can change it at any time. This method may report an error if 51 // the controller cannot currently support another advertising set. 52 void StartAdvertising(const DeviceAddress& address, 53 const AdvertisingData& data, 54 const AdvertisingData& scan_rsp, 55 const AdvertisingOptions& options, 56 ConnectionCallback connect_callback, 57 ResultFunction<> result_callback) override; 58 59 void StopAdvertising() override; 60 void StopAdvertising(const DeviceAddress& address, 61 bool extended_pdu) override; 62 63 void OnIncomingConnection( 64 hci_spec::ConnectionHandle handle, 65 pw::bluetooth::emboss::ConnectionRole role, 66 const DeviceAddress& peer_address, 67 const hci_spec::LEConnectionParameters& conn_params) override; 68 MaxAdvertisements()69 size_t MaxAdvertisements() const override { 70 return advertising_handle_map_.capacity(); 71 } 72 73 // Returns the last used advertising handle that was used for an advertising 74 // set when communicating with the controller. LastUsedHandleForTesting()75 std::optional<hci_spec::AdvertisingHandle> LastUsedHandleForTesting() const { 76 return advertising_handle_map_.LastUsedHandleForTesting(); 77 } 78 79 private: 80 struct StagedConnectionParameters { 81 pw::bluetooth::emboss::ConnectionRole role; 82 DeviceAddress peer_address; 83 hci_spec::LEConnectionParameters conn_params; 84 }; 85 86 CommandPacket BuildEnablePacket( 87 const DeviceAddress& address, 88 pw::bluetooth::emboss::GenericEnableParam enable, 89 bool extended_pdu) override; 90 91 std::optional<CommandPacket> BuildSetAdvertisingParams( 92 const DeviceAddress& address, 93 const AdvertisingEventProperties& properties, 94 pw::bluetooth::emboss::LEOwnAddressType own_address_type, 95 const AdvertisingIntervalRange& interval, 96 bool extended_pdu) override; 97 98 std::vector<CommandPacket> BuildSetAdvertisingData( 99 const DeviceAddress& address, 100 const AdvertisingData& data, 101 AdvFlags flags, 102 bool extended_pdu) override; 103 104 CommandPacket BuildUnsetAdvertisingData(const DeviceAddress& address, 105 bool extended_pdu) override; 106 107 std::vector<CommandPacket> BuildSetScanResponse(const DeviceAddress& address, 108 const AdvertisingData& data, 109 bool extended_pdu) override; 110 111 CommandPacket BuildUnsetScanResponse(const DeviceAddress& address, 112 bool extended_pdu) override; 113 114 CommandPacket BuildRemoveAdvertisingSet(const DeviceAddress& address, 115 bool extended_pdu) override; 116 117 void OnCurrentOperationComplete() override; 118 119 // Event handler for the LE multi-advertising state change sub-event 120 CommandChannel::EventCallbackResult OnAdvertisingStateChangedSubevent( 121 const EventPacket& event); 122 CommandChannel::EventHandlerId state_changed_event_handler_id_; 123 124 AdvertisingHandleMap advertising_handle_map_; 125 std::queue<fit::closure> op_queue_; 126 127 // Incoming connections to Android LE Multiple Advertising occur through two 128 // events: HCI_LE_Connection_Complete and LE multi-advertising state change 129 // subevent. The HCI_LE_Connection_Complete event provides the connection 130 // handle along with some other connection related parameters. Notably missing 131 // is the advertising handle, which we need to obtain the advertised device 132 // address. Until we receive the LE multi-advertising state change subevent, 133 // we stage these parameters. 134 std::unordered_map<hci_spec::ConnectionHandle, StagedConnectionParameters> 135 staged_connections_map_; 136 137 BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(AndroidExtendedLowEnergyAdvertiser); 138 }; 139 140 } // namespace bt::hci 141