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