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